Beispiel #1
0
    def create_virtual_machine(
        self,
        location,
        resource_group_name,
        vm_name,
        size_name,
        nic_id,
        image_reference,
        username,
        password,
        custom_data=None,
        ssh_key=None,
    ):
        os_profile = OSProfile(
            computer_name=vm_name,
            admin_username=username,
            admin_password=password,
        )
        if custom_data:
            os_profile.custom_data = custom_data

        if ssh_key:
            os_profile.linux_configuration = LinuxConfiguration(
                ssh=SshConfiguration(public_keys=[
                    SshPublicKey(key_data=ssh_key),
                ], ))
        try:
            return self.compute_client.virtual_machines.begin_create_or_update(
                resource_group_name,
                vm_name,
                {
                    'location': location,
                    'os_profile': os_profile,
                    'hardware_profile': {
                        'vm_size': size_name
                    },
                    'storage_profile': {
                        'image_reference': {
                            'publisher': image_reference['publisher'],
                            'offer': image_reference['offer'],
                            'sku': image_reference['sku'],
                            'version': image_reference['version'],
                        },
                    },
                    'network_profile': {
                        'network_interfaces': [{
                            'id': nic_id,
                        }]
                    },
                },
            )
        except ClientException as exc:
            raise AzureBackendError(exc)
Beispiel #2
0
    def virtual_machine(
        self,
        name: str,
        network_interface: NetworkInterface = None,
        image: dict = None,
        size: str = "Standard_B2s",
        user: str = None,
        password: str = None,
        spot_instance: bool = True,
        max_price_per_hour: float = 2.0,
        disk_size_gb: int = 32,
        ssh_pubkey: str = None,
    ) -> VirtualMachine:
        """Get existing / Create new a Virtual Machine in Azure

        Args:
            name (str): Name of the virtual machine
            network_interface (NetworkInterface, optional): network interface to use. Defaults to None.
            image (dict, optional): image description to use. Defaults to None.
            size (str, optional): size of the VM. Defaults to "Standard_B2s".
            user (str, optional): default username. Defaults to None.
            password (str, optional): user's password. Defaults to None.
            spot_instance (bool, optional): Whether to deploy a spot / pay as you go instance. Defaults to True.
            max_price_per_hour (float, optional): Max price/hour in euros. Defaults to 2.0.
            disk_size_gb (int, optional): Size of the OS disk. Defaults to 32.
            ssh_pubkey (str, optional): SSH public key for logging in as user. Defaults to None.

        Raises:
            AzureError: If VM creation is not successful.

        Returns:
            VirtualMachine: The created virtual machine's descriptor.
        """
        try:
            vm = self.client(ComputeManagementClient).virtual_machines.get(
                self.rsg, name)
        except CloudError:
            if not network_interface:
                raise AzureError(
                    "Cannot create VM without network interface, please supply it."
                )

            self.logger.info(f"Creating virtual machine: {name}")
        else:
            self.logger.info(f"Found virtual machine: {name}")
            return vm

        vm_params = {
            "location": self.config["location"],
            "os_profile": {
                "computer_name": name,
                "admin_username": user,
                "admin_password": password
            },
            "hardware_profile": {
                "vm_size":
                size,
                "os_disk":
                OSDisk(disk_size_gb=disk_size_gb, create_option="FromImage"),
            },
            "storage_profile": {
                "image_reference": image
            },
            "network_profile": {
                "network_interfaces": [network_interface]
            },
            "tags": {
                "persistent": "0",
                "development": "1"
            },
            "plan": self.config["nvidia_plan"],
        }

        if spot_instance:
            # use Azure spot instance
            vm_params["priority"] = VirtualMachinePriorityTypes.spot
            # For Azure Spot virtual machines, the only supported value is 'Deallocate'
            vm_params[
                "eviction_policy"] = VirtualMachineEvictionPolicyTypes.deallocate
            # set max price
            vm_params["billing_profile"] = BillingProfile(
                max_price=max_price_per_hour)

        if ssh_pubkey:
            key_path = f"/home/{user}/.ssh/authorized_keys"
            pubkey = SshPublicKey(path=key_path, key_data=ssh_pubkey)
            vm_params["os_profile"][
                "linux_configuration"] = LinuxConfiguration(
                    ssh=SshConfiguration(public_keys=[pubkey]))

        self.logger.info(f"Creating VM:  {name}")

        vm_job = self.client(
            ComputeManagementClient).virtual_machines.create_or_update(
                self.rsg, name, vm_params)
        self._async_wait(vm_job)

        vm = self.client(ComputeManagementClient).virtual_machines.get(
            self.rsg, name)

        self.logger.info(f"Created VM: {vm.name}")
        return vm
Beispiel #3
0
  def create_virtual_machine(self, credentials, network_client, network_id,
                             parameters, vm_network_name):
    """ Creates an Azure virtual machine using the network interface created.
    Args:
      credentials: A ServicePrincipalCredentials instance, that can be used to
        access or create any resources.
      network_client: A NetworkManagementClient instance.
      network_id: The network id of the network interface created.
      parameters: A dict, containing all the parameters necessary to
        authenticate this user with Azure.
      vm_network_name: The name of the virtual machine to use.
    """
    resource_group = parameters[self.PARAM_RESOURCE_GROUP]
    storage_account = parameters[self.PARAM_STORAGE_ACCOUNT]
    zone = parameters[self.PARAM_ZONE]
    utils.log("Creating a Virtual Machine '{}'".format(vm_network_name))
    subscription_id = str(parameters[self.PARAM_SUBSCRIBER_ID])
    azure_instance_type = parameters[self.PARAM_INSTANCE_TYPE]
    compute_client = ComputeManagementClient(credentials, subscription_id)
    auth_keys_path = self.AUTHORIZED_KEYS_FILE.format(self.ADMIN_USERNAME)

    with open(auth_keys_path, 'r') as pub_ssh_key_fd:
      pub_ssh_key = pub_ssh_key_fd.read()

    public_keys = [SshPublicKey(path=auth_keys_path, key_data=pub_ssh_key)]
    ssh_config = SshConfiguration(public_keys=public_keys)
    linux_config = LinuxConfiguration(disable_password_authentication=True,
                                      ssh=ssh_config)
    os_profile = OSProfile(admin_username=self.ADMIN_USERNAME,
                           computer_name=vm_network_name,
                           linux_configuration=linux_config)

    hardware_profile = HardwareProfile(vm_size=azure_instance_type)

    network_profile = NetworkProfile(
      network_interfaces=[NetworkInterfaceReference(id=network_id)])

    virtual_hd = VirtualHardDisk(
      uri='https://{0}.blob.core.windows.net/vhds/{1}.vhd'.
        format(storage_account, vm_network_name))

    image_hd = VirtualHardDisk(uri=parameters[self.PARAM_IMAGE_ID])
    os_type = OperatingSystemTypes.linux
    os_disk = OSDisk(os_type=os_type, caching=CachingTypes.read_write,
                     create_option=DiskCreateOptionTypes.from_image,
                     name=vm_network_name, vhd=virtual_hd, image=image_hd)

    compute_client.virtual_machines.create_or_update(
      resource_group, vm_network_name, VirtualMachine(
        location=zone, os_profile=os_profile,
        hardware_profile=hardware_profile,
        network_profile=network_profile,
        storage_profile=StorageProfile(os_disk=os_disk)))

    # Sleep until an IP address gets associated with the VM.
    while True:
      public_ip_address = network_client.public_ip_addresses.get(resource_group,
                                                                 vm_network_name)
      if public_ip_address.ip_address:
        utils.log('Azure VM is available at {}'.
                  format(public_ip_address.ip_address))
        break
      utils.log("Waiting {} second(s) for IP address to be available".
                format(self.SLEEP_TIME))
      time.sleep(self.SLEEP_TIME)
Beispiel #4
0
    def exec_module(self, **kwargs):

        for key in list(self.module_arg_spec.keys()) + ['tags']:
            setattr(self, key, kwargs[key])

        # make sure options are lower case
        self.remove_on_absent = set(
            [resource.lower() for resource in self.remove_on_absent])

        changed = False
        results = dict()
        vmss = None
        disable_ssh_password = None
        vmss_dict = None
        virtual_network = None
        subnet = None

        resource_group = self.get_resource_group(self.resource_group)
        if not self.location:
            # Set default location
            self.location = resource_group.location

        if self.state == 'present':
            # Verify parameters and resolve any defaults

            if self.vm_size and not self.vm_size_is_valid():
                self.fail(
                    "Parameter error: vm_size {0} is not valid for your subscription and location."
                    .format(self.vm_size))

            # if self.virtual_network_name:
            #     virtual_network = self.get_virtual_network(self.virtual_network_name)

            if self.ssh_public_keys:
                msg = "Parameter error: expecting ssh_public_keys to be a list of type dict where " \
                    "each dict contains keys: path, key_data."
                for key in self.ssh_public_keys:
                    if not isinstance(key, dict):
                        self.fail(msg)
                    if not key.get('path') or not key.get('key_data'):
                        self.fail(msg)

            if self.image:
                if not self.image.get('publisher') or not self.image.get('offer') or not self.image.get('sku') \
                   or not self.image.get('version'):
                    self.error(
                        "parameter error: expecting image to contain publisher, offer, sku and version keys."
                    )
                image_version = self.get_image_version()
                if self.image['version'] == 'latest':
                    self.image['version'] = image_version.name
                    self.log("Using image version {0}".format(
                        self.image['version']))

            disable_ssh_password = not self.ssh_password_enabled

        try:
            self.log("Fetching virtual machine scale set {0}".format(
                self.name))
            vmss = self.compute_client.virtual_machine_scale_sets.get(
                self.resource_group, self.name)
            self.check_provisioning_state(vmss, self.state)
            vmss_dict = self.serialize_vmss(vmss)

            if self.state == 'present':
                differences = []
                results = vmss_dict

                if self.os_disk_caching and \
                   self.os_disk_caching != vmss_dict['properties']['virtualMachineProfile']['storageProfile']['osDisk']['caching']:
                    self.log(
                        'CHANGED: virtual machine scale set {0} - OS disk caching'
                        .format(self.name))
                    differences.append('OS Disk caching')
                    changed = True
                    vmss_dict['properties']['virtualMachineProfile'][
                        'storageProfile']['osDisk'][
                            'caching'] = self.os_disk_caching

                if self.capacity and \
                   self.capacity != vmss_dict['sku']['capacity']:
                    self.log(
                        'CHANGED: virtual machine scale set {0} - Capacity'.
                        format(self.name))
                    differences.append('Capacity')
                    changed = True
                    vmss_dict['sku']['capacity'] = self.capacity

                if self.data_disks and \
                   len(self.data_disks) != len(vmss_dict['properties']['virtualMachineProfile']['storageProfile']['dataDisks']):
                    self.log(
                        'CHANGED: virtual machine scale set {0} - Data Disks'.
                        format(self.name))
                    differences.append('Data Disks')
                    changed = True

                update_tags, vmss_dict['tags'] = self.update_tags(
                    vmss_dict.get('tags', dict()))
                if update_tags:
                    differences.append('Tags')
                    changed = True

                self.differences = differences

            elif self.state == 'absent':
                self.log(
                    "CHANGED: virtual machine scale set {0} exists and requested state is 'absent'"
                    .format(self.name))
                results = dict()
                changed = True

        except CloudError:
            self.log('Virtual machine scale set {0} does not exist'.format(
                self.name))
            if self.state == 'present':
                self.log(
                    "CHANGED: virtual machine scale set {0} does not exist but state is 'present'."
                    .format(self.name))
                changed = True

        self.results['changed'] = changed
        self.results['ansible_facts']['azure_vmss'] = results

        if self.check_mode:
            return self.results

        if changed:
            if self.state == 'present':
                if not vmss:
                    # Create the VMSS
                    self.log("Create virtual machine scale set {0}".format(
                        self.name))
                    self.results['actions'].append('Created VMSS {0}'.format(
                        self.name))

                    # Validate parameters
                    if not self.admin_username:
                        self.fail(
                            "Parameter error: admin_username required when creating a virtual machine scale set."
                        )

                    if self.os_type == 'Linux':
                        if disable_ssh_password and not self.ssh_public_keys:
                            self.fail(
                                "Parameter error: ssh_public_keys required when disabling SSH password."
                            )

                    if self.subnet_name:
                        subnet = self.get_subnet(self.virtual_network_name,
                                                 self.subnet_name)

                    if not self.virtual_network_name:
                        default_vnet = self.create_default_vnet()
                        virtual_network = default_vnet.id

                    if not self.short_hostname:
                        self.short_hostname = self.name

                    managed_disk = VirtualMachineScaleSetManagedDiskParameters(
                        storage_account_type=self.managed_disk_type)

                    vmss_resource = VirtualMachineScaleSet(
                        self.location,
                        tags=self.tags,
                        upgrade_policy=UpgradePolicy(mode=self.upgrade_policy),
                        sku=Sku(
                            name=self.vm_size,
                            capacity=self.capacity,
                            tier=self.tier,
                        ),
                        virtual_machine_profile=VirtualMachineScaleSetVMProfile(
                            os_profile=VirtualMachineScaleSetOSProfile(
                                admin_username=self.admin_username,
                                computer_name_prefix=self.short_hostname,
                            ),
                            storage_profile=
                            VirtualMachineScaleSetStorageProfile(
                                os_disk=VirtualMachineScaleSetOSDisk(
                                    managed_disk=managed_disk,
                                    create_option=DiskCreateOptionTypes.
                                    from_image,
                                    caching=self.os_disk_caching,
                                ),
                                image_reference=ImageReference(
                                    publisher=self.image['publisher'],
                                    offer=self.image['offer'],
                                    sku=self.image['sku'],
                                    version=self.image['version'],
                                ),
                            ),
                            network_profile=
                            VirtualMachineScaleSetNetworkProfile(
                                network_interface_configurations=[
                                    VirtualMachineScaleSetNetworkConfiguration(
                                        name=self.name,
                                        primary=True,
                                        ip_configurations=[
                                            VirtualMachineScaleSetIPConfiguration(
                                                name='default',
                                                subnet=ApiEntityReference(
                                                    id=subnet.id))
                                        ])
                                ])))

                    if self.admin_password:
                        vmss_resource.virtual_machine_profile.os_profile.admin_password = self.admin_password

                    if self.os_type == 'Linux':
                        vmss_resource.virtual_machine_profile.os_profile.linux_configuration = LinuxConfiguration(
                            disable_password_authentication=disable_ssh_password
                        )

                    if self.ssh_public_keys:
                        ssh_config = SshConfiguration()
                        ssh_config.public_keys = \
                            [SshPublicKey(path=key['path'], key_data=key['key_data']) for key in self.ssh_public_keys]
                        vmss_resource.virtual_machine_profile.os_profile.linux_configuration.ssh = ssh_config

                    if self.data_disks:
                        data_disks = []

                        for data_disk in self.data_disks:
                            data_disk_managed_disk = VirtualMachineScaleSetManagedDiskParameters(
                                storage_account_type=data_disk[
                                    'managed_disk_type'])

                            data_disk['caching'] = data_disk.get(
                                'caching', CachingTypes.read_only)

                            data_disks.append(
                                VirtualMachineScaleSetDataDisk(
                                    lun=data_disk['lun'],
                                    caching=data_disk['caching'],
                                    create_option=DiskCreateOptionTypes.empty,
                                    disk_size_gb=data_disk['disk_size_gb'],
                                    managed_disk=data_disk_managed_disk,
                                ))

                        vmss_resource.virtual_machine_profile.storage_profile.data_disks = data_disks

                    self.log("Create virtual machine with parameters:")
                    self.create_or_update_vmss(vmss_resource)

                elif self.differences and len(self.differences) > 0:
                    self.log("Update virtual machine scale set {0}".format(
                        self.name))
                    self.results['actions'].append('Updated VMSS {0}'.format(
                        self.name))

                    vmss_resource = self.get_vmss()
                    vmss_resource.virtual_machine_profile.storage_profile.os_disk.caching = self.os_disk_caching
                    vmss_resource.sku.capacity = self.capacity

                    data_disks = []
                    for data_disk in self.data_disks:
                        data_disks.append(
                            VirtualMachineScaleSetDataDisk(
                                lun=data_disk['lun'],
                                caching=data_disk['caching'],
                                create_option=DiskCreateOptionTypes.empty,
                                disk_size_gb=data_disk['disk_size_gb'],
                                managed_disk=
                                VirtualMachineScaleSetManagedDiskParameters(
                                    storage_account_type=data_disk[
                                        'managed_disk_type']),
                            ))
                    vmss_resource.virtual_machine_profile.storage_profile.data_disks = data_disks

                    self.log("Update virtual machine with parameters:")
                    self.create_or_update_vmss(vmss_resource)

                self.results['ansible_facts'][
                    'azure_vmss'] = self.serialize_vmss(self.get_vmss())

            elif self.state == 'absent':
                # delete the VM
                self.log("Delete virtual machine scale set {0}".format(
                    self.name))
                self.results['ansible_facts']['azure_vmss'] = None
                self.delete_vmss(vmss)

        # until we sort out how we want to do this globally
        del self.results['actions']

        return self.results