diff --git a/lib/ansible/module_utils/azure_rm_common.py b/lib/ansible/module_utils/azure_rm_common.py index 7bc1fba7905..248b5d8eae0 100644 --- a/lib/ansible/module_utils/azure_rm_common.py +++ b/lib/ansible/module_utils/azure_rm_common.py @@ -149,6 +149,7 @@ try: from azure.mgmt.dns import DnsManagementClient from azure.mgmt.web import WebSiteManagementClient from azure.mgmt.containerservice import ContainerServiceClient + from azure.mgmt.marketplaceordering import MarketplaceOrderingAgreements from azure.storage.cloudstorageaccount import CloudStorageAccount from adal.authentication_context import AuthenticationContext from azure.mgmt.rdbms.postgresql import PostgreSQLManagementClient @@ -275,6 +276,7 @@ class AzureRMModuleBase(object): self._compute_client = None self._dns_client = None self._web_client = None + self._marketplace_client = None self._containerservice_client = None self._mysql_client = None self._postgresql_client = None @@ -1099,3 +1101,11 @@ class AzureRMModuleBase(object): api_version='2018-06-01') return self._containerinstance_client + + @property + def marketplace_client(self): + self.log('Getting marketplace agreement client') + if not self._marketplace_client: + self._marketplace_client = self.get_mgmt_svc_client(MarketplaceOrderingAgreements, + base_url=self._cloud_environment.endpoints.resource_manager) + return self._marketplace_client diff --git a/lib/ansible/modules/cloud/azure/azure_rm_storageaccount.py b/lib/ansible/modules/cloud/azure/azure_rm_storageaccount.py index 1cdc0ebc50e..fb0314e1570 100644 --- a/lib/ansible/modules/cloud/azure/azure_rm_storageaccount.py +++ b/lib/ansible/modules/cloud/azure/azure_rm_storageaccount.py @@ -51,6 +51,7 @@ options: - Premium_LRS - Standard_GRS - Standard_LRS + - StandardSSD_LRS - Standard_RAGRS - Standard_ZRS aliases: @@ -158,7 +159,8 @@ class AzureRMStorageAccount(AzureRMModuleBase): def __init__(self): self.module_arg_spec = dict( - account_type=dict(type='str', choices=[], aliases=['type']), + account_type=dict(type='str', choices=['Premium_LRS', 'Standard_GRS', 'Standard_LRS', 'StandardSSD_LRS', 'Standard_RAGRS', 'Standard_ZRS'], + aliases=['type']), custom_domain=dict(type='dict'), location=dict(type='str'), name=dict(type='str', required=True), diff --git a/lib/ansible/modules/cloud/azure/azure_rm_virtualmachine.py b/lib/ansible/modules/cloud/azure/azure_rm_virtualmachine.py index 51445c09c65..a63623d308d 100644 --- a/lib/ansible/modules/cloud/azure/azure_rm_virtualmachine.py +++ b/lib/ansible/modules/cloud/azure/azure_rm_virtualmachine.py @@ -284,6 +284,13 @@ options: promotion_code: description: - optional promotion code + accept_terms: + description: + - Accept terms for marketplace images that require it + - Only Azure service admin/account admin users can purchase images from the marketplace + type: bool + default: false + version_added: "2.7" extends_documentation_fragment: - azure @@ -292,7 +299,6 @@ extends_documentation_fragment: author: - "Chris Houseknecht (@chouseknecht)" - "Matt Davis (@nitzmahone)" - ''' EXAMPLES = ''' @@ -308,21 +314,27 @@ EXAMPLES = ''' sku: '7.1' version: latest +- name: Create an availability set for managed disk vm + azure_rm_availabilityset: + name: avs-managed-disk + resource_group: Testing + platform_update_domain_count: 5 + platform_fault_domain_count: 2 + sku: Aligned + - name: Create a VM with managed disk azure_rm_virtualmachine: resource_group: Testing - name: testvm001 - vm_size: Standard_D4 - managed_disk_type: Standard_LRS + name: vm-managed-disk admin_username: adminUser - ssh_public_keys: - - path: /home/adminUser/.ssh/authorized_keys - key_data: < insert yor ssh public key here... > + availability_set: avs-managed-disk + managed_disk_type: Standard_LRS image: offer: CoreOS publisher: CoreOS sku: Stable version: latest + vm_size: Standard_D4 - name: Create a VM with existing storage account and NIC azure_rm_virtualmachine: @@ -412,6 +424,35 @@ EXAMPLES = ''' name: customimage001 resource_group: Testing +- name: Create VM with spcified OS disk size + azure_rm_virtualmachine: + resource_group: Testing + name: big-os-disk + admin_username: chouseknecht + admin_password: + os_disk_size_gb: 512 + image: + offer: CentOS + publisher: OpenLogic + sku: '7.1' + version: latest + +- name: Create VM with OS and Plan, accepting the terms + azure_rm_virtualmachine: + resource_group: Testing + name: f5-nva + admin_username: chouseknecht + admin_password: + image: + publisher: f5-networks + offer: f5-big-ip-best + sku: f5-bigip-virtual-edition-200m-best-hourly + version: latest + plan: + name: f5-bigip-virtual-edition-200m-best-hourly + product: f5-big-ip-best + publisher: f5-networks + - name: Power Off azure_rm_virtualmachine: resource_group: Testing @@ -678,7 +719,8 @@ class AzureRMVirtualMachine(AzureRMModuleBase): restarted=dict(type='bool', default=False), started=dict(type='bool', default=True), data_disks=dict(type='list'), - plan=dict(type='dict') + plan=dict(type='dict'), + accept_terms=dict(type='bool', default=False) ) self.resource_group = None @@ -716,6 +758,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase): self.differences = None self.data_disks = None self.plan = None + self.accept_terms = None self.results = dict( changed=False, @@ -1079,6 +1122,24 @@ class AzureRMVirtualMachine(AzureRMModuleBase): vm_resource.storage_profile.data_disks = data_disks + # Before creating VM accept terms of plan if `accept_terms` is True + if self.accept_terms is True: + if not all([self.plan.get('name'), self.plan.get('product'), self.plan.get('publisher')]): + self.fail("parameter error: plan must be specified and include name, product, and publisher") + try: + plan_name = self.plan.get('name') + plan_product = self.plan.get('product') + plan_publisher = self.plan.get('publisher') + term = self.marketplace_client.marketplace_agreements.get( + publisher_id=plan_publisher, offer_id=plan_product, plan_id=plan_name) + term.accepted = True + agreement = self.marketplace_client.marketplace_agreements.create( + publisher_id=plan_publisher, offer_id=plan_product, plan_id=plan_name, parameters=term) + except Exception as exc: + self.fail(("Error accepting terms for virtual machine {0} with plan {1}. " + + "Only service admin/account admin users can purchase images " + + "from the marketplace. - {2}").format(self.name, self.plan, str(exc))) + self.log("Create virtual machine with parameters:") self.create_or_update_vm(vm_resource) @@ -1483,6 +1544,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase): self.image['offer'], self.image['sku'], self.image['version'])) + return None def get_custom_image_reference(self, name, resource_group=None): try: @@ -1499,6 +1561,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase): return self.compute_models.ImageReference(id=vm_image.id) self.fail("Error could not find image with name {0}".format(name)) + return None def get_availability_set(self, resource_group, name): try: diff --git a/packaging/requirements/requirements-azure.txt b/packaging/requirements/requirements-azure.txt index 027d31d8821..80d167835e6 100644 --- a/packaging/requirements/requirements-azure.txt +++ b/packaging/requirements/requirements-azure.txt @@ -10,6 +10,7 @@ azure-mgmt-containerregistry==2.0.0 azure-mgmt-containerservice==3.0.1 azure-mgmt-dns==1.2.0 azure-mgmt-keyvault==0.40.0 +azure-mgmt-marketplaceordering==0.1.0 azure-mgmt-network==1.7.1 azure-mgmt-nspkg==2.0.0 azure-mgmt-rdbms==1.2.0 diff --git a/test/integration/targets/azure_rm_virtualmachine/tasks/virtualmachine.yml b/test/integration/targets/azure_rm_virtualmachine/tasks/virtualmachine.yml index 7dd2c7d59d9..319d52fa84f 100644 --- a/test/integration/targets/azure_rm_virtualmachine/tasks/virtualmachine.yml +++ b/test/integration/targets/azure_rm_virtualmachine/tasks/virtualmachine.yml @@ -403,3 +403,57 @@ name: invalid-image register: fail_missing_custom_image_dict failed_when: fail_missing_custom_image_dict.msg != "Error could not find image with name invalid-image" + +## Tests possible when CI user acccount setup with required authority +#- name: Set test facts + #set_fact: + #image_paid: + #publisher: cognosys + #offer: ubuntu-14-04-lts + #sku: hardened-ubuntu-14-04 + #version: latest + #plan_paid: + #name: hardened-ubuntu-14-04 + #product: ubuntu-14-04-lts + #publisher: cognosys + +#- name: Create virtual machine with image and plan which requires acceptance of terms + #azure_rm_virtualmachine: + #resource_group: "{{ resource_group }}" + #name: testvm009 + #vm_size: Standard_A0 + #storage_account: "{{ storage_account }}" + #storage_container: testvm001 + #storage_blob: testvm003.vhd + #admin_username: adminuser + #admin_password: Password123! + #short_hostname: testvm + #os_type: Linux + #availability_set: "avbs{{ resource_group | hash('md5') | truncate(7, True, '') }}" + #image: "{{ image_paid }}" + #plan_paid: "{{ plan_paid }}" + #register: output + +#- assert: + #that: + #- output.changed + #- output.ansible_facts.azure_vm.properties.storageProfile.imageReference.publisher == image_paid.publisher + +#- name: Should be idempotent with image and plan which requires acceptance of terms + #azure_rm_virtualmachine: + #resource_group: "{{ resource_group }}" + #name: testvm009 + #vm_size: Standard_A0 + #storage_account: "{{ storage_account }}" + #storage_container: testvm001 + #storage_blob: testvm003.vhd + #admin_username: adminuser + #admin_password: Password123! + #short_hostname: testvm + #os_type: Linux + #availability_set: "avbs{{ resource_group | hash('md5') | truncate(7, True, '') }}" + #image: "{{ image_paid }}" + #plan_paid: "{{ plan_paid }}" + +#- assert: + #that: not output.changed diff --git a/test/runner/requirements/integration.cloud.azure.txt b/test/runner/requirements/integration.cloud.azure.txt index 027d31d8821..80d167835e6 100644 --- a/test/runner/requirements/integration.cloud.azure.txt +++ b/test/runner/requirements/integration.cloud.azure.txt @@ -10,6 +10,7 @@ azure-mgmt-containerregistry==2.0.0 azure-mgmt-containerservice==3.0.1 azure-mgmt-dns==1.2.0 azure-mgmt-keyvault==0.40.0 +azure-mgmt-marketplaceordering==0.1.0 azure-mgmt-network==1.7.1 azure-mgmt-nspkg==2.0.0 azure-mgmt-rdbms==1.2.0