blob: 7f2b2ea33c17f9d56b5bc4795da15b7804092884 [file] [log] [blame]
seryio34478552019-05-23 14:50:49 +02001# -*- coding: utf-8 -*-
tiernob569e4b2019-11-21 16:10:32 +00002##
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14##
seryio34478552019-05-23 14:50:49 +020015
jamartinezv14a823d2019-08-01 11:45:15 +020016import base64
seryio34478552019-05-23 14:50:49 +020017import vimconn
18import logging
tierno24620412019-06-03 14:05:08 +000019import netaddr
lloretgalleg45220152019-10-29 11:53:49 +010020import re
seryio34478552019-05-23 14:50:49 +020021
22from os import getenv
seryio34478552019-05-23 14:50:49 +020023from azure.common.credentials import ServicePrincipalCredentials
24from azure.mgmt.resource import ResourceManagementClient
25from azure.mgmt.network import NetworkManagementClient
26from azure.mgmt.compute import ComputeManagementClient
lloretgallegbfc28b02019-11-21 09:31:16 +010027from azure.mgmt.compute.models import DiskCreateOption
tierno84efdc12019-05-29 09:29:01 +000028from msrestazure.azure_exceptions import CloudError
lloretgalleg45220152019-10-29 11:53:49 +010029from msrest.exceptions import AuthenticationError
30from requests.exceptions import ConnectionError
31
tiernob569e4b2019-11-21 16:10:32 +000032__author__ = 'Isabel Lloret, Sergio Gonzalez, Alfonso Tierno'
33__date__ = '$18-apr-2019 23:59:59$'
lloretgalleg45220152019-10-29 11:53:49 +010034
tiernodeb74b22019-05-27 10:24:50 +000035
jamartinezv14a823d2019-08-01 11:45:15 +020036if getenv('OSMRO_PDB_DEBUG'):
37 import sys
38 print(sys.path)
39 import pdb
40 pdb.set_trace()
seryio34478552019-05-23 14:50:49 +020041
42
43class vimconnector(vimconn.vimconnector):
44
lloretgalleg45220152019-10-29 11:53:49 +010045 # Translate azure provisioning state to OSM provision state
46 # The first three ones are the transitional status once a user initiated action has been requested
47 # Once the operation is complete, it will transition into the states Succeeded or Failed
48 # https://docs.microsoft.com/en-us/azure/virtual-machines/windows/states-lifecycle
tierno84efdc12019-05-29 09:29:01 +000049 provision_state2osm = {
lloretgalleg45220152019-10-29 11:53:49 +010050 "Creating": "BUILD",
tierno84efdc12019-05-29 09:29:01 +000051 "Updating": "BUILD",
lloretgalleg45220152019-10-29 11:53:49 +010052 "Deleting": "INACTIVE",
53 "Succeeded": "ACTIVE",
54 "Failed": "ERROR"
55 }
56
57 # Translate azure power state to OSM provision state
58 power_state2osm = {
59 "starting": "INACTIVE",
60 "running": "ACTIVE",
61 "stopping": "INACTIVE",
62 "stopped": "INACTIVE",
63 "unknown": "OTHER",
64 "deallocated": "BUILD",
65 "deallocating": "BUILD"
tierno84efdc12019-05-29 09:29:01 +000066 }
67
seryio34478552019-05-23 14:50:49 +020068 def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level=None,
69 config={}, persistent_info={}):
lloretgalleg45220152019-10-29 11:53:49 +010070 """
71 Constructor of VIM. Raise an exception is some needed parameter is missing, but it must not do any connectivity
72 checking against the VIM
73 Using common constructor parameters.
74 In this case: config must include the following parameters:
75 subscription_id: assigned azure subscription identifier
76 region_name: current region for azure network
77 resource_group: used for all azure created resources
78 vnet_name: base vnet for azure, created networks will be subnets from this base network
79 config may also include the following parameter:
80 flavors_pattern: pattern that will be used to select a range of vm sizes, for example
81 "^((?!Standard_B).)*$" will filter out Standard_B range that is cheap but is very overused
82 "^Standard_B" will select a serie B maybe for test environment
83 """
seryio34478552019-05-23 14:50:49 +020084
85 vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, log_level,
86 config, persistent_info)
87
lloretgalleg45220152019-10-29 11:53:49 +010088 # Variable that indicates if client must be reloaded or initialized
89 self.reload_client = True
90
tierno84efdc12019-05-29 09:29:01 +000091 self.vnet_address_space = None
seryio34478552019-05-23 14:50:49 +020092 # LOGGER
93 self.logger = logging.getLogger('openmano.vim.azure')
94 if log_level:
95 logging.basicConfig()
96 self.logger.setLevel(getattr(logging, log_level))
97
lloretgalleg45220152019-10-29 11:53:49 +010098 self.tenant = (tenant_id or tenant_name)
tierno30d0d6d2019-05-27 08:14:01 +000099
lloretgalleg45220152019-10-29 11:53:49 +0100100 # Store config to create azure subscription later
tiernob569e4b2019-11-21 16:10:32 +0000101 self._config = {
102 "user": user,
103 "passwd": passwd,
104 "tenant": tenant_id or tenant_name
105 }
tierno30d0d6d2019-05-27 08:14:01 +0000106
107 # SUBSCRIPTION
seryio34478552019-05-23 14:50:49 +0200108 if 'subscription_id' in config:
lloretgalleg45220152019-10-29 11:53:49 +0100109 self._config["subscription_id"] = config.get('subscription_id')
tiernob569e4b2019-11-21 16:10:32 +0000110 # self.logger.debug('Setting subscription to: %s', self.config["subscription_id"])
seryio34478552019-05-23 14:50:49 +0200111 else:
112 raise vimconn.vimconnException('Subscription not specified')
lloretgalleg45220152019-10-29 11:53:49 +0100113
tierno30d0d6d2019-05-27 08:14:01 +0000114 # REGION
seryio34478552019-05-23 14:50:49 +0200115 if 'region_name' in config:
116 self.region = config.get('region_name')
117 else:
118 raise vimconn.vimconnException('Azure region_name is not specified at config')
lloretgalleg45220152019-10-29 11:53:49 +0100119
tierno30d0d6d2019-05-27 08:14:01 +0000120 # RESOURCE_GROUP
seryio34478552019-05-23 14:50:49 +0200121 if 'resource_group' in config:
122 self.resource_group = config.get('resource_group')
123 else:
124 raise vimconn.vimconnException('Azure resource_group is not specified at config')
lloretgalleg45220152019-10-29 11:53:49 +0100125
seryio34478552019-05-23 14:50:49 +0200126 # VNET_NAME
127 if 'vnet_name' in config:
128 self.vnet_name = config["vnet_name"]
129
130 # public ssh key
131 self.pub_key = config.get('pub_key')
lloretgalleg45220152019-10-29 11:53:49 +0100132
133 # flavor pattern regex
134 if 'flavors_pattern' in config:
135 self._config['flavors_pattern'] = config['flavors_pattern']
seryio34478552019-05-23 14:50:49 +0200136
137 def _reload_connection(self):
tiernodeb74b22019-05-27 10:24:50 +0000138 """
lloretgalleg45220152019-10-29 11:53:49 +0100139 Called before any operation, checks python azure clients
tiernodeb74b22019-05-27 10:24:50 +0000140 """
lloretgalleg45220152019-10-29 11:53:49 +0100141 if self.reload_client:
142 self.logger.debug('reloading azure client')
143 try:
144 self.credentials = ServicePrincipalCredentials(
145 client_id=self._config["user"],
146 secret=self._config["passwd"],
147 tenant=self._config["tenant"]
148 )
149 self.conn = ResourceManagementClient(self.credentials, self._config["subscription_id"])
150 self.conn_compute = ComputeManagementClient(self.credentials, self._config["subscription_id"])
151 self.conn_vnet = NetworkManagementClient(self.credentials, self._config["subscription_id"])
152 self._check_or_create_resource_group()
153 self._check_or_create_vnet()
154
155 # Set to client created
156 self.reload_client = False
157 except Exception as e:
158 self._format_vimconn_exception(e)
seryio34478552019-05-23 14:50:49 +0200159
160 def _get_resource_name_from_resource_id(self, resource_id):
lloretgalleg45220152019-10-29 11:53:49 +0100161 """
162 Obtains resource_name from the azure complete identifier: resource_name will always be last item
163 """
jamartinezv14a823d2019-08-01 11:45:15 +0200164 try:
lloretgalleg45220152019-10-29 11:53:49 +0100165 resource = str(resource_id.split('/')[-1])
jamartinezv14a823d2019-08-01 11:45:15 +0200166 return resource
167 except Exception as e:
tiernob569e4b2019-11-21 16:10:32 +0000168 raise vimconn.vimconnException("Unable to get resource name from resource_id '{}' Error: '{}'".
169 format(resource_id, e))
seryio34478552019-05-23 14:50:49 +0200170
171 def _get_location_from_resource_group(self, resource_group_name):
jamartinezv14a823d2019-08-01 11:45:15 +0200172 try:
lloretgalleg45220152019-10-29 11:53:49 +0100173 location = self.conn.resource_groups.get(resource_group_name).location
jamartinezv14a823d2019-08-01 11:45:15 +0200174 return location
175 except Exception as e:
176 raise vimconn.vimconnNotFoundException("Location '{}' not found".format(resource_group_name))
177
seryio34478552019-05-23 14:50:49 +0200178 def _get_resource_group_name_from_resource_id(self, resource_id):
jamartinezv14a823d2019-08-01 11:45:15 +0200179
180 try:
lloretgalleg45220152019-10-29 11:53:49 +0100181 rg = str(resource_id.split('/')[4])
jamartinezv14a823d2019-08-01 11:45:15 +0200182 return rg
183 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +0100184 raise vimconn.vimconnException("Unable to get resource group from invalid resource_id format '{}'".
185 format(resource_id))
jamartinezv14a823d2019-08-01 11:45:15 +0200186
187 def _get_net_name_from_resource_id(self, resource_id):
188
189 try:
lloretgalleg45220152019-10-29 11:53:49 +0100190 net_name = str(resource_id.split('/')[8])
jamartinezv14a823d2019-08-01 11:45:15 +0200191 return net_name
192 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +0100193 raise vimconn.vimconnException("Unable to get azure net_name from invalid resource_id format '{}'".
194 format(resource_id))
seryio34478552019-05-23 14:50:49 +0200195
196 def _check_subnets_for_vm(self, net_list):
tierno30d0d6d2019-05-27 08:14:01 +0000197 # All subnets must belong to the same resource group and vnet
lloretgalleg45220152019-10-29 11:53:49 +0100198 rg_vnet = set(self._get_resource_group_name_from_resource_id(net['net_id']) +
199 self._get_net_name_from_resource_id(net['net_id']) for net in net_list)
seryio34478552019-05-23 14:50:49 +0200200
lloretgalleg45220152019-10-29 11:53:49 +0100201 if len(rg_vnet) != 1:
202 raise self._format_vimconn_exception('Azure VMs can only attach to subnets in same VNET')
seryio34478552019-05-23 14:50:49 +0200203
lloretgalleg45220152019-10-29 11:53:49 +0100204 def _format_vimconn_exception(self, e):
tiernodeb74b22019-05-27 10:24:50 +0000205 """
lloretgalleg45220152019-10-29 11:53:49 +0100206 Transforms a generic or azure exception to a vimcommException
tiernodeb74b22019-05-27 10:24:50 +0000207 """
lloretgalleg45220152019-10-29 11:53:49 +0100208 if isinstance(e, vimconn.vimconnException):
209 raise
210 elif isinstance(e, AuthenticationError):
211 raise vimconn.vimconnAuthException(type(e).__name__ + ': ' + str(e))
212 elif isinstance(e, ConnectionError):
213 raise vimconn.vimconnConnectionException(type(e).__name__ + ': ' + str(e))
214 else:
215 # In case of generic error recreate client
216 self.reload_client = True
217 raise vimconn.vimconnException(type(e).__name__ + ': ' + str(e))
seryio34478552019-05-23 14:50:49 +0200218
219 def _check_or_create_resource_group(self):
tiernodeb74b22019-05-27 10:24:50 +0000220 """
lloretgalleg45220152019-10-29 11:53:49 +0100221 Creates the base resource group if it does not exist
tiernodeb74b22019-05-27 10:24:50 +0000222 """
lloretgalleg45220152019-10-29 11:53:49 +0100223 try:
224 rg_exists = self.conn.resource_groups.check_existence(self.resource_group)
225 if not rg_exists:
226 self.logger.debug("create base rgroup: %s", self.resource_group)
227 self.conn.resource_groups.create_or_update(self.resource_group, {'location': self.region})
228 except Exception as e:
229 self._format_vimconn_exception(e)
tiernodeb74b22019-05-27 10:24:50 +0000230
231 def _check_or_create_vnet(self):
lloretgalleg45220152019-10-29 11:53:49 +0100232 """
233 Try to get existent base vnet, in case it does not exist it creates it
234 """
tiernodeb74b22019-05-27 10:24:50 +0000235 try:
tierno84efdc12019-05-29 09:29:01 +0000236 vnet = self.conn_vnet.virtual_networks.get(self.resource_group, self.vnet_name)
237 self.vnet_address_space = vnet.address_space.address_prefixes[0]
tierno24620412019-06-03 14:05:08 +0000238 self.vnet_id = vnet.id
tierno84efdc12019-05-29 09:29:01 +0000239 return
240 except CloudError as e:
lloretgalleg45220152019-10-29 11:53:49 +0100241 if e.error.error and "notfound" in e.error.error.lower():
tierno84efdc12019-05-29 09:29:01 +0000242 pass
lloretgalleg45220152019-10-29 11:53:49 +0100243 # continue and create it
tierno84efdc12019-05-29 09:29:01 +0000244 else:
lloretgalleg45220152019-10-29 11:53:49 +0100245 self._format_vimconn_exception(e)
246
247 # if it does not exist, create it
tiernodeb74b22019-05-27 10:24:50 +0000248 try:
249 vnet_params = {
250 'location': self.region,
251 'address_space': {
tierno84efdc12019-05-29 09:29:01 +0000252 'address_prefixes': ["10.0.0.0/8"]
tiernodeb74b22019-05-27 10:24:50 +0000253 },
254 }
tierno84efdc12019-05-29 09:29:01 +0000255 self.vnet_address_space = "10.0.0.0/8"
jamartinezv14a823d2019-08-01 11:45:15 +0200256
lloretgalleg45220152019-10-29 11:53:49 +0100257 self.logger.debug("create base vnet: %s", self.vnet_name)
tiernodeb74b22019-05-27 10:24:50 +0000258 self.conn_vnet.virtual_networks.create_or_update(self.resource_group, self.vnet_name, vnet_params)
tierno24620412019-06-03 14:05:08 +0000259 vnet = self.conn_vnet.virtual_networks.get(self.resource_group, self.vnet_name)
260 self.vnet_id = vnet.id
tiernodeb74b22019-05-27 10:24:50 +0000261 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +0100262 self._format_vimconn_exception(e)
seryio34478552019-05-23 14:50:49 +0200263
kbsuba85c54d2019-10-17 16:30:32 +0000264 def new_network(self, net_name, net_type, ip_profile=None, shared=False, provider_network_profile=None):
tiernodeb74b22019-05-27 10:24:50 +0000265 """
266 Adds a tenant network to VIM
267 :param net_name: name of the network
lloretgalleg45220152019-10-29 11:53:49 +0100268 :param net_type: not used for azure networks
tiernodeb74b22019-05-27 10:24:50 +0000269 :param ip_profile: is a dict containing the IP parameters of the network (Currently only IPv4 is implemented)
seryio34478552019-05-23 14:50:49 +0200270 'ip-version': can be one of ['IPv4','IPv6']
271 'subnet-address': ip_prefix_schema, that is X.X.X.X/Y
lloretgalleg45220152019-10-29 11:53:49 +0100272 'gateway-address': (Optional) ip_schema, that is X.X.X.X, not implemented for azure connector
273 'dns-address': (Optional) ip_schema, not implemented for azure connector
274 'dhcp': (Optional) dict containing, not implemented for azure connector
seryio34478552019-05-23 14:50:49 +0200275 'enabled': {'type': 'boolean'},
276 'start-address': ip_schema, first IP to grant
277 'count': number of IPs to grant.
lloretgalleg45220152019-10-29 11:53:49 +0100278 :param shared: Not allowed for Azure Connector
kbsuba85c54d2019-10-17 16:30:32 +0000279 :param provider_network_profile: (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk}
tiernodeb74b22019-05-27 10:24:50 +0000280 :return: a tuple with the network identifier and created_items, or raises an exception on error
seryio34478552019-05-23 14:50:49 +0200281 created_items can be None or a dictionary where this method can include key-values that will be passed to
282 the method delete_network. Can be used to store created segments, created l2gw connections, etc.
283 Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
284 as not present.
tiernodeb74b22019-05-27 10:24:50 +0000285 """
seryio34478552019-05-23 14:50:49 +0200286 return self._new_subnet(net_name, ip_profile)
287
288 def _new_subnet(self, net_name, ip_profile):
tiernodeb74b22019-05-27 10:24:50 +0000289 """
lloretgalleg45220152019-10-29 11:53:49 +0100290 Adds a tenant network to VIM. It creates a new subnet at existing base vnet
291 :param net_name: subnet name
tiernodeb74b22019-05-27 10:24:50 +0000292 :param ip_profile:
lloretgalleg45220152019-10-29 11:53:49 +0100293 subnet-address: if it is not provided a subnet/24 in the default vnet is created,
294 otherwise it creates a subnet in the indicated address
295 :return: a tuple with the network identifier and created_items, or raises an exception on error
tiernodeb74b22019-05-27 10:24:50 +0000296 """
lloretgalleg45220152019-10-29 11:53:49 +0100297 self.logger.debug('create subnet name %s, ip_profile %s', net_name, ip_profile)
seryio34478552019-05-23 14:50:49 +0200298 self._reload_connection()
seryio34478552019-05-23 14:50:49 +0200299
300 if ip_profile is None:
tierno24620412019-06-03 14:05:08 +0000301 # get a non used vnet ip range /24 and allocate automatically inside the range self.vnet_address_space
302 used_subnets = self.get_network_list()
303 for ip_range in netaddr.IPNetwork(self.vnet_address_space).subnet(24):
304 for used_subnet in used_subnets:
305 subnet_range = netaddr.IPNetwork(used_subnet["cidr_block"])
306 if subnet_range in ip_range or ip_range in subnet_range:
307 # this range overlaps with an existing subnet ip range. Breaks and look for another
308 break
309 else:
310 ip_profile = {"subnet_address": str(ip_range)}
lloretgalleg45220152019-10-29 11:53:49 +0100311 self.logger.debug('dinamically obtained ip_profile: %s', ip_range)
tierno24620412019-06-03 14:05:08 +0000312 break
313 else:
lloretgalleg45220152019-10-29 11:53:49 +0100314 raise vimconn.vimconnException("Cannot find a non-used subnet range in {}".
315 format(self.vnet_address_space))
jamartinezv14a823d2019-08-01 11:45:15 +0200316 else:
317 ip_profile = {"subnet_address": ip_profile['subnet_address']}
seryio34478552019-05-23 14:50:49 +0200318
319 try:
tiernob569e4b2019-11-21 16:10:32 +0000320 # subnet_name = "{}-{}".format(net_name[:24], uuid4())
lloretgalleg45220152019-10-29 11:53:49 +0100321 subnet_params = {
tierno24620412019-06-03 14:05:08 +0000322 'address_prefix': ip_profile['subnet_address']
seryio34478552019-05-23 14:50:49 +0200323 }
lloretgalleg45220152019-10-29 11:53:49 +0100324 # Assign a not duplicated net name
325 subnet_name = self._get_unused_subnet_name(net_name)
seryio34478552019-05-23 14:50:49 +0200326
lloretgalleg45220152019-10-29 11:53:49 +0100327 self.logger.debug('creating subnet_name: {}'.format(subnet_name))
328 async_creation = self.conn_vnet.subnets.create_or_update(self.resource_group, self.vnet_name,
329 subnet_name, subnet_params)
330 async_creation.wait()
331 self.logger.debug('created subnet_name: {}'.format(subnet_name))
332
jamartinezv14a823d2019-08-01 11:45:15 +0200333 return "{}/subnets/{}".format(self.vnet_id, subnet_name), None
seryio34478552019-05-23 14:50:49 +0200334 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +0100335 self._format_vimconn_exception(e)
336
337 def _get_unused_subnet_name(self, subnet_name):
338 """
339 Adds a prefix to the subnet_name with a number in case the indicated name is repeated
340 Checks subnets with the indicated name (without suffix) and adds a suffix with a number
341 """
342 all_subnets = self.conn_vnet.subnets.list(self.resource_group, self.vnet_name)
343 # Filter to subnets starting with the indicated name
344 subnets = list(filter(lambda subnet: (subnet.name.startswith(subnet_name)), all_subnets))
345 net_names = [str(subnet.name) for subnet in subnets]
346
347 # get the name with the first not used suffix
348 name_suffix = 0
tiernob569e4b2019-11-21 16:10:32 +0000349 # name = subnet_name + "-" + str(name_suffix)
350 name = subnet_name # first subnet created will have no prefix
lloretgalleg45220152019-10-29 11:53:49 +0100351 while name in net_names:
352 name_suffix += 1
353 name = subnet_name + "-" + str(name_suffix)
354 return name
seryio34478552019-05-23 14:50:49 +0200355
jamartinezv14a823d2019-08-01 11:45:15 +0200356 def _create_nic(self, net, nic_name, static_ip=None):
seryio34478552019-05-23 14:50:49 +0200357
lloretgalleg45220152019-10-29 11:53:49 +0100358 self.logger.debug('create nic name %s, net_name %s', nic_name, net)
seryio34478552019-05-23 14:50:49 +0200359 self._reload_connection()
jamartinezv14a823d2019-08-01 11:45:15 +0200360
361 subnet_id = net['net_id']
362 location = self._get_location_from_resource_group(self.resource_group)
jamartinezv14a823d2019-08-01 11:45:15 +0200363 try:
tiernob569e4b2019-11-21 16:10:32 +0000364 net_ifz = {'location': location}
lloretgallegbfc28b02019-11-21 09:31:16 +0100365 net_ip_config = {'name': nic_name + '-ipconfiguration', 'subnet': {'id': subnet_id}}
jamartinezv14a823d2019-08-01 11:45:15 +0200366 if static_ip:
lloretgallegbfc28b02019-11-21 09:31:16 +0100367 net_ip_config['privateIPAddress'] = static_ip
368 net_ip_config['privateIPAllocationMethod'] = 'Static'
369 net_ifz['ip_configurations'] = [net_ip_config]
370 mac_address = net.get('mac_address')
371 if mac_address:
372 net_ifz['mac_address'] = mac_address
373
tiernob569e4b2019-11-21 16:10:32 +0000374 async_nic_creation = self.conn_vnet.network_interfaces.create_or_update(self.resource_group, nic_name,
375 net_ifz)
lloretgallegbfc28b02019-11-21 09:31:16 +0100376 async_nic_creation.wait()
lloretgalleg45220152019-10-29 11:53:49 +0100377 self.logger.debug('created nic name %s', nic_name)
jamartinezv14a823d2019-08-01 11:45:15 +0200378
379 public_ip = net.get('floating_ip')
lloretgalleg45220152019-10-29 11:53:49 +0100380 if public_ip:
381 public_ip_address_params = {
seryio34478552019-05-23 14:50:49 +0200382 'location': location,
jamartinezv14a823d2019-08-01 11:45:15 +0200383 'public_ip_allocation_method': 'Dynamic'
seryio34478552019-05-23 14:50:49 +0200384 }
jamartinezv14a823d2019-08-01 11:45:15 +0200385 public_ip_name = nic_name + '-public-ip'
386 public_ip = self.conn_vnet.public_ip_addresses.create_or_update(
387 self.resource_group,
388 public_ip_name,
lloretgalleg45220152019-10-29 11:53:49 +0100389 public_ip_address_params
jamartinezv14a823d2019-08-01 11:45:15 +0200390 )
lloretgalleg45220152019-10-29 11:53:49 +0100391 self.logger.debug('created public IP: {}'.format(public_ip.result()))
jamartinezv14a823d2019-08-01 11:45:15 +0200392
tiernob569e4b2019-11-21 16:10:32 +0000393 # Associate NIC to Public IP
jamartinezv14a823d2019-08-01 11:45:15 +0200394 nic_data = self.conn_vnet.network_interfaces.get(
395 self.resource_group,
396 nic_name)
397
398 nic_data.ip_configurations[0].public_ip_address = public_ip.result()
399
jamartinezv14a823d2019-08-01 11:45:15 +0200400 self.conn_vnet.network_interfaces.create_or_update(
401 self.resource_group,
402 nic_name,
403 nic_data)
404
405 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +0100406 self._format_vimconn_exception(e)
seryio34478552019-05-23 14:50:49 +0200407
408 return async_nic_creation.result()
409
jamartinezv14a823d2019-08-01 11:45:15 +0200410 def new_flavor(self, flavor_data):
tiernodeb74b22019-05-27 10:24:50 +0000411 """
lloretgalleg45220152019-10-29 11:53:49 +0100412 It is not allowed to create new flavors in Azure, must always use an existing one
413 """
414 raise vimconn.vimconnAuthException("It is not possible to create new flavors in AZURE")
tiernodeb74b22019-05-27 10:24:50 +0000415
lloretgalleg45220152019-10-29 11:53:49 +0100416 def new_tenant(self, tenant_name, tenant_description):
tiernodeb74b22019-05-27 10:24:50 +0000417 """
lloretgalleg45220152019-10-29 11:53:49 +0100418 It is not allowed to create new tenants in azure
419 """
jamartinezv14a823d2019-08-01 11:45:15 +0200420 raise vimconn.vimconnAuthException("It is not possible to create a TENANT in AZURE")
421
422 def new_image(self, image_dict):
lloretgalleg45220152019-10-29 11:53:49 +0100423 """
424 It is not allowed to create new images in Azure, must always use an existing one
425 """
426 raise vimconn.vimconnAuthException("It is not possible to create new images in AZURE")
jamartinezv14a823d2019-08-01 11:45:15 +0200427
428 def get_image_id_from_path(self, path):
429 """Get the image id from image path in the VIM database.
430 Returns the image_id or raises a vimconnNotFoundException
431 """
lloretgalleg45220152019-10-29 11:53:49 +0100432 raise vimconn.vimconnAuthException("It is not possible to obtain image from path in AZURE")
jamartinezv14a823d2019-08-01 11:45:15 +0200433
434 def get_image_list(self, filter_dict={}):
435 """Obtain tenant images from VIM
436 Filter_dict can be:
lloretgalleg45220152019-10-29 11:53:49 +0100437 name: image name with the format: publisher:offer:sku:version
438 If some part of the name is provide ex: publisher:offer it will search all availables skus and version
439 for the provided publisher and offer
440 id: image uuid, currently not supported for azure
jamartinezv14a823d2019-08-01 11:45:15 +0200441 Returns the image list of dictionaries:
442 [{<the fields at Filter_dict plus some VIM specific>}, ...]
443 List can be empty
444 """
lloretgalleg45220152019-10-29 11:53:49 +0100445
446 self.logger.debug("get_image_list filter {}".format(filter_dict))
tiernodeb74b22019-05-27 10:24:50 +0000447
448 self._reload_connection()
lloretgalleg45220152019-10-29 11:53:49 +0100449 try:
450 image_list = []
451 if filter_dict.get("name"):
452 # name will have the format 'publisher:offer:sku:version'
453 # publisher is required, offer sku and version will be searched if not provided
454 params = filter_dict["name"].split(":")
tiernodeb74b22019-05-27 10:24:50 +0000455 publisher = params[0]
lloretgalleg45220152019-10-29 11:53:49 +0100456 if publisher:
457 # obtain offer list
458 offer_list = self._get_offer_list(params, publisher)
459 for offer in offer_list:
460 # obtain skus
461 sku_list = self._get_sku_list(params, publisher, offer)
462 for sku in sku_list:
463 # if version is defined get directly version, else list images
464 if len(params) == 4 and params[3]:
465 version = params[3]
466 image_list = self._get_version_image_list(publisher, offer, sku, version)
467 else:
468 image_list = self._get_sku_image_list(publisher, offer, sku)
469 else:
470 raise vimconn.vimconnAuthException(
471 "List images in Azure must include name param with at least publisher")
472 else:
473 raise vimconn.vimconnAuthException("List images in Azure must include name param with at"
474 " least publisher")
tiernodeb74b22019-05-27 10:24:50 +0000475
lloretgalleg45220152019-10-29 11:53:49 +0100476 return image_list
477 except Exception as e:
478 self._format_vimconn_exception(e)
tiernodeb74b22019-05-27 10:24:50 +0000479
lloretgalleg45220152019-10-29 11:53:49 +0100480 def _get_offer_list(self, params, publisher):
481 """
482 Helper method to obtain offer list for defined publisher
483 """
484 if len(params) >= 2 and params[1]:
485 return [params[1]]
486 else:
487 try:
488 # get list of offers from azure
489 result_offers = self.conn_compute.virtual_machine_images.list_offers(self.region, publisher)
490 return [offer.name for offer in result_offers]
491 except CloudError as e:
492 # azure raises CloudError when not found
tiernob569e4b2019-11-21 16:10:32 +0000493 self.logger.info("error listing offers for publisher {}, Error: {}".format(publisher, e))
lloretgalleg45220152019-10-29 11:53:49 +0100494 return []
495
496 def _get_sku_list(self, params, publisher, offer):
497 """
498 Helper method to obtain sku list for defined publisher and offer
499 """
500 if len(params) >= 3 and params[2]:
501 return [params[2]]
502 else:
503 try:
504 # get list of skus from azure
505 result_skus = self.conn_compute.virtual_machine_images.list_skus(self.region, publisher, offer)
506 return [sku.name for sku in result_skus]
507 except CloudError as e:
508 # azure raises CloudError when not found
tiernob569e4b2019-11-21 16:10:32 +0000509 self.logger.info("error listing skus for publisher {}, offer {}, Error: {}".format(publisher, offer, e))
lloretgalleg45220152019-10-29 11:53:49 +0100510 return []
511
512 def _get_sku_image_list(self, publisher, offer, sku):
513 """
514 Helper method to obtain image list for publisher, offer and sku
515 """
516 image_list = []
517 try:
518 result_images = self.conn_compute.virtual_machine_images.list(self.region, publisher, offer, sku)
519 for result_image in result_images:
520 image_list.append({
521 'id': str(result_image.id),
522 'name': ":".join([publisher, offer, sku, result_image.name])
523 })
524 except CloudError as e:
525 self.logger.info(
tiernob569e4b2019-11-21 16:10:32 +0000526 "error listing skus for publisher {}, offer {}, Error: {}".format(publisher, offer, e))
lloretgalleg45220152019-10-29 11:53:49 +0100527 image_list = []
528 return image_list
529
530 def _get_version_image_list(self, publisher, offer, sku, version):
531 image_list = []
532 try:
533 result_image = self.conn_compute.virtual_machine_images.get(self.region, publisher, offer, sku, version)
534 if result_image:
535 image_list.append({
536 'id': str(result_image.id),
537 'name': ":".join([publisher, offer, sku, version])
538 })
539 except CloudError as e:
540 # azure gives CloudError when not found
tiernob569e4b2019-11-21 16:10:32 +0000541 self.logger.info("error listing images for publisher {}, offer {}, sku {}, version {} Error: {}".
542 format(publisher, offer, sku, version, e))
lloretgalleg45220152019-10-29 11:53:49 +0100543 image_list = []
tiernodeb74b22019-05-27 10:24:50 +0000544 return image_list
545
seryio34478552019-05-23 14:50:49 +0200546 def get_network_list(self, filter_dict={}):
tiernodeb74b22019-05-27 10:24:50 +0000547 """Obtain tenant networks of VIM
seryio34478552019-05-23 14:50:49 +0200548 Filter_dict can be:
549 name: network name
lloretgalleg45220152019-10-29 11:53:49 +0100550 id: network id
551 shared: boolean, not implemented in Azure
552 tenant_id: tenant, not used in Azure, all networks same tenants
553 admin_state_up: boolean, not implemented in Azure
554 status: 'ACTIVE', not implemented in Azure #
seryio34478552019-05-23 14:50:49 +0200555 Returns the network list of dictionaries
tiernodeb74b22019-05-27 10:24:50 +0000556 """
tiernob569e4b2019-11-21 16:10:32 +0000557 # self.logger.debug('getting network list for vim, filter %s', filter_dict)
seryio34478552019-05-23 14:50:49 +0200558 try:
559 self._reload_connection()
jamartinezv14a823d2019-08-01 11:45:15 +0200560
561 vnet = self.conn_vnet.virtual_networks.get(self.resource_group, self.vnet_name)
seryio34478552019-05-23 14:50:49 +0200562 subnet_list = []
jamartinezv14a823d2019-08-01 11:45:15 +0200563
seryio34478552019-05-23 14:50:49 +0200564 for subnet in vnet.subnets:
seryio34478552019-05-23 14:50:49 +0200565 if filter_dict:
566 if filter_dict.get("id") and str(subnet.id) != filter_dict["id"]:
567 continue
568 if filter_dict.get("name") and \
lloretgalleg45220152019-10-29 11:53:49 +0100569 str(subnet.name) != filter_dict["name"]:
seryio34478552019-05-23 14:50:49 +0200570 continue
571
jamartinezv14a823d2019-08-01 11:45:15 +0200572 name = self._get_resource_name_from_resource_id(subnet.id)
573
seryio34478552019-05-23 14:50:49 +0200574 subnet_list.append({
575 'id': str(subnet.id),
tiernob569e4b2019-11-21 16:10:32 +0000576 'name': name,
lloretgalleg45220152019-10-29 11:53:49 +0100577 'status': self.provision_state2osm[subnet.provisioning_state],
jamartinezv14a823d2019-08-01 11:45:15 +0200578 'cidr_block': str(subnet.address_prefix),
579 'type': 'bridge',
580 'shared': False
tiernob569e4b2019-11-21 16:10:32 +0000581 })
jamartinezv14a823d2019-08-01 11:45:15 +0200582
seryio34478552019-05-23 14:50:49 +0200583 return subnet_list
584 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +0100585 self._format_vimconn_exception(e)
seryio34478552019-05-23 14:50:49 +0200586
tiernob569e4b2019-11-21 16:10:32 +0000587 def new_vminstance(self, name, description, start, image_id, flavor_id, net_list, cloud_config=None,
seryio34478552019-05-23 14:50:49 +0200588 disk_list=None, availability_zone_index=None, availability_zone_list=None):
589
tiernob569e4b2019-11-21 16:10:32 +0000590 self.logger.debug("new vm instance name: %s, image_id: %s, flavor_id: %s, net_list: %s, cloud_config: %s, "
591 "disk_list: %s, availability_zone_index: %s, availability_zone_list: %s",
lloretgalleg45220152019-10-29 11:53:49 +0100592 name, image_id, flavor_id, net_list, cloud_config, disk_list,
593 availability_zone_index, availability_zone_list)
594
595 self._reload_connection()
596
597 # Validate input data is valid
598 # The virtual machine name must have less or 64 characters and it can not have the following
599 # characters: (~ ! @ # $ % ^ & * ( ) = + _ [ ] { } \ | ; : ' " , < > / ?.)
600 vm_name = self._check_vm_name(name)
601 # Obtain vm unused name
602 vm_name = self._get_unused_vm_name(vm_name)
603
604 # At least one network must be provided
605 if not net_list:
606 raise vimconn.vimconnException("At least one net must be provided to create a new VM")
607
608 # image_id are several fields of the image_id
609 image_reference = self._get_image_reference(image_id)
jamartinezv14a823d2019-08-01 11:45:15 +0200610
seryio34478552019-05-23 14:50:49 +0200611 self._check_subnets_for_vm(net_list)
612 vm_nics = []
613 for idx, net in enumerate(net_list):
jamartinezv14a823d2019-08-01 11:45:15 +0200614 # Fault with subnet_id
615 # subnet_id=net['subnet_id']
616 # subnet_id=net['net_id']
seryio34478552019-05-23 14:50:49 +0200617 nic_name = vm_name + '-nic-'+str(idx)
lloretgallegbfc28b02019-11-21 09:31:16 +0100618 vm_nic = self._create_nic(net, nic_name, net.get('ip_address'))
lloretgalleg45220152019-10-29 11:53:49 +0100619 vm_nics.append({'id': str(vm_nic.id)})
620 net['vim_id'] = vm_nic.id
seryio34478552019-05-23 14:50:49 +0200621
622 try:
jamartinezv14a823d2019-08-01 11:45:15 +0200623
624 # cloud-init configuration
625 # cloud config
626 if cloud_config:
627 config_drive, userdata = self._create_user_data(cloud_config)
628 custom_data = base64.b64encode(userdata.encode('utf-8')).decode('latin-1')
lloretgalleg45220152019-10-29 11:53:49 +0100629 key_data = None
630 key_pairs = cloud_config.get("key-pairs")
631 if key_pairs:
632 key_data = key_pairs[0]
633
634 if cloud_config.get("users"):
635 user_name = cloud_config.get("users")[0].get("name", "osm")
636 else:
tiernob569e4b2019-11-21 16:10:32 +0000637 user_name = "osm" # DEFAULT USER IS OSM
lloretgalleg45220152019-10-29 11:53:49 +0100638
jamartinezv14a823d2019-08-01 11:45:15 +0200639 os_profile = {
lloretgalleg45220152019-10-29 11:53:49 +0100640 'computer_name': vm_name,
641 'admin_username': user_name,
642 'linux_configuration': {
643 "disable_password_authentication": True,
644 "ssh": {
645 "public_keys": [{
646 "path": "/home/{}/.ssh/authorized_keys".format(user_name),
647 "key_data": key_data
648 }]
649 }
650 },
jamartinezv14a823d2019-08-01 11:45:15 +0200651 'custom_data': custom_data
652 }
653 else:
654 os_profile = {
tiernob569e4b2019-11-21 16:10:32 +0000655 'computer_name': vm_name,
656 'admin_username': 'osm',
657 'admin_password': 'Osm4u!',
jamartinezv14a823d2019-08-01 11:45:15 +0200658 }
659
seryio34478552019-05-23 14:50:49 +0200660 vm_parameters = {
661 'location': self.region,
jamartinezv14a823d2019-08-01 11:45:15 +0200662 'os_profile': os_profile,
seryio34478552019-05-23 14:50:49 +0200663 'hardware_profile': {
jamartinezv14a823d2019-08-01 11:45:15 +0200664 'vm_size': flavor_id
seryio34478552019-05-23 14:50:49 +0200665 },
666 'storage_profile': {
jamartinezv14a823d2019-08-01 11:45:15 +0200667 'image_reference': image_reference
seryio34478552019-05-23 14:50:49 +0200668 }
669 }
jamartinezv14a823d2019-08-01 11:45:15 +0200670
lloretgalleg45220152019-10-29 11:53:49 +0100671 # Add data disks if they are provided
672 if disk_list:
673 data_disks = []
674 for lun_name, disk in enumerate(disk_list):
675 self.logger.debug("add disk size: %s, image: %s", disk.get("size"), disk.get("image_id"))
676 if not disk.get("image_id"):
677 data_disks.append({
678 'lun': lun_name, # You choose the value, depending of what is available for you
679 'name': vm_name + "_data_disk-" + str(lun_name),
lloretgallegbfc28b02019-11-21 09:31:16 +0100680 'create_option': DiskCreateOption.empty,
lloretgalleg45220152019-10-29 11:53:49 +0100681 'disk_size_gb': disk.get("size")
682 })
683 else:
tiernob569e4b2019-11-21 16:10:32 +0000684 # self.logger.debug("currently not able to create data disks from image for azure, ignoring")
lloretgallegbfc28b02019-11-21 09:31:16 +0100685 data_disks.append({
686 'lun': lun_name, # You choose the value, depending of what is available for you
687 'name': vm_name + "_data_disk-" + str(lun_name),
688 'create_option': 'Attach',
689 'disk_size_gb': disk.get("size"),
690 'managed_disk': {
691 'id': disk.get("image_id")
692 }
693 })
lloretgalleg45220152019-10-29 11:53:49 +0100694
695 if data_disks:
696 vm_parameters["storage_profile"]["data_disks"] = data_disks
697
698 # If the machine has several networks one must be marked as primary
699 # As it is not indicated in the interface the first interface will be marked as primary
700 if len(vm_nics) > 1:
701 for idx, vm_nic in enumerate(vm_nics):
702 if idx == 0:
703 vm_nics[0]['Primary'] = True
704 else:
705 vm_nics[idx]['Primary'] = False
706
707 vm_parameters['network_profile'] = {'network_interfaces': vm_nics}
708
709 self.logger.debug("create vm name: %s", vm_name)
seryio34478552019-05-23 14:50:49 +0200710 creation_result = self.conn_compute.virtual_machines.create_or_update(
711 self.resource_group,
lloretgalleg45220152019-10-29 11:53:49 +0100712 vm_name,
seryio34478552019-05-23 14:50:49 +0200713 vm_parameters
714 )
tiernob569e4b2019-11-21 16:10:32 +0000715 # creation_result.wait()
jamartinezv14a823d2019-08-01 11:45:15 +0200716 result = creation_result.result()
lloretgallegbfc28b02019-11-21 09:31:16 +0100717 self.logger.debug("created vm name: %s", vm_name)
jamartinezv14a823d2019-08-01 11:45:15 +0200718
lloretgalleg45220152019-10-29 11:53:49 +0100719 if start:
tiernob569e4b2019-11-21 16:10:32 +0000720 self.conn_compute.virtual_machines.start(
jamartinezv14a823d2019-08-01 11:45:15 +0200721 self.resource_group,
lloretgalleg45220152019-10-29 11:53:49 +0100722 vm_name)
tiernob569e4b2019-11-21 16:10:32 +0000723 # start_result.wait()
jamartinezv14a823d2019-08-01 11:45:15 +0200724
725 return result.id, None
seryio34478552019-05-23 14:50:49 +0200726
tiernob569e4b2019-11-21 16:10:32 +0000727 # run_command_parameters = {
728 # 'command_id': 'RunShellScript', # For linux, don't change it
729 # 'script': [
730 # 'date > /tmp/test.txt'
731 # ]
732 # }
seryio34478552019-05-23 14:50:49 +0200733 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +0100734 self.logger.debug('Exception creating new vminstance: %s', e, exc_info=True)
735 self._format_vimconn_exception(e)
736
737 def _get_unused_vm_name(self, vm_name):
738 """
739 Checks the vm name and in case it is used adds a suffix to the name to allow creation
740 :return:
741 """
742 all_vms = self.conn_compute.virtual_machines.list(self.resource_group)
743 # Filter to vms starting with the indicated name
744 vms = list(filter(lambda vm: (vm.name.startswith(vm_name)), all_vms))
745 vm_names = [str(vm.name) for vm in vms]
746
747 # get the name with the first not used suffix
748 name_suffix = 0
749 # name = subnet_name + "-" + str(name_suffix)
750 name = vm_name # first subnet created will have no prefix
751 while name in vm_names:
752 name_suffix += 1
753 name = vm_name + "-" + str(name_suffix)
754 return name
755
jamartinezv14a823d2019-08-01 11:45:15 +0200756 # It is necesary extract from image_id data to create the VM with this format
757 # 'image_reference': {
758 # 'publisher': vm_reference['publisher'],
759 # 'offer': vm_reference['offer'],
760 # 'sku': vm_reference['sku'],
761 # 'version': vm_reference['version']
762 # },
lloretgalleg45220152019-10-29 11:53:49 +0100763 def _get_image_reference(self, image_id):
jamartinezv14a823d2019-08-01 11:45:15 +0200764
lloretgalleg45220152019-10-29 11:53:49 +0100765 try:
766 # The data input format example:
767 # /Subscriptions/ca3d18ab-d373-4afb-a5d6-7c44f098d16a/Providers/Microsoft.Compute/Locations/westeurope/
768 # Publishers/Canonical/ArtifactTypes/VMImage/
769 # Offers/UbuntuServer/
770 # Skus/18.04-LTS/
771 # Versions/18.04.201809110
772 publisher = str(image_id.split('/')[8])
773 offer = str(image_id.split('/')[12])
774 sku = str(image_id.split('/')[14])
775 version = str(image_id.split('/')[16])
jamartinezv14a823d2019-08-01 11:45:15 +0200776
lloretgalleg45220152019-10-29 11:53:49 +0100777 return {
tiernob569e4b2019-11-21 16:10:32 +0000778 'publisher': publisher,
779 'offer': offer,
780 'sku': sku,
781 'version': version
lloretgalleg45220152019-10-29 11:53:49 +0100782 }
783 except Exception as e:
784 raise vimconn.vimconnException(
785 "Unable to get image_reference from invalid image_id format: '{}'".format(image_id))
jamartinezv14a823d2019-08-01 11:45:15 +0200786
787 # Azure VM names can not have some special characters
lloretgalleg45220152019-10-29 11:53:49 +0100788 def _check_vm_name(self, vm_name):
789 """
790 Checks vm name, in case the vm has not allowed characters they are removed, not error raised
791 """
jamartinezv14a823d2019-08-01 11:45:15 +0200792
jamartinezv14a823d2019-08-01 11:45:15 +0200793 chars_not_allowed_list = "~!@#$%^&*()=+_[]{}|;:<>/?."
794
795 # First: the VM name max length is 64 characters
796 vm_name_aux = vm_name[:64]
797
798 # Second: replace not allowed characters
lloretgalleg45220152019-10-29 11:53:49 +0100799 for elem in chars_not_allowed_list:
jamartinezv14a823d2019-08-01 11:45:15 +0200800 # Check if string is in the main string
lloretgalleg45220152019-10-29 11:53:49 +0100801 if elem in vm_name_aux:
tiernob569e4b2019-11-21 16:10:32 +0000802 # self.logger.debug('Dentro del IF')
jamartinezv14a823d2019-08-01 11:45:15 +0200803 # Replace the string
804 vm_name_aux = vm_name_aux.replace(elem, '-')
805
806 return vm_name_aux
seryio34478552019-05-23 14:50:49 +0200807
808 def get_flavor_id_from_data(self, flavor_dict):
seryio34478552019-05-23 14:50:49 +0200809
lloretgalleg45220152019-10-29 11:53:49 +0100810 self.logger.debug("getting flavor id from data, flavor_dict: %s", flavor_dict)
811 filter_dict = flavor_dict or {}
jamartinezv14a823d2019-08-01 11:45:15 +0200812 try:
813 self._reload_connection()
tiernob569e4b2019-11-21 16:10:32 +0000814 vm_sizes_list = [vm_size.serialize() for vm_size in
815 self.conn_compute.virtual_machine_sizes.list(self.region)]
tierno30d0d6d2019-05-27 08:14:01 +0000816
lloretgalleg45220152019-10-29 11:53:49 +0100817 cpus = filter_dict.get('vcpus') or 0
818 memMB = filter_dict.get('ram') or 0
tierno30d0d6d2019-05-27 08:14:01 +0000819
lloretgalleg45220152019-10-29 11:53:49 +0100820 # Filter
821 if self._config.get("flavors_pattern"):
tiernob569e4b2019-11-21 16:10:32 +0000822 filtered_sizes = [size for size in vm_sizes_list if size['numberOfCores'] >= cpus and
823 size['memoryInMB'] >= memMB and
824 re.search(self._config.get("flavors_pattern"), size["name"])]
lloretgalleg45220152019-10-29 11:53:49 +0100825 else:
tiernob569e4b2019-11-21 16:10:32 +0000826 filtered_sizes = [size for size in vm_sizes_list if size['numberOfCores'] >= cpus and
827 size['memoryInMB'] >= memMB]
lloretgalleg45220152019-10-29 11:53:49 +0100828
829 # Sort
tiernob569e4b2019-11-21 16:10:32 +0000830 listedFilteredSizes = sorted(filtered_sizes, key=lambda k: (k['numberOfCores'], k['memoryInMB'],
831 k['resourceDiskSizeInMB']))
lloretgalleg45220152019-10-29 11:53:49 +0100832
833 if listedFilteredSizes:
834 return listedFilteredSizes[0]['name']
835 raise vimconn.vimconnNotFoundException("Cannot find any flavor matching '{}'".format(str(flavor_dict)))
jamartinezv14a823d2019-08-01 11:45:15 +0200836
837 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +0100838 self._format_vimconn_exception(e)
jamartinezv14a823d2019-08-01 11:45:15 +0200839
840 def _get_flavor_id_from_flavor_name(self, flavor_name):
jamartinezv14a823d2019-08-01 11:45:15 +0200841
tiernob569e4b2019-11-21 16:10:32 +0000842 # self.logger.debug("getting flavor id from flavor name {}".format(flavor_name))
jamartinezv14a823d2019-08-01 11:45:15 +0200843 try:
844 self._reload_connection()
tiernob569e4b2019-11-21 16:10:32 +0000845 vm_sizes_list = [vm_size.serialize() for vm_size in
846 self.conn_compute.virtual_machine_sizes.list(self.region)]
jamartinezv14a823d2019-08-01 11:45:15 +0200847
848 output_flavor = None
849 for size in vm_sizes_list:
850 if size['name'] == flavor_name:
851 output_flavor = size
852
tiernob569e4b2019-11-21 16:10:32 +0000853 # None is returned if not found anything
jamartinezv14a823d2019-08-01 11:45:15 +0200854 return output_flavor
855
856 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +0100857 self._format_vimconn_exception(e)
tierno30d0d6d2019-05-27 08:14:01 +0000858
859 def check_vim_connectivity(self):
seryio34478552019-05-23 14:50:49 +0200860 try:
861 self._reload_connection()
tierno30d0d6d2019-05-27 08:14:01 +0000862 return True
863 except Exception as e:
864 raise vimconn.vimconnException("Connectivity issue with Azure API: {}".format(e))
seryio34478552019-05-23 14:50:49 +0200865
866 def get_network(self, net_id):
seryio34478552019-05-23 14:50:49 +0200867
tiernob569e4b2019-11-21 16:10:32 +0000868 # self.logger.debug('get network id: {}'.format(net_id))
869 # res_name = self._get_resource_name_from_resource_id(net_id)
seryio34478552019-05-23 14:50:49 +0200870 self._reload_connection()
seryio34478552019-05-23 14:50:49 +0200871
lloretgalleg45220152019-10-29 11:53:49 +0100872 filter_dict = {'name': net_id}
jamartinezv14a823d2019-08-01 11:45:15 +0200873 network_list = self.get_network_list(filter_dict)
874
875 if not network_list:
876 raise vimconn.vimconnNotFoundException("network '{}' not found".format(net_id))
877 else:
878 return network_list[0]
879
jamartinezv14a823d2019-08-01 11:45:15 +0200880 def delete_network(self, net_id, created_items=None):
881
lloretgalleg45220152019-10-29 11:53:49 +0100882 self.logger.debug('deleting network {} - {}'.format(self.resource_group, net_id))
jamartinezv14a823d2019-08-01 11:45:15 +0200883
seryio34478552019-05-23 14:50:49 +0200884 self._reload_connection()
lloretgalleg45220152019-10-29 11:53:49 +0100885 res_name = self._get_resource_name_from_resource_id(net_id)
886 filter_dict = {'name': res_name}
jamartinezv14a823d2019-08-01 11:45:15 +0200887 network_list = self.get_network_list(filter_dict)
888 if not network_list:
889 raise vimconn.vimconnNotFoundException("network '{}' not found".format(net_id))
890
891 try:
892 # Subnet API fails (CloudError: Azure Error: ResourceNotFound)
893 # Put the initial virtual_network API
lloretgalleg45220152019-10-29 11:53:49 +0100894 async_delete = self.conn_vnet.subnets.delete(self.resource_group, self.vnet_name, res_name)
895 async_delete.wait()
jamartinezv14a823d2019-08-01 11:45:15 +0200896 return net_id
897
898 except CloudError as e:
lloretgalleg45220152019-10-29 11:53:49 +0100899 if e.error.error and "notfound" in e.error.error.lower():
jamartinezv14a823d2019-08-01 11:45:15 +0200900 raise vimconn.vimconnNotFoundException("network '{}' not found".format(net_id))
901 else:
lloretgalleg45220152019-10-29 11:53:49 +0100902 self._format_vimconn_exception(e)
jamartinezv14a823d2019-08-01 11:45:15 +0200903 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +0100904 self._format_vimconn_exception(e)
jamartinezv14a823d2019-08-01 11:45:15 +0200905
jamartinezv14a823d2019-08-01 11:45:15 +0200906 def delete_vminstance(self, vm_id, created_items=None):
lloretgalleg45220152019-10-29 11:53:49 +0100907 """ Deletes a vm instance from the vim.
908 """
909 self.logger.debug('deleting VM instance {} - {}'.format(self.resource_group, vm_id))
jamartinezv14a823d2019-08-01 11:45:15 +0200910 self._reload_connection()
911
912 try:
913
lloretgalleg45220152019-10-29 11:53:49 +0100914 res_name = self._get_resource_name_from_resource_id(vm_id)
915 vm = self.conn_compute.virtual_machines.get(self.resource_group, res_name)
jamartinezv14a823d2019-08-01 11:45:15 +0200916
917 # Shuts down the virtual machine and releases the compute resources
tiernob569e4b2019-11-21 16:10:32 +0000918 # vm_stop = self.conn_compute.virtual_machines.power_off(self.resource_group, resName)
919 # vm_stop.wait()
jamartinezv14a823d2019-08-01 11:45:15 +0200920
lloretgalleg45220152019-10-29 11:53:49 +0100921 vm_delete = self.conn_compute.virtual_machines.delete(self.resource_group, res_name)
jamartinezv14a823d2019-08-01 11:45:15 +0200922 vm_delete.wait()
lloretgalleg45220152019-10-29 11:53:49 +0100923 self.logger.debug('deleted VM name: %s', res_name)
jamartinezv14a823d2019-08-01 11:45:15 +0200924
925 # Delete OS Disk
926 os_disk_name = vm.storage_profile.os_disk.name
lloretgalleg45220152019-10-29 11:53:49 +0100927 self.logger.debug('delete OS DISK: %s', os_disk_name)
jamartinezv14a823d2019-08-01 11:45:15 +0200928 self.conn_compute.disks.delete(self.resource_group, os_disk_name)
lloretgalleg45220152019-10-29 11:53:49 +0100929 self.logger.debug('deleted OS DISK name: %s', os_disk_name)
jamartinezv14a823d2019-08-01 11:45:15 +0200930
lloretgalleg45220152019-10-29 11:53:49 +0100931 for data_disk in vm.storage_profile.data_disks:
932 self.logger.debug('delete data_disk: %s', data_disk.name)
933 self.conn_compute.disks.delete(self.resource_group, data_disk.name)
934 self.logger.debug('deleted OS DISK name: %s', data_disk.name)
935
936 # After deleting VM, it is necessary to delete NIC, because if is not deleted delete_network
jamartinezv14a823d2019-08-01 11:45:15 +0200937 # does not work because Azure says that is in use the subnet
938 network_interfaces = vm.network_profile.network_interfaces
939
940 for network_interface in network_interfaces:
941
jamartinezv14a823d2019-08-01 11:45:15 +0200942 nic_name = self._get_resource_name_from_resource_id(network_interface.id)
jamartinezv14a823d2019-08-01 11:45:15 +0200943 nic_data = self.conn_vnet.network_interfaces.get(
944 self.resource_group,
945 nic_name)
946
lloretgalleg45220152019-10-29 11:53:49 +0100947 public_ip_name = None
jamartinezv14a823d2019-08-01 11:45:15 +0200948 exist_public_ip = nic_data.ip_configurations[0].public_ip_address
949 if exist_public_ip:
950 public_ip_id = nic_data.ip_configurations[0].public_ip_address.id
jamartinezv14a823d2019-08-01 11:45:15 +0200951
952 # Delete public_ip
953 public_ip_name = self._get_resource_name_from_resource_id(public_ip_id)
954
lloretgalleg45220152019-10-29 11:53:49 +0100955 # Public ip must be deleted afterwards of nic that is attached
jamartinezv14a823d2019-08-01 11:45:15 +0200956
lloretgalleg45220152019-10-29 11:53:49 +0100957 self.logger.debug('delete NIC name: %s', nic_name)
958 nic_delete = self.conn_vnet.network_interfaces.delete(self.resource_group, nic_name)
959 nic_delete.wait()
960 self.logger.debug('deleted NIC name: %s', nic_name)
961
962 # Delete list of public ips
963 if public_ip_name:
964 self.logger.debug('delete PUBLIC IP - ' + public_ip_name)
tiernob569e4b2019-11-21 16:10:32 +0000965 self.conn_vnet.public_ip_addresses.delete(self.resource_group, public_ip_name)
lloretgalleg45220152019-10-29 11:53:49 +0100966
967 except CloudError as e:
968 if e.error.error and "notfound" in e.error.error.lower():
969 raise vimconn.vimconnNotFoundException("No vm instance found '{}'".format(vm_id))
970 else:
971 self._format_vimconn_exception(e)
972 except Exception as e:
973 self._format_vimconn_exception(e)
974
tiernob569e4b2019-11-21 16:10:32 +0000975 def action_vminstance(self, vm_id, action_dict, created_items={}):
jamartinezv14a823d2019-08-01 11:45:15 +0200976 """Send and action over a VM instance from VIM
lloretgalleg45220152019-10-29 11:53:49 +0100977 Returns the vm_id if the action was successfully sent to the VIM
978 """
jamartinezv14a823d2019-08-01 11:45:15 +0200979
980 self.logger.debug("Action over VM '%s': %s", vm_id, str(action_dict))
981 try:
982 self._reload_connection()
983 resName = self._get_resource_name_from_resource_id(vm_id)
984 if "start" in action_dict:
lloretgalleg45220152019-10-29 11:53:49 +0100985 self.conn_compute.virtual_machines.start(self.resource_group, resName)
jamartinezv14a823d2019-08-01 11:45:15 +0200986 elif "stop" in action_dict or "shutdown" in action_dict or "shutoff" in action_dict:
lloretgalleg45220152019-10-29 11:53:49 +0100987 self.conn_compute.virtual_machines.power_off(self.resource_group, resName)
jamartinezv14a823d2019-08-01 11:45:15 +0200988 elif "terminate" in action_dict:
lloretgalleg45220152019-10-29 11:53:49 +0100989 self.conn_compute.virtual_machines.delete(self.resource_group, resName)
jamartinezv14a823d2019-08-01 11:45:15 +0200990 elif "reboot" in action_dict:
lloretgalleg45220152019-10-29 11:53:49 +0100991 self.conn_compute.virtual_machines.restart(self.resource_group, resName)
jamartinezv14a823d2019-08-01 11:45:15 +0200992 return None
993 except CloudError as e:
lloretgalleg45220152019-10-29 11:53:49 +0100994 if e.error.error and "notfound" in e.error.error.lower():
jamartinezv14a823d2019-08-01 11:45:15 +0200995 raise vimconn.vimconnNotFoundException("No vm found '{}'".format(vm_id))
996 else:
lloretgalleg45220152019-10-29 11:53:49 +0100997 self._format_vimconn_exception(e)
jamartinezv14a823d2019-08-01 11:45:15 +0200998 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +0100999 self._format_vimconn_exception(e)
jamartinezv14a823d2019-08-01 11:45:15 +02001000
1001 def delete_flavor(self, flavor_id):
jamartinezv14a823d2019-08-01 11:45:15 +02001002 raise vimconn.vimconnAuthException("It is not possible to delete a FLAVOR in AZURE")
1003
lloretgalleg45220152019-10-29 11:53:49 +01001004 def delete_tenant(self, tenant_id,):
jamartinezv14a823d2019-08-01 11:45:15 +02001005 raise vimconn.vimconnAuthException("It is not possible to delete a TENANT in AZURE")
1006
1007 def delete_image(self, image_id):
jamartinezv14a823d2019-08-01 11:45:15 +02001008 raise vimconn.vimconnAuthException("It is not possible to delete a IMAGE in AZURE")
seryio34478552019-05-23 14:50:49 +02001009
1010 def get_vminstance(self, vm_id):
lloretgalleg45220152019-10-29 11:53:49 +01001011 """
1012 Obtaing the vm instance data from v_id
1013 """
1014 self.logger.debug("get vm instance: %s", vm_id)
seryio34478552019-05-23 14:50:49 +02001015 self._reload_connection()
jamartinezv14a823d2019-08-01 11:45:15 +02001016 try:
1017 resName = self._get_resource_name_from_resource_id(vm_id)
tiernob569e4b2019-11-21 16:10:32 +00001018 vm = self.conn_compute.virtual_machines.get(self.resource_group, resName)
jamartinezv14a823d2019-08-01 11:45:15 +02001019 except CloudError as e:
lloretgalleg45220152019-10-29 11:53:49 +01001020 if e.error.error and "notfound" in e.error.error.lower():
jamartinezv14a823d2019-08-01 11:45:15 +02001021 raise vimconn.vimconnNotFoundException("No vminstance found '{}'".format(vm_id))
1022 else:
lloretgalleg45220152019-10-29 11:53:49 +01001023 self._format_vimconn_exception(e)
jamartinezv14a823d2019-08-01 11:45:15 +02001024 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +01001025 self._format_vimconn_exception(e)
seryio34478552019-05-23 14:50:49 +02001026
1027 return vm
1028
1029 def get_flavor(self, flavor_id):
lloretgalleg45220152019-10-29 11:53:49 +01001030 """
1031 Obtains the flavor_data from the flavor_id
1032 """
seryio34478552019-05-23 14:50:49 +02001033 self._reload_connection()
lloretgalleg45220152019-10-29 11:53:49 +01001034 self.logger.debug("get flavor from id: %s", flavor_id)
jamartinezv14a823d2019-08-01 11:45:15 +02001035 flavor_data = self._get_flavor_id_from_flavor_name(flavor_id)
1036 if flavor_data:
1037 flavor = {
1038 'id': flavor_id,
1039 'name': flavor_id,
1040 'ram': flavor_data['memoryInMB'],
1041 'vcpus': flavor_data['numberOfCores'],
lloretgalleg45220152019-10-29 11:53:49 +01001042 'disk': flavor_data['resourceDiskSizeInMB']/1024
jamartinezv14a823d2019-08-01 11:45:15 +02001043 }
1044 return flavor
1045 else:
1046 raise vimconn.vimconnNotFoundException("flavor '{}' not found".format(flavor_id))
seryio34478552019-05-23 14:50:49 +02001047
jamartinezv14a823d2019-08-01 11:45:15 +02001048 def get_tenant_list(self, filter_dict={}):
lloretgalleg45220152019-10-29 11:53:49 +01001049 """ Obtains the list of tenants
1050 For the azure connector only the azure tenant will be returned if it is compatible
1051 with filter_dict
1052 """
tiernob569e4b2019-11-21 16:10:32 +00001053 tenants_azure = [{'name': self.tenant, 'id': self.tenant}]
1054 tenant_list = []
seryio34478552019-05-23 14:50:49 +02001055
lloretgalleg45220152019-10-29 11:53:49 +01001056 self.logger.debug("get tenant list: %s", filter_dict)
jamartinezv14a823d2019-08-01 11:45:15 +02001057 for tenant_azure in tenants_azure:
1058 if filter_dict:
1059 if filter_dict.get("id") and str(tenant_azure.get("id")) != filter_dict["id"]:
1060 continue
lloretgalleg45220152019-10-29 11:53:49 +01001061 if filter_dict.get("name") and str(tenant_azure.get("name")) != filter_dict["name"]:
jamartinezv14a823d2019-08-01 11:45:15 +02001062 continue
1063
1064 tenant_list.append(tenant_azure)
1065
1066 return tenant_list
seryio34478552019-05-23 14:50:49 +02001067
tierno84efdc12019-05-29 09:29:01 +00001068 def refresh_nets_status(self, net_list):
lloretgalleg45220152019-10-29 11:53:49 +01001069 """Get the status of the networks
1070 Params: the list of network identifiers
1071 Returns a dictionary with:
1072 net_id: #VIM id of this network
1073 status: #Mandatory. Text with one of:
1074 # DELETED (not found at vim)
1075 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
1076 # OTHER (Vim reported other status not understood)
1077 # ERROR (VIM indicates an ERROR status)
1078 # ACTIVE, INACTIVE, DOWN (admin down),
1079 # BUILD (on building process)
1080 #
1081 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
1082 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
1083
1084 """
jamartinezv14a823d2019-08-01 11:45:15 +02001085
tierno84efdc12019-05-29 09:29:01 +00001086 out_nets = {}
1087 self._reload_connection()
lloretgalleg45220152019-10-29 11:53:49 +01001088
1089 self.logger.debug("reload nets status net_list: %s", net_list)
tierno84efdc12019-05-29 09:29:01 +00001090 for net_id in net_list:
1091 try:
jamartinezv14a823d2019-08-01 11:45:15 +02001092 netName = self._get_net_name_from_resource_id(net_id)
tierno84efdc12019-05-29 09:29:01 +00001093 resName = self._get_resource_name_from_resource_id(net_id)
seryio34478552019-05-23 14:50:49 +02001094
jamartinezv14a823d2019-08-01 11:45:15 +02001095 net = self.conn_vnet.subnets.get(self.resource_group, netName, resName)
1096
lloretgalleg45220152019-10-29 11:53:49 +01001097 out_nets[net_id] = {
jamartinezv14a823d2019-08-01 11:45:15 +02001098 "status": self.provision_state2osm[net.provisioning_state],
1099 "vim_info": str(net)
tierno84efdc12019-05-29 09:29:01 +00001100 }
1101 except CloudError as e:
lloretgalleg45220152019-10-29 11:53:49 +01001102 if e.error.error and "notfound" in e.error.error.lower():
1103 self.logger.info("Not found subnet net_name: %s, subnet_name: %s", netName, resName)
tierno84efdc12019-05-29 09:29:01 +00001104 out_nets[net_id] = {
1105 "status": "DELETED",
jamartinezv14a823d2019-08-01 11:45:15 +02001106 "error_msg": str(e)
tierno84efdc12019-05-29 09:29:01 +00001107 }
1108 else:
lloretgalleg45220152019-10-29 11:53:49 +01001109 self.logger.error("CloudError Exception %s when searching subnet", e)
1110 out_nets[net_id] = {
1111 "status": "VIM_ERROR",
1112 "error_msg": str(e)
1113 }
jamartinezv14a823d2019-08-01 11:45:15 +02001114 except vimconn.vimconnNotFoundException as e:
lloretgalleg45220152019-10-29 11:53:49 +01001115 self.logger.error("VimConnNotFoundException %s when searching subnet", e)
jamartinezv14a823d2019-08-01 11:45:15 +02001116 out_nets[net_id] = {
1117 "status": "DELETED",
1118 "error_msg": str(e)
1119 }
tierno84efdc12019-05-29 09:29:01 +00001120 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +01001121 self.logger.error("Exception %s when searching subnet", e, exc_info=True)
tierno84efdc12019-05-29 09:29:01 +00001122 out_nets[net_id] = {
1123 "status": "VIM_ERROR",
tierno84efdc12019-05-29 09:29:01 +00001124 "error_msg": str(e)
1125 }
tierno84efdc12019-05-29 09:29:01 +00001126 return out_nets
1127
1128 def refresh_vms_status(self, vm_list):
lloretgalleg45220152019-10-29 11:53:49 +01001129 """ Get the status of the virtual machines and their interfaces/ports
1130 Params: the list of VM identifiers
1131 Returns a dictionary with:
1132 vm_id: # VIM id of this Virtual Machine
1133 status: # Mandatory. Text with one of:
1134 # DELETED (not found at vim)
1135 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
1136 # OTHER (Vim reported other status not understood)
1137 # ERROR (VIM indicates an ERROR status)
1138 # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
1139 # BUILD (on building process), ERROR
1140 # ACTIVE:NoMgmtIP (Active but none of its interfaces has an IP address
1141 # (ACTIVE:NoMgmtIP is not returned for Azure)
1142 #
1143 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
1144 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
1145 interfaces: list with interface info. Each item a dictionary with:
1146 vim_interface_id - The ID of the interface
1147 mac_address - The MAC address of the interface.
1148 ip_address - The IP address of the interface within the subnet.
1149 """
jamartinezv14a823d2019-08-01 11:45:15 +02001150
tierno84efdc12019-05-29 09:29:01 +00001151 out_vms = {}
1152 self._reload_connection()
jamartinezv14a823d2019-08-01 11:45:15 +02001153
lloretgalleg45220152019-10-29 11:53:49 +01001154 self.logger.debug("refresh vm status vm_list: %s", vm_list)
1155 search_vm_list = vm_list or {}
1156
1157 for vm_id in search_vm_list:
1158 out_vm = {}
tierno84efdc12019-05-29 09:29:01 +00001159 try:
lloretgalleg45220152019-10-29 11:53:49 +01001160 res_name = self._get_resource_name_from_resource_id(vm_id)
jamartinezv14a823d2019-08-01 11:45:15 +02001161
lloretgalleg45220152019-10-29 11:53:49 +01001162 vm = self.conn_compute.virtual_machines.get(self.resource_group, res_name)
1163 out_vm['vim_info'] = str(vm)
1164 out_vm['status'] = self.provision_state2osm.get(vm.provisioning_state, 'OTHER')
1165 if vm.provisioning_state == 'Succeeded':
1166 # check if machine is running or stopped
1167 instance_view = self.conn_compute.virtual_machines.instance_view(self.resource_group,
1168 res_name)
1169 for status in instance_view.statuses:
1170 splitted_status = status.code.split("/")
1171 if len(splitted_status) == 2 and splitted_status[0] == 'PowerState':
1172 out_vm['status'] = self.power_state2osm.get(splitted_status[1], 'OTHER')
jamartinezv14a823d2019-08-01 11:45:15 +02001173
1174 network_interfaces = vm.network_profile.network_interfaces
lloretgalleg45220152019-10-29 11:53:49 +01001175 out_vm['interfaces'] = self._get_vm_interfaces_status(vm_id, network_interfaces)
jamartinezv14a823d2019-08-01 11:45:15 +02001176
lloretgalleg45220152019-10-29 11:53:49 +01001177 except CloudError as e:
1178 if e.error.error and "notfound" in e.error.error.lower():
1179 self.logger.debug("Not found vm id: %s", vm_id)
1180 out_vm['status'] = "DELETED"
1181 out_vm['error_msg'] = str(e)
1182 out_vm['vim_info'] = None
1183 else:
1184 # maybe connection error or another type of error, return vim error
1185 self.logger.error("Exception %s refreshing vm_status", e)
1186 out_vm['status'] = "VIM_ERROR"
1187 out_vm['error_msg'] = str(e)
1188 out_vm['vim_info'] = None
tierno84efdc12019-05-29 09:29:01 +00001189 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +01001190 self.logger.error("Exception %s refreshing vm_status", e, exc_info=True)
1191 out_vm['status'] = "VIM_ERROR"
1192 out_vm['error_msg'] = str(e)
1193 out_vm['vim_info'] = None
jamartinezv14a823d2019-08-01 11:45:15 +02001194
lloretgalleg45220152019-10-29 11:53:49 +01001195 out_vms[vm_id] = out_vm
tierno84efdc12019-05-29 09:29:01 +00001196
1197 return out_vms
seryio07ad1362019-05-29 09:16:24 +02001198
lloretgalleg45220152019-10-29 11:53:49 +01001199 def _get_vm_interfaces_status(self, vm_id, interfaces):
1200 """
1201 Gets the interfaces detail for a vm
1202 :param interfaces: List of interfaces.
1203 :return: Dictionary with list of interfaces including, vim_interface_id, mac_address and ip_address
1204 """
1205 try:
1206 interface_list = []
1207 for network_interface in interfaces:
1208 interface_dict = {}
1209 nic_name = self._get_resource_name_from_resource_id(network_interface.id)
1210 interface_dict['vim_interface_id'] = network_interface.id
1211
1212 nic_data = self.conn_vnet.network_interfaces.get(
1213 self.resource_group,
1214 nic_name)
1215
lloretgallegbfc28b02019-11-21 09:31:16 +01001216 ips = []
1217 if nic_data.ip_configurations[0].public_ip_address:
1218 self.logger.debug("Obtain public ip address")
tiernob569e4b2019-11-21 16:10:32 +00001219 public_ip_name = self._get_resource_name_from_resource_id(
1220 nic_data.ip_configurations[0].public_ip_address.id)
lloretgallegbfc28b02019-11-21 09:31:16 +01001221 public_ip = self.conn_vnet.public_ip_addresses.get(self.resource_group, public_ip_name)
1222 self.logger.debug("Public ip address is: %s", public_ip.ip_address)
1223 ips.append(public_ip.ip_address)
1224
lloretgalleg45220152019-10-29 11:53:49 +01001225 private_ip = nic_data.ip_configurations[0].private_ip_address
lloretgallegbfc28b02019-11-21 09:31:16 +01001226 ips.append(private_ip)
lloretgalleg45220152019-10-29 11:53:49 +01001227
1228 interface_dict['mac_address'] = nic_data.mac_address
lloretgallegbfc28b02019-11-21 09:31:16 +01001229 interface_dict['ip_address'] = ";".join(ips)
lloretgalleg45220152019-10-29 11:53:49 +01001230 interface_list.append(interface_dict)
1231
1232 return interface_list
1233 except Exception as e:
1234 self.logger.error("Exception %s obtaining interface data for vm: %s, error: %s", vm_id, e, exc_info=True)
1235 self._format_vimconn_exception(e)
1236
seryio34478552019-05-23 14:50:49 +02001237
1238if __name__ == "__main__":
1239
1240 # Making some basic test
lloretgalleg45220152019-10-29 11:53:49 +01001241 vim_id = 'azure'
1242 vim_name = 'azure'
seryio34478552019-05-23 14:50:49 +02001243 needed_test_params = {
tiernodeb74b22019-05-27 10:24:50 +00001244 "client_id": "AZURE_CLIENT_ID",
1245 "secret": "AZURE_SECRET",
1246 "tenant": "AZURE_TENANT",
1247 "resource_group": "AZURE_RESOURCE_GROUP",
1248 "subscription_id": "AZURE_SUBSCRIPTION_ID",
tierno30d0d6d2019-05-27 08:14:01 +00001249 "vnet_name": "AZURE_VNET_NAME",
seryio34478552019-05-23 14:50:49 +02001250 }
1251 test_params = {}
1252
1253 for param, env_var in needed_test_params.items():
1254 value = getenv(env_var)
1255 if not value:
1256 raise Exception("Provide a valid value for env '{}'".format(env_var))
1257 test_params[param] = value
1258
1259 config = {
tiernob569e4b2019-11-21 16:10:32 +00001260 'region_name': getenv("AZURE_REGION_NAME", 'westeurope'),
1261 'resource_group': getenv("AZURE_RESOURCE_GROUP"),
1262 'subscription_id': getenv("AZURE_SUBSCRIPTION_ID"),
1263 'pub_key': getenv("AZURE_PUB_KEY", None),
1264 'vnet_name': getenv("AZURE_VNET_NAME", 'myNetwork'),
seryio34478552019-05-23 14:50:49 +02001265 }
tierno30d0d6d2019-05-27 08:14:01 +00001266
seryio34478552019-05-23 14:50:49 +02001267 virtualMachine = {
tierno30d0d6d2019-05-27 08:14:01 +00001268 'name': 'sergio',
1269 'description': 'new VM',
seryio34478552019-05-23 14:50:49 +02001270 'status': 'running',
1271 'image': {
1272 'publisher': 'Canonical',
1273 'offer': 'UbuntuServer',
1274 'sku': '16.04.0-LTS',
1275 'version': 'latest'
1276 },
1277 'hardware_profile': {
1278 'vm_size': 'Standard_DS1_v2'
1279 },
1280 'networks': [
1281 'sergio'
1282 ]
1283 }
1284
1285 vnet_config = {
1286 'subnet_address': '10.1.2.0/24',
tiernob569e4b2019-11-21 16:10:32 +00001287 # 'subnet_name': 'subnet-oam'
seryio34478552019-05-23 14:50:49 +02001288 }
1289 ###########################
1290
tierno30d0d6d2019-05-27 08:14:01 +00001291 azure = vimconnector(vim_id, vim_name, tenant_id=test_params["tenant"], tenant_name=None, url=None, url_admin=None,
1292 user=test_params["client_id"], passwd=test_params["secret"], log_level=None, config=config)
seryio34478552019-05-23 14:50:49 +02001293
tiernodeb74b22019-05-27 10:24:50 +00001294 # azure.get_flavor_id_from_data("here")
1295 # subnets=azure.get_network_list()
1296 # azure.new_vminstance(virtualMachine['name'], virtualMachine['description'], virtualMachine['status'],
1297 # virtualMachine['image'], virtualMachine['hardware_profile']['vm_size'], subnets)
1298
tierno24620412019-06-03 14:05:08 +00001299 azure.new_network("mynet", None)
tierno84efdc12019-05-29 09:29:01 +00001300 net_id = "/subscriptions/82f80cc1-876b-4591-9911-1fb5788384fd/resourceGroups/osmRG/providers/Microsoft."\
1301 "Network/virtualNetworks/test"
1302 net_id_not_found = "/subscriptions/82f80cc1-876b-4591-9911-1fb5788384fd/resourceGroups/osmRG/providers/"\
1303 "Microsoft.Network/virtualNetworks/testALF"
1304 azure.refresh_nets_status([net_id, net_id_not_found])