'Create Azure Virtual Machine
Reference: http://bit.ly/1fIsCb7
[www.windowsazure.com/en-us/documentation/]
We default to:
+ 3389/TCP - RDP - 1st Microsoft instance.
+ RANDOM/TCP - RDP - All succeeding Microsoft instances.
+ 22/TCP - SSH - 1st Linux instance
+ RANDOM/TCP - SSH - All succeeding Linux instances.
The above replicates the standard behavior of the Azure UI.
You can retrieve the assigned ports to each instance by
using the following private function:
_get_endpoint_ports(service_name)
Returns public,private port key pair.
@inherits: :class:`NodeDriver.create_node`
: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`
:keyword     ex_cloud_service_name: Required.
Name of the Azure Cloud Service.
:type        ex_cloud_service_name:  ``str``
:keyword     ex_storage_service_name: Optional:
Name of the Azure Storage Service.
:type        ex_storage_service_name:  ``str``
:keyword     ex_new_deployment: Optional. Tells azure to create a
new deployment rather than add to an
existing one.
:type        ex_new_deployment: ``boolean``
:keyword     ex_deployment_slot: Optional: Valid values: production|
staging.
Defaults to production.
:type        ex_deployment_slot:  ``str``
:keyword     ex_deployment_name: Optional. The name of the
deployment.
If this is not passed in we default
to using the Cloud Service name.
:type        ex_deployment_name: ``str``
:type        ex_custom_data: ``str``
:keyword     ex_custom_data: Optional script or other data which is
injected into the VM when it\'s beginning
provisioned.
:keyword     ex_admin_user_id: Optional. Defaults to \'azureuser\'.
:type        ex_admin_user_id:  ``str``
:keyword     ex_virtual_network_name: Optional. If this is not passed
in no virtual network is used.
:type        ex_virtual_network_name:  ``str``
:keyword     ex_network_config: Optional. The ConfigurationSet to use
for network configuration
:type        ex_network_config:  `ConfigurationSet`'

def create_node(self, name, size, image, ex_cloud_service_name, ex_storage_service_name=None, ex_new_deployment=False, ex_deployment_slot='Production', ex_deployment_name=None, ex_admin_user_id='azureuser', ex_custom_data=None, ex_virtual_network_name=None, ex_network_config=None, auth=None, **kwargs):

    auth = self._get_and_check_auth(auth)
    password = auth.password
    if (not isinstance(size, NodeSize)):
        raise ValueError('Size    must    be    an    instance    of    NodeSize')
    if (not isinstance(image, NodeImage)):
        raise ValueError('Image    must    be    an    instance    of    NodeImage,    produced    by    list_images()')
    node_list = self.list_nodes(ex_cloud_service_name=ex_cloud_service_name)
    if (ex_network_config is None):
        network_config = ConfigurationSet()
    else:
        network_config = ex_network_config
    network_config.configuration_set_type = 'NetworkConfiguration'
    if ex_custom_data:
        ex_custom_data = self._encode_base64(data=ex_custom_data)
    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)
        machine_config.domain_join = None
        if ((not node_list) or ex_new_deployment):
            port = '3389'
        else:
            port = random.randint(41952, 65535)
            endpoints = self._get_deployment(service_name=ex_cloud_service_name, deployment_slot=ex_deployment_slot)
            for instances in endpoints.role_instance_list:
                ports = [ep.public_port for ep in instances.instance_endpoints]
                while (port in ports):
                    port = random.randint(41952, 65535)
        endpoint = ConfigurationSetInputEndpoint(name='Remote    Desktop', protocol='tcp', port=port, local_port='3389', load_balanced_endpoint_set_name=None, enable_direct_server_return=False)
    else:
        if ((not node_list) or ex_new_deployment):
            port = '22'
        else:
            port = random.randint(41952, 65535)
            endpoints = self._get_deployment(service_name=ex_cloud_service_name, deployment_slot=ex_deployment_slot)
            for instances in endpoints.role_instance_list:
                ports = []
                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)
        endpoint = ConfigurationSetInputEndpoint(name='SSH', protocol='tcp', port=port, local_port='22', load_balanced_endpoint_set_name=None, enable_direct_server_return=False)
        machine_config = LinuxConfigurationSet(name, ex_admin_user_id, password, False, ex_custom_data)
    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 is None):
        ex_storage_service_name = ex_cloud_service_name
        ex_storage_service_name = re.sub('[\\W_-]+', '', 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 ((not node_list) or ex_new_deployment):
        if (not ex_deployment_name):
            ex_deployment_name = ex_cloud_service_name
        vm_image_id = None
        disk_config = None
        if image.extra.get('vm_image', False):
            vm_image_id = image.id
        else:
            blob_url = ('http://%s.blob.core.windows.net' % ex_storage_service_name)
            disk_name = ('%s-%s-%s.vhd' % (ex_cloud_service_name, name, time.strftime('%Y-%m-%d')))
            media_link = ('%s/vhds/%s' % (blob_url, 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, ex_virtual_network_name, vm_image_id))
        self.raise_for_response(response, 202)
        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
        vm_image_id = None
        disk_config = None
        if image.extra.get('vm_image', False):
            vm_image_id = image.id
        else:
            blob_url = ('http://%s.blob.core.windows.net' % ex_storage_service_name)
            disk_name = ('%s-%s-%s.vhd' % (ex_cloud_service_name, name, time.strftime('%Y-%m-%d')))
            media_link = ('%s/vhds/%s' % (blob_url, disk_name))
            disk_config = OSVirtualHardDisk(image.id, media_link)
        path = self._get_role_path(ex_cloud_service_name, _deployment_name)
        body = AzureXmlSerializer.add_role_to_xml(name, machine_config, disk_config, 'PersistentVMRole', network_config, None, None, vm_image_id, size.id)
        response = self._perform_post(path, body)
        self.raise_for_response(response, 202)
        self._ex_complete_async_azure_operation(response)
    return Node(id=name, name=name, state=NodeState.PENDING, public_ips=[], private_ips=[], driver=self.connection.driver, extra={'ex_cloud_service_name': ex_cloud_service_name})
