Feature 7432 Merge branch 'Azure' 07/8207/3
authortierno <alfonso.tiernosepulveda@telefonica.com>
Thu, 21 Nov 2019 16:10:32 +0000 (16:10 +0000)
committertierno <alfonso.tiernosepulveda@telefonica.com>
Thu, 21 Nov 2019 18:07:17 +0000 (18:07 +0000)
flake8 fix on vincomm_azure

Change-Id: Ife862080a0ad1824e22a04d7ae2511f25ed90372
Signed-off-by: tierno <alfonso.tiernosepulveda@telefonica.com>
LICENSE
osm_ro/vimconn_azure.py
test/test_RO.py

diff --git a/LICENSE b/LICENSE
index 8dada3e..1be3676 100644 (file)
--- a/LICENSE
+++ b/LICENSE
       same "printed page" as the copyright notice for easier
       identification within third-party archives.
 
-   Copyright {yyyy} {name of copyright owner}
+   Copyright Copyright 2019 ETSI
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
index 24a9878..ad96da1 100755 (executable)
 # -*- coding: utf-8 -*-
+##
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+##
 
-__author__='Sergio Gonzalez'
-__date__ ='$18-apr-2019 23:59:59$'
-
+import base64
 import vimconn
 import logging
+import netaddr
+import re
 
 from os import getenv
-from uuid import uuid4
-
 from azure.common.credentials import ServicePrincipalCredentials
 from azure.mgmt.resource import ResourceManagementClient
 from azure.mgmt.network import NetworkManagementClient
 from azure.mgmt.compute import ComputeManagementClient
+from azure.mgmt.compute.models import DiskCreateOption
+from msrestazure.azure_exceptions import CloudError
+from msrest.exceptions import AuthenticationError
+from requests.exceptions import ConnectionError
+
+__author__ = 'Isabel Lloret, Sergio Gonzalez, Alfonso Tierno'
+__date__ = '$18-apr-2019 23:59:59$'
+
+
+if getenv('OSMRO_PDB_DEBUG'):
+    import sys
+    print(sys.path)
+    import pdb
+    pdb.set_trace()
 
 
 class vimconnector(vimconn.vimconnector):
 
+    # Translate azure provisioning state to OSM provision state
+    # The first three ones are the transitional status once a user initiated action has been requested
+    # Once the operation is complete, it will transition into the states Succeeded or Failed
+    # https://docs.microsoft.com/en-us/azure/virtual-machines/windows/states-lifecycle
+    provision_state2osm = {
+        "Creating": "BUILD",
+        "Updating": "BUILD",
+        "Deleting": "INACTIVE",
+        "Succeeded": "ACTIVE",
+        "Failed": "ERROR"
+    }
+
+    # Translate azure power state to OSM provision state
+    power_state2osm = {
+        "starting": "INACTIVE",
+        "running": "ACTIVE",
+        "stopping": "INACTIVE",
+        "stopped": "INACTIVE",
+        "unknown": "OTHER",
+        "deallocated": "BUILD",
+        "deallocating": "BUILD"
+    }
+
     def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level=None,
                  config={}, persistent_info={}):
+        """
+        Constructor of VIM. Raise an exception is some needed parameter is missing, but it must not do any connectivity
+        checking against the VIM
+        Using common constructor parameters.
+        In this case: config must include the following parameters:
+        subscription_id: assigned azure subscription identifier
+        region_name: current region for azure network
+        resource_group: used for all azure created resources
+        vnet_name: base vnet for azure, created networks will be subnets from this base network
+        config may also include the following parameter:
+        flavors_pattern: pattern that will be used to select a range of vm sizes, for example
+            "^((?!Standard_B).)*$" will filter out Standard_B range that is cheap but is very overused
+            "^Standard_B" will select a serie B maybe for test environment
+        """
 
         vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, log_level,
                                       config, persistent_info)
 
+        # Variable that indicates if client must be reloaded or initialized
+        self.reload_client = True
+
+        self.vnet_address_space = None
         # LOGGER
         self.logger = logging.getLogger('openmano.vim.azure')
         if log_level:
             logging.basicConfig()
             self.logger.setLevel(getattr(logging, log_level))
 
-        # CREDENTIALS 
-        self.credentials = ServicePrincipalCredentials(
-            client_id=user,
-            secret=passwd,
-            tenant=(tenant_id or tenant_name)
-        )
+        self.tenant = (tenant_id or tenant_name)
+
+        # Store config to create azure subscription later
+        self._config = {
+            "user": user,
+            "passwd": passwd,
+            "tenant": tenant_id or tenant_name
+        }
 
         # SUBSCRIPTION
         if 'subscription_id' in config:
-            self.subscription_id = config.get('subscription_id')
-            self.logger.debug('Setting subscription '+str(self.subscription_id))
+            self._config["subscription_id"] = config.get('subscription_id')
+            # self.logger.debug('Setting subscription to: %s', self.config["subscription_id"])
         else:
             raise vimconn.vimconnException('Subscription not specified')
+
         # REGION
         if 'region_name' in config:
             self.region = config.get('region_name')
         else:
             raise vimconn.vimconnException('Azure region_name is not specified at config')
+
         # RESOURCE_GROUP
         if 'resource_group' in config:
             self.resource_group = config.get('resource_group')
         else:
             raise vimconn.vimconnException('Azure resource_group is not specified at config')
+
         # VNET_NAME
         if 'vnet_name' in config:
             self.vnet_name = config["vnet_name"]
             
         # public ssh key
         self.pub_key = config.get('pub_key')
+
+        # flavor pattern regex
+        if 'flavors_pattern' in config:
+            self._config['flavors_pattern'] = config['flavors_pattern']
             
     def _reload_connection(self):
         """
-        Sets connections to work with Azure service APIs
-        :return:
+        Called before any operation, checks python azure clients
         """
-        self.logger.debug('Reloading API Connection')
-        try:
-            self.conn = ResourceManagementClient(self.credentials, self.subscription_id)
-            self.conn_compute = ComputeManagementClient(self.credentials, self.subscription_id)
-            self.conn_vnet = NetworkManagementClient(self.credentials, self.subscription_id)
-            self._check_or_create_resource_group()
-            self._check_or_create_vnet()
-        except Exception as e:
-            self.format_vimconn_exception(e)            
+        if self.reload_client:
+            self.logger.debug('reloading azure client')
+            try:
+                self.credentials = ServicePrincipalCredentials(
+                    client_id=self._config["user"],
+                    secret=self._config["passwd"],
+                    tenant=self._config["tenant"]
+                )
+                self.conn = ResourceManagementClient(self.credentials, self._config["subscription_id"])
+                self.conn_compute = ComputeManagementClient(self.credentials, self._config["subscription_id"])
+                self.conn_vnet = NetworkManagementClient(self.credentials, self._config["subscription_id"])
+                self._check_or_create_resource_group()
+                self._check_or_create_vnet()
+
+                # Set to client created
+                self.reload_client = False
+            except Exception as e:
+                self._format_vimconn_exception(e)
 
     def _get_resource_name_from_resource_id(self, resource_id):
-        return str(resource_id.split('/')[-1])
+        """
+        Obtains resource_name from the azure complete identifier: resource_name will always be last item
+        """
+        try:
+            resource = str(resource_id.split('/')[-1])
+            return resource
+        except Exception as e:
+            raise vimconn.vimconnException("Unable to get resource name from resource_id '{}' Error: '{}'".
+                                           format(resource_id, e))
 
     def _get_location_from_resource_group(self, resource_group_name):
-        return self.conn.resource_groups.get(resource_group_name).location
-        
+        try:
+            location = self.conn.resource_groups.get(resource_group_name).location
+            return location
+        except Exception as e:
+            raise vimconn.vimconnNotFoundException("Location '{}' not found".format(resource_group_name))
+
     def _get_resource_group_name_from_resource_id(self, resource_id):
-        return str(resource_id.split('/')[4])
+
+        try:
+            rg = str(resource_id.split('/')[4])
+            return rg
+        except Exception as e:
+            raise vimconn.vimconnException("Unable to get resource group from invalid resource_id format '{}'".
+                                           format(resource_id))
+
+    def _get_net_name_from_resource_id(self, resource_id):
+
+        try:
+            net_name = str(resource_id.split('/')[8])
+            return net_name
+        except Exception as e:
+            raise vimconn.vimconnException("Unable to get azure net_name from invalid resource_id format '{}'".
+                                           format(resource_id))
 
     def _check_subnets_for_vm(self, net_list):
         # All subnets must belong to the same resource group and vnet
-        if len(set(self._get_resource_group_name_from_resource_id(net['id']) +
-                   self._get_resource_name_from_resource_id(net['id']) for net in net_list)) != 1:
-            raise self.format_vimconn_exception('Azure VMs can only attach to subnets in same VNET')
+        rg_vnet = set(self._get_resource_group_name_from_resource_id(net['net_id']) +
+                      self._get_net_name_from_resource_id(net['net_id']) for net in net_list)
+
+        if len(rg_vnet) != 1:
+            raise self._format_vimconn_exception('Azure VMs can only attach to subnets in same VNET')
 
-    def format_vimconn_exception(self, e):
+    def _format_vimconn_exception(self, e):
         """
-        Params: an Exception object
-        :param e:
-        :return: Raises the proper vimconnException
+        Transforms a generic or azure exception to a vimcommException
         """
-        self.conn = None
-        self.conn_vnet = None
-        raise vimconn.vimconnConnectionException(type(e).__name__ + ': ' + str(e))        
+        if isinstance(e, vimconn.vimconnException):
+            raise
+        elif isinstance(e, AuthenticationError):
+            raise vimconn.vimconnAuthException(type(e).__name__ + ': ' + str(e))
+        elif isinstance(e, ConnectionError):
+            raise vimconn.vimconnConnectionException(type(e).__name__ + ': ' + str(e))
+        else:
+            # In case of generic error recreate client
+            self.reload_client = True
+            raise vimconn.vimconnException(type(e).__name__ + ': ' + str(e))
 
     def _check_or_create_resource_group(self):
         """
-        Creates a resource group in indicated region
-        :return: None
+        Creates the base resource group if it does not exist
         """
-        self.logger.debug('Creating RG {} in location {}'.format(self.resource_group, self.region))
-        self.conn.resource_groups.create_or_update(self.resource_group, {'location': self.region})
+        try:
+            rg_exists = self.conn.resource_groups.check_existence(self.resource_group)
+            if not rg_exists:
+                self.logger.debug("create base rgroup: %s", self.resource_group)
+                self.conn.resource_groups.create_or_update(self.resource_group, {'location': self.region})
+        except Exception as e:
+            self._format_vimconn_exception(e)
 
     def _check_or_create_vnet(self):
+        """
+        Try to get existent base vnet, in case it does not exist it creates it
+        """
+        try:
+            vnet = self.conn_vnet.virtual_networks.get(self.resource_group, self.vnet_name)
+            self.vnet_address_space = vnet.address_space.address_prefixes[0]
+            self.vnet_id = vnet.id
+            return
+        except CloudError as e:
+            if e.error.error and "notfound" in e.error.error.lower():
+                pass
+                # continue and create it
+            else:
+                self._format_vimconn_exception(e)
+
+        # if it does not exist, create it
         try:
             vnet_params = {
                 'location': self.region,
                 'address_space': {
-                    'address_prefixes': "10.0.0.0/8"
+                    'address_prefixes': ["10.0.0.0/8"]
                 },
             }
+            self.vnet_address_space = "10.0.0.0/8"
+
+            self.logger.debug("create base vnet: %s", self.vnet_name)
             self.conn_vnet.virtual_networks.create_or_update(self.resource_group, self.vnet_name, vnet_params)
+            vnet = self.conn_vnet.virtual_networks.get(self.resource_group, self.vnet_name)
+            self.vnet_id = vnet.id
         except Exception as e:
-            self.format_vimconn_exception(e)
+            self._format_vimconn_exception(e)
 
     def new_network(self, net_name, net_type, ip_profile=None, shared=False, vlan=None):
         """
         Adds a tenant network to VIM
         :param net_name: name of the network
-        :param net_type:
+        :param net_type: not used for azure networks
         :param ip_profile: is a dict containing the IP parameters of the network (Currently only IPv4 is implemented)
                 'ip-version': can be one of ['IPv4','IPv6']
                 'subnet-address': ip_prefix_schema, that is X.X.X.X/Y
-                'gateway-address': (Optional) ip_schema, that is X.X.X.X
-                'dns-address': (Optional) ip_schema,
-                'dhcp': (Optional) dict containing
+                'gateway-address': (Optional) ip_schema, that is X.X.X.X, not implemented for azure connector
+                'dns-address': (Optional) ip_schema, not implemented for azure connector
+                'dhcp': (Optional) dict containing, not implemented for azure connector
                     'enabled': {'type': 'boolean'},
                     'start-address': ip_schema, first IP to grant
                     'count': number of IPs to grant.
-        :param shared:
-        :param vlan:
+        :param shared: Not allowed for Azure Connector
+        :param vlan: VLAN tagging is not allowed for Azure
         :return: a tuple with the network identifier and created_items, or raises an exception on error
             created_items can be None or a dictionary where this method can include key-values that will be passed to
             the method delete_network. Can be used to store created segments, created l2gw connections, etc.
             Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
             as not present.
         """
-
         return self._new_subnet(net_name, ip_profile)
 
     def _new_subnet(self, net_name, ip_profile):
         """
-        Adds a tenant network to VIM. It creates a new VNET with a single subnet
-        :param net_name:
+        Adds a tenant network to VIM. It creates a new subnet at existing base vnet
+        :param net_name: subnet name
         :param ip_profile:
-        :return:
+                subnet-address: if it is not provided a subnet/24 in the default vnet is created,
+                otherwise it creates a subnet in the indicated address
+        :return: a tuple with the network identifier and created_items, or raises an exception on error
         """
-        self.logger.debug('Adding a subnet to VNET '+self.vnet_name)
+        self.logger.debug('create subnet name %s, ip_profile %s', net_name, ip_profile)
         self._reload_connection()
 
         if ip_profile is None:
-            # TODO get a non used vnet ip range /24 and allocate automatically
-            raise vimconn.vimconnException('Azure cannot create VNET with no CIDR')
+            # get a non used vnet ip range /24 and allocate automatically inside the range self.vnet_address_space
+            used_subnets = self.get_network_list()
+            for ip_range in netaddr.IPNetwork(self.vnet_address_space).subnet(24):
+                for used_subnet in used_subnets:
+                    subnet_range = netaddr.IPNetwork(used_subnet["cidr_block"])
+                    if subnet_range in ip_range or ip_range in subnet_range:
+                        # this range overlaps with an existing subnet ip range. Breaks and look for another
+                        break
+                else:
+                    ip_profile = {"subnet_address": str(ip_range)}
+                    self.logger.debug('dinamically obtained ip_profile: %s', ip_range)
+                    break
+            else:
+                raise vimconn.vimconnException("Cannot find a non-used subnet range in {}".
+                                               format(self.vnet_address_space))
+        else:
+            ip_profile = {"subnet_address": ip_profile['subnet_address']}
 
         try:
-            vnet_params= {
-                'location': self.region,
-                'address_space': {
-                    'address_prefixes': [ip_profile['subnet_address']]
-                },
-                'subnets': [
-                    {
-                        'name': "{}-{}".format(net_name[:24], uuid4()),
-                        'address_prefix': ip_profile['subnet_address']
-                    }
-                ]
+            # subnet_name = "{}-{}".format(net_name[:24], uuid4())
+            subnet_params = {
+                'address_prefix': ip_profile['subnet_address']
             }
-            self.conn_vnet.virtual_networks.create_or_update(self.resource_group, self.vnet_name, vnet_params)
-            # TODO return a tuple (subnet-ID, None)
+            # Assign a not duplicated net name
+            subnet_name = self._get_unused_subnet_name(net_name)
+
+            self.logger.debug('creating subnet_name: {}'.format(subnet_name))
+            async_creation = self.conn_vnet.subnets.create_or_update(self.resource_group, self.vnet_name,
+                                                                     subnet_name, subnet_params)
+            async_creation.wait()
+            self.logger.debug('created subnet_name: {}'.format(subnet_name))
+
+            return "{}/subnets/{}".format(self.vnet_id, subnet_name), None
         except Exception as e:
-            self.format_vimconn_exception(e)
+            self._format_vimconn_exception(e)
+
+    def _get_unused_subnet_name(self, subnet_name):
+        """
+        Adds a prefix to the subnet_name with a number in case the indicated name is repeated
+        Checks subnets with the indicated name (without suffix) and adds a suffix with a number
+        """
+        all_subnets = self.conn_vnet.subnets.list(self.resource_group, self.vnet_name)
+        # Filter to subnets starting with the indicated name
+        subnets = list(filter(lambda subnet: (subnet.name.startswith(subnet_name)), all_subnets))
+        net_names = [str(subnet.name) for subnet in subnets]
 
-    def _create_nic(self, subnet_id, nic_name, static_ip=None):
+        # get the name with the first not used suffix
+        name_suffix = 0
+        # name = subnet_name + "-" + str(name_suffix)
+        name = subnet_name  # first subnet created will have no prefix
+        while name in net_names:
+            name_suffix += 1
+            name = subnet_name + "-" + str(name_suffix)
+        return name
+
+    def _create_nic(self, net, nic_name, static_ip=None):
+
+        self.logger.debug('create nic name %s, net_name %s', nic_name, net)
         self._reload_connection()
-        
-        resource_group_name=self._get_resource_group_name_from_resource_id(subnet_id)
-        location = self._get_location_from_resource_group(resource_group_name)
-            
-        if static_ip:
-            async_nic_creation = self.conn_vnet.network_interfaces.create_or_update(
-                resource_group_name,
-                nic_name,
-                {
-                    'location': location,
-                    'ip_configurations': [{
-                        'name': nic_name + 'ipconfiguration',
-                        'privateIPAddress': static_ip,
-                        'privateIPAllocationMethod': 'Static',
-                        'subnet': {
-                            'id': subnet_id
-                        }
-                    }]
-                }
-            )
-        else:
-            async_nic_creation = self.conn_vnet.network_interfaces.create_or_update(
-                resource_group_name,
-                nic_name,
-                {
+
+        subnet_id = net['net_id']
+        location = self._get_location_from_resource_group(self.resource_group)
+        try:
+            net_ifz = {'location': location}
+            net_ip_config = {'name': nic_name + '-ipconfiguration', 'subnet': {'id': subnet_id}}
+            if static_ip:
+                net_ip_config['privateIPAddress'] = static_ip
+                net_ip_config['privateIPAllocationMethod'] = 'Static'
+            net_ifz['ip_configurations'] = [net_ip_config]
+            mac_address = net.get('mac_address')
+            if mac_address:
+                net_ifz['mac_address'] = mac_address
+
+            async_nic_creation = self.conn_vnet.network_interfaces.create_or_update(self.resource_group, nic_name,
+                                                                                    net_ifz)
+            async_nic_creation.wait()
+            self.logger.debug('created nic name %s', nic_name)
+
+            public_ip = net.get('floating_ip')
+            if public_ip:
+                public_ip_address_params = {
                     'location': location,
-                    'ip_configurations': [{
-                        'name': nic_name + 'ipconfiguration',
-                        'subnet': {
-                            'id': subnet_id
-                        }
-                    }]
+                    'public_ip_allocation_method': 'Dynamic'
                 }
-            )
+                public_ip_name = nic_name + '-public-ip'
+                public_ip = self.conn_vnet.public_ip_addresses.create_or_update(
+                    self.resource_group,
+                    public_ip_name,
+                    public_ip_address_params
+                )
+                self.logger.debug('created public IP: {}'.format(public_ip.result()))
+
+                # Associate NIC to Public IP
+                nic_data = self.conn_vnet.network_interfaces.get(
+                    self.resource_group,
+                    nic_name)
+
+                nic_data.ip_configurations[0].public_ip_address = public_ip.result()
+
+                self.conn_vnet.network_interfaces.create_or_update(
+                    self.resource_group,
+                    nic_name,
+                    nic_data)
+
+        except Exception as e:
+            self._format_vimconn_exception(e)
 
         return async_nic_creation.result()
 
-    def get_image_list(self, filter_dict={}):
+    def new_flavor(self, flavor_data):
         """
-        The urn contains for marketplace  'publisher:offer:sku:version'
+        It is not allowed to create new flavors in Azure, must always use an existing one
+        """
+        raise vimconn.vimconnAuthException("It is not possible to create new flavors in AZURE")
 
-        :param filter_dict:
-        :return:
+    def new_tenant(self, tenant_name, tenant_description):
         """
-        image_list = []
+        It is not allowed to create new tenants in azure
+        """
+        raise vimconn.vimconnAuthException("It is not possible to create a TENANT in AZURE")
+
+    def new_image(self, image_dict):
+        """
+        It is not allowed to create new images in Azure, must always use an existing one
+        """
+        raise vimconn.vimconnAuthException("It is not possible to create new images in AZURE")
+
+    def get_image_id_from_path(self, path):
+        """Get the image id from image path in the VIM database.
+           Returns the image_id or raises a vimconnNotFoundException
+        """
+        raise vimconn.vimconnAuthException("It is not possible to obtain image from path in AZURE")
+
+    def get_image_list(self, filter_dict={}):
+        """Obtain tenant images from VIM
+        Filter_dict can be:
+            name: image name with the format: publisher:offer:sku:version
+            If some part of the name is provide ex: publisher:offer it will search all availables skus and version
+            for the provided publisher and offer
+            id: image uuid, currently not supported for azure
+        Returns the image list of dictionaries:
+            [{<the fields at Filter_dict plus some VIM specific>}, ...]
+            List can be empty
+        """
+
+        self.logger.debug("get_image_list filter {}".format(filter_dict))
 
         self._reload_connection()
-        if filter_dict.get("name"):
-            params = filter_dict["name"].split(":")
-            if len(params) >= 3:
+        try:
+            image_list = []
+            if filter_dict.get("name"):
+                # name will have the format 'publisher:offer:sku:version'
+                # publisher is required, offer sku and version will be searched if not provided
+                params = filter_dict["name"].split(":")
                 publisher = params[0]
-                offer = params[1]
-                sku = params[2]
-                version = None
-                if len(params) == 4:
-                    version = params[3]
-                images = self.conn_compute.virtual_machine_images.list(self.region, publisher, offer, sku)
-                for image in images:
-                    if version:
-                        image_version = str(image.id).split("/")[-1]
-                        if image_version != version:
-                            continue
-                    image_list.append({
-                        'id': str(image.id),
-                        'name': self._get_resource_name_from_resource_id(image.id)
-                    })
-                return image_list
-
-        images = self.conn_compute.virtual_machine_images.list()
-
-        for image in images:
-            # TODO implement filter_dict
-            if filter_dict:
-                if filter_dict.get("id") and str(image.id) != filter_dict["id"]:
-                    continue
-                if filter_dict.get("name") and \
-                        self._get_resource_name_from_resource_id(image.id) != filter_dict["name"]:
-                    continue
-                # TODO add checksum
-            image_list.append({
-                'id': str(image.id),
-                'name': self._get_resource_name_from_resource_id(image.id),
-            })
+                if publisher:
+                    # obtain offer list
+                    offer_list = self._get_offer_list(params, publisher)
+                    for offer in offer_list:
+                        # obtain skus
+                        sku_list = self._get_sku_list(params, publisher, offer)
+                        for sku in sku_list:
+                            # if version is defined get directly version, else list images
+                            if len(params) == 4 and params[3]:
+                                version = params[3]
+                                image_list = self._get_version_image_list(publisher, offer, sku, version)
+                            else:
+                                image_list = self._get_sku_image_list(publisher, offer, sku)
+                else:
+                    raise vimconn.vimconnAuthException(
+                        "List images in Azure must include name param with at least publisher")
+            else:
+                raise vimconn.vimconnAuthException("List images in Azure must include name param with at"
+                                                   " least publisher")
+
+            return image_list
+        except Exception as e:
+            self._format_vimconn_exception(e)
+
+    def _get_offer_list(self, params, publisher):
+        """
+        Helper method to obtain offer list for defined publisher
+        """
+        if len(params) >= 2 and params[1]:
+            return [params[1]]
+        else:
+            try:
+                # get list of offers from azure
+                result_offers = self.conn_compute.virtual_machine_images.list_offers(self.region, publisher)
+                return [offer.name for offer in result_offers]
+            except CloudError as e:
+                # azure raises CloudError when not found
+                self.logger.info("error listing offers for publisher {}, Error: {}".format(publisher, e))
+                return []
+
+    def _get_sku_list(self, params, publisher, offer):
+        """
+        Helper method to obtain sku list for defined publisher and offer
+        """
+        if len(params) >= 3 and params[2]:
+            return [params[2]]
+        else:
+            try:
+                # get list of skus from azure
+                result_skus = self.conn_compute.virtual_machine_images.list_skus(self.region, publisher, offer)
+                return [sku.name for sku in result_skus]
+            except CloudError as e:
+                # azure raises CloudError when not found
+                self.logger.info("error listing skus for publisher {}, offer {}, Error: {}".format(publisher, offer, e))
+                return []
+
+    def _get_sku_image_list(self, publisher, offer, sku):
+        """
+        Helper method to obtain image list for publisher, offer and sku
+        """
+        image_list = []
+        try:
+            result_images = self.conn_compute.virtual_machine_images.list(self.region, publisher, offer, sku)
+            for result_image in result_images:
+                image_list.append({
+                    'id': str(result_image.id),
+                    'name': ":".join([publisher, offer, sku, result_image.name])
+                })
+        except CloudError as e:
+            self.logger.info(
+                "error listing skus for publisher {}, offer {}, Error: {}".format(publisher, offer, e))
+            image_list = []
+        return image_list
+
+    def _get_version_image_list(self, publisher, offer, sku, version):
+        image_list = []
+        try:
+            result_image = self.conn_compute.virtual_machine_images.get(self.region, publisher, offer, sku, version)
+            if result_image:
+                image_list.append({
+                    'id': str(result_image.id),
+                    'name': ":".join([publisher, offer, sku, version])
+                })
+        except CloudError as e:
+            # azure gives CloudError when not found
+            self.logger.info("error listing images for publisher {}, offer {}, sku {}, version {} Error: {}".
+                             format(publisher, offer, sku, version, e))
+            image_list = []
         return image_list
 
     def get_network_list(self, filter_dict={}):
         """Obtain tenant networks of VIM
         Filter_dict can be:
             name: network name
-            id: network uuid
-            shared: boolean
-            tenant_id: tenant
-            admin_state_up: boolean
-            status: 'ACTIVE'
+            id: network id
+            shared: boolean, not implemented in Azure
+            tenant_id: tenant, not used in Azure, all networks same tenants
+            admin_state_up: boolean, not implemented in Azure
+            status: 'ACTIVE', not implemented in Azure #
         Returns the network list of dictionaries
         """
-        self.logger.debug('Getting all subnets from VIM')
+        # self.logger.debug('getting network list for vim, filter %s', filter_dict)
         try:
             self._reload_connection()
-            vnet = self.conn_vnet.virtual_networks.get(self.config["resource_group"], self.vnet_name)
+
+            vnet = self.conn_vnet.virtual_networks.get(self.resource_group, self.vnet_name)
             subnet_list = []
-            
+
             for subnet in vnet.subnets:
-                # TODO implement filter_dict
                 if filter_dict:
                     if filter_dict.get("id") and str(subnet.id) != filter_dict["id"]:
                         continue
                     if filter_dict.get("name") and \
-                            self._get_resource_name_from_resource_id(subnet.id) != filter_dict["name"]:
+                            str(subnet.name) != filter_dict["name"]:
                         continue
 
+                name = self._get_resource_name_from_resource_id(subnet.id)
+
                 subnet_list.append({
                     'id': str(subnet.id),
-                     'name': self._get_resource_name_from_resource_id(subnet.id),
-                     'status': str(vnet.provisioning_state),  # TODO Does subnet contains status???
-                     'cidr_block': str(subnet.address_prefix)
-                    }
-                )
+                    'name': name,
+                    'status': self.provision_state2osm[subnet.provisioning_state],
+                    'cidr_block': str(subnet.address_prefix),
+                    'type': 'bridge',
+                    'shared': False
+                })
+
             return subnet_list
         except Exception as e:
-            self.format_vimconn_exception(e)
+            self._format_vimconn_exception(e)
 
-    def new_vminstance(self, vm_name, description, start, image_id, flavor_id, net_list, cloud_config=None,
+    def new_vminstance(self, name, description, start, image_id, flavor_id, net_list, cloud_config=None,
                        disk_list=None, availability_zone_index=None, availability_zone_list=None):
 
-        return self._new_vminstance(vm_name, image_id, flavor_id, net_list)
-        
-    def _new_vminstance(self, vm_name, image_id, flavor_id, net_list, cloud_config=None, disk_list=None,
-                        availability_zone_index=None, availability_zone_list=None):
-        #Create NICs
+        self.logger.debug("new vm instance name: %s, image_id: %s, flavor_id: %s, net_list: %s, cloud_config: %s, "
+                          "disk_list: %s, availability_zone_index: %s, availability_zone_list: %s",
+                          name, image_id, flavor_id, net_list, cloud_config, disk_list,
+                          availability_zone_index, availability_zone_list)
+
+        self._reload_connection()
+
+        # Validate input data is valid
+        # The virtual machine name must have less or 64 characters and it can not have the following
+        # characters: (~ ! @ # $ % ^ & * ( ) = + _ [ ] { } \ | ; : ' " , < > / ?.)
+        vm_name = self._check_vm_name(name)
+        # Obtain vm unused name
+        vm_name = self._get_unused_vm_name(vm_name)
+
+        # At least one network must be provided
+        if not net_list:
+            raise vimconn.vimconnException("At least one net must be provided to create a new VM")
+
+        # image_id are several fields of the image_id
+        image_reference = self._get_image_reference(image_id)
+
         self._check_subnets_for_vm(net_list)
         vm_nics = []
         for idx, net in enumerate(net_list):
-            subnet_id=net['subnet_id']
+            # Fault with subnet_id
+            # subnet_id=net['subnet_id']
+            # subnet_id=net['net_id']
             nic_name = vm_name + '-nic-'+str(idx)
-            vm_nic = self._create_nic(subnet_id, nic_name)
-            vm_nics.append({ 'id': str(vm_nic.id)})
+            vm_nic = self._create_nic(net, nic_name, net.get('ip_address'))
+            vm_nics.append({'id': str(vm_nic.id)})
+            net['vim_id'] = vm_nic.id
 
         try:
+
+            # cloud-init configuration
+            # cloud config
+            if cloud_config:
+                config_drive, userdata = self._create_user_data(cloud_config)
+                custom_data = base64.b64encode(userdata.encode('utf-8')).decode('latin-1')
+                key_data = None
+                key_pairs = cloud_config.get("key-pairs")
+                if key_pairs:
+                    key_data = key_pairs[0]
+
+                if cloud_config.get("users"):
+                    user_name = cloud_config.get("users")[0].get("name", "osm")
+                else:
+                    user_name = "osm"  # DEFAULT USER IS OSM
+
+                os_profile = {
+                    'computer_name': vm_name,
+                    'admin_username': user_name,
+                    'linux_configuration': {
+                        "disable_password_authentication": True,
+                        "ssh": {
+                            "public_keys": [{
+                                "path": "/home/{}/.ssh/authorized_keys".format(user_name),
+                                "key_data": key_data
+                            }]
+                        }
+                    },
+                    'custom_data': custom_data
+                }
+            else:
+                os_profile = {
+                    'computer_name': vm_name,
+                    'admin_username': 'osm',
+                    'admin_password': 'Osm4u!',
+                }
+
             vm_parameters = {
                 'location': self.region,
-                'os_profile': {
-                    'computer_name': vm_name,  # TODO if vm_name cannot be repeated add uuid4() suffix
-                    'admin_username': 'sergio',  # TODO is it mandatory???
-                    'linuxConfiguration': {
-                        'disablePasswordAuthentication': 'true',
-                        'ssh': {
-                          'publicKeys': [
-                            {
-                              'path': '/home/sergio/.ssh/authorized_keys',
-                              'keyData': self.pub_key
-                            }
-                          ]
-                        }
-                    }                    
-                    
-                },
+                'os_profile': os_profile,
                 'hardware_profile': {
-                    'vm_size':flavor_id
+                    'vm_size': flavor_id
                 },
                 'storage_profile': {
-                    'image_reference': image_id
-                },
-                'network_profile': {
-                    'network_interfaces': [
-                        vm_nics[0]
-                    ]
+                    'image_reference': image_reference
                 }
             }
+
+            # Add data disks if they are provided
+            if disk_list:
+                data_disks = []
+                for lun_name, disk in enumerate(disk_list):
+                    self.logger.debug("add disk size: %s, image: %s", disk.get("size"), disk.get("image_id"))
+                    if not disk.get("image_id"):
+                        data_disks.append({
+                            'lun': lun_name,  # You choose the value, depending of what is available for you
+                            'name': vm_name + "_data_disk-" + str(lun_name),
+                            'create_option': DiskCreateOption.empty,
+                            'disk_size_gb': disk.get("size")
+                        })
+                    else:
+                        # self.logger.debug("currently not able to create data disks from image for azure, ignoring")
+                        data_disks.append({
+                            'lun': lun_name,  # You choose the value, depending of what is available for you
+                            'name': vm_name + "_data_disk-" + str(lun_name),
+                            'create_option': 'Attach',
+                            'disk_size_gb': disk.get("size"),
+                            'managed_disk': {
+                                'id': disk.get("image_id")
+                            }
+                        })
+
+                if data_disks:
+                    vm_parameters["storage_profile"]["data_disks"] = data_disks
+
+            # If the machine has several networks one must be marked as primary
+            # As it is not indicated in the interface the first interface will be marked as primary
+            if len(vm_nics) > 1:
+                for idx, vm_nic in enumerate(vm_nics):
+                    if idx == 0:
+                        vm_nics[0]['Primary'] = True
+                    else:
+                        vm_nics[idx]['Primary'] = False
+
+            vm_parameters['network_profile'] = {'network_interfaces': vm_nics}
+
+            self.logger.debug("create vm name: %s", vm_name)
             creation_result = self.conn_compute.virtual_machines.create_or_update(
                 self.resource_group, 
-                vm_name, 
+                vm_name,
                 vm_parameters
             )
+            # creation_result.wait()
+            result = creation_result.result()
+            self.logger.debug("created vm name: %s", vm_name)
+
+            if start:
+                self.conn_compute.virtual_machines.start(
+                    self.resource_group,
+                    vm_name)
+            # start_result.wait()
+
+            return result.id, None
             
-            run_command_parameters = {
-                'command_id': 'RunShellScript', # For linux, don't change it
-                'script': [
-                'date > /home/sergio/test.txt'
-                ]
+            # run_command_parameters = {
+            #     'command_id': 'RunShellScript', # For linux, don't change it
+            #     'script': [
+            #     'date > /tmp/test.txt'
+            #     ]
+            # }
+        except Exception as e:
+            self.logger.debug('Exception creating new vminstance: %s', e, exc_info=True)
+            self._format_vimconn_exception(e)
+
+    def _get_unused_vm_name(self, vm_name):
+        """
+        Checks the vm name and in case it is used adds a suffix to the name to allow creation
+        :return:
+        """
+        all_vms = self.conn_compute.virtual_machines.list(self.resource_group)
+        # Filter to vms starting with the indicated name
+        vms = list(filter(lambda vm: (vm.name.startswith(vm_name)), all_vms))
+        vm_names = [str(vm.name) for vm in vms]
+
+        # get the name with the first not used suffix
+        name_suffix = 0
+        # name = subnet_name + "-" + str(name_suffix)
+        name = vm_name  # first subnet created will have no prefix
+        while name in vm_names:
+            name_suffix += 1
+            name = vm_name + "-" + str(name_suffix)
+        return name
+
+    # It is necesary extract from image_id data to create the VM with this format
+    #        'image_reference': {
+    #           'publisher': vm_reference['publisher'],
+    #           'offer': vm_reference['offer'],
+    #           'sku': vm_reference['sku'],
+    #           'version': vm_reference['version']
+    #        },
+    def _get_image_reference(self, image_id):
+
+        try:
+            # The data input format example:
+            # /Subscriptions/ca3d18ab-d373-4afb-a5d6-7c44f098d16a/Providers/Microsoft.Compute/Locations/westeurope/
+            # Publishers/Canonical/ArtifactTypes/VMImage/
+            # Offers/UbuntuServer/
+            # Skus/18.04-LTS/
+            # Versions/18.04.201809110
+            publisher = str(image_id.split('/')[8])
+            offer = str(image_id.split('/')[12])
+            sku = str(image_id.split('/')[14])
+            version = str(image_id.split('/')[16])
+
+            return {
+                'publisher': publisher,
+                'offer': offer,
+                'sku': sku,
+                'version': version
             }
-            poller = self.conn_compute.virtual_machines.run_command(
-                self.resource_group, 
-                vm_name, 
-                run_command_parameters
-            )
-            # TODO return a tuple (vm-ID, None)
         except Exception as e:
-            self.format_vimconn_exception(e)
+            raise vimconn.vimconnException(
+                "Unable to get image_reference from invalid image_id format: '{}'".format(image_id))
+
+    # Azure VM names can not have some special characters
+    def _check_vm_name(self, vm_name):
+        """
+        Checks vm name, in case the vm has not allowed characters they are removed, not error raised
+        """
+
+        chars_not_allowed_list = "~!@#$%^&*()=+_[]{}|;:<>/?."
+
+        # First: the VM name max length is 64 characters
+        vm_name_aux = vm_name[:64]
+
+        # Second: replace not allowed characters
+        for elem in chars_not_allowed_list:
+            # Check if string is in the main string
+            if elem in vm_name_aux:
+                # self.logger.debug('Dentro del IF')
+                # Replace the string
+                vm_name_aux = vm_name_aux.replace(elem, '-')
+
+        return vm_name_aux
 
     def get_flavor_id_from_data(self, flavor_dict):
-        self.logger.debug("Getting flavor id from data")
-        self._reload_connection()
-        vm_sizes_list = [vm_size.serialize() for vm_size in self.conn_compute.virtual_machine_sizes.list(self.region)]
 
-        cpus = flavor_dict['vcpus']
-        memMB = flavor_dict['ram']
+        self.logger.debug("getting flavor id from data, flavor_dict: %s", flavor_dict)
+        filter_dict = flavor_dict or {}
+        try:
+            self._reload_connection()
+            vm_sizes_list = [vm_size.serialize() for vm_size in
+                             self.conn_compute.virtual_machine_sizes.list(self.region)]
+
+            cpus = filter_dict.get('vcpus') or 0
+            memMB = filter_dict.get('ram') or 0
+
+            # Filter
+            if self._config.get("flavors_pattern"):
+                filtered_sizes = [size for size in vm_sizes_list if size['numberOfCores'] >= cpus and
+                                  size['memoryInMB'] >= memMB and
+                                  re.search(self._config.get("flavors_pattern"), size["name"])]
+            else:
+                filtered_sizes = [size for size in vm_sizes_list if size['numberOfCores'] >= cpus and
+                                  size['memoryInMB'] >= memMB]
 
-        filteredSizes = [size for size in vm_sizes_list if size['numberOfCores'] > cpus and size['memoryInMB'] > memMB]
-        listedFilteredSizes = sorted(filteredSizes, key=lambda k: k['numberOfCores'])
+            # Sort
+            listedFilteredSizes = sorted(filtered_sizes, key=lambda k: (k['numberOfCores'], k['memoryInMB'],
+                                                                        k['resourceDiskSizeInMB']))
 
-        return listedFilteredSizes[0]['name']
+            if listedFilteredSizes:
+                return listedFilteredSizes[0]['name']
+            raise vimconn.vimconnNotFoundException("Cannot find any flavor matching '{}'".format(str(flavor_dict)))
+
+        except Exception as e:
+            self._format_vimconn_exception(e)
+
+    def _get_flavor_id_from_flavor_name(self, flavor_name):
+
+        # self.logger.debug("getting flavor id from flavor name {}".format(flavor_name))
+        try:
+            self._reload_connection()
+            vm_sizes_list = [vm_size.serialize() for vm_size in
+                             self.conn_compute.virtual_machine_sizes.list(self.region)]
+
+            output_flavor = None
+            for size in vm_sizes_list:
+                if size['name'] == flavor_name:
+                    output_flavor = size
+
+            # None is returned if not found anything
+            return output_flavor
+
+        except Exception as e:
+            self._format_vimconn_exception(e)
 
     def check_vim_connectivity(self):
         try:
@@ -389,53 +864,382 @@ class vimconnector(vimconn.vimconnector):
             raise vimconn.vimconnException("Connectivity issue with Azure API: {}".format(e))
 
     def get_network(self, net_id):
-        resGroup = self._get_resource_group_name_from_resource_id(net_id)
-        resName = self._get_resource_name_from_resource_id(net_id)
-        
+
+        # self.logger.debug('get network id: {}'.format(net_id))
+        # res_name = self._get_resource_name_from_resource_id(net_id)
         self._reload_connection()
-        vnet = self.conn_vnet.virtual_networks.get(resGroup, resName)
 
-        return vnet
+        filter_dict = {'name': net_id}
+        network_list = self.get_network_list(filter_dict)
+
+        if not network_list:
+            raise vimconn.vimconnNotFoundException("network '{}' not found".format(net_id))
+        else:
+            return network_list[0]
+
+    def delete_network(self, net_id, created_items=None):
+
+        self.logger.debug('deleting network {} - {}'.format(self.resource_group, net_id))
 
-    def delete_network(self, net_id):
-        resGroup = self._get_resource_group_name_from_resource_id(net_id)
-        resName = self._get_resource_name_from_resource_id(net_id)
-        
         self._reload_connection()
-        self.conn_vnet.virtual_networks.delete(resGroup, resName)
+        res_name = self._get_resource_name_from_resource_id(net_id)
+        filter_dict = {'name': res_name}
+        network_list = self.get_network_list(filter_dict)
+        if not network_list:
+            raise vimconn.vimconnNotFoundException("network '{}' not found".format(net_id))
+
+        try:
+            # Subnet API fails (CloudError: Azure Error: ResourceNotFound)
+            # Put the initial virtual_network API
+            async_delete = self.conn_vnet.subnets.delete(self.resource_group, self.vnet_name, res_name)
+            async_delete.wait()
+            return net_id
+
+        except CloudError as e:
+            if e.error.error and "notfound" in e.error.error.lower():
+                raise vimconn.vimconnNotFoundException("network '{}' not found".format(net_id))
+            else:
+                self._format_vimconn_exception(e)
+        except Exception as e:
+            self._format_vimconn_exception(e)
 
-    def delete_vminstance(self, vm_id):
-        resGroup = self._get_resource_group_name_from_resource_id(net_id)
-        resName = self._get_resource_name_from_resource_id(net_id)
-        
+    def delete_vminstance(self, vm_id, created_items=None):
+        """ Deletes a vm instance from the vim.
+        """
+        self.logger.debug('deleting VM instance {} - {}'.format(self.resource_group, vm_id))
         self._reload_connection()
-        self.conn_compute.virtual_machines.delete(resGroup, resName)
+
+        try:
+
+            res_name = self._get_resource_name_from_resource_id(vm_id)
+            vm = self.conn_compute.virtual_machines.get(self.resource_group, res_name)
+
+            # Shuts down the virtual machine and releases the compute resources
+            # vm_stop = self.conn_compute.virtual_machines.power_off(self.resource_group, resName)
+            # vm_stop.wait()
+
+            vm_delete = self.conn_compute.virtual_machines.delete(self.resource_group, res_name)
+            vm_delete.wait()
+            self.logger.debug('deleted VM name: %s', res_name)
+
+            # Delete OS Disk
+            os_disk_name = vm.storage_profile.os_disk.name
+            self.logger.debug('delete OS DISK: %s', os_disk_name)
+            self.conn_compute.disks.delete(self.resource_group, os_disk_name)
+            self.logger.debug('deleted OS DISK name: %s', os_disk_name)
+
+            for data_disk in vm.storage_profile.data_disks:
+                self.logger.debug('delete data_disk: %s', data_disk.name)
+                self.conn_compute.disks.delete(self.resource_group, data_disk.name)
+                self.logger.debug('deleted OS DISK name: %s', data_disk.name)
+
+            # After deleting VM, it is necessary to delete NIC, because if is not deleted delete_network
+            # does not work because Azure says that is in use the subnet
+            network_interfaces = vm.network_profile.network_interfaces
+
+            for network_interface in network_interfaces:
+
+                nic_name = self._get_resource_name_from_resource_id(network_interface.id)
+                nic_data = self.conn_vnet.network_interfaces.get(
+                    self.resource_group,
+                    nic_name)
+
+                public_ip_name = None
+                exist_public_ip = nic_data.ip_configurations[0].public_ip_address
+                if exist_public_ip:
+                    public_ip_id = nic_data.ip_configurations[0].public_ip_address.id
+
+                    # Delete public_ip
+                    public_ip_name = self._get_resource_name_from_resource_id(public_ip_id)
+
+                    # Public ip must be deleted afterwards of nic that is attached
+
+                self.logger.debug('delete NIC name: %s', nic_name)
+                nic_delete = self.conn_vnet.network_interfaces.delete(self.resource_group, nic_name)
+                nic_delete.wait()
+                self.logger.debug('deleted NIC name: %s', nic_name)
+
+                # Delete list of public ips
+                if public_ip_name:
+                    self.logger.debug('delete PUBLIC IP - ' + public_ip_name)
+                    self.conn_vnet.public_ip_addresses.delete(self.resource_group, public_ip_name)
+
+        except CloudError as e:
+            if e.error.error and "notfound" in e.error.error.lower():
+                raise vimconn.vimconnNotFoundException("No vm instance found '{}'".format(vm_id))
+            else:
+                self._format_vimconn_exception(e)
+        except Exception as e:
+            self._format_vimconn_exception(e)
+
+    def action_vminstance(self, vm_id, action_dict, created_items={}):
+        """Send and action over a VM instance from VIM
+        Returns the vm_id if the action was successfully sent to the VIM
+        """
+
+        self.logger.debug("Action over VM '%s': %s", vm_id, str(action_dict))
+        try:
+            self._reload_connection()
+            resName = self._get_resource_name_from_resource_id(vm_id)
+            if "start" in action_dict:
+                self.conn_compute.virtual_machines.start(self.resource_group, resName)
+            elif "stop" in action_dict or "shutdown" in action_dict or "shutoff" in action_dict:
+                self.conn_compute.virtual_machines.power_off(self.resource_group, resName)
+            elif "terminate" in action_dict:
+                self.conn_compute.virtual_machines.delete(self.resource_group, resName)
+            elif "reboot" in action_dict:
+                self.conn_compute.virtual_machines.restart(self.resource_group, resName)
+            return None
+        except CloudError as e:
+            if e.error.error and "notfound" in e.error.error.lower():
+                raise vimconn.vimconnNotFoundException("No vm found '{}'".format(vm_id))
+            else:
+                self._format_vimconn_exception(e)
+        except Exception as e:
+            self._format_vimconn_exception(e)
+
+    def delete_flavor(self, flavor_id):
+        raise vimconn.vimconnAuthException("It is not possible to delete a FLAVOR in AZURE")
+
+    def delete_tenant(self, tenant_id,):
+        raise vimconn.vimconnAuthException("It is not possible to delete a TENANT in AZURE")
+
+    def delete_image(self, image_id):
+        raise vimconn.vimconnAuthException("It is not possible to delete a IMAGE in AZURE")
 
     def get_vminstance(self, vm_id):
-        resGroup = self._get_resource_group_name_from_resource_id(net_id)
-        resName = self._get_resource_name_from_resource_id(net_id)
-        
+        """
+        Obtaing the vm instance data from v_id
+        """
+        self.logger.debug("get vm instance: %s", vm_id)
         self._reload_connection()
-        vm=self.conn_compute.virtual_machines.get(resGroup, resName)
+        try:
+            resName = self._get_resource_name_from_resource_id(vm_id)
+            vm = self.conn_compute.virtual_machines.get(self.resource_group, resName)
+        except CloudError as e:
+            if e.error.error and "notfound" in e.error.error.lower():
+                raise vimconn.vimconnNotFoundException("No vminstance found '{}'".format(vm_id))
+            else:
+                self._format_vimconn_exception(e)
+        except Exception as e:
+            self._format_vimconn_exception(e)
 
         return vm
 
     def get_flavor(self, flavor_id):
+        """
+        Obtains the flavor_data from the flavor_id
+        """
         self._reload_connection()
-        for vm_size in self.conn_compute.virtual_machine_sizes.list(self.region):
-            if vm_size.name == flavor_id :
-                return vm_size
+        self.logger.debug("get flavor from id: %s", flavor_id)
+        flavor_data = self._get_flavor_id_from_flavor_name(flavor_id)
+        if flavor_data:
+            flavor = {
+                'id': flavor_id,
+                'name': flavor_id,
+                'ram': flavor_data['memoryInMB'],
+                'vcpus': flavor_data['numberOfCores'],
+                'disk': flavor_data['resourceDiskSizeInMB']/1024
+            }
+            return flavor
+        else:
+            raise vimconn.vimconnNotFoundException("flavor '{}' not found".format(flavor_id))
+
+    def get_tenant_list(self, filter_dict={}):
+        """ Obtains the list of tenants
+            For the azure connector only the azure tenant will be returned if it is compatible
+            with filter_dict
+        """
+        tenants_azure = [{'name': self.tenant, 'id': self.tenant}]
+        tenant_list = []
+
+        self.logger.debug("get tenant list: %s", filter_dict)
+        for tenant_azure in tenants_azure:
+            if filter_dict:
+                if filter_dict.get("id") and str(tenant_azure.get("id")) != filter_dict["id"]:
+                    continue
+                if filter_dict.get("name") and str(tenant_azure.get("name")) != filter_dict["name"]:
+                    continue
+
+            tenant_list.append(tenant_azure)
+
+        return tenant_list
 
+    def refresh_nets_status(self, net_list):
+        """Get the status of the networks
+            Params: the list of network identifiers
+            Returns a dictionary with:
+                net_id:  #VIM id of this network
+                status:  #Mandatory. Text with one of:
+                         #  DELETED (not found at vim)
+                         #  VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
+                         #  OTHER (Vim reported other status not understood)
+                         #  ERROR (VIM indicates an ERROR status)
+                         #  ACTIVE, INACTIVE, DOWN (admin down),
+                         #  BUILD (on building process)
+                         #
+                error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR
+                 vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
+
+        """
+
+        out_nets = {}
+        self._reload_connection()
+
+        self.logger.debug("reload nets status net_list: %s", net_list)
+        for net_id in net_list:
+            try:
+                netName = self._get_net_name_from_resource_id(net_id)
+                resName = self._get_resource_name_from_resource_id(net_id)
+
+                net = self.conn_vnet.subnets.get(self.resource_group, netName, resName)
+
+                out_nets[net_id] = {
+                    "status": self.provision_state2osm[net.provisioning_state],
+                    "vim_info": str(net)
+                }
+            except CloudError as e:
+                if e.error.error and "notfound" in e.error.error.lower():
+                    self.logger.info("Not found subnet net_name: %s, subnet_name: %s", netName, resName)
+                    out_nets[net_id] = {
+                        "status": "DELETED",
+                        "error_msg": str(e)
+                    }
+                else:
+                    self.logger.error("CloudError Exception %s when searching subnet", e)
+                    out_nets[net_id] = {
+                        "status": "VIM_ERROR",
+                        "error_msg": str(e)
+                    }
+            except vimconn.vimconnNotFoundException as e:
+                self.logger.error("VimConnNotFoundException %s when searching subnet", e)
+                out_nets[net_id] = {
+                    "status": "DELETED",
+                    "error_msg": str(e)
+                }
+            except Exception as e:
+                self.logger.error("Exception %s when searching subnet", e, exc_info=True)
+                out_nets[net_id] = {
+                    "status": "VIM_ERROR",
+                    "error_msg": str(e)
+                }
+        return out_nets
+
+    def refresh_vms_status(self, vm_list):
+        """ Get the status of the virtual machines and their interfaces/ports
+        Params: the list of VM identifiers
+        Returns a dictionary with:
+            vm_id:          # VIM id of this Virtual Machine
+                status:     # Mandatory. Text with one of:
+                            #  DELETED (not found at vim)
+                            #  VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
+                            #  OTHER (Vim reported other status not understood)
+                            #  ERROR (VIM indicates an ERROR status)
+                            #  ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
+                            #  BUILD (on building process), ERROR
+                            #  ACTIVE:NoMgmtIP (Active but none of its interfaces has an IP address
+                            #     (ACTIVE:NoMgmtIP is not returned for Azure)
+                            #
+                error_msg:  #Text with VIM error message, if any. Or the VIM connection ERROR
+                vim_info:   #Text with plain information obtained from vim (yaml.safe_dump)
+                interfaces: list with interface info. Each item a dictionary with:
+                    vim_interface_id -  The ID of the interface
+                    mac_address - The MAC address of the interface.
+                    ip_address - The IP address of the interface within the subnet.
+        """
+
+        out_vms = {}
+        self._reload_connection()
+
+        self.logger.debug("refresh vm status vm_list: %s", vm_list)
+        search_vm_list = vm_list or {}
+
+        for vm_id in search_vm_list:
+            out_vm = {}
+            try:
+                res_name = self._get_resource_name_from_resource_id(vm_id)
+
+                vm = self.conn_compute.virtual_machines.get(self.resource_group, res_name)
+                out_vm['vim_info'] = str(vm)
+                out_vm['status'] = self.provision_state2osm.get(vm.provisioning_state, 'OTHER')
+                if vm.provisioning_state == 'Succeeded':
+                    # check if machine is running or stopped
+                    instance_view = self.conn_compute.virtual_machines.instance_view(self.resource_group,
+                                                                                     res_name)
+                    for status in instance_view.statuses:
+                        splitted_status = status.code.split("/")
+                        if len(splitted_status) == 2 and splitted_status[0] == 'PowerState':
+                            out_vm['status'] = self.power_state2osm.get(splitted_status[1], 'OTHER')
+
+                network_interfaces = vm.network_profile.network_interfaces
+                out_vm['interfaces'] = self._get_vm_interfaces_status(vm_id, network_interfaces)
+
+            except CloudError as e:
+                if e.error.error and "notfound" in e.error.error.lower():
+                    self.logger.debug("Not found vm id: %s", vm_id)
+                    out_vm['status'] = "DELETED"
+                    out_vm['error_msg'] = str(e)
+                    out_vm['vim_info'] = None
+                else:
+                    # maybe connection error or another type of error, return vim error
+                    self.logger.error("Exception %s refreshing vm_status", e)
+                    out_vm['status'] = "VIM_ERROR"
+                    out_vm['error_msg'] = str(e)
+                    out_vm['vim_info'] = None
+            except Exception as e:
+                self.logger.error("Exception %s refreshing vm_status", e, exc_info=True)
+                out_vm['status'] = "VIM_ERROR"
+                out_vm['error_msg'] = str(e)
+                out_vm['vim_info'] = None
+
+            out_vms[vm_id] = out_vm
+
+        return out_vms
+
+    def _get_vm_interfaces_status(self, vm_id, interfaces):
+        """
+        Gets the interfaces detail for a vm
+        :param interfaces: List of interfaces.
+        :return: Dictionary with list of interfaces including, vim_interface_id, mac_address and ip_address
+        """
+        try:
+            interface_list = []
+            for network_interface in interfaces:
+                interface_dict = {}
+                nic_name = self._get_resource_name_from_resource_id(network_interface.id)
+                interface_dict['vim_interface_id'] = network_interface.id
+
+                nic_data = self.conn_vnet.network_interfaces.get(
+                    self.resource_group,
+                    nic_name)
+
+                ips = []
+                if nic_data.ip_configurations[0].public_ip_address:
+                    self.logger.debug("Obtain public ip address")
+                    public_ip_name = self._get_resource_name_from_resource_id(
+                        nic_data.ip_configurations[0].public_ip_address.id)
+                    public_ip = self.conn_vnet.public_ip_addresses.get(self.resource_group, public_ip_name)
+                    self.logger.debug("Public ip address is: %s", public_ip.ip_address)
+                    ips.append(public_ip.ip_address)
+
+                private_ip = nic_data.ip_configurations[0].private_ip_address
+                ips.append(private_ip)
+
+                interface_dict['mac_address'] = nic_data.mac_address
+                interface_dict['ip_address'] = ";".join(ips)
+                interface_list.append(interface_dict)
+
+            return interface_list
+        except Exception as e:
+            self.logger.error("Exception %s obtaining interface data for vm: %s, error: %s", vm_id, e, exc_info=True)
+            self._format_vimconn_exception(e)
 
-# TODO refresh_nets_status ver estado activo
-# TODO refresh_vms_status  ver estado activo
-# TODO get_vminstance_console  for getting console
 
 if __name__ == "__main__":
 
     # Making some basic test
-    vim_id='azure'
-    vim_name='azure'
+    vim_id = 'azure'
+    vim_name = 'azure'
     needed_test_params = {
         "client_id": "AZURE_CLIENT_ID",
         "secret": "AZURE_SECRET",
@@ -453,11 +1257,11 @@ if __name__ == "__main__":
         test_params[param] = value
 
     config = {
-            'region_name': getenv("AZURE_REGION_NAME", 'westeurope'),
-            'resource_group': getenv("AZURE_RESOURCE_GROUP"),
-            'subscription_id': getenv("AZURE_SUBSCRIPTION_ID"),
-            'pub_key': getenv("AZURE_PUB_KEY", None),
-            'vnet_name': getenv("AZURE_VNET_NAME", 'myNetwork'),
+        'region_name': getenv("AZURE_REGION_NAME", 'westeurope'),
+        'resource_group': getenv("AZURE_RESOURCE_GROUP"),
+        'subscription_id': getenv("AZURE_SUBSCRIPTION_ID"),
+        'pub_key': getenv("AZURE_PUB_KEY", None),
+        'vnet_name': getenv("AZURE_VNET_NAME", 'myNetwork'),
     }
 
     virtualMachine = {
@@ -480,7 +1284,7 @@ if __name__ == "__main__":
 
     vnet_config = {
         'subnet_address': '10.1.2.0/24',
-        #'subnet_name': 'subnet-oam'
+        # 'subnet_name': 'subnet-oam'
     }
     ###########################
 
@@ -492,4 +1296,9 @@ if __name__ == "__main__":
     # azure.new_vminstance(virtualMachine['name'], virtualMachine['description'], virtualMachine['status'],
     #                      virtualMachine['image'], virtualMachine['hardware_profile']['vm_size'], subnets)
 
-    azure.get_flavor("Standard_A11")
\ No newline at end of file
+    azure.new_network("mynet", None)
+    net_id = "/subscriptions/82f80cc1-876b-4591-9911-1fb5788384fd/resourceGroups/osmRG/providers/Microsoft."\
+             "Network/virtualNetworks/test"
+    net_id_not_found = "/subscriptions/82f80cc1-876b-4591-9911-1fb5788384fd/resourceGroups/osmRG/providers/"\
+                       "Microsoft.Network/virtualNetworks/testALF"
+    azure.refresh_nets_status([net_id, net_id_not_found])
index 932853c..a777f69 100755 (executable)
 #
 ##
 
+# DEBUG WITH PDB
+from os import getenv
+if getenv('OSMRO_PDB_DEBUG'):
+    import sys
+    print(sys.path)
+    import pdb
+    pdb.set_trace()
+
+
 """
 Module for testing openmano functionality. It uses openmanoclient.py for invoking openmano
 """
@@ -97,6 +106,7 @@ class test_VIM_datacenter_tenant_operations(test_base):
         self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index,
                                                            inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
+        logger.debug("Test create tenant")
         tenant = test_config["client"].create_tenant(name=self.__class__.tenant_name,
                                                      description=self.__class__.tenant_name)
         logger.debug("{}".format(tenant))
@@ -291,12 +301,13 @@ class test_vimconn_connect(test_base):
             vca_object = test_config["vim_conn"].connect()
             logger.debug("{}".format(vca_object))
             self.assertIsNotNone(vca_object)
-        elif test_config['vimtype'] == 'openstack':
+        elif test_config['vimtype'] in ('openstack', 'azure'):
             test_config["vim_conn"]._reload_connection()
             network_list = test_config["vim_conn"].get_network_list()
             logger.debug("{}".format(network_list))
             self.assertIsNotNone(network_list)
 
+
 class test_vimconn_new_network(test_base):
     network_name = None
 
@@ -311,9 +322,10 @@ class test_vimconn_new_network(test_base):
         network, _ = test_config["vim_conn"].new_network(net_name=self.__class__.network_name,
                                                           net_type=network_type)
         self.__class__.network_id = network
-        logger.debug("{}".format(network))
+        logger.debug("Created network {}".format(network))
 
         network_list = test_config["vim_conn"].get_network_list()
+        logger.debug("Network list {}".format(network_list))
         for net in network_list:
             if self.__class__.network_name in net.get('name'):
                 self.assertIn(self.__class__.network_name, net.get('name'))
@@ -326,12 +338,17 @@ class test_vimconn_new_network(test_base):
         else:
             logger.info("Failed to delete network id {}".format(self.__class__.network_id))
 
+        network_list = test_config["vim_conn"].get_network_list()
+        logger.debug("Network list after deletion {}".format(network_list))
+
     def test_010_new_network_by_types(self):
         delete_net_ids = []
         network_types = ['data','bridge','mgmt']
         self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"],
                                                             self.__class__.test_index,
                                                 inspect.currentframe().f_code.co_name)
+        network_list = test_config["vim_conn"].get_network_list()
+        logger.debug("Network list at start {}".format(network_list))
         self.__class__.test_index += 1
         for net_type in network_types:
             self.__class__.network_name = _get_random_string(20)
@@ -357,6 +374,8 @@ class test_vimconn_new_network(test_base):
                 logger.info("Network id {} sucessfully deleted".format(net_id))
             else:
                 logger.info("Failed to delete network id {}".format(net_id))
+        network_list = test_config["vim_conn"].get_network_list()
+        logger.debug("Network list after test {}".format(network_list))
 
     def test_020_new_network_by_ipprofile(self):
         test_directory_content = os.listdir(test_config["test_directory"])
@@ -371,15 +390,14 @@ class test_vimconn_new_network(test_base):
             with open(vnfd, 'r') as stream:
                 vnf_descriptor = yaml.load(stream)
 
-            internal_connections_list = vnf_descriptor['vnf']['internal-connections']
+            #internal_connections_list = vnf_descriptor['vnf']['internal-connections']
+            internal_connections_list = vnf_descriptor['vnfd-catalog']['vnfd'][0]['ip-profiles']
             for item in internal_connections_list:
-                if 'ip-profile' in item:
-                    version = item['ip-profile']['ip-version']
-                    dhcp_count = item['ip-profile']['dhcp']['count']
-                    dhcp_enabled = item['ip-profile']['dhcp']['enabled']
-                    dhcp_start_address = item['ip-profile']['dhcp']['start-address']
-                    subnet_address = item['ip-profile']['subnet-address']
-
+                version = item['ip-version']
+                dhcp_count = item['dhcp-params']['count']
+                dhcp_enabled = item['dhcp-params']['enabled']
+                dhcp_start_address = item['dhcp-params']['start-address']
+                subnet_address = item['subnet-address']
 
         self.__class__.network_name = _get_random_string(20)
         ip_profile = {'dhcp_count': dhcp_count,
@@ -399,6 +417,7 @@ class test_vimconn_new_network(test_base):
         logger.debug("{}".format(network))
 
         network_list = test_config["vim_conn"].get_network_list()
+        logger.debug("Created network by ip_profile {}".format(network_list))
         for net in network_list:
             if self.__class__.network_name in net.get('name'):
                 self.assertIn(self.__class__.network_name, net.get('name'))
@@ -489,8 +508,17 @@ class test_vimconn_new_network(test_base):
         self.__class__.test_index += 1
 
         # refresh net status
+        # if azure network name must have the following format
+        if test_config['vimtype'] == 'azure':
+            unknown_net_id = "/" + "/".join(["subscriptions", test_config["vim_conn"].subscription_id,
+                                      "resourceGroups", test_config["vim_conn"].resource_group,
+                                      "providers", "Microsoft.Network",
+                                      "virtualNetworks", test_config["vim_conn"].vnet_name,
+                                      "subnets", unknown_net_id])
+        #unknown_net_id = "/subscriptions/ca3d18ab-d373-4afb-a5d6-7c44f098d16a/resourceGroups/osmRG/providers/Microsoft.Network/virtualNetworks/osm_vnet/subnets/unnkown_net"
+
         net_dict = test_config["vim_conn"].refresh_nets_status([unknown_net_id])
-        if test_config['vimtype'] == 'openstack':
+        if test_config['vimtype'] in ('openstack', 'azure'):
             self.assertEqual(net_dict[unknown_net_id]['status'], 'DELETED')
         else:
             # TODO : Fix vmware connector to return status DELETED as per vimconn.py
@@ -530,7 +558,8 @@ class test_vimconn_get_network_list(test_base):
                 self.assertIn(self.__class__.network_name, net.get('name'))
                 self.assertEqual(net.get('type'), self.__class__.net_type)
                 self.assertEqual(net.get('status'), 'ACTIVE')
-                self.assertEqual(net.get('shared'), False)
+                if test_config['vimtype'] != 'azure':
+                    self.assertEqual(net.get('shared'), False)
 
     def test_010_get_network_list_by_name(self):
         self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"],
@@ -538,7 +567,7 @@ class test_vimconn_get_network_list(test_base):
                                                 inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
 
-        if test_config['vimtype'] == 'openstack':
+        if test_config['vimtype'] in ('openstack', 'azure'):
             network_name = test_config['vim_conn'].get_network(self.__class__.network_id)['name']
         else:
             network_name = test_config['vim_conn'].get_network_name_by_id(self.__class__.network_id)
@@ -572,7 +601,7 @@ class test_vimconn_get_network_list(test_base):
                                                 inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
 
-        if test_config['vimtype'] == 'openstack':
+        if test_config['vimtype'] in ('openstack', 'azure'):
             network_name = test_config['vim_conn'].get_network(self.__class__.network_id)['name']
         else:
             network_name = test_config['vim_conn'].get_network_name_by_id(self.__class__.network_id)
@@ -592,7 +621,7 @@ class test_vimconn_get_network_list(test_base):
         self.__class__.test_index += 1
 
         tenant_list = test_config["vim_conn"].get_tenant_list()
-        if test_config['vimtype'] == 'openstack':
+        if test_config['vimtype'] in ('openstack', 'azure'):
             network_name = test_config['vim_conn'].get_network(self.__class__.network_id)['name']
         else:
             network_name = test_config['vim_conn'].get_network_name_by_id(self.__class__.network_id)
@@ -616,7 +645,7 @@ class test_vimconn_get_network_list(test_base):
         self.__class__.test_index += 1
         status = 'ACTIVE'
 
-        if test_config['vimtype'] == 'openstack':
+        if test_config['vimtype'] in ('openstack', 'azure'):
             network_name = test_config['vim_conn'].get_network(self.__class__.network_id)['name']
         else:
             network_name = test_config['vim_conn'].get_network_name_by_id(self.__class__.network_id)
@@ -788,17 +817,23 @@ class test_vimconn_new_flavor(test_base):
     flavor_id = None
 
     def test_000_new_flavor(self):
-        flavor_data = {'name': _get_random_string(20), 'ram': 1024, 'vpcus': 1, 'disk': 10}
+        flavor_data = {'name': _get_random_string(20), 'ram': 1024, 'vcpus': 1, 'disk': 10}
 
         self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"],
                                                             self.__class__.test_index,
                                                 inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
 
-        # create new flavor
-        self.__class__.flavor_id = test_config["vim_conn"].new_flavor(flavor_data)
-        self.assertIsInstance(self.__class__.flavor_id, (str, unicode))
-        self.assertIsInstance(uuid.UUID(self.__class__.flavor_id), uuid.UUID)
+        if test_config['vimtype'] == 'azure':
+            with self.assertRaises(Exception) as context:
+                test_config["vim_conn"].new_flavor(flavor_data)
+
+            self.assertEqual((context.exception).http_code, 401)
+        else:
+            # create new flavor
+            self.__class__.flavor_id = test_config["vim_conn"].new_flavor(flavor_data)
+            self.assertIsInstance(self.__class__.flavor_id, (str, unicode))
+            self.assertIsInstance(uuid.UUID(self.__class__.flavor_id), uuid.UUID)
 
     def test_010_delete_flavor(self):
         self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"],
@@ -807,12 +842,18 @@ class test_vimconn_new_flavor(test_base):
         self.__class__.test_index += 1
 
         # delete flavor
-        result = test_config["vim_conn"].delete_flavor(self.__class__.flavor_id)
-        if result:
-            logger.info("Flavor id {} sucessfully deleted".format(result))
+        if test_config['vimtype'] == 'azure':
+            with self.assertRaises(Exception) as context:
+                test_config["vim_conn"].delete_flavor(self.__class__.flavor_id)
+
+            self.assertEqual((context.exception).http_code, 401)
         else:
-            logger.error("Failed to delete flavor id {}".format(result))
-            raise Exception ("Failed to delete created flavor")
+            result = test_config["vim_conn"].delete_flavor(self.__class__.flavor_id)
+            if result:
+                logger.info("Flavor id {} sucessfully deleted".format(result))
+            else:
+                logger.error("Failed to delete flavor id {}".format(result))
+                raise Exception ("Failed to delete created flavor")
 
     def test_020_new_flavor_negative(self):
         Invalid_flavor_data = {'ram': '1024', 'vcpus': 2.0, 'disk': 2.0}
@@ -824,8 +865,10 @@ class test_vimconn_new_flavor(test_base):
 
         with self.assertRaises(Exception) as context:
             test_config["vim_conn"].new_flavor(Invalid_flavor_data)
-
-        self.assertEqual((context.exception).http_code, 400)
+        if test_config['vimtype'] != 'azure':
+            self.assertEqual((context.exception).http_code, 400)
+        else:
+            self.assertEqual((context.exception).http_code, 401)
 
     def test_030_delete_flavor_negative(self):
         Non_exist_flavor_id = str(uuid.uuid4())
@@ -838,7 +881,10 @@ class test_vimconn_new_flavor(test_base):
         with self.assertRaises(Exception) as context:
             test_config["vim_conn"].delete_flavor(Non_exist_flavor_id)
 
-        self.assertEqual((context.exception).http_code, 404)
+        if test_config['vimtype'] != 'azure':
+            self.assertEqual((context.exception).http_code, 404)
+        else:
+            self.assertEqual((context.exception).http_code, 401)
 
 # class test_vimconn_new_image(test_base):
 #
@@ -931,27 +977,38 @@ class test_vimconn_get_image_list(test_base):
                                                             self.__class__.test_index,
                                                 inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
-        image_list = test_config["vim_conn"].get_image_list()
 
-        for item in image_list:
-            if 'name' in item:
-                self.__class__.image_name = item['name']
-                self.__class__.image_id = item['id']
-                self.assertIsInstance(self.__class__.image_name, (str, unicode))
-                self.assertIsInstance(self.__class__.image_id, (str, unicode))
+        if test_config['vimtype'] != 'azure':
+            image_list = test_config["vim_conn"].get_image_list()
+            logger.debug("{}: Result image list: {}".format(self.__class__.test_text, image_list))
+
+            for item in image_list:
+                if 'name' in item:
+                    self.__class__.image_name = item['name']
+                    self.__class__.image_id = item['id']
+                    self.assertIsInstance(self.__class__.image_name, (str, unicode))
+                    self.assertIsInstance(self.__class__.image_id, (str, unicode))
+        else:
+            with self.assertRaises(Exception) as context:
+                image_list = test_config["vim_conn"].get_image_list()
+                self.assertEqual((context.exception).http_code, 401)
+                logger.debug(self.__class__.test_text + "Exception unauthorized: " + str(context.exception))
 
     def test_010_get_image_list_by_name(self):
         self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"],
                                                             self.__class__.test_index,
                                                 inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
+        self.__class__.image_name = test_config['image_name']
+        logger.debug("{}: Image name: {}".format(self.__class__.test_text, self.__class__.image_name))
 
         image_list = test_config["vim_conn"].get_image_list({'name': self.__class__.image_name})
+        logger.debug("{}: Result image list: {}".format(self.__class__.test_text, image_list))
 
         for item in image_list:
             self.assertIsInstance(item['id'], (str, unicode))
             self.assertIsInstance(item['name'], (str, unicode))
-            self.assertEqual(item['id'], self.__class__.image_id)
+            #self.assertEqual(item['id'], self.__class__.image_id)
             self.assertEqual(item['name'], self.__class__.image_name)
 
     def test_020_get_image_list_by_id(self):
@@ -1031,9 +1088,13 @@ class test_vimconn_new_vminstance(test_base):
                                                 inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
 
-        net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'vpci': vpci, 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}]
+        net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'vpci': vpci,
+                     'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}]
 
-        self.__class__.instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, image_id=self.__class__.image_id, flavor_id=flavor_id, net_list=net_list)
+        self.__class__.instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='',
+                                                                               start=False,
+                                                                               image_id=self.__class__.image_id,
+                                                                               flavor_id=flavor_id, net_list=net_list)
 
         self.assertIsInstance(self.__class__.instance_id, (str, unicode))
 
@@ -1050,9 +1111,12 @@ class test_vimconn_new_vminstance(test_base):
                                                 inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
 
-        net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'port_security': True, 'model': model_name, 'type': 'virtual', 'net_id': self.__class__.network_id}]
+        net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'port_security': True,
+                     'model': model_name, 'type': 'virtual', 'net_id': self.__class__.network_id}]
 
-        instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, image_id=self.__class__.image_id,flavor_id=flavor_id,net_list=net_list)
+        instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False,
+                                                                image_id=self.__class__.image_id,
+                                                                flavor_id=flavor_id,net_list=net_list)
 
         self.assertIsInstance(instance_id, (str, unicode))
 
@@ -1074,11 +1138,12 @@ class test_vimconn_new_vminstance(test_base):
                                                 inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
 
-        net_list = [{'use': net_use, 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}]
+        net_list = [{'use': net_use, 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'virtual',
+                     'net_id': self.__class__.network_id}]
 
-        instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, image_id=self.__class__.image_id,disk_list=None,
-                                                                                           flavor_id=flavor_id,
-                                                                                             net_list=net_list)
+        instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False,
+                                                                image_id=self.__class__.image_id,disk_list=None,
+                                                                flavor_id=flavor_id, net_list=net_list)
         self.assertIsInstance(instance_id, (str, unicode))
 
         # Deleting created vm instance
@@ -1108,7 +1173,7 @@ class test_vimconn_new_vminstance(test_base):
                                                                     net_list=net_list)
             self.assertEqual(type(instance_id),str)
 
-        if test_config['vimtype'] == 'openstack':
+        if test_config['vimtype'] in ('openstack', 'azure'):
             # create network of type data
             network_name = _get_random_string(20)
             net_type = 'data'
@@ -1119,9 +1184,9 @@ class test_vimconn_new_vminstance(test_base):
                          'type': _type, 'net_id': network_id}]
 
             instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False,
-                                                                    image_id=self.__class__.image_id, disk_list=None,
-                                                                    flavor_id=flavor_id,
-                                                                    net_list=net_list)
+                                                                   image_id=self.__class__.image_id, disk_list=None,
+                                                                   flavor_id=flavor_id,
+                                                                   net_list=net_list)
 
             self.assertEqual(type(instance_id), unicode)
 
@@ -1142,11 +1207,12 @@ class test_vimconn_new_vminstance(test_base):
         name = 'eth0'
         user_name = 'test_user'
 
-        key_pairs = ['ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCy2w9GHMKKNkpCmrDK2ovc3XBYDETuLWwaW24S+feHhLBQiZlzh3gSQoINlA+2ycM9zYbxl4BGzEzpTVyCQFZv5PidG4m6ox7LR+KYkDcITMyjsVuQJKDvt6oZvRt6KbChcCi0n2JJD/oUiJbBFagDBlRslbaFI2mmqmhLlJ5TLDtmYxzBLpjuX4m4tv+pdmQVfg7DYHsoy0hllhjtcDlt1nn05WgWYRTu7mfQTWfVTavu+OjIX3e0WN6NW7yIBWZcE/Q9lC0II3W7PZDE3QaT55se4SPIO2JTdqsx6XGbekdG1n6adlduOI27sOU5m4doiyJ8554yVbuDB/z5lRBD alfonso.tiernosepulveda@telefonica.com']
+        key_pairs = ['ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDtAjl5R+GSKP3gFrdFxgizKEUzhXKQbyjaxJH9thsK     0/fDiYlaNEjvijgPgiVZkfwvqgWeLprPcpzL2j4jvmmSJ3+7C8ihCwObWP0VUiuewmbIINBPAR0RqusjMRyPsa+q0asFBPOoZLx3Cv3vzmC1AA3mKuCNeT     EuA0rlWhDIOVwMcU5sP1grnmuexQB8HcR7BdKcA9y08pTwnCQR8vmtW77SRkaxEGXm4Gnw5qw8Z27mHdk2wWS2SnbVH7aFwWvDXc6jjf5TpEWypdr/EAPC     +eJipeS2Oa4FsntEqAu3Fz6gp/9ub8uNqgCgHfMzs6FhYpZpipwS0hXYyF6eVsSx osm@osm']
 
-        users_data = [{'key-pairs': ['ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCy2w9GHMKKNkpCmrDK2ovc3XBYDETuLWwaW24S+feHhLBQiZlzh3gSQoINlA+2ycM9zYbxl4BGzEzpTVyCQFZv5PidG4m6ox7LR+KYkDcITMyjsVuQJKDvt6oZvRt6KbChcCi0n2JJD/oUiJbBFagDBlRslbaFI2mmqmhLlJ5TLDtmYxzBLpjuX4m4tv+pdmQVfg7DYHsoy0hllhjtcDlt1nn05WgWYRTu7mfQTWfVTavu+OjIX3e0WN6NW7yIBWZcE/Q9lC0II3W7PZDE3QaT55se4SPIO2JTdqsx6XGbekdG1n6adlduOI27sOU5m4doiyJ8554yVbuDB/z5lRBD alfonso.tiernosepulveda@telefonica.com'], 'name': user_name}]
+        users_data = [{'key-pairs': ['ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDtAjl5R+GSKP3gFrdFxgizKEUzhXKQbyjaxJH9thsK0/fDiYlaNEjvijgPgiVZkfwvqgWeLprPcpzL2j4jvmmSJ3+7C8ihCwObWP0VUiuewmbIINBPAR0RqusjMRyPsa+q0asFBPOoZLx3Cv3vzmC1AA3mKuCNeTEuA0rlWhDIOVwMcU5sP1grnmuexQB8HcR7BdKcA9y08pTwnCQR8vmtW77SRkaxEGXm4Gnw5qw8Z27mHdk2wWS2SnbVH7aFwWvDXc6jjf5TpEWypdr/EAPC+eJipeS2Oa4FsntEqAu3Fz6gp/9ub8uNqgCgHfMzs6FhYpZpipwS0hXYyF6eVsSx osm@osm'], 'name': 'cloudinit'}]
 
         cloud_data = {'config-files': [{'content': 'auto enp0s3\niface enp0s3 inet dhcp\n', 'dest': '/etc/network/interfaces.d/enp0s3.cfg', 'owner': 'root:root', 'permissions': '0644'}, {'content': '#! /bin/bash\nls -al >> /var/log/osm.log\n', 'dest': '/etc/rc.local', 'permissions': '0755'}, {'content': 'file content', 'dest': '/etc/test_delete'}], 'boot-data-drive': True, 'key-pairs': key_pairs, 'users': users_data }
+        #cloud_data = {'users': users_data }
 
         # create new flavor
         flavor_id = test_config["vim_conn"].new_flavor(flavor_data)
@@ -1156,10 +1222,13 @@ class test_vimconn_new_vminstance(test_base):
                                                 inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
 
-        net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}]
+        net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'port_security': True,
+                     'type': 'virtual', 'net_id': self.__class__.network_id}]
 
         instance_id, _ = test_config["vim_conn"].new_vminstance(name='Cloud_vm', description='', start=False,
-                                                                image_id=self.__class__.image_id, flavor_id=flavor_id,net_list=net_list,cloud_config=cloud_data)
+                                                                image_id=self.__class__.image_id,
+                                                                flavor_id=flavor_id,net_list=net_list,
+                                                                cloud_config=cloud_data)
 
         self.assertIsInstance(instance_id, (str, unicode))
 
@@ -1182,12 +1251,13 @@ class test_vimconn_new_vminstance(test_base):
                                                 inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
 
-        net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}]
+        net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'port_security': True,
+                     'type': 'virtual', 'net_id': self.__class__.network_id}]
 
-        instance_id, _ = test_config["vim_conn"].new_vminstance(name='VM_test1', description='', start=False, image_id=self.__class__.image_id,
-                                                                                           flavor_id=flavor_id,
-                                                                                             net_list=net_list,
-                                                                                         disk_list=device_data)
+        instance_id, _ = test_config["vim_conn"].new_vminstance(name='VM_test1', description='', start=False,
+                                                                image_id=self.__class__.image_id,
+                                                                flavor_id=flavor_id, net_list=net_list,
+                                                                disk_list=device_data)
 
         self.assertIsInstance(instance_id, (str, unicode))
         # Deleting created vm instance
@@ -1205,12 +1275,14 @@ class test_vimconn_new_vminstance(test_base):
                                                 inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
 
-        net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}]
+        net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'port_security': True,
+                     'type': 'virtual', 'net_id': self.__class__.network_id}]
 
         with self.assertRaises(Exception) as context:
-            test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, image_id=unknown_image_id,
-                                                                  flavor_id=unknown_flavor_id,
-                                                                            net_list=net_list)
+            test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False,
+                                                   image_id=unknown_image_id,
+                                                   flavor_id=unknown_flavor_id,
+                                                   net_list=net_list)
 
         self.assertIn((context.exception).http_code, (400, 404))
 
@@ -1267,7 +1339,7 @@ class test_vimconn_new_vminstance(test_base):
                 if attr == 'interfaces':
                     self.assertEqual(type(vm_info[self.__class__.instance_id][attr]), list)
 
-        if test_config['vimtype'] == 'openstack':
+        if test_config['vimtype'] in ('openstack', 'azure'):
             vpci = "0000:00:11.0"
             name = "eth0"
 
@@ -1276,9 +1348,12 @@ class test_vimconn_new_vminstance(test_base):
             # create new flavor
             flavor_id = test_config["vim_conn"].new_flavor(flavor_data)
              # create new vm instance
-            net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'vpci': vpci, 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}]
+            net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'vpci': vpci,
+                         'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}]
 
-            instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, image_id=self.__class__.image_id, flavor_id=flavor_id, net_list=net_list)
+            instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False,
+                                                                    image_id=self.__class__.image_id,
+                                                                    flavor_id=flavor_id, net_list=net_list)
 
             time.sleep(30)
             vm_list = []
@@ -1311,7 +1386,7 @@ class test_vimconn_new_vminstance(test_base):
         if test_config['vimtype'] == 'vmware':
             self.assertEqual(vm_dict,{})
 
-        if test_config['vimtype'] == 'openstack':
+        if test_config['vimtype'] in ('openstack', 'azure'):
             self.assertEqual(vm_dict[unknown_id]['status'], 'DELETED')
 
     def test_110_action_vminstance(self):
@@ -1328,7 +1403,7 @@ class test_vimconn_new_vminstance(test_base):
                                                                         {action: None})
                 self.assertEqual(instance_id, self.__class__.instance_id)
 
-        if test_config['vimtype'] == 'openstack':
+        if test_config['vimtype'] in ('openstack', 'azure'):
             # create new vm instance
             vpci = "0000:00:11.0"
             name = "eth0"
@@ -1338,11 +1413,17 @@ class test_vimconn_new_vminstance(test_base):
             # create new flavor
             flavor_id = test_config["vim_conn"].new_flavor(flavor_data)
 
-            net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'vpci': vpci, 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}]
+            net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'vpci': vpci,
+                         'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}]
 
-            new_instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, image_id=self.__class__.image_id, flavor_id=flavor_id, net_list=net_list)
+            new_instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='',
+                                                                        start=False, image_id=self.__class__.image_id,
+                                                                        flavor_id=flavor_id, net_list=net_list)
 
-            action_list =  ['shutdown','start','shutoff','rebuild','start','pause','start']
+            if test_config['vimtype'] == 'openstack':
+                action_list =  ['shutdown','start','shutoff','rebuild','start','pause','start']
+            else:
+                action_list =  ['shutdown','start','stop','start','shutoff','start','reboot']
 
             # various action on vminstace
             for action in action_list:
@@ -1402,9 +1483,12 @@ class test_vimconn_new_vminstance(test_base):
             self.assertEqual(sriov_net_name, list_item.get('name'))
             self.__class__.sriov_network_id = list_item.get('id')
 
-        net_list = [{'use': 'data', 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'VF', 'net_id': self.__class__.sriov_network_id}]
+        net_list = [{'use': 'data', 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'VF',
+                     'net_id': self.__class__.sriov_network_id}]
 
-        instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_sriov_vm', description='', start=False, image_id=self.__class__.image_id, flavor_id=flavor_id, net_list=net_list)
+        instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_sriov_vm', description='', start=False,
+                                                                image_id=self.__class__.image_id, flavor_id=flavor_id,
+                                                                net_list=net_list)
 
         self.assertIsInstance(instance_id, (str, unicode))
 
@@ -1426,6 +1510,7 @@ class test_vimconn_get_tenant_list(test_base):
 
         # Getting tenant list
         tenant_list = test_config["vim_conn"].get_tenant_list()
+        logger.debug(self.__class__.test_text + "Tenant list: " + str(tenant_list))
 
         for item in tenant_list:
             if test_config['tenant'] == item['name']:
@@ -1441,6 +1526,7 @@ class test_vimconn_get_tenant_list(test_base):
 
         # Getting filter tenant list by its id
         filter_tenant_list = test_config["vim_conn"].get_tenant_list({'id': self.__class__.tenant_id})
+        logger.debug(self.__class__.test_text + "Tenant list: " + str(filter_tenant_list))
 
         for item in filter_tenant_list:
             self.assertIsInstance(item['id'], (str, unicode))
@@ -1454,6 +1540,7 @@ class test_vimconn_get_tenant_list(test_base):
 
         # Getting filter tenant list by its name
         filter_tenant_list = test_config["vim_conn"].get_tenant_list({'name': test_config['tenant']})
+        logger.debug(self.__class__.test_text + "Tenant list: " + str(filter_tenant_list))
 
         for item in filter_tenant_list:
             self.assertIsInstance(item['name'], (str, unicode))
@@ -1468,6 +1555,7 @@ class test_vimconn_get_tenant_list(test_base):
         # Getting filter tenant list by its name and id
         filter_tenant_list = test_config["vim_conn"].get_tenant_list({'name': test_config['tenant'],
                                                                     'id': self.__class__.tenant_id})
+        logger.debug(self.__class__.test_text + "Tenant list: " + str(filter_tenant_list))
 
         for item in filter_tenant_list:
             self.assertIsInstance(item['name'], (str, unicode))
@@ -1485,6 +1573,7 @@ class test_vimconn_get_tenant_list(test_base):
 
         filter_tenant_list = test_config["vim_conn"].get_tenant_list({'name': non_exist_tenant_name,
                                                                          'id': non_exist_tenant_id})
+        logger.debug(self.__class__.test_text + "Tenant list: " + str(filter_tenant_list))
 
         self.assertEqual(filter_tenant_list, [])
 
@@ -1499,10 +1588,16 @@ class test_vimconn_new_tenant(test_base):
                                                 inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
 
-        self.__class__.tenant_id = test_config["vim_conn"].new_tenant(tenant_name, "")
-        time.sleep(15)
+        if test_config['vimtype'] != 'azure':
+            self.__class__.tenant_id = test_config["vim_conn"].new_tenant(tenant_name, "")
+            time.sleep(15)
 
-        self.assertIsInstance(self.__class__.tenant_id, (str, unicode))
+            self.assertIsInstance(self.__class__.tenant_id, (str, unicode))
+        else:
+            with self.assertRaises(Exception) as context:
+                test_config["vim_conn"].new_tenant(self.__class__.tenant_id, "")
+            self.assertEqual((context.exception).http_code, 401)
+            logger.debug(self.__class__.test_text + "Exception unauthorized: " + str(context.exception))
 
 
     def test_010_new_tenant_negative(self):
@@ -1515,7 +1610,11 @@ class test_vimconn_new_tenant(test_base):
         with self.assertRaises(Exception) as context:
             test_config["vim_conn"].new_tenant(Invalid_tenant_name, "")
 
-        self.assertEqual((context.exception).http_code, 400)
+        if test_config['vimtype'] != 'azure':
+            self.assertEqual((context.exception).http_code, 400)
+        else:
+            self.assertEqual((context.exception).http_code, 401)
+            logger.debug(self.__class__.test_text + "Exception unauthorized: " + str(context.exception))
 
 
     def test_020_delete_tenant(self):
@@ -1524,21 +1623,30 @@ class test_vimconn_new_tenant(test_base):
                                                 inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
 
-        tenant_id = test_config["vim_conn"].delete_tenant(self.__class__.tenant_id)
-
-        self.assertIsInstance(tenant_id, (str, unicode))
+        if test_config['vimtype'] != 'azure':
+            tenant_id = test_config["vim_conn"].delete_tenant(self.__class__.tenant_id)
+            self.assertIsInstance(tenant_id, (str, unicode))
+        else:
+            with self.assertRaises(Exception) as context:
+                test_config["vim_conn"].delete_tenant(self.__class__.tenant_id)
+            self.assertEqual((context.exception).http_code, 401)
+            logger.debug(self.__class__.test_text + "Exception unauthorized: " + str(context.exception))
 
     def test_030_delete_tenant_negative(self):
-        Non_exist_tenant_name = 'Test_30_tenant'
+        non_exist_tenant_name = 'Test_30_tenant'
         self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"],
                                                             self.__class__.test_index,
                                                 inspect.currentframe().f_code.co_name)
         self.__class__.test_index += 1
 
         with self.assertRaises(Exception) as context:
-            test_config["vim_conn"].delete_tenant(Non_exist_tenant_name)
+            test_config["vim_conn"].delete_tenant(non_exist_tenant_name)
 
-        self.assertEqual((context.exception).http_code, 404)
+        if test_config['vimtype'] != 'azure':
+            self.assertEqual((context.exception).http_code, 404)
+        else:
+            self.assertEqual((context.exception).http_code, 401)
+            logger.debug(self.__class__.test_text + "Exception unauthorized: " + str(context.exception))
 
 
 def get_image_id():
@@ -1789,7 +1897,8 @@ class test_vimconn_vminstance_by_existing_disk(test_base):
         net_list = [{'use': 'bridge', 'name': name, 'floating_ip': False, 'port_security': True,
                                         'type': 'virtual', 'net_id': self.network_id}]
 
-        instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', image_id=image_id,
+        instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, 
+                                        image_id=image_id,
                                         flavor_id=flavor_id, net_list=net_list,disk_list=disk_list)
 
         self.assertEqual(type(instance_id),str)
@@ -1816,7 +1925,8 @@ class test_vimconn_vminstance_by_existing_disk(test_base):
         net_list = [{'use': 'bridge', 'name': name, 'floating_ip': False, 'port_security': True,
                                                   'type': 'virtual', 'net_id': self.network_id}]
 
-        instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', image_id=image_id,
+        instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, 
+                                        image_id=image_id,
                                         flavor_id=flavor_id, net_list=net_list,disk_list=disk_list)
 
         self.assertEqual(type(instance_id),str)
@@ -1847,7 +1957,8 @@ class test_vimconn_vminstance_by_existing_disk(test_base):
         net_list = [{'use': 'bridge', 'name': name, 'floating_ip': False, 'port_security': True,
                                                   'type': 'virtual', 'net_id': self.network_id}]
 
-        instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', image_id=image_id,
+        instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False,
+                                       image_id=image_id,
                                        flavor_id=flavor_id, net_list=net_list,disk_list=disk_list )
 
         self.assertEqual(type(instance_id),str)
@@ -1897,7 +2008,8 @@ class test_vimconn_vminstance_by_affinity_anti_affinity(test_base):
         net_list = [{'use': 'bridge', 'name': name, 'floating_ip': False, 'port_security': True,
                                         'type': 'virtual', 'net_id': self.network_id}]
 
-        instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', image_id=image_id,
+        instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False,
+                                  image_id=image_id,
                                   flavor_id=flavor_id, net_list=net_list,availability_zone_index=1,
                                                         availability_zone_list=['HG_174','HG_175'])
 
@@ -1927,8 +2039,8 @@ class test_vimconn_vminstance_by_numa_affinity(test_base):
 
     def test_000_vminstance_by_numa_affinity(self):
         flavor_data = {'extended': {'numas': [{'paired-threads-id': [['1', '3'], ['2', '4']],
-                                                                        ' paired-threads': 2,                                                                                                                                  'memory': 1}]},
-                                                         'ram': 1024, 'vcpus': 1, 'disk': 10}
+                                               ' paired-threads': 2, 'memory': 1}]},
+                                               'ram': 1024, 'vcpus': 1, 'disk': 10}
         name = "eth10"
 
         # create new flavor
@@ -1945,7 +2057,8 @@ class test_vimconn_vminstance_by_numa_affinity(test_base):
         net_list = [{'use': 'bridge', 'name': name, 'floating_ip': False, 'port_security': True,
                                         'type': 'virtual', 'net_id': self.network_id}]
 
-        instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', image_id=image_id,
+        instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, 
+                                                            image_id=image_id,
                                                             flavor_id=flavor_id, net_list=net_list)
 
         self.assertEqual(type(instance_id),str)
@@ -2131,7 +2244,8 @@ def test_vimconnector(args):
         test_config['sriov_net_name'] = args.sriov_net_name
 
         # vmware connector obj
-        test_config['vim_conn'] = vim.vimconnector(name=org_name, tenant_name=tenant_name, user=org_user,passwd=org_passwd, url=vim_url, config=config_params)
+        test_config['vim_conn'] = vim.vimconnector(name=org_name, tenant_name=tenant_name, user=org_user,
+                                                   passwd=org_passwd, url=vim_url, config=config_params)
 
     elif args.vimtype == "aws":
         import vimconn_aws as vim
@@ -2163,6 +2277,33 @@ def test_vimconnector(args):
 
     elif args.vimtype == "openvim":
         import vimconn_openvim as vim
+    elif args.vimtype == "azure":
+        import vimconn_azure as vim
+
+        test_config["test_directory"] = os.path.dirname(__file__) + "/RO_tests"
+
+        tenant_name = args.tenant_name
+        test_config['tenant'] = tenant_name
+        config_params = yaml.load(args.config_param)
+        os_user = config_params.get('user')
+        os_passwd = config_params.get('passwd')
+        vim_url = args.endpoint_url
+        test_config['image_path'] = args.image_path
+        test_config['image_name'] = args.image_name
+        #test_config['sriov_net_name'] = args.sriov_net_name
+        args_log_level = "DEBUG" if args.debug else "INFO"
+
+        # azure connector obj
+        vim_persistent_info = {}
+        test_config['vim_conn'] = vim.vimconnector(
+            uuid="test-uuid-1", name="VIO-azure",
+            tenant_id=None, tenant_name=tenant_name,
+            url=vim_url, url_admin=None,
+            user=os_user, passwd=os_passwd, log_level= args_log_level,
+            config=config_params, persistent_info=vim_persistent_info
+        )
+        test_config['vim_conn'].debug = "true"
+
     else:
         logger.critical("vimtype '{}' not supported".format(args.vimtype))
         sys.exit(1)
@@ -2468,7 +2609,7 @@ if __name__=="__main__":
     vimconn_parser.set_defaults(func=test_vimconnector)
     # Mandatory arguments
     mandatory_arguments = vimconn_parser.add_argument_group('mandatory arguments')
-    mandatory_arguments.add_argument('--vimtype', choices=['vmware', 'aws', 'openstack', 'openvim'], required=True,
+    mandatory_arguments.add_argument('--vimtype', choices=['vmware', 'aws', 'openstack', 'openvim','azure'], required=True,
                                      help='Set the vimconnector type to test')
     mandatory_arguments.add_argument('-c', '--config', dest='config_param', required=True,
                                     help='Set the vimconnector specific config parameters in dictionary format')