http://git-wip-us.apache.org/repos/asf/libcloud/blob/76d3e2e8/libcloud/compute/drivers/azure.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/drivers/azure.py b/libcloud/compute/drivers/azure.py index 5534eb1..501b083 100644 --- a/libcloud/compute/drivers/azure.py +++ b/libcloud/compute/drivers/azure.py @@ -162,7 +162,8 @@ _KNOWN_SERIALIZATION_XFORMS = { 'os': 'OS', 'persistent_vm_downtime_info': 'PersistentVMDowntimeInfo', 'copy_id': 'CopyId', - 'os_disk_configuration': 'OSDiskConfiguration' + 'os_disk_configuration': 'OSDiskConfiguration', + 'is_dns_programmed': 'IsDnsProgrammed' } @@ -285,13 +286,19 @@ class AzureNodeDriver(NodeDriver): data = self._parse_response(response, HostedService) + vips = [vip.address for vip in data.deployments[0].virtual_ips] + try: - return [self._to_node(n) for n in - data.deployments[0].role_instance_list] + return [ + self._to_node(n, ex_cloud_service_name, vips) + for n in data.deployments[0].role_instance_list + ] except IndexError: return None - def reboot_node(self, node=None, ex_cloud_service_name=None, + def reboot_node(self, + node=None, + ex_cloud_service_name=None, ex_deployment_slot=None): """ Reboots a node. @@ -304,36 +311,44 @@ class AzureNodeDriver(NodeDriver): :param ex_cloud_service_name: Cloud Service name :type ex_cloud_service_name: ``str`` - :param ex_deployment_name: Options are "production" (default) + :param ex_deployment_slot: Options are "production" (default) or "Staging". (Optional) - :type ex_deployment_name: ``str`` + :type ex_deployment_slot: ``str`` :rtype: ``bool`` """ + if not node: + raise ValueError("node is required.") + + ex_cloud_service_name = ex_cloud_service_name or (node.extra and node.extra.get('ex_cloud_service_name')) if not ex_cloud_service_name: raise ValueError("ex_cloud_service_name is required.") if not ex_deployment_slot: - ex_deployment_slot = "production" + ex_deployment_slot = "Production" - if not node: - raise ValueError("node is required.") _deployment_name = self._get_deployment( service_name=ex_cloud_service_name, - deployment_slot=ex_deployment_slot).name + deployment_slot=ex_deployment_slot + ).name try: response = self._perform_post( self._get_deployment_path_using_name( - ex_cloud_service_name, _deployment_name) + '/roleinstances/' - + _str(node.id) + '?comp=reboot', '') + ex_cloud_service_name, + _deployment_name + ) + '/roleinstances/' + _str(node.id) + '?comp=reboot', + '' + ) if response.status != 202: - raise LibcloudError('Message: %s, Body: %s, Status code: %d' % - (response.error, response.body, - response.status), driver=self) + raise LibcloudError( + 'Message: %s, Body: %s, Status code: %d' % + (response.error, response.body, response.status), + driver=self + ) if self._parse_response_for_async_op(response): return True @@ -354,9 +369,7 @@ class AzureNodeDriver(NodeDriver): """ data = self._perform_get(self._get_disk_path(), Disks) - - volumes = [self._to_volume(volume=v,node=node) for v in data] - + volumes = [self._to_volume(volume=v, node=node) for v in data] return volumes def create_node(self, ex_cloud_service_name=None, **kwargs): @@ -395,6 +408,11 @@ class AzureNodeDriver(NodeDriver): to using the Cloud Service name. :type ex_deployment_name: ``str`` + :keyword ex_new_deployment: Optional. Tells azure to create a new + deployment rather than add to an existing + one. + :type ex_deployment_name: ``boolean`` + :keyword ex_deployment_slot: Optional: Valid values: production| staging. Defaults to production. @@ -403,14 +421,22 @@ class AzureNodeDriver(NodeDriver): :keyword ex_admin_user_id: Optional. Defaults to 'azureuser'. :type ex_admin_user_id: ``str`` + :keyword image: The image to use when creating this node + :type image: `NodeImage` + + :keyword size: The size of the instance to create + :type size: `NodeSize` + """ - password = None + auth = self._get_and_check_auth(kwargs["auth"]) password = auth.password if not ex_cloud_service_name: raise ValueError("ex_cloud_service_name is required.") + ex_new_deployment = kwargs.get("ex_new_deployment", False) + if "ex_deployment_slot" in kwargs: ex_deployment_slot = kwargs['ex_deployment_slot'] else: @@ -447,30 +473,31 @@ class AzureNodeDriver(NodeDriver): network_config.configuration_set_type = 'NetworkConfiguration' # We do this because we need to pass a Configuration to the - # method. This will be either Linux or Windows. - if re.search("Win|SQL|SharePoint|Visual|Dynamics|DynGP|BizTalk", - image.name, re.I): + # method. This will be either Linux or Windows. + windows_server_regex = re.compile(r'Win|SQL|SharePoint|Visual|Dynamics|DynGP|BizTalk') + if windows_server_regex.search(image.id, re.I): machine_config = WindowsConfigurationSet( - computer_name=name, admin_password=password, - admin_user_name=ex_admin_user_id) + computer_name=name, + admin_password=password, + admin_user_name=ex_admin_user_id + ) machine_config.domain_join = None - if node_list is None: + if node_list is None or ex_new_deployment: port = "3389" else: - port = random.randint(41952,65535) + port = random.randint(41952, 65535) endpoints = self._get_deployment( service_name=ex_cloud_service_name, - deployment_slot=ex_deployment_slot) + deployment_slot=ex_deployment_slot + ) for instances in endpoints.role_instance_list: - ports = [] - for ep in instances.instance_endpoints: - ports += [ep.public_port] + ports = [ep.public_port for ep in instances.instance_endpoints] while port in ports: - port = random.randint(41952,65535) + port = random.randint(41952, 65535) endpoint = ConfigurationSetInputEndpoint( name='Remote Desktop', @@ -481,18 +508,20 @@ class AzureNodeDriver(NodeDriver): enable_direct_server_return=False ) else: - if node_list is None: + if node_list is None or ex_new_deployment: port = "22" else: - port = random.randint(41952,65535) + port = random.randint(41952, 65535) endpoints = self._get_deployment( service_name=ex_cloud_service_name, - deployment_slot=ex_deployment_slot) + deployment_slot=ex_deployment_slot + ) for instances in endpoints.role_instance_list: ports = [] - for ep in instances.instance_endpoints: - ports += [ep.public_port] + if instances.instance_endpoints is not None: + for ep in instances.instance_endpoints: + ports += [ep.public_port] while port in ports: port = random.randint(41952,65535) @@ -506,153 +535,144 @@ class AzureNodeDriver(NodeDriver): enable_direct_server_return=False ) machine_config = LinuxConfigurationSet( - name, ex_admin_user_id, password, False) + name, + ex_admin_user_id, + password, + False + ) - network_config.input_endpoints.input_endpoints.append(endpoint) + network_config.input_endpoints.items.append(endpoint) _storage_location = self._get_cloud_service_location( service_name=ex_cloud_service_name) + if "ex_storage_service_name" in kwargs: + ex_storage_service_name = kwargs['ex_storage_service_name'] + else: + ex_storage_service_name = ex_cloud_service_name + ex_storage_service_name = re.sub( + ur'[\W_]+', + u'', + ex_storage_service_name.lower(), + flags=re.UNICODE + ) + + if self._is_storage_service_unique( + service_name=ex_storage_service_name): + + self._create_storage_account( + service_name=ex_storage_service_name, + location=_storage_location.service_location, + is_affinity_group=_storage_location.is_affinity_group + ) + # OK, bit annoying here. You must create a deployment before # you can create an instance; however, the deployment function # creates the first instance, but all subsequent instances # must be created using the add_role function. # # So, yeah, annoying. - - if node_list is None: + if node_list is None or ex_new_deployment: # This is the first node in this cloud service. - if "ex_storage_service_name" in kwargs: - ex_storage_service_name = kwargs['ex_storage_service_name'] - else: - ex_storage_service_name = ex_cloud_service_name - ex_storage_service_name = re.sub( - ur'[\W_]+', u'', ex_storage_service_name.lower(), - flags=re.UNICODE) - if self._is_storage_service_unique( - service_name=ex_storage_service_name): - self._create_storage_account( - service_name=ex_storage_service_name, - location=_storage_location.service_location, - is_affinity_group=_storage_location.is_affinity_group - ) if "ex_deployment_name" in kwargs: ex_deployment_name = kwargs['ex_deployment_name'] else: ex_deployment_name = ex_cloud_service_name + vm_image_id = None + disk_config = None + if image.extra['vm_image']: - response = self._perform_post( - self._get_deployment_path_using_name(ex_cloud_service_name), - AzureXmlSerializer.virtual_machine_deployment_to_xml( - ex_deployment_name, - ex_deployment_slot, - name, - name, - machine_config, - None, - 'PersistentVMRole', - None, - None, - None, - size.id, - None, - image.id)) + vm_image_id = image.id + #network_config = None else: - blob_url = "http://" + ex_storage_service_name \ - + ".blob.core.windows.net" + blob_url = "http://" + ex_storage_service_name + ".blob.core.windows.net" # Azure's pattern in the UI. disk_name = "{0}-{1}-{2}.vhd".format( - ex_cloud_service_name,name,time.strftime("%Y-%m-%d")) + ex_cloud_service_name, + name, + time.strftime("%Y-%m-%d") + ) + media_link = blob_url + "/vhds/" + disk_name disk_config = OSVirtualHardDisk(image.id, media_link) - response = self._perform_post( - self._get_deployment_path_using_name(ex_cloud_service_name), - AzureXmlSerializer.virtual_machine_deployment_to_xml( - ex_deployment_name, - ex_deployment_slot, - name, - name, - machine_config, - disk_config, - 'PersistentVMRole', - network_config, - None, - None, - size.id, - None, - None)) + response = self._perform_post( + self._get_deployment_path_using_name(ex_cloud_service_name), + AzureXmlSerializer.virtual_machine_deployment_to_xml( + ex_deployment_name, + ex_deployment_slot, + name, + name, + machine_config, + disk_config, + 'PersistentVMRole', + network_config, + None, + None, + size.id, + None, + vm_image_id + ) + ) if response.status != 202: - raise LibcloudError('Message: %s, Body: %s, Status code: %d' % - (response.error, response.body, response.status), driver=self) + raise LibcloudError( + 'Message: %s, Body: %s, Status code: %d' % + (response.error, response.body, response.status), + driver=self + ) self._ex_complete_async_azure_operation(response) else: _deployment_name = self._get_deployment( service_name=ex_cloud_service_name, - deployment_slot=ex_deployment_slot).name + deployment_slot=ex_deployment_slot + ).name - if "ex_storage_service_name" in kwargs: - ex_storage_service_name = kwargs['ex_storage_service_name'] - else: - ex_storage_service_name = ex_cloud_service_name - ex_storage_service_name = re.sub( - ur'[\W_]+', u'', ex_storage_service_name.lower(), - flags=re.UNICODE) - - if self._is_storage_service_unique( - service_name=ex_storage_service_name): - self._create_storage_account( - service_name=ex_storage_service_name, - location=_storage_location.service_location, - is_affinity_group=_storage_location.is_affinity_group - ) + vm_image_id = None + disk_config = None if image.extra['vm_image']: - response = self._perform_post( - self._get_role_path(ex_cloud_service_name, - image.extra['deployment_name']), - AzureXmlSerializer.add_role_to_xml( - name, # role_name - machine_config, # system_config - None, # os_virtual_hard_disk - 'PersistentVMRole', # role_type - None, # network_config - None, # availability_set_name - None, # data_virtual_hard_disks - image.id, #vm_image - size.id)) # role_size + vm_image_id = image.id + #network_config = None else: - blob_url = "http://" + ex_storage_service_name + \ - ".blob.core.windows.net" + blob_url = "http://" + ex_storage_service_name + ".blob.core.windows.net" disk_name = "{0}-{1}-{2}.vhd".format( - ex_cloud_service_name,name,time.strftime("%Y-%m-%d")) + ex_cloud_service_name, + name, + time.strftime("%Y-%m-%d") + ) media_link = blob_url + "/vhds/" + disk_name disk_config = OSVirtualHardDisk(image.id, media_link) - response = self._perform_post( - self._get_role_path(ex_cloud_service_name, - _deployment_name), - AzureXmlSerializer.add_role_to_xml( - name, # role_name - machine_config, # system_config - disk_config, # os_virtual_hard_disk - 'PersistentVMRole', # role_type - network_config, # network_config - None, # availability_set_name - None, # data_virtual_hard_disks - size.id, # role_size - None)) #vm_image) + response = self._perform_post( + self._get_role_path( + ex_cloud_service_name, + _deployment_name + ), + AzureXmlSerializer.add_role_to_xml( + name, # role_name + machine_config, # system_config + disk_config, # os_virtual_hard_disk + 'PersistentVMRole', # role_type + network_config, # network_config + None, # availability_set_name + None, # data_virtual_hard_disks + vm_image_id, # vm_image + size.id # role_size + ) + ) if response.status != 202: - raise LibcloudError('Message: %s, Body: %s, Status code: %d' % - (response.error, response.body, - response.status), driver=self) + raise LibcloudError( + 'Message: %s, Body: %s, Status code: %d' % + (response.error, response.body, response.status), + driver=self.connection.driver + ) self._ex_complete_async_azure_operation(response) @@ -662,10 +682,15 @@ class AzureNodeDriver(NodeDriver): state=NodeState.PENDING, public_ips=[], private_ips=[], - driver=self.connection.driver + driver=self.connection.driver, + extra={ + 'ex_cloud_service_name': ex_cloud_service_name + } ) - def destroy_node(self, node=None, ex_cloud_service_name=None, + def destroy_node(self, + node=None, + ex_cloud_service_name=None, ex_deployment_slot=None): """Remove Azure Virtual Machine @@ -684,44 +709,54 @@ class AzureNodeDriver(NodeDriver): :type ex_deployment_slot: ``str`` """ - if not ex_cloud_service_name: - raise ValueError("ex_cloud_service_name is required.") - if not node: raise ValueError("node is required.") + ex_cloud_service_name = ex_cloud_service_name or (node.extra and node.extra.get('ex_cloud_service_name')) + + if not ex_cloud_service_name: + raise ValueError("ex_cloud_service_name is required.") + if not ex_deployment_slot: ex_deployment_slot = "production" _deployment = self._get_deployment( service_name=ex_cloud_service_name, - deployment_slot=ex_deployment_slot) + deployment_slot=ex_deployment_slot + ) _deployment_name = _deployment.name _server_deployment_count = len(_deployment.role_instance_list) if _server_deployment_count > 1: - path = self._get_role_path(ex_cloud_service_name, - _deployment_name, node.id) - path += '?comp=media' # forces deletion of attached disks + path = self._get_role_path( + ex_cloud_service_name, + _deployment_name, + node.id + ) + path += '?comp=media' # forces deletion of attached disks - data = self._perform_delete(path) + self._perform_delete(path) return True else: path = self._get_deployment_path_using_name( ex_cloud_service_name, - _deployment_name) + _deployment_name + ) path += '?comp=media' - data = self._perform_delete(path) + self._perform_delete(path) return True - def create_cloud_service(self, ex_cloud_service_name=None, location=None, - description=None, extended_properties=None): + def create_cloud_service(self, + ex_cloud_service_name=None, + location=None, + description=None, + extended_properties=None): """ creates an azure cloud service. @@ -745,17 +780,24 @@ class AzureNodeDriver(NodeDriver): if not location: raise ValueError("location is required.") - response = self._perform_cloud_service_create( + response = self._perform_cloud_service_create( self._get_hosted_service_path(), AzureXmlSerializer.create_hosted_service_to_xml( ex_cloud_service_name, self._encode_base64(ex_cloud_service_name), - description, location, None, extended_properties)) + description, + location, + None, + extended_properties + ) + ) if response.status != 201: - raise LibcloudError('Message: %s, Body: %s, Status code: %d' - % (response.error, response.body, - response.status), driver=self) + raise LibcloudError( + 'Message: %s, Body: %s, Status code: %d' + % (response.error, response.body, response.status), + driver=self + ) return True @@ -772,45 +814,63 @@ class AzureNodeDriver(NodeDriver): if not ex_cloud_service_name: raise ValueError("ex_cloud_service_name is required.") + #add check to ensure all nodes have been deleted response = self._perform_cloud_service_delete( - self._get_hosted_service_path(ex_cloud_service_name)) + self._get_hosted_service_path(ex_cloud_service_name) + ) if response.status != 200: - raise LibcloudError('Message: %s, Body: %s, Status code: %d' % - (response.error, response.body, response.status) - , driver=self) + raise LibcloudError( + 'Message: %s, Body: %s, Status code: %d' % + (response.error, response.body, response.status), + driver=self + ) return True - """ Functions not implemented + def list_cloud_services(self): + + return self._perform_get( + self._get_hosted_service_path(), + HostedServices + ) + + """ + Functions not implemented """ def create_volume_snapshot(self): raise NotImplementedError( 'You cannot create snapshots of ' - 'Azure VMs at this time.') + 'Azure VMs at this time.' + ) def attach_volume(self): raise NotImplementedError( 'attach_volume is not supported ' - 'at this time.') + 'at this time.' + ) def create_volume(self): raise NotImplementedError( 'create_volume is not supported ' - 'at this time.') + 'at this time.' + ) def detach_volume(self): raise NotImplementedError( 'detach_volume is not supported ' - 'at this time.') + 'at this time.' + ) def destroy_volume(self): raise NotImplementedError( 'destroy_volume is not supported ' - 'at this time.') + 'at this time.' + ) - """Private Functions + """ + Private Functions """ def _perform_cloud_service_create(self, path, data): @@ -836,40 +896,44 @@ class AzureNodeDriver(NodeDriver): return response - def _to_node(self, data): + def _to_node(self, data, ex_cloud_service_name=None, virtual_ips=None): """ Convert the data from a Azure response object into a Node """ - if len(data.instance_endpoints) >= 1: - public_ip = data.instance_endpoints[0].vip - else: - public_ip = [] + remote_desktop_port = u'' + ssh_port = u'' + public_ips = virtual_ips or [] - for port in data.instance_endpoints: - if port.name == 'Remote Desktop': - remote_desktop_port = port.public_port - else: - remote_desktop_port = [] + if data.instance_endpoints is not None: + if len(data.instance_endpoints) >= 1: + public_ips = [data.instance_endpoints[0].vip] - if port.name == "SSH": - ssh_port = port.public_port - else: - ssh_port = [] + for port in data.instance_endpoints: + if port.name == 'Remote Desktop': + remote_desktop_port = port.public_port + + if port.name == "SSH": + ssh_port = port.public_port return Node( id=data.role_name, name=data.role_name, state=self.NODE_STATE_MAP.get( - data.instance_status, NodeState.UNKNOWN), - public_ips=[public_ip], + data.instance_status, + NodeState.UNKNOWN + ), + public_ips=public_ips, private_ips=[data.ip_address], - driver=AzureNodeDriver, + driver=self.connection.driver, extra={ 'remote_desktop_port': remote_desktop_port, 'ssh_port': ssh_port, 'power_state': data.power_state, - 'instance_size': data.instance_size}) + 'instance_size': data.instance_size, + 'ex_cloud_service_name': ex_cloud_service_name + } + ) def _to_location(self, data): """ @@ -897,9 +961,9 @@ class AzureNodeDriver(NodeDriver): name=data.display_name, country=country, driver=self.connection.driver, - available_services =data.available_services, - virtual_machine_role_sizes = - (data.compute_capabilities).virtual_machines_role_sizes) + available_services=data.available_services, + virtual_machine_role_sizes=data.compute_capabilities.virtual_machines_role_sizes + ) def _to_node_size(self, data): """ @@ -915,9 +979,10 @@ class AzureNodeDriver(NodeDriver): price=data["price"], driver=self.connection.driver, extra={ - 'max_data_disks' : data["max_data_disks"], - 'cores' : data["cores"] - }) + 'max_data_disks': data["max_data_disks"], + 'cores': data["cores"] + } + ) def _to_image(self, data): @@ -933,7 +998,8 @@ class AzureNodeDriver(NodeDriver): 'affinity_group': data.affinity_group, 'media_link': data.media_link, 'vm_image': False - }) + } + ) def _vm_to_image(self, data): @@ -949,41 +1015,46 @@ class AzureNodeDriver(NodeDriver): 'affinity_group': data.affinity_group, 'deployment_name': data.deployment_name, 'vm_image': True - }) + } + ) def _to_volume(self, volume, node): if node: if hasattr(volume.attached_to, 'role_name'): if volume.attached_to.role_name == node.id: - extra = {} - extra['affinity_group'] = volume.affinity_group + extra = {'affinity_group': volume.affinity_group} + if hasattr(volume.attached_to, 'hosted_service_name'): - extra['hosted_service_name'] = \ - volume.attached_to.hosted_service_name + extra['hosted_service_name'] = volume.attached_to.hosted_service_name + if hasattr(volume.attached_to, 'role_name'): extra['role_name'] = volume.attached_to.role_name + if hasattr(volume.attached_to, 'deployment_name'): - extra['deployment_name'] = \ - volume.attached_to.deployment_name + extra['deployment_name'] = volume.attached_to.deployment_name + extra['os'] = volume.os extra['location'] = volume.location extra['media_link'] = volume.media_link extra['source_image_name'] = volume.source_image_name - return StorageVolume(id=volume.name, + return StorageVolume( + id=volume.name, name=volume.name, size=int(volume.logical_disk_size_in_gb), driver=self.connection.driver, - extra=extra) + extra=extra + ) else: - extra = {} - extra['affinity_group'] = volume.affinity_group + extra = {'affinity_group': volume.affinity_group} + if hasattr(volume.attached_to, 'hosted_service_name'): - extra['hosted_service_name'] = \ - volume.attached_to.hosted_service_name + extra['hosted_service_name'] = volume.attached_to.hosted_service_name + if hasattr(volume.attached_to, 'role_name'): extra['role_name'] = volume.attached_to.role_name + if hasattr(volume.attached_to, 'deployment_name'): extra['deployment_name'] = volume.attached_to.deployment_name extra['os'] = volume.os @@ -991,11 +1062,13 @@ class AzureNodeDriver(NodeDriver): extra['media_link'] = volume.media_link extra['source_image_name'] = volume.source_image_name - return StorageVolume(id=volume.name, + return StorageVolume( + id=volume.name, name=volume.name, size=int(volume.logical_disk_size_in_gb), driver=self.connection.driver, - extra=extra) + extra=extra + ) def _get_deployment(self, **kwargs): _service_name = kwargs['service_name'] @@ -1003,25 +1076,30 @@ class AzureNodeDriver(NodeDriver): response = self._perform_get( self._get_deployment_path_using_slot( - _service_name, _deployment_slot), None) + _service_name, + _deployment_slot + ), + None + ) if response.status != 200: - raise LibcloudError('Message: %s, Body: %s, Status code: %d' % - (response.error, response.body, response.status) - , driver=self) + raise LibcloudError( + 'Message: %s, Body: %s, Status code: %d' % + (response.error, response.body, response.status), + driver=self.connection.driver + ) return self._parse_response(response, Deployment) - def _get_cloud_service_location(self, service_name=None): if not service_name: raise ValueError("service_name is required.") res = self._perform_get( - self._get_hosted_service_path(service_name) + - '?embed-detail=False', - HostedService) + self._get_hosted_service_path(service_name) + '?embed-detail=False', + HostedService + ) _affinity_group = res.hosted_service_properties.affinity_group _cloud_service_location = res.hosted_service_properties.location @@ -1041,7 +1119,8 @@ class AzureNodeDriver(NodeDriver): self._get_storage_service_path() + '/operations/isavailable/' + _str(service_name) + '', - AvailabilityResponse) + AvailabilityResponse + ) return _check_availability.result @@ -1056,12 +1135,16 @@ class AzureNodeDriver(NodeDriver): kwargs['location'], None, # Location True, # geo_replication_enabled - None)) # extended_properties + None # extended_properties + ) + ) if response.status != 202: - raise LibcloudError('Message: %s, Body: %s, Status code: %d' % - (response.error, response.body, - response.status), driver=self) + raise LibcloudError( + 'Message: %s, Body: %s, Status code: %d' % + (response.error, response.body, response.status), + driver=self.connection.driver + ) else: response = self._perform_post( @@ -1073,25 +1156,29 @@ class AzureNodeDriver(NodeDriver): None, # Affinity Group kwargs['location'], # Location True, # geo_replication_enabled - None)) # extended_properties + None # extended_properties + ) + ) if response.status != 202: - raise LibcloudError('Message: %s, Body: %s, Status code: %d' % - (response.error, response.body, - response.status), driver=self) - + raise LibcloudError( + 'Message: %s, Body: %s, Status code: %d' % + (response.error, response.body, response.status), + driver=self.connection.driver + ) # We need to wait for this to be created before we can # create the storage container and the instance. - self._ex_complete_async_azure_operation(response, - "create_storage_account") - - return + self._ex_complete_async_azure_operation( + response, + "create_storage_account" + ) def _get_operation_status(self, request_id): return self._perform_get( '/' + self.subscription_id + '/operations/' + _str(request_id), - Operation) + Operation + ) def _perform_get(self, path, response_type): request = AzureHTTPRequest() @@ -1113,8 +1200,7 @@ class AzureNodeDriver(NodeDriver): request.host = azure_service_management_host request.path = path request.body = self._get_request_body(body) - request.path, request.query = \ - self._update_request_uri_query(request) + request.path, request.query = self._update_request_uri_query(request) request.headers = self._update_management_header(request) response = self._perform_request(request) @@ -1130,34 +1216,33 @@ class AzureNodeDriver(NodeDriver): response = self._perform_request(request) if response.status != 202: - raise LibcloudError('Message: %s, Body: %s, Status code: %d' % - (response.error, response.body, response.status) - , driver=self) + raise LibcloudError( + 'Message: %s, Body: %s, Status code: %d' % + (response.error, response.body, response.status), + driver=self.connection.driver + ) if async: return self._parse_response_for_async_op(response) - return None - def _perform_request(self, request): try: return self.connection.request( action="https://%s%s" % (request.host, request.path), data=request.body, headers=request.headers, - method=request.method) + method=request.method + ) except Exception, e: print e.message - - - - def _update_request_uri_query(self, request): - '''pulls the query string out of the URI and moves it into + """ + pulls the query string out of the URI and moves it into the query portion of the request object. If there are already query parameters on the request the parameters in the URI will - appear after the existing parameters''' + appear after the existing parameters + """ if '?' in request.path: request.path, _, query_string = request.path.partition('?') @@ -1175,14 +1260,13 @@ class AzureNodeDriver(NodeDriver): request.path += '?' for name, value in request.query: if value is not None: - request.path += name + '=' + \ - url_quote(value, '/()$=\',') + '&' + request.path += name + '=' + url_quote(value, '/()$=\',') + '&' request.path = request.path[:-1] return request.path, request.query def _update_management_header(self, request): - ''' Add additional headers for management. ''' + """ Add additional headers for management. """ if request.method in ['PUT', 'POST', 'MERGE', 'DELETE']: request.headers['Content-Length'] = str(len(request.body)) @@ -1196,38 +1280,42 @@ class AzureNodeDriver(NodeDriver): if 'content-type' == key.lower(): break else: - request.headers['Content-Type']='application/xml' + request.headers['Content-Type'] = 'application/xml' return request.headers def send_request_headers(self, connection, request_headers): - for name, value in request_headers: - if value: - connection.putheader(name, value) + for name, value in request_headers: + if value: + connection.putheader(name, value) - connection.putheader('User-Agent', _USER_AGENT_STRING) - connection.endheaders() + connection.putheader('User-Agent', _USER_AGENT_STRING) + connection.endheaders() def send_request_body(self, connection, request_body): - if request_body: - assert isinstance(request_body, bytes) - connection.send(request_body) - elif (not isinstance(connection, HTTPSConnection) and - not isinstance(connection, httplib.HTTPConnection)): - connection.send(None) + if request_body: + assert isinstance(request_body, bytes) + connection.send(request_body) + elif (not isinstance(connection, HTTPSConnection) and + not isinstance(connection, httplib.HTTPConnection)): + connection.send(None) def _parse_response(self, response, return_type): - ''' + """ Parse the HTTPResponse's body and fill all the data into a class of return_type. - ''' + """ + return self._parse_response_body_from_xml_text( - response.body, return_type) + response.body, + return_type + ) def _parse_response_body_from_xml_text(self, respbody, return_type): - ''' + """ parse the xml and fill all the data into a class of return_type - ''' + """ + doc = minidom.parseString(respbody) return_obj = return_type() for node in self._get_child_nodes(doc, return_type.__name__): @@ -1235,43 +1323,61 @@ class AzureNodeDriver(NodeDriver): return return_obj - def _get_child_nodes(self, node, tagName): - return [childNode for childNode in node.getElementsByTagName(tagName) + def _get_child_nodes(self, node, tag_name): + return [childNode for childNode in node.getElementsByTagName(tag_name) if childNode.parentNode == node] def _fill_data_to_return_object(self, node, return_obj): members = dict(vars(return_obj)) for name, value in members.items(): if isinstance(value, _list_of): - setattr(return_obj, - name, - self._fill_list_of(node, - value.list_type, - value.xml_element_name)) + setattr( + return_obj, + name, + self._fill_list_of( + node, + value.list_type, + value.xml_element_name + ) + ) elif isinstance(value, _scalar_list_of): - setattr(return_obj, - name, - self._fill_scalar_list_of(node, - value.list_type, - self._get_serialization_name(name), - value.xml_element_name)) + setattr( + return_obj, + name, + self._fill_scalar_list_of( + node, + value.list_type, + self._get_serialization_name(name), + value.xml_element_name + ) + ) elif isinstance(value, _dict_of): - setattr(return_obj, - name, - self._fill_dict_of(node, - self._get_serialization_name(name), - value.pair_xml_element_name, - value.key_xml_element_name, - value.value_xml_element_name)) + setattr( + return_obj, + name, + self._fill_dict_of( + node, + self._get_serialization_name(name), + value.pair_xml_element_name, + value.key_xml_element_name, + value.value_xml_element_name + ) + ) elif isinstance(value, WindowsAzureData): - setattr(return_obj, - name, - self._fill_instance_child(node, name, value.__class__)) + setattr( + return_obj, + name, + self._fill_instance_child(node, name, value.__class__) + ) elif isinstance(value, dict): - setattr(return_obj, - name, - self._fill_dict(node, - self._get_serialization_name(name))) + setattr( + return_obj, + name, + self._fill_dict( + node, + self._get_serialization_name(name) + ) + ) elif isinstance(value, _Base64String): value = self._fill_data_minidom(node, name, '') if value is not None: @@ -1287,27 +1393,33 @@ class AzureNodeDriver(NodeDriver): def _fill_list_of(self, xmldoc, element_type, xml_element_name): xmlelements = self._get_child_nodes(xmldoc, xml_element_name) - return [self._parse_response_body_from_xml_node( - xmlelement, element_type) \ - for xmlelement in xmlelements] + return [ + self._parse_response_body_from_xml_node(xmlelement, element_type) + for xmlelement in xmlelements + ] def _parse_response_body_from_xml_node(self, node, return_type): - ''' + """ parse the xml and fill all the data into a class of return_type - ''' + """ return_obj = return_type() self._fill_data_to_return_object(node, return_obj) return return_obj - def _fill_scalar_list_of(self, xmldoc, element_type, parent_xml_element_name, + def _fill_scalar_list_of(self, + xmldoc, + element_type, + parent_xml_element_name, xml_element_name): xmlelements = self._get_child_nodes(xmldoc, parent_xml_element_name) + if xmlelements: - xmlelements = \ - self._get_child_nodes(xmlelements[0], xml_element_name) - return [self._get_node_value(xmlelement, element_type) \ - for xmlelement in xmlelements] + xmlelements = self._get_child_nodes(xmlelements[0], xml_element_name) + return [ + self._get_node_value(xmlelement, element_type) + for xmlelement in xmlelements + ] def _get_node_value(self, xmlelement, data_type): value = xmlelement.firstChild.nodeValue @@ -1318,31 +1430,38 @@ class AzureNodeDriver(NodeDriver): else: return data_type(value) - def _get_serialization_name(self,element_name): + def _get_serialization_name(self, element_name): """converts a Python name into a serializable name""" + known = _KNOWN_SERIALIZATION_XFORMS.get(element_name) if known is not None: return known if element_name.startswith('x_ms_'): return element_name.replace('_', '-') + if element_name.endswith('_id'): element_name = element_name.replace('_id', 'ID') + for name in ['content_', 'last_modified', 'if_', 'cache_control']: if element_name.startswith(name): element_name = element_name.replace('_', '-_') return ''.join(name.capitalize() for name in element_name.split('_')) - def _fill_dict_of( - self, xmldoc, parent_xml_element_name, pair_xml_element_name, - key_xml_element_name, value_xml_element_name): + def _fill_dict_of(self, + xmldoc, + parent_xml_element_name, + pair_xml_element_name, + key_xml_element_name, + value_xml_element_name): + return_obj = {} xmlelements = self._get_child_nodes(xmldoc, parent_xml_element_name) + if xmlelements: - xmlelements = \ - self._get_child_nodes(xmlelements[0], pair_xml_element_name) + xmlelements = self._get_child_nodes(xmlelements[0], pair_xml_element_name) for pair in xmlelements: keys = self._get_child_nodes(pair, key_xml_element_name) values = self._get_child_nodes(pair, value_xml_element_name) @@ -1354,10 +1473,13 @@ class AzureNodeDriver(NodeDriver): return return_obj def _fill_instance_child(self, xmldoc, element_name, return_type): - '''Converts a child of the current dom element to the specified type. - ''' + """ + Converts a child of the current dom element to the specified type. + """ xmlelements = self._get_child_nodes( - xmldoc, self._get_serialization_name(element_name)) + xmldoc, + self._get_serialization_name(element_name) + ) if not xmlelements: return None @@ -1369,6 +1491,7 @@ class AzureNodeDriver(NodeDriver): def _fill_dict(self, xmldoc, element_name): xmlelements = self._get_child_nodes(xmldoc, element_name) + if xmlelements: return_obj = {} for child in xmlelements[0].childNodes: @@ -1393,7 +1516,9 @@ class AzureNodeDriver(NodeDriver): def _fill_data_minidom(self, xmldoc, element_name, data_member): xmlelements = self._get_child_nodes( - xmldoc, self._get_serialization_name(element_name)) + xmldoc, + self._get_serialization_name(element_name) + ) if not xmlelements or not xmlelements[0].childNodes: return None @@ -1440,20 +1565,20 @@ class AzureNodeDriver(NodeDriver): xmlstr = '<?xml version="1.0" encoding="utf-8"?>' if isinstance(source, list): - for value in source: - xmlstr += self._convert_class_to_xml(value, False) + xmlstr += ''.join(self._convert_class_to_xml(value, False) for value in source) elif isinstance(source, WindowsAzureData): class_name = source.__class__.__name__ xmlstr += '<' + class_name + '>' for name, value in vars(source).items(): if value is not None: - if isinstance(value, list) or \ - isinstance(value, WindowsAzureData): + if isinstance(value, list) or isinstance(value, WindowsAzureData): xmlstr += self._convert_class_to_xml(value, False) else: - xmlstr += ('<' + self._get_serialization_name(name) + - '>' + xml_escape(str(value)) + '</' + - self._get_serialization_name(name) + '>') + xmlstr += ( + '<' + self._get_serialization_name(name) + '>' + + xml_escape(str(value)) + + '</' + self._get_serialization_name(name) + '>' + ) xmlstr += '</' + class_name + '>' return xmlstr @@ -1469,17 +1594,21 @@ class AzureNodeDriver(NodeDriver): return result - def _get_deployment_path_using_name(self, service_name, - deployment_name=None): - return self._get_path('services/hostedservices/' - + _str(service_name) + - '/deployments', deployment_name) + def _get_deployment_path_using_name(self, + service_name, + deployment_name=None): + return self._get_path( + 'services/hostedservices/' + + _str(service_name) + + '/deployments', + deployment_name + ) def _get_path(self, resource, name): - path = '/' + self.subscription_id + '/' + resource - if name is not None: - path += '/' + _str(name) - return path + path = '/' + self.subscription_id + '/' + resource + if name is not None: + path += '/' + _str(name) + return path def _get_image_path(self, image_name=None): return self._get_path('services/images', image_name) @@ -1498,14 +1627,20 @@ class AzureNodeDriver(NodeDriver): return self._get_path('services/disks', disk_name) def _get_role_path(self, service_name, deployment_name, role_name=None): - return self._get_path('services/hostedservices/' + _str(service_name) + - '/deployments/' + deployment_name + - '/roles', role_name) + return self._get_path( + 'services/hostedservices/' + + _str(service_name) + + '/deployments/' + + deployment_name + + '/roles', + role_name + ) def _get_storage_service_path(self, service_name=None): return self._get_path('services/storageservices', service_name) - def _ex_complete_async_azure_operation(self, response=None, + def _ex_complete_async_azure_operation(self, + response=None, operation_type='create_node'): request_id = self._parse_response_for_async_op(response) @@ -1525,8 +1660,10 @@ class AzureNodeDriver(NodeDriver): if operation_status.status == 'Failed': raise LibcloudError( - 'Message: Async request for operation %s has failed'% - operation_type, driver=self) + 'Message: Async request for operation %s has failed' % + operation_type, + driver=self.connection.driver + ) #def get_connection(self): # certificate_path = "/Users/baldwin/.azure/managementCertificate.pem" @@ -1539,284 +1676,396 @@ class AzureNodeDriver(NodeDriver): # return connection -"""XML Serializer +""" +XML Serializer Borrowed from the Azure SDK for Python. """ + + def _lower(text): return text.lower() + class AzureXmlSerializer(): @staticmethod - def create_storage_service_input_to_xml(service_name, description, label, - affinity_group, location, + def create_storage_service_input_to_xml(service_name, + description, + label, + affinity_group, + location, geo_replication_enabled, extended_properties): return AzureXmlSerializer.doc_from_data( 'CreateStorageServiceInput', - [('ServiceName', service_name), - ('Description', description), - ('Label', label), - ('AffinityGroup', affinity_group), - ('Location', location), - ('GeoReplicationEnabled', geo_replication_enabled, _lower)], - extended_properties) + [ + ('ServiceName', service_name), + ('Description', description), + ('Label', label), + ('AffinityGroup', affinity_group), + ('Location', location), + ('GeoReplicationEnabled', geo_replication_enabled, _lower) + ], + extended_properties + ) @staticmethod - def update_storage_service_input_to_xml(description, label, + def update_storage_service_input_to_xml(description, + label, geo_replication_enabled, extended_properties): return AzureXmlSerializer.doc_from_data( 'UpdateStorageServiceInput', - [('Description', description), - ('Label', label, AzureNodeDriver._encode_base64), - ('GeoReplicationEnabled', geo_replication_enabled, _lower)], - extended_properties) + [ + ('Description', description), + ('Label', label, AzureNodeDriver._encode_base64), + ('GeoReplicationEnabled', geo_replication_enabled, _lower) + ], + extended_properties + ) @staticmethod def regenerate_keys_to_xml(key_type): - return AzureXmlSerializer.doc_from_data('RegenerateKeys', - [('KeyType', key_type)]) + return AzureXmlSerializer.doc_from_data( + 'RegenerateKeys', + [('KeyType', key_type)] + ) @staticmethod def update_hosted_service_to_xml(label, description, extended_properties): - return AzureXmlSerializer.doc_from_data('UpdateHostedService', - [('Label', label, - AzureNodeDriver._encode_base64), - ('Description', description)], - extended_properties) + return AzureXmlSerializer.doc_from_data( + 'UpdateHostedService', + [ + ('Label', label, AzureNodeDriver._encode_base64), + ('Description', description) + ], + extended_properties + ) @staticmethod - def create_hosted_service_to_xml(service_name, label, description, - location, affinity_group, + def create_hosted_service_to_xml(service_name, + label, + description, + location, + affinity_group, extended_properties): return AzureXmlSerializer.doc_from_data( 'CreateHostedService', - [('ServiceName', service_name), - ('Label', label), - ('Description', description), - ('Location', location), - ('AffinityGroup', affinity_group)], - extended_properties) + [ + ('ServiceName', service_name), + ('Label', label), + ('Description', description), + ('Location', location), + ('AffinityGroup', affinity_group) + ], + extended_properties + ) @staticmethod - def create_deployment_to_xml(name, package_url, label, configuration, - start_deployment, treat_warnings_as_error, + def create_deployment_to_xml(name, + package_url, + label, + configuration, + start_deployment, + treat_warnings_as_error, extended_properties): return AzureXmlSerializer.doc_from_data( 'CreateDeployment', - [('Name', name), - ('PackageUrl', package_url), - ('Label', label, AzureNodeDriver._encode_base64), - ('Configuration', configuration), - ('StartDeployment', - start_deployment, _lower), - ('TreatWarningsAsError', treat_warnings_as_error, _lower)], - extended_properties) + [ + ('Name', name), + ('PackageUrl', package_url), + ('Label', label, AzureNodeDriver._encode_base64), + ('Configuration', configuration), + ('StartDeployment', start_deployment, _lower), + ('TreatWarningsAsError', treat_warnings_as_error, _lower) + ], + extended_properties + ) @staticmethod def swap_deployment_to_xml(production, source_deployment): return AzureXmlSerializer.doc_from_data( 'Swap', - [('Production', production), - ('SourceDeployment', source_deployment)]) + [ + ('Production', production), + ('SourceDeployment', source_deployment) + ] + ) @staticmethod def update_deployment_status_to_xml(status): return AzureXmlSerializer.doc_from_data( 'UpdateDeploymentStatus', - [('Status', status)]) + [('Status', status)] + ) @staticmethod - def change_deployment_to_xml(configuration, treat_warnings_as_error, mode, + def change_deployment_to_xml(configuration, + treat_warnings_as_error, + mode, extended_properties): return AzureXmlSerializer.doc_from_data( 'ChangeConfiguration', - [('Configuration', configuration), - ('TreatWarningsAsError', treat_warnings_as_error, _lower), - ('Mode', mode)], - extended_properties) + [ + ('Configuration', configuration), + ('TreatWarningsAsError', treat_warnings_as_error, _lower), + ('Mode', mode) + ], + extended_properties + ) @staticmethod - def upgrade_deployment_to_xml(mode, package_url, configuration, label, - role_to_upgrade, force, extended_properties): + def upgrade_deployment_to_xml(mode, + package_url, + configuration, + label, + role_to_upgrade, + force, + extended_properties): return AzureXmlSerializer.doc_from_data( 'UpgradeDeployment', - [('Mode', mode), - ('PackageUrl', package_url), - ('Configuration', configuration), - ('Label', label, AzureNodeDriver._encode_base64), - ('RoleToUpgrade', role_to_upgrade), - ('Force', force, _lower)], - extended_properties) + [ + ('Mode', mode), + ('PackageUrl', package_url), + ('Configuration', configuration), + ('Label', label, AzureNodeDriver._encode_base64), + ('RoleToUpgrade', role_to_upgrade), + ('Force', force, _lower) + ], + extended_properties + ) @staticmethod def rollback_upgrade_to_xml(mode, force): return AzureXmlSerializer.doc_from_data( 'RollbackUpdateOrUpgrade', - [('Mode', mode), - ('Force', force, _lower)]) + [ + ('Mode', mode), + ('Force', force, _lower) + ] + ) @staticmethod def walk_upgrade_domain_to_xml(upgrade_domain): return AzureXmlSerializer.doc_from_data( 'WalkUpgradeDomain', - [('UpgradeDomain', upgrade_domain)]) + [('UpgradeDomain', upgrade_domain)] + ) @staticmethod def certificate_file_to_xml(data, certificate_format, password): return AzureXmlSerializer.doc_from_data( 'CertificateFile', - [('Data', data), - ('CertificateFormat', certificate_format), - ('Password', password)]) + [ + ('Data', data), + ('CertificateFormat', certificate_format), + ('Password', password) + ] + ) @staticmethod def create_affinity_group_to_xml(name, label, description, location): return AzureXmlSerializer.doc_from_data( 'CreateAffinityGroup', - [('Name', name), - ('Label', label, AzureNodeDriver._encode_base64), - ('Description', description), - ('Location', location)]) + [ + ('Name', name), + ('Label', label, AzureNodeDriver._encode_base64), + ('Description', description), + ('Location', location) + ] + ) @staticmethod def update_affinity_group_to_xml(label, description): return AzureXmlSerializer.doc_from_data( 'UpdateAffinityGroup', - [('Label', label, AzureNodeDriver._encode_base64), - ('Description', description)]) + [ + ('Label', label, AzureNodeDriver._encode_base64), + ('Description', description) + ] + ) @staticmethod def subscription_certificate_to_xml(public_key, thumbprint, data): return AzureXmlSerializer.doc_from_data( 'SubscriptionCertificate', - [('SubscriptionCertificatePublicKey', public_key), - ('SubscriptionCertificateThumbprint', thumbprint), - ('SubscriptionCertificateData', data)]) + [ + ('SubscriptionCertificatePublicKey', public_key), + ('SubscriptionCertificateThumbprint', thumbprint), + ('SubscriptionCertificateData', data) + ] + ) @staticmethod def os_image_to_xml(label, media_link, name, os): return AzureXmlSerializer.doc_from_data( 'OSImage', - [('Label', label), - ('MediaLink', media_link), - ('Name', name), - ('OS', os)]) + [ + ('Label', label), + ('MediaLink', media_link), + ('Name', name), + ('OS', os) + ] + ) @staticmethod - def data_virtual_hard_disk_to_xml(host_caching, disk_label, disk_name, lun, - logical_disk_size_in_gb, media_link, + def data_virtual_hard_disk_to_xml(host_caching, + disk_label, + disk_name, + lun, + logical_disk_size_in_gb, + media_link, source_media_link): return AzureXmlSerializer.doc_from_data( 'DataVirtualHardDisk', - [('HostCaching', host_caching), - ('DiskLabel', disk_label), - ('DiskName', disk_name), - ('Lun', lun), - ('LogicalDiskSizeInGB', logical_disk_size_in_gb), - ('MediaLink', media_link), - ('SourceMediaLink', source_media_link)]) + [ + ('HostCaching', host_caching), + ('DiskLabel', disk_label), + ('DiskName', disk_name), + ('Lun', lun), + ('LogicalDiskSizeInGB', logical_disk_size_in_gb), + ('MediaLink', media_link), + ('SourceMediaLink', source_media_link) + ] + ) @staticmethod def disk_to_xml(has_operating_system, label, media_link, name, os): return AzureXmlSerializer.doc_from_data( 'Disk', - [('HasOperatingSystem', has_operating_system, _lower), - ('Label', label), - ('MediaLink', media_link), - ('Name', name), - ('OS', os)]) + [ + ('HasOperatingSystem', has_operating_system, _lower), + ('Label', label), + ('MediaLink', media_link), + ('Name', name), + ('OS', os) + ] + ) @staticmethod def restart_role_operation_to_xml(): return AzureXmlSerializer.doc_from_xml( 'RestartRoleOperation', - '<OperationType>RestartRoleOperation</OperationType>') + '<OperationType>RestartRoleOperation</OperationType>' + ) @staticmethod def shutdown_role_operation_to_xml(): return AzureXmlSerializer.doc_from_xml( 'ShutdownRoleOperation', - '<OperationType>ShutdownRoleOperation</OperationType>') + '<OperationType>ShutdownRoleOperation</OperationType>' + ) @staticmethod def start_role_operation_to_xml(): return AzureXmlSerializer.doc_from_xml( 'StartRoleOperation', - '<OperationType>StartRoleOperation</OperationType>') + '<OperationType>StartRoleOperation</OperationType>' + ) @staticmethod def windows_configuration_to_xml(configuration): xml = AzureXmlSerializer.data_to_xml( - [('ConfigurationSetType', configuration.configuration_set_type), - ('ComputerName', configuration.computer_name), - ('AdminPassword', configuration.admin_password), - ('ResetPasswordOnFirstLogon', - configuration.reset_password_on_first_logon, - _lower), - ('EnableAutomaticUpdates', - configuration.enable_automatic_updates, - _lower), - ('TimeZone', configuration.time_zone)]) + [ + ('ConfigurationSetType', configuration.configuration_set_type), + ('ComputerName', configuration.computer_name), + ('AdminPassword', configuration.admin_password), + ( + 'ResetPasswordOnFirstLogon', + configuration.reset_password_on_first_logon, + _lower + ), + ( + 'EnableAutomaticUpdates', + configuration.enable_automatic_updates, + _lower + ), + ('TimeZone', configuration.time_zone) + ] + ) if configuration.domain_join is not None: xml += '<DomainJoin>' xml += '<Credentials>' xml += AzureXmlSerializer.data_to_xml( - [('Domain', configuration.domain_join.credentials.domain), - ('Username', configuration.domain_join.credentials.username), - ('Password', configuration.domain_join.credentials.password)]) + [ + ('Domain', configuration.domain_join.credentials.domain), + ('Username', configuration.domain_join.credentials.username), + ('Password', configuration.domain_join.credentials.password) + ] + ) xml += '</Credentials>' xml += AzureXmlSerializer.data_to_xml( - [('JoinDomain', configuration.domain_join.join_domain), - ('MachineObjectOU', - configuration.domain_join.machine_object_ou)]) + [ + ('JoinDomain', configuration.domain_join.join_domain), + ( + 'MachineObjectOU', + configuration.domain_join.machine_object_ou + ) + ] + ) xml += '</DomainJoin>' if configuration.stored_certificate_settings is not None: xml += '<StoredCertificateSettings>' + for cert in configuration.stored_certificate_settings: xml += '<CertificateSetting>' xml += AzureXmlSerializer.data_to_xml( - [('StoreLocation', cert.store_location), - ('StoreName', cert.store_name), - ('Thumbprint', cert.thumbprint)]) + [ + ('StoreLocation', cert.store_location), + ('StoreName', cert.store_name), + ('Thumbprint', cert.thumbprint) + ] + ) xml += '</CertificateSetting>' xml += '</StoredCertificateSettings>' xml += AzureXmlSerializer.data_to_xml( - [('AdminUsername', configuration.admin_user_name)]) + [('AdminUsername', configuration.admin_user_name)] + ) return xml @staticmethod def linux_configuration_to_xml(configuration): xml = AzureXmlSerializer.data_to_xml( - [('ConfigurationSetType', configuration.configuration_set_type), - ('HostName', configuration.host_name), - ('UserName', configuration.user_name), - ('UserPassword', configuration.user_password), - ('DisableSshPasswordAuthentication', - configuration.disable_ssh_password_authentication, - _lower)]) + [ + ('ConfigurationSetType', configuration.configuration_set_type), + ('HostName', configuration.host_name), + ('UserName', configuration.user_name), + ('UserPassword', configuration.user_password), + ( + 'DisableSshPasswordAuthentication', + configuration.disable_ssh_password_authentication, + _lower + ) + ] + ) if configuration.ssh is not None: xml += '<SSH>' xml += '<PublicKeys>' + for key in configuration.ssh.public_keys: xml += '<PublicKey>' xml += AzureXmlSerializer.data_to_xml( - [('Fingerprint', key.fingerprint), - ('Path', key.path)]) + [ + ('Fingerprint', key.fingerprint), + ('Path', key.path) + ] + ) xml += '</PublicKey>' + xml += '</PublicKeys>' xml += '<KeyPairs>' + for key in configuration.ssh.key_pairs: xml += '<KeyPair>' xml += AzureXmlSerializer.data_to_xml( [('Fingerprint', key.fingerprint), ('Path', key.path)]) xml += '</KeyPair>' + xml += '</KeyPairs>' xml += '</SSH>' return xml @@ -1824,25 +2073,35 @@ class AzureXmlSerializer(): @staticmethod def network_configuration_to_xml(configuration): xml = AzureXmlSerializer.data_to_xml( - [('ConfigurationSetType', configuration.configuration_set_type)]) + [('ConfigurationSetType', configuration.configuration_set_type)] + ) xml += '<InputEndpoints>' + for endpoint in configuration.input_endpoints: xml += '<InputEndpoint>' xml += AzureXmlSerializer.data_to_xml( - [('LoadBalancedEndpointSetName', - endpoint.load_balanced_endpoint_set_name), - ('LocalPort', endpoint.local_port), - ('Name', endpoint.name), - ('Port', endpoint.port)]) - - if endpoint.load_balancer_probe.path or\ - endpoint.load_balancer_probe.port or\ - endpoint.load_balancer_probe.protocol: + [ + ( + 'LoadBalancedEndpointSetName', + endpoint.load_balanced_endpoint_set_name + ), + ('LocalPort', endpoint.local_port), + ('Name', endpoint.name), + ('Port', endpoint.port) + ] + ) + + if (endpoint.load_balancer_probe.path or + endpoint.load_balancer_probe.port or + endpoint.load_balancer_probe.protocol): xml += '<LoadBalancerProbe>' xml += AzureXmlSerializer.data_to_xml( - [('Path', endpoint.load_balancer_probe.path), - ('Port', endpoint.load_balancer_probe.port), - ('Protocol', endpoint.load_balancer_probe.protocol)]) + [ + ('Path', endpoint.load_balancer_probe.path), + ('Port', endpoint.load_balancer_probe.port), + ('Protocol', endpoint.load_balancer_probe.protocol) + ] + ) xml += '</LoadBalancerProbe>' xml += AzureXmlSerializer.data_to_xml( @@ -1854,17 +2113,29 @@ class AzureXmlSerializer(): xml += '</InputEndpoint>' xml += '</InputEndpoints>' xml += '<SubnetNames>' - for name in configuration.subnet_names: - xml += AzureXmlSerializer.data_to_xml([('SubnetName', name)]) + xml += ''.join( + AzureXmlSerializer.data_to_xml([('SubnetName', name)]) + for name in configuration.subnet_names + ) xml += '</SubnetNames>' return xml @staticmethod - def role_to_xml(availability_set_name, data_virtual_hard_disks, - network_configuration_set, os_virtual_hard_disk, vm_image_name, role_name, - role_size, role_type, system_configuration_set): - xml = AzureXmlSerializer.data_to_xml([('RoleName', role_name), - ('RoleType', role_type)]) + def role_to_xml(availability_set_name, + data_virtual_hard_disks, + network_configuration_set, + os_virtual_hard_disk, + vm_image_name, + role_name, + role_size, + role_type, + system_configuration_set): + xml = AzureXmlSerializer.data_to_xml( + [ + ('RoleName', role_name), + ('RoleType', role_type) + ] + ) xml += '<ConfigurationSets>' @@ -1872,46 +2143,56 @@ class AzureXmlSerializer(): xml += '<ConfigurationSet>' if isinstance(system_configuration_set, WindowsConfigurationSet): xml += AzureXmlSerializer.windows_configuration_to_xml( - system_configuration_set) + system_configuration_set + ) elif isinstance(system_configuration_set, LinuxConfigurationSet): xml += AzureXmlSerializer.linux_configuration_to_xml( - system_configuration_set) + system_configuration_set + ) xml += '</ConfigurationSet>' if network_configuration_set is not None: xml += '<ConfigurationSet>' xml += AzureXmlSerializer.network_configuration_to_xml( - network_configuration_set) + network_configuration_set + ) xml += '</ConfigurationSet>' xml += '</ConfigurationSets>' if availability_set_name is not None: xml += AzureXmlSerializer.data_to_xml( - [('AvailabilitySetName', availability_set_name)]) + [('AvailabilitySetName', availability_set_name)] + ) if data_virtual_hard_disks is not None: xml += '<DataVirtualHardDisks>' for hd in data_virtual_hard_disks: xml += '<DataVirtualHardDisk>' xml += AzureXmlSerializer.data_to_xml( - [('HostCaching', hd.host_caching), - ('DiskLabel', hd.disk_label), - ('DiskName', hd.disk_name), - ('Lun', hd.lun), - ('LogicalDiskSizeInGB', hd.logical_disk_size_in_gb), - ('MediaLink', hd.media_link)]) + [ + ('HostCaching', hd.host_caching), + ('DiskLabel', hd.disk_label), + ('DiskName', hd.disk_name), + ('Lun', hd.lun), + ('LogicalDiskSizeInGB', hd.logical_disk_size_in_gb), + ('MediaLink', hd.media_link) + ] + ) xml += '</DataVirtualHardDisk>' xml += '</DataVirtualHardDisks>' if os_virtual_hard_disk is not None: xml += '<OSVirtualHardDisk>' xml += AzureXmlSerializer.data_to_xml( - [('HostCaching', os_virtual_hard_disk.host_caching), - ('DiskLabel', os_virtual_hard_disk.disk_label), - ('DiskName', os_virtual_hard_disk.disk_name), - ('MediaLink', os_virtual_hard_disk.media_link), - ('SourceImageName', os_virtual_hard_disk.source_image_name)]) + [ + ('HostCaching', os_virtual_hard_disk.host_caching), + ('DiskLabel', os_virtual_hard_disk.disk_label), + ('DiskName', os_virtual_hard_disk.disk_name), + ('MediaLink', os_virtual_hard_disk.media_link), + ('SourceImageName', os_virtual_hard_disk.source_image_name) + ] + ) xml += '</OSVirtualHardDisk>' if vm_image_name is not None: @@ -1923,10 +2204,15 @@ class AzureXmlSerializer(): return xml @staticmethod - def add_role_to_xml(role_name, system_configuration_set, - os_virtual_hard_disk, role_type, - network_configuration_set, availability_set_name, - data_virtual_hard_disks, vm_image_name, role_size): + def add_role_to_xml(role_name, + system_configuration_set, + os_virtual_hard_disk, + role_type, + network_configuration_set, + availability_set_name, + data_virtual_hard_disks, + vm_image_name, + role_size): xml = AzureXmlSerializer.role_to_xml( availability_set_name, data_virtual_hard_disks, @@ -1936,13 +2222,17 @@ class AzureXmlSerializer(): role_name, role_size, role_type, - system_configuration_set) + system_configuration_set + ) return AzureXmlSerializer.doc_from_xml('PersistentVMRole', xml) @staticmethod - def update_role_to_xml(role_name, os_virtual_hard_disk, role_type, - network_configuration_set, availability_set_name, - data_virtual_hard_disks, role_size): + def update_role_to_xml(role_name, + os_virtual_hard_disk, + role_type, + network_configuration_set, + availability_set_name, + data_virtual_hard_disks,role_size): xml = AzureXmlSerializer.role_to_xml( availability_set_name, data_virtual_hard_disks, @@ -1951,44 +2241,64 @@ class AzureXmlSerializer(): role_name, role_size, role_type, - None) + None + ) return AzureXmlSerializer.doc_from_xml('PersistentVMRole', xml) @staticmethod - def capture_role_to_xml(post_capture_action, target_image_name, - target_image_label, provisioning_configuration): + def capture_role_to_xml(post_capture_action, + target_image_name, + target_image_label, + provisioning_configuration): xml = AzureXmlSerializer.data_to_xml( - [('OperationType', 'CaptureRoleOperation'), - ('PostCaptureAction', post_capture_action)]) + [ + ('OperationType', 'CaptureRoleOperation'), + ('PostCaptureAction', post_capture_action) + ] + ) if provisioning_configuration is not None: xml += '<ProvisioningConfiguration>' if isinstance(provisioning_configuration, WindowsConfigurationSet): xml += AzureXmlSerializer.windows_configuration_to_xml( - provisioning_configuration) + provisioning_configuration + ) elif isinstance(provisioning_configuration, LinuxConfigurationSet): xml += AzureXmlSerializer.linux_configuration_to_xml( - provisioning_configuration) + provisioning_configuration + ) xml += '</ProvisioningConfiguration>' xml += AzureXmlSerializer.data_to_xml( - [('TargetImageLabel', target_image_label), - ('TargetImageName', target_image_name)]) + [ + ('TargetImageLabel', target_image_label), + ('TargetImageName', target_image_name) + ] + ) return AzureXmlSerializer.doc_from_xml('CaptureRoleOperation', xml) @staticmethod - def virtual_machine_deployment_to_xml(deployment_name, deployment_slot, - label, role_name, + def virtual_machine_deployment_to_xml(deployment_name, + deployment_slot, + label, + role_name, system_configuration_set, - os_virtual_hard_disk, role_type, + os_virtual_hard_disk, + role_type, network_configuration_set, availability_set_name, - data_virtual_hard_disks, role_size, - virtual_network_name, vm_image_name): - xml = AzureXmlSerializer.data_to_xml([('Name', deployment_name), - ('DeploymentSlot', deployment_slot), - ('Label', label)]) + data_virtual_hard_disks, + role_size, + virtual_network_name, + vm_image_name): + xml = AzureXmlSerializer.data_to_xml( + [ + ('Name', deployment_name), + ('DeploymentSlot', deployment_slot), + ('Label', label) + ] + ) xml += '<RoleList>' xml += '<Role>' xml += AzureXmlSerializer.role_to_xml( @@ -2000,23 +2310,26 @@ class AzureXmlSerializer(): role_name, role_size, role_type, - system_configuration_set) + system_configuration_set + ) xml += '</Role>' xml += '</RoleList>' if virtual_network_name is not None: xml += AzureXmlSerializer.data_to_xml( - [('VirtualNetworkName', virtual_network_name)]) + [('VirtualNetworkName', virtual_network_name)] + ) return AzureXmlSerializer.doc_from_xml('Deployment', xml) @staticmethod def data_to_xml(data): - '''Creates an xml fragment from the specified data. + """ + Creates an xml fragment from the specified data. data: Array of tuples, where first: xml element name second: xml element text third: conversion function - ''' + """ xml = '' for element in data: name = element[0] @@ -2037,11 +2350,18 @@ class AzureXmlSerializer(): @staticmethod def doc_from_xml(document_element_name, inner_xml): - '''Wraps the specified xml in an xml root element with default azure - namespaces''' - xml = ''.join(['<', document_element_name, - ' xmlns:i="http://www.w3.org/2001/XMLSchema-instance"', - ' xmlns="http://schemas.microsoft.com/windowsazure">']) + """ + W
<TRUNCATED>
