Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ACA-1842: VM Image SKUs support in Ansible collection for Azure module creation #1719

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 226 additions & 0 deletions plugins/modules/azure_rm_imagesku_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
#!/usr/bin/python
#
# Copyright (c) 2024
# Hen Yaish <[email protected]>
#
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function

__metaclass__ = type

DOCUMENTATION = '''
---
module: azure_rm_imagesku_info

version_added: "2.4.0"

short_description: Get compute-related Image SKUs list

description:
- Get details for compute-related resource Image SKUs.

options:
location:
description:
- A region supported by current subscription.
type: str
offer:
description:
- The `Offer` refers to the specific product line of the operating system or software.
- The offer usually includes multiple versions or configurations of the product.
type: str
publisher:
description:
- The `Publisher` is the entity that provides the OS image. It could be Microsoft, Canonical (for Ubuntu), Red Hat, etc.
- It is a mandatory field that identifies the provider of the image.
type: str

extends_documentation_fragment:
- azure.azcollection.azure

author:
- Hen Yaish (@hyaish)

'''

EXAMPLES = '''
- name: Gather Resource Group info
azure.azcollection.azure_rm_resourcegroup_info:
name: "{{ resource_group }}"
register: rg_info

- name: List available Image SKUs for 0001-com-ubuntu-server-focal
azure.azcollection.azure_rm_imagesku_info:
location: westus
offer: 0001-com-ubuntu-server-focal
publisher: Canonical
register: available_image_skus_results
'''

RETURN = '''
available_skus:
description:
- List of Azure image SKUs for provisioning virtual machines.
returned: always
type: complex
contains:
name:
description:
- The specific SKU name or version.
returned: always
type: str
sample: "20_04-lts"
id:
description:
- The full Azure resource ID for the SKU.
returned: always
type: str
sample: "0001-com-ubuntu-server-focal/Skus/20_04-lts"
location:
description:
- The Azure region where the SKU is available.
returned: always
type: str
sample: "westus"
automatic_os_upgrade_supported:
description:
- Whether automatic OS upgrades are supported for this SKU.
returned: always
type: bool
sample: false
restrictions:
description:
- Restrictions that may apply to the use of this image SKU, such as region limitations or feature incompatibility.
returned: always
type: complex
contains:
type:
description:
- The type of restriction, which could include location-based restrictions or hardware compatibility issues.
type: str
returned: always
sample: "location"
values:
description:
- A list of restricted locations, regions, or zones where the image SKU cannot be used.
type: list
returned: always
sample: ["eastus", "westeurope"]
reason_code:
description:
- The reason for the restriction, such as quota limitations or specific hardware requirements.
type: str
sample: "NotSupported"
restriction_info:
description:
- Additional information about the restrictions, such as unsupported regions or features.
returned: always
type: complex
contains:
locations:
description:
- Locations where this SKU is restricted or unavailable.
type: list
sample: ["eastus"]
zones:
description:
- Availability zones within the region where this SKU is restricted.
type: list
sample: ["1", "2"]
'''


from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common import AzureRMModuleBase
try:
from azure.mgmt.compute import ComputeManagementClient
from azure.core.exceptions import HttpResponseError
except ImportError:
# This is handled in azure_rm_common
pass


class AzureRMImageskuInfo(AzureRMModuleBase):
def __init__(self):

self.module_arg_spec = dict(
location=dict(type='str'),
publisher=dict(type='str'),
offer=dict(type='str'),
)

self.results = dict(
available_skus=[],
count=0
)
self.location = None
self.publisher = None
self.offer = None
super(AzureRMImageskuInfo, self).__init__(derived_arg_spec=self.module_arg_spec,
supports_check_mode=True,
supports_tags=False)

def exec_module(self, **kwargs):
for key in self.module_arg_spec:
setattr(self, key, kwargs[key])

available_skus = self.list_skus()
self.results['available_skus'] = available_skus
self.results['count'] = len(available_skus)
return self.results

def list_skus(self):
Yaish25491 marked this conversation as resolved.
Show resolved Hide resolved
try:
compute_client = self.get_mgmt_svc_client(ComputeManagementClient,
base_url=self._cloud_environment.endpoints.resource_manager,
api_version='2021-07-01')
skus_result = compute_client.virtual_machine_images.list_skus(location=self.location,
publisher_name=self.publisher,
offer=self.offer)
available_skus = []

for sku_info in skus_result:
available_skus.append(sku_info.as_dict())
return available_skus

except HttpResponseError as e:
# Handle exceptions
raise e


def _match_location(loc, locations):
return next((x for x in locations if x.lower() == loc.lower()), None)


def _is_sku_available(sku_info, zone):
"""
The SKU is unavailable in the following cases:
1. regional restriction and the region is restricted
2. parameter "zone" is input which indicates only showing skus with availability zones.
Meanwhile, zonal restriction and all zones are restricted
"""
is_available = True
is_restrict_zone = False
is_restrict_location = False
if not sku_info.restrictions:
return is_available
for restriction in sku_info.restrictions:
if restriction.reason_code == 'NotAvailableForSubscription':
if restriction.type == 'Zone' and not (
set(sku_info.location_info[0].zones or []) - set(restriction.restriction_info.zones or [])):
is_restrict_zone = True
if restriction.type == 'Location' and (
sku_info.location_info[0].location in (restriction.restriction_info.locations or [])):
is_restrict_location = True
if is_restrict_location or (is_restrict_zone and zone):
is_available = False
break
return is_available


def main():
AzureRMImageskuInfo()


if __name__ == '__main__':
main()
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ all:
network: 10.42.8.0/24
subnet: 10.42.8.0/28

azure_test_image_skus:
network: 10.42.3.0/24
subnet: 10.42.3.0/28

vars:
ansible_connection: local
ansible_python_interpreter: "{{ ansible_playbook_python }}"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
- name: Set variables
ansible.builtin.include_tasks: setup.yml

- name: Set variables
ansible.builtin.set_fact:
network: 10.42.0.0/24
subnet: 10.42.0.0/28
vm_name: "vm{{ resource_group | hash('md5') | truncate(6, True, '') }}"
network_name: "vnet{{ resource_group | hash('md5') | truncate(6, True, '') }}"
subnet_name: "subnet{{ resource_group | hash('md5') | truncate(6, True, '') }}"
location: eastus
offer: 0001-com-ubuntu-server-focal
publisher: Canonical

- name: List available Image SKUs for 0001-com-ubuntu-server-focal
azure_rm_imagesku_info:
location: "{{ location }}"
offer: "{{ offer }}"
publisher: "{{ publisher }}"
register: available_image_skus_results

- name: Set specific 0001-com-ubuntu-server-focal image version
ansible.builtin.set_fact:
specific_image_name: "16.04.202104140"

- name: Get the first sku from the available skus list
ansible.builtin.set_fact:
first_image_sku_option: "{{ available_image_skus_results.available_skus[0] }}"

- name: SETUP | Create virtual network
azure_rm_virtualnetwork:
resource_group: "{{ resource_group }}"
name: "{{ network_name }}"
location: "{{ location }}"
address_prefixes: "{{ network }}"

- name: SETUP | Create subnet
azure_rm_subnet:
resource_group: "{{ resource_group }}"
name: "{{ subnet_name }}"
address_prefix: "{{ subnet }}"
virtual_network: "{{ network_name }}"

- name: Create VM with first Image SKU result
azure_rm_virtualmachine:
resource_group: "{{ resource_group }}"
name: "{{ vm_name }}"
admin_username: "testuser"
ssh_password_enabled: false
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please set the open ports, Now , The default 22 port was disallowed by policy!

Suggested change
ssh_password_enabled: false
ssh_password_enabled: false
open_ports:
- 33

ssh_public_keys:
- path: /home/testuser/.ssh/authorized_keys
key_data: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDfoYlIV4lTPZTv7hXaVwQQuqBgGs4yeNRX0SPo2+HQt9u4X7IGwrtXc0nEUm6LfaCikMH58bOL8f20NTGz285kxdFHZRcBXtqmnMz2rXwhK9gwq5h1khc+GzHtdcJXsGA4y0xuaNcidcg04jxAlN/06fwb/VYwwWTVbypNC0gpGEpWckCNm8vlDlA55sU5et0SZ+J0RKVvEaweUOeNbFZqckGPA384imfeYlADppK/7eAxqfBVadVvZG8IJk4yvATgaIENIFj2cXxqu2mQ/Bp5Wr45uApvJsFXmi+v/nkiOEV1QpLOnEwAZo6EfFS4CCQtsymxJCl1PxdJ5LD4ZOtP [email protected]"
vm_size: Standard_B1ms
virtual_network: "{{ network_name }}"
image:
offer: "{{ offer }}"
publisher: "{{ publisher }}"
sku: "{{ first_image_sku_option.name }}"
version: "latest"
register: vm_output

- name: Ensure VM was created using the specific image sku
ansible.builtin.assert:
that:
- vm_output.ansible_facts.azure_vm.storage_profile.image_reference.sku == first_image_sku_option.name

- name: Delete VM
azure_rm_virtualmachine:
resource_group: "{{ resource_group }}"
name: "{{ vm_name }}"
remove_on_absent: all_autocreated
state: absent

- name: Destroy subnet
azure_rm_subnet:
resource_group: "{{ resource_group }}"
virtual_network: "{{ network_name }}"
name: "{{ subnet_name }}"
state: absent

- name: Destroy availability set
azure_rm_availabilityset:
resource_group: "{{ resource_group }}"
name: "{{ availability_set }}"
state: absent

- name: Destroy storage account
azure_rm_storageaccount:
resource_group: "{{ resource_group }}"
name: "{{ storage_account }}"
force_delete_nonempty: true
state: absent

- name: Destroy virtual network
azure_rm_virtualnetwork:
resource_group: "{{ resource_group }}"
name: "{{ network_name }}"
state: absent