blob: 485bf05ddd5efc093f585df297da936a13de70e8 [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
tierno72774862020-05-04 11:44:15 +000017from osm_ro_plugin import vimconn
seryio34478552019-05-23 14:50:49 +020018import 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
lloretgalleg064b05a2019-11-29 14:46:31 +010030import msrestazure.tools as azure_tools
lloretgalleg45220152019-10-29 11:53:49 +010031from requests.exceptions import ConnectionError
32
sousaedu80135b92021-02-17 15:05:18 +010033__author__ = "Isabel Lloret, Sergio Gonzalez, Alfonso Tierno"
34__date__ = "$18-apr-2019 23:59:59$"
lloretgalleg45220152019-10-29 11:53:49 +010035
tiernodeb74b22019-05-27 10:24:50 +000036
sousaedu80135b92021-02-17 15:05:18 +010037if getenv("OSMRO_PDB_DEBUG"):
jamartinezv14a823d2019-08-01 11:45:15 +020038 import sys
sousaedu80135b92021-02-17 15:05:18 +010039
jamartinezv14a823d2019-08-01 11:45:15 +020040 print(sys.path)
41 import pdb
sousaedu80135b92021-02-17 15:05:18 +010042
jamartinezv14a823d2019-08-01 11:45:15 +020043 pdb.set_trace()
seryio34478552019-05-23 14:50:49 +020044
45
tierno72774862020-05-04 11:44:15 +000046class vimconnector(vimconn.VimConnector):
seryio34478552019-05-23 14:50:49 +020047
lloretgalleg45220152019-10-29 11:53:49 +010048 # Translate azure provisioning state to OSM provision state
49 # The first three ones are the transitional status once a user initiated action has been requested
50 # Once the operation is complete, it will transition into the states Succeeded or Failed
51 # https://docs.microsoft.com/en-us/azure/virtual-machines/windows/states-lifecycle
tierno84efdc12019-05-29 09:29:01 +000052 provision_state2osm = {
lloretgalleg45220152019-10-29 11:53:49 +010053 "Creating": "BUILD",
tierno84efdc12019-05-29 09:29:01 +000054 "Updating": "BUILD",
lloretgalleg45220152019-10-29 11:53:49 +010055 "Deleting": "INACTIVE",
56 "Succeeded": "ACTIVE",
sousaedu80135b92021-02-17 15:05:18 +010057 "Failed": "ERROR",
lloretgalleg45220152019-10-29 11:53:49 +010058 }
59
60 # Translate azure power state to OSM provision state
61 power_state2osm = {
62 "starting": "INACTIVE",
63 "running": "ACTIVE",
64 "stopping": "INACTIVE",
65 "stopped": "INACTIVE",
66 "unknown": "OTHER",
67 "deallocated": "BUILD",
sousaedu80135b92021-02-17 15:05:18 +010068 "deallocating": "BUILD",
tierno84efdc12019-05-29 09:29:01 +000069 }
70
lloretgalleg064b05a2019-11-29 14:46:31 +010071 AZURE_ZONES = ["1", "2", "3"]
72
sousaedu80135b92021-02-17 15:05:18 +010073 def __init__(
74 self,
75 uuid,
76 name,
77 tenant_id,
78 tenant_name,
79 url,
80 url_admin=None,
81 user=None,
82 passwd=None,
83 log_level=None,
84 config={},
85 persistent_info={},
86 ):
lloretgalleg45220152019-10-29 11:53:49 +010087 """
88 Constructor of VIM. Raise an exception is some needed parameter is missing, but it must not do any connectivity
89 checking against the VIM
90 Using common constructor parameters.
91 In this case: config must include the following parameters:
92 subscription_id: assigned azure subscription identifier
93 region_name: current region for azure network
94 resource_group: used for all azure created resources
95 vnet_name: base vnet for azure, created networks will be subnets from this base network
96 config may also include the following parameter:
97 flavors_pattern: pattern that will be used to select a range of vm sizes, for example
98 "^((?!Standard_B).)*$" will filter out Standard_B range that is cheap but is very overused
99 "^Standard_B" will select a serie B maybe for test environment
100 """
sousaedu80135b92021-02-17 15:05:18 +0100101 vimconn.VimConnector.__init__(
102 self,
103 uuid,
104 name,
105 tenant_id,
106 tenant_name,
107 url,
108 url_admin,
109 user,
110 passwd,
111 log_level,
112 config,
113 persistent_info,
114 )
seryio34478552019-05-23 14:50:49 +0200115
lloretgalleg45220152019-10-29 11:53:49 +0100116 # Variable that indicates if client must be reloaded or initialized
117 self.reload_client = True
118
tierno84efdc12019-05-29 09:29:01 +0000119 self.vnet_address_space = None
seryio34478552019-05-23 14:50:49 +0200120 # LOGGER
sousaedu80135b92021-02-17 15:05:18 +0100121 self.logger = logging.getLogger("ro.vim.azure")
122
seryio34478552019-05-23 14:50:49 +0200123 if log_level:
124 logging.basicConfig()
125 self.logger.setLevel(getattr(logging, log_level))
126
sousaedu80135b92021-02-17 15:05:18 +0100127 self.tenant = tenant_id or tenant_name
tierno30d0d6d2019-05-27 08:14:01 +0000128
lloretgalleg45220152019-10-29 11:53:49 +0100129 # Store config to create azure subscription later
tiernob569e4b2019-11-21 16:10:32 +0000130 self._config = {
131 "user": user,
132 "passwd": passwd,
sousaedu80135b92021-02-17 15:05:18 +0100133 "tenant": tenant_id or tenant_name,
tiernob569e4b2019-11-21 16:10:32 +0000134 }
tierno30d0d6d2019-05-27 08:14:01 +0000135
136 # SUBSCRIPTION
sousaedu80135b92021-02-17 15:05:18 +0100137 if "subscription_id" in config:
138 self._config["subscription_id"] = config.get("subscription_id")
139 # self.logger.debug("Setting subscription to: %s", self.config["subscription_id"])
seryio34478552019-05-23 14:50:49 +0200140 else:
sousaedu80135b92021-02-17 15:05:18 +0100141 raise vimconn.VimConnException("Subscription not specified")
lloretgalleg45220152019-10-29 11:53:49 +0100142
tierno30d0d6d2019-05-27 08:14:01 +0000143 # REGION
sousaedu80135b92021-02-17 15:05:18 +0100144 if "region_name" in config:
145 self.region = config.get("region_name")
seryio34478552019-05-23 14:50:49 +0200146 else:
sousaedu80135b92021-02-17 15:05:18 +0100147 raise vimconn.VimConnException(
148 "Azure region_name is not specified at config"
149 )
lloretgalleg45220152019-10-29 11:53:49 +0100150
tierno30d0d6d2019-05-27 08:14:01 +0000151 # RESOURCE_GROUP
sousaedu80135b92021-02-17 15:05:18 +0100152 if "resource_group" in config:
153 self.resource_group = config.get("resource_group")
seryio34478552019-05-23 14:50:49 +0200154 else:
sousaedu80135b92021-02-17 15:05:18 +0100155 raise vimconn.VimConnException(
156 "Azure resource_group is not specified at config"
157 )
lloretgalleg45220152019-10-29 11:53:49 +0100158
seryio34478552019-05-23 14:50:49 +0200159 # VNET_NAME
sousaedu80135b92021-02-17 15:05:18 +0100160 if "vnet_name" in config:
seryio34478552019-05-23 14:50:49 +0200161 self.vnet_name = config["vnet_name"]
sousaedu80135b92021-02-17 15:05:18 +0100162
seryio34478552019-05-23 14:50:49 +0200163 # public ssh key
sousaedu80135b92021-02-17 15:05:18 +0100164 self.pub_key = config.get("pub_key")
lloretgalleg45220152019-10-29 11:53:49 +0100165
166 # flavor pattern regex
sousaedu80135b92021-02-17 15:05:18 +0100167 if "flavors_pattern" in config:
168 self._config["flavors_pattern"] = config["flavors_pattern"]
169
seryio34478552019-05-23 14:50:49 +0200170 def _reload_connection(self):
tiernodeb74b22019-05-27 10:24:50 +0000171 """
lloretgalleg45220152019-10-29 11:53:49 +0100172 Called before any operation, checks python azure clients
tiernodeb74b22019-05-27 10:24:50 +0000173 """
lloretgalleg45220152019-10-29 11:53:49 +0100174 if self.reload_client:
sousaedu80135b92021-02-17 15:05:18 +0100175 self.logger.debug("reloading azure client")
176
lloretgalleg45220152019-10-29 11:53:49 +0100177 try:
178 self.credentials = ServicePrincipalCredentials(
179 client_id=self._config["user"],
180 secret=self._config["passwd"],
sousaedu80135b92021-02-17 15:05:18 +0100181 tenant=self._config["tenant"],
lloretgalleg45220152019-10-29 11:53:49 +0100182 )
sousaedu80135b92021-02-17 15:05:18 +0100183 self.conn = ResourceManagementClient(
184 self.credentials, self._config["subscription_id"]
185 )
186 self.conn_compute = ComputeManagementClient(
187 self.credentials, self._config["subscription_id"]
188 )
189 self.conn_vnet = NetworkManagementClient(
190 self.credentials, self._config["subscription_id"]
191 )
lloretgalleg45220152019-10-29 11:53:49 +0100192 self._check_or_create_resource_group()
193 self._check_or_create_vnet()
194
195 # Set to client created
196 self.reload_client = False
197 except Exception as e:
198 self._format_vimconn_exception(e)
seryio34478552019-05-23 14:50:49 +0200199
200 def _get_resource_name_from_resource_id(self, resource_id):
lloretgalleg45220152019-10-29 11:53:49 +0100201 """
202 Obtains resource_name from the azure complete identifier: resource_name will always be last item
203 """
jamartinezv14a823d2019-08-01 11:45:15 +0200204 try:
sousaedu80135b92021-02-17 15:05:18 +0100205 resource = str(resource_id.split("/")[-1])
206
jamartinezv14a823d2019-08-01 11:45:15 +0200207 return resource
208 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100209 raise vimconn.VimConnException(
210 "Unable to get resource name from resource_id '{}' Error: '{}'".format(
211 resource_id, e
212 )
213 )
seryio34478552019-05-23 14:50:49 +0200214
215 def _get_location_from_resource_group(self, resource_group_name):
jamartinezv14a823d2019-08-01 11:45:15 +0200216 try:
lloretgalleg45220152019-10-29 11:53:49 +0100217 location = self.conn.resource_groups.get(resource_group_name).location
sousaedu80135b92021-02-17 15:05:18 +0100218
jamartinezv14a823d2019-08-01 11:45:15 +0200219 return location
tierno1ec592d2020-06-16 15:29:47 +0000220 except Exception:
sousaedu80135b92021-02-17 15:05:18 +0100221 raise vimconn.VimConnNotFoundException(
222 "Location '{}' not found".format(resource_group_name)
223 )
jamartinezv14a823d2019-08-01 11:45:15 +0200224
seryio34478552019-05-23 14:50:49 +0200225 def _get_resource_group_name_from_resource_id(self, resource_id):
jamartinezv14a823d2019-08-01 11:45:15 +0200226 try:
sousaedu80135b92021-02-17 15:05:18 +0100227 rg = str(resource_id.split("/")[4])
228
jamartinezv14a823d2019-08-01 11:45:15 +0200229 return rg
tierno1ec592d2020-06-16 15:29:47 +0000230 except Exception:
sousaedu80135b92021-02-17 15:05:18 +0100231 raise vimconn.VimConnException(
232 "Unable to get resource group from invalid resource_id format '{}'".format(
233 resource_id
234 )
235 )
jamartinezv14a823d2019-08-01 11:45:15 +0200236
237 def _get_net_name_from_resource_id(self, resource_id):
jamartinezv14a823d2019-08-01 11:45:15 +0200238 try:
sousaedu80135b92021-02-17 15:05:18 +0100239 net_name = str(resource_id.split("/")[8])
240
jamartinezv14a823d2019-08-01 11:45:15 +0200241 return net_name
tierno1ec592d2020-06-16 15:29:47 +0000242 except Exception:
sousaedu80135b92021-02-17 15:05:18 +0100243 raise vimconn.VimConnException(
244 "Unable to get azure net_name from invalid resource_id format '{}'".format(
245 resource_id
246 )
247 )
seryio34478552019-05-23 14:50:49 +0200248
249 def _check_subnets_for_vm(self, net_list):
tierno30d0d6d2019-05-27 08:14:01 +0000250 # All subnets must belong to the same resource group and vnet
sousaedu80135b92021-02-17 15:05:18 +0100251 rg_vnet = set(
252 self._get_resource_group_name_from_resource_id(net["net_id"])
253 + self._get_net_name_from_resource_id(net["net_id"])
254 for net in net_list
255 )
seryio34478552019-05-23 14:50:49 +0200256
lloretgalleg45220152019-10-29 11:53:49 +0100257 if len(rg_vnet) != 1:
sousaedu80135b92021-02-17 15:05:18 +0100258 raise self._format_vimconn_exception(
259 "Azure VMs can only attach to subnets in same VNET"
260 )
seryio34478552019-05-23 14:50:49 +0200261
lloretgalleg45220152019-10-29 11:53:49 +0100262 def _format_vimconn_exception(self, e):
tiernodeb74b22019-05-27 10:24:50 +0000263 """
lloretgalleg45220152019-10-29 11:53:49 +0100264 Transforms a generic or azure exception to a vimcommException
tiernodeb74b22019-05-27 10:24:50 +0000265 """
tierno72774862020-05-04 11:44:15 +0000266 if isinstance(e, vimconn.VimConnException):
lloretgalleg45220152019-10-29 11:53:49 +0100267 raise
268 elif isinstance(e, AuthenticationError):
sousaedu80135b92021-02-17 15:05:18 +0100269 raise vimconn.VimConnAuthException(type(e).__name__ + ": " + str(e))
lloretgalleg45220152019-10-29 11:53:49 +0100270 elif isinstance(e, ConnectionError):
sousaedu80135b92021-02-17 15:05:18 +0100271 raise vimconn.VimConnConnectionException(type(e).__name__ + ": " + str(e))
lloretgalleg45220152019-10-29 11:53:49 +0100272 else:
273 # In case of generic error recreate client
274 self.reload_client = True
sousaedu80135b92021-02-17 15:05:18 +0100275
276 raise vimconn.VimConnException(type(e).__name__ + ": " + str(e))
seryio34478552019-05-23 14:50:49 +0200277
278 def _check_or_create_resource_group(self):
tiernodeb74b22019-05-27 10:24:50 +0000279 """
lloretgalleg45220152019-10-29 11:53:49 +0100280 Creates the base resource group if it does not exist
tiernodeb74b22019-05-27 10:24:50 +0000281 """
lloretgalleg45220152019-10-29 11:53:49 +0100282 try:
283 rg_exists = self.conn.resource_groups.check_existence(self.resource_group)
sousaedu80135b92021-02-17 15:05:18 +0100284
lloretgalleg45220152019-10-29 11:53:49 +0100285 if not rg_exists:
286 self.logger.debug("create base rgroup: %s", self.resource_group)
sousaedu80135b92021-02-17 15:05:18 +0100287 self.conn.resource_groups.create_or_update(
288 self.resource_group, {"location": self.region}
289 )
lloretgalleg45220152019-10-29 11:53:49 +0100290 except Exception as e:
291 self._format_vimconn_exception(e)
tiernodeb74b22019-05-27 10:24:50 +0000292
293 def _check_or_create_vnet(self):
lloretgalleg45220152019-10-29 11:53:49 +0100294 """
295 Try to get existent base vnet, in case it does not exist it creates it
296 """
tiernodeb74b22019-05-27 10:24:50 +0000297 try:
sousaedu80135b92021-02-17 15:05:18 +0100298 vnet = self.conn_vnet.virtual_networks.get(
299 self.resource_group, self.vnet_name
300 )
tierno84efdc12019-05-29 09:29:01 +0000301 self.vnet_address_space = vnet.address_space.address_prefixes[0]
tierno24620412019-06-03 14:05:08 +0000302 self.vnet_id = vnet.id
sousaedu80135b92021-02-17 15:05:18 +0100303
tierno84efdc12019-05-29 09:29:01 +0000304 return
305 except CloudError as e:
lloretgalleg45220152019-10-29 11:53:49 +0100306 if e.error.error and "notfound" in e.error.error.lower():
tierno84efdc12019-05-29 09:29:01 +0000307 pass
lloretgalleg45220152019-10-29 11:53:49 +0100308 # continue and create it
tierno84efdc12019-05-29 09:29:01 +0000309 else:
lloretgalleg45220152019-10-29 11:53:49 +0100310 self._format_vimconn_exception(e)
311
312 # if it does not exist, create it
tiernodeb74b22019-05-27 10:24:50 +0000313 try:
314 vnet_params = {
sousaedu80135b92021-02-17 15:05:18 +0100315 "location": self.region,
316 "address_space": {"address_prefixes": ["10.0.0.0/8"]},
tiernodeb74b22019-05-27 10:24:50 +0000317 }
tierno84efdc12019-05-29 09:29:01 +0000318 self.vnet_address_space = "10.0.0.0/8"
jamartinezv14a823d2019-08-01 11:45:15 +0200319
lloretgalleg45220152019-10-29 11:53:49 +0100320 self.logger.debug("create base vnet: %s", self.vnet_name)
sousaedu80135b92021-02-17 15:05:18 +0100321 self.conn_vnet.virtual_networks.create_or_update(
322 self.resource_group, self.vnet_name, vnet_params
323 )
324 vnet = self.conn_vnet.virtual_networks.get(
325 self.resource_group, self.vnet_name
326 )
tierno24620412019-06-03 14:05:08 +0000327 self.vnet_id = vnet.id
tiernodeb74b22019-05-27 10:24:50 +0000328 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +0100329 self._format_vimconn_exception(e)
seryio34478552019-05-23 14:50:49 +0200330
sousaedu80135b92021-02-17 15:05:18 +0100331 def new_network(
332 self,
333 net_name,
334 net_type,
335 ip_profile=None,
336 shared=False,
337 provider_network_profile=None,
338 ):
tiernodeb74b22019-05-27 10:24:50 +0000339 """
340 Adds a tenant network to VIM
341 :param net_name: name of the network
lloretgalleg45220152019-10-29 11:53:49 +0100342 :param net_type: not used for azure networks
tiernodeb74b22019-05-27 10:24:50 +0000343 :param ip_profile: is a dict containing the IP parameters of the network (Currently only IPv4 is implemented)
seryio34478552019-05-23 14:50:49 +0200344 'ip-version': can be one of ['IPv4','IPv6']
345 'subnet-address': ip_prefix_schema, that is X.X.X.X/Y
lloretgalleg45220152019-10-29 11:53:49 +0100346 'gateway-address': (Optional) ip_schema, that is X.X.X.X, not implemented for azure connector
347 'dns-address': (Optional) ip_schema, not implemented for azure connector
348 'dhcp': (Optional) dict containing, not implemented for azure connector
seryio34478552019-05-23 14:50:49 +0200349 'enabled': {'type': 'boolean'},
350 'start-address': ip_schema, first IP to grant
351 'count': number of IPs to grant.
lloretgalleg45220152019-10-29 11:53:49 +0100352 :param shared: Not allowed for Azure Connector
kbsuba85c54d2019-10-17 16:30:32 +0000353 :param provider_network_profile: (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk}
tiernodeb74b22019-05-27 10:24:50 +0000354 :return: a tuple with the network identifier and created_items, or raises an exception on error
seryio34478552019-05-23 14:50:49 +0200355 created_items can be None or a dictionary where this method can include key-values that will be passed to
356 the method delete_network. Can be used to store created segments, created l2gw connections, etc.
357 Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
358 as not present.
tiernodeb74b22019-05-27 10:24:50 +0000359 """
seryio34478552019-05-23 14:50:49 +0200360 return self._new_subnet(net_name, ip_profile)
361
362 def _new_subnet(self, net_name, ip_profile):
tiernodeb74b22019-05-27 10:24:50 +0000363 """
lloretgalleg45220152019-10-29 11:53:49 +0100364 Adds a tenant network to VIM. It creates a new subnet at existing base vnet
365 :param net_name: subnet name
tiernodeb74b22019-05-27 10:24:50 +0000366 :param ip_profile:
lloretgalleg45220152019-10-29 11:53:49 +0100367 subnet-address: if it is not provided a subnet/24 in the default vnet is created,
368 otherwise it creates a subnet in the indicated address
369 :return: a tuple with the network identifier and created_items, or raises an exception on error
tiernodeb74b22019-05-27 10:24:50 +0000370 """
sousaedu80135b92021-02-17 15:05:18 +0100371 self.logger.debug("create subnet name %s, ip_profile %s", net_name, ip_profile)
seryio34478552019-05-23 14:50:49 +0200372 self._reload_connection()
seryio34478552019-05-23 14:50:49 +0200373
374 if ip_profile is None:
tierno24620412019-06-03 14:05:08 +0000375 # get a non used vnet ip range /24 and allocate automatically inside the range self.vnet_address_space
376 used_subnets = self.get_network_list()
377 for ip_range in netaddr.IPNetwork(self.vnet_address_space).subnet(24):
378 for used_subnet in used_subnets:
379 subnet_range = netaddr.IPNetwork(used_subnet["cidr_block"])
sousaedu80135b92021-02-17 15:05:18 +0100380
tierno24620412019-06-03 14:05:08 +0000381 if subnet_range in ip_range or ip_range in subnet_range:
382 # this range overlaps with an existing subnet ip range. Breaks and look for another
383 break
384 else:
385 ip_profile = {"subnet_address": str(ip_range)}
sousaedu80135b92021-02-17 15:05:18 +0100386 self.logger.debug("dinamically obtained ip_profile: %s", ip_range)
tierno24620412019-06-03 14:05:08 +0000387 break
388 else:
sousaedu80135b92021-02-17 15:05:18 +0100389 raise vimconn.VimConnException(
390 "Cannot find a non-used subnet range in {}".format(
391 self.vnet_address_space
392 )
393 )
jamartinezv14a823d2019-08-01 11:45:15 +0200394 else:
sousaedu80135b92021-02-17 15:05:18 +0100395 ip_profile = {"subnet_address": ip_profile["subnet_address"]}
seryio34478552019-05-23 14:50:49 +0200396
397 try:
tiernob569e4b2019-11-21 16:10:32 +0000398 # subnet_name = "{}-{}".format(net_name[:24], uuid4())
sousaedu80135b92021-02-17 15:05:18 +0100399 subnet_params = {"address_prefix": ip_profile["subnet_address"]}
lloretgalleg45220152019-10-29 11:53:49 +0100400 # Assign a not duplicated net name
401 subnet_name = self._get_unused_subnet_name(net_name)
seryio34478552019-05-23 14:50:49 +0200402
sousaedu80135b92021-02-17 15:05:18 +0100403 self.logger.debug("creating subnet_name: {}".format(subnet_name))
404 async_creation = self.conn_vnet.subnets.create_or_update(
405 self.resource_group, self.vnet_name, subnet_name, subnet_params
406 )
lloretgalleg45220152019-10-29 11:53:49 +0100407 async_creation.wait()
sousaedu80135b92021-02-17 15:05:18 +0100408 self.logger.debug("created subnet_name: {}".format(subnet_name))
lloretgalleg45220152019-10-29 11:53:49 +0100409
jamartinezv14a823d2019-08-01 11:45:15 +0200410 return "{}/subnets/{}".format(self.vnet_id, subnet_name), None
seryio34478552019-05-23 14:50:49 +0200411 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +0100412 self._format_vimconn_exception(e)
413
414 def _get_unused_subnet_name(self, subnet_name):
415 """
416 Adds a prefix to the subnet_name with a number in case the indicated name is repeated
417 Checks subnets with the indicated name (without suffix) and adds a suffix with a number
418 """
419 all_subnets = self.conn_vnet.subnets.list(self.resource_group, self.vnet_name)
420 # Filter to subnets starting with the indicated name
sousaedu80135b92021-02-17 15:05:18 +0100421 subnets = list(
422 filter(lambda subnet: (subnet.name.startswith(subnet_name)), all_subnets)
423 )
lloretgalleg45220152019-10-29 11:53:49 +0100424 net_names = [str(subnet.name) for subnet in subnets]
425
426 # get the name with the first not used suffix
427 name_suffix = 0
tiernob569e4b2019-11-21 16:10:32 +0000428 # name = subnet_name + "-" + str(name_suffix)
429 name = subnet_name # first subnet created will have no prefix
lloretgalleg45220152019-10-29 11:53:49 +0100430 while name in net_names:
431 name_suffix += 1
432 name = subnet_name + "-" + str(name_suffix)
sousaedu80135b92021-02-17 15:05:18 +0100433
lloretgalleg45220152019-10-29 11:53:49 +0100434 return name
seryio34478552019-05-23 14:50:49 +0200435
lloretgalleg064b05a2019-11-29 14:46:31 +0100436 def _create_nic(self, net, nic_name, static_ip=None, created_items={}):
sousaedu80135b92021-02-17 15:05:18 +0100437 self.logger.debug("create nic name %s, net_name %s", nic_name, net)
seryio34478552019-05-23 14:50:49 +0200438 self._reload_connection()
jamartinezv14a823d2019-08-01 11:45:15 +0200439
sousaedu80135b92021-02-17 15:05:18 +0100440 subnet_id = net["net_id"]
jamartinezv14a823d2019-08-01 11:45:15 +0200441 location = self._get_location_from_resource_group(self.resource_group)
jamartinezv14a823d2019-08-01 11:45:15 +0200442 try:
sousaedu80135b92021-02-17 15:05:18 +0100443 net_ifz = {"location": location}
444 net_ip_config = {
445 "name": nic_name + "-ipconfiguration",
446 "subnet": {"id": subnet_id},
447 }
lloretgallegbfc28b02019-11-21 09:31:16 +0100448
sousaedu80135b92021-02-17 15:05:18 +0100449 if static_ip:
450 net_ip_config["privateIPAddress"] = static_ip
451 net_ip_config["privateIPAllocationMethod"] = "Static"
452
453 net_ifz["ip_configurations"] = [net_ip_config]
454 mac_address = net.get("mac_address")
455
456 if mac_address:
457 net_ifz["mac_address"] = mac_address
458
459 async_nic_creation = self.conn_vnet.network_interfaces.create_or_update(
460 self.resource_group, nic_name, net_ifz
461 )
lloretgalleg064b05a2019-11-29 14:46:31 +0100462 nic_data = async_nic_creation.result()
463 created_items[nic_data.id] = True
sousaedu80135b92021-02-17 15:05:18 +0100464 self.logger.debug("created nic name %s", nic_name)
jamartinezv14a823d2019-08-01 11:45:15 +0200465
sousaedu80135b92021-02-17 15:05:18 +0100466 public_ip = net.get("floating_ip")
lloretgalleg45220152019-10-29 11:53:49 +0100467 if public_ip:
468 public_ip_address_params = {
sousaedu80135b92021-02-17 15:05:18 +0100469 "location": location,
470 "public_ip_allocation_method": "Dynamic",
seryio34478552019-05-23 14:50:49 +0200471 }
sousaedu80135b92021-02-17 15:05:18 +0100472 public_ip_name = nic_name + "-public-ip"
lloretgalleg064b05a2019-11-29 14:46:31 +0100473 async_public_ip = self.conn_vnet.public_ip_addresses.create_or_update(
sousaedu80135b92021-02-17 15:05:18 +0100474 self.resource_group, public_ip_name, public_ip_address_params
jamartinezv14a823d2019-08-01 11:45:15 +0200475 )
lloretgalleg064b05a2019-11-29 14:46:31 +0100476 public_ip = async_public_ip.result()
sousaedu80135b92021-02-17 15:05:18 +0100477 self.logger.debug("created public IP: {}".format(public_ip))
jamartinezv14a823d2019-08-01 11:45:15 +0200478
tiernob569e4b2019-11-21 16:10:32 +0000479 # Associate NIC to Public IP
jamartinezv14a823d2019-08-01 11:45:15 +0200480 nic_data = self.conn_vnet.network_interfaces.get(
sousaedu80135b92021-02-17 15:05:18 +0100481 self.resource_group, nic_name
482 )
jamartinezv14a823d2019-08-01 11:45:15 +0200483
lloretgalleg064b05a2019-11-29 14:46:31 +0100484 nic_data.ip_configurations[0].public_ip_address = public_ip
485 created_items[public_ip.id] = True
jamartinezv14a823d2019-08-01 11:45:15 +0200486
jamartinezv14a823d2019-08-01 11:45:15 +0200487 self.conn_vnet.network_interfaces.create_or_update(
sousaedu80135b92021-02-17 15:05:18 +0100488 self.resource_group, nic_name, nic_data
489 )
jamartinezv14a823d2019-08-01 11:45:15 +0200490
491 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +0100492 self._format_vimconn_exception(e)
seryio34478552019-05-23 14:50:49 +0200493
lloretgalleg064b05a2019-11-29 14:46:31 +0100494 return nic_data, created_items
seryio34478552019-05-23 14:50:49 +0200495
jamartinezv14a823d2019-08-01 11:45:15 +0200496 def new_flavor(self, flavor_data):
tiernodeb74b22019-05-27 10:24:50 +0000497 """
lloretgalleg45220152019-10-29 11:53:49 +0100498 It is not allowed to create new flavors in Azure, must always use an existing one
499 """
sousaedu80135b92021-02-17 15:05:18 +0100500 raise vimconn.VimConnAuthException(
501 "It is not possible to create new flavors in AZURE"
502 )
tiernodeb74b22019-05-27 10:24:50 +0000503
lloretgalleg45220152019-10-29 11:53:49 +0100504 def new_tenant(self, tenant_name, tenant_description):
tiernodeb74b22019-05-27 10:24:50 +0000505 """
lloretgalleg45220152019-10-29 11:53:49 +0100506 It is not allowed to create new tenants in azure
507 """
sousaedu80135b92021-02-17 15:05:18 +0100508 raise vimconn.VimConnAuthException(
509 "It is not possible to create a TENANT in AZURE"
510 )
jamartinezv14a823d2019-08-01 11:45:15 +0200511
512 def new_image(self, image_dict):
lloretgalleg45220152019-10-29 11:53:49 +0100513 """
514 It is not allowed to create new images in Azure, must always use an existing one
515 """
sousaedu80135b92021-02-17 15:05:18 +0100516 raise vimconn.VimConnAuthException(
517 "It is not possible to create new images in AZURE"
518 )
jamartinezv14a823d2019-08-01 11:45:15 +0200519
520 def get_image_id_from_path(self, path):
521 """Get the image id from image path in the VIM database.
sousaedu80135b92021-02-17 15:05:18 +0100522 Returns the image_id or raises a vimconnNotFoundException
jamartinezv14a823d2019-08-01 11:45:15 +0200523 """
sousaedu80135b92021-02-17 15:05:18 +0100524 raise vimconn.VimConnAuthException(
525 "It is not possible to obtain image from path in AZURE"
526 )
jamartinezv14a823d2019-08-01 11:45:15 +0200527
528 def get_image_list(self, filter_dict={}):
529 """Obtain tenant images from VIM
530 Filter_dict can be:
lloretgalleg45220152019-10-29 11:53:49 +0100531 name: image name with the format: publisher:offer:sku:version
532 If some part of the name is provide ex: publisher:offer it will search all availables skus and version
533 for the provided publisher and offer
534 id: image uuid, currently not supported for azure
jamartinezv14a823d2019-08-01 11:45:15 +0200535 Returns the image list of dictionaries:
536 [{<the fields at Filter_dict plus some VIM specific>}, ...]
537 List can be empty
538 """
lloretgalleg45220152019-10-29 11:53:49 +0100539 self.logger.debug("get_image_list filter {}".format(filter_dict))
tiernodeb74b22019-05-27 10:24:50 +0000540
541 self._reload_connection()
lloretgalleg45220152019-10-29 11:53:49 +0100542 try:
543 image_list = []
544 if filter_dict.get("name"):
sousaedu80135b92021-02-17 15:05:18 +0100545 # name will have the format "publisher:offer:sku:version"
lloretgalleg45220152019-10-29 11:53:49 +0100546 # publisher is required, offer sku and version will be searched if not provided
547 params = filter_dict["name"].split(":")
tiernodeb74b22019-05-27 10:24:50 +0000548 publisher = params[0]
lloretgalleg45220152019-10-29 11:53:49 +0100549 if publisher:
550 # obtain offer list
551 offer_list = self._get_offer_list(params, publisher)
sousaedu80135b92021-02-17 15:05:18 +0100552
lloretgalleg45220152019-10-29 11:53:49 +0100553 for offer in offer_list:
554 # obtain skus
555 sku_list = self._get_sku_list(params, publisher, offer)
sousaedu80135b92021-02-17 15:05:18 +0100556
lloretgalleg45220152019-10-29 11:53:49 +0100557 for sku in sku_list:
558 # if version is defined get directly version, else list images
559 if len(params) == 4 and params[3]:
560 version = params[3]
sousaedu80135b92021-02-17 15:05:18 +0100561 image_list = self._get_version_image_list(
562 publisher, offer, sku, version
563 )
lloretgalleg45220152019-10-29 11:53:49 +0100564 else:
sousaedu80135b92021-02-17 15:05:18 +0100565 image_list = self._get_sku_image_list(
566 publisher, offer, sku
567 )
lloretgalleg45220152019-10-29 11:53:49 +0100568 else:
tierno72774862020-05-04 11:44:15 +0000569 raise vimconn.VimConnAuthException(
sousaedu80135b92021-02-17 15:05:18 +0100570 "List images in Azure must include name param with at least publisher"
571 )
lloretgalleg45220152019-10-29 11:53:49 +0100572 else:
sousaedu80135b92021-02-17 15:05:18 +0100573 raise vimconn.VimConnAuthException(
574 "List images in Azure must include name param with at"
575 " least publisher"
576 )
tiernodeb74b22019-05-27 10:24:50 +0000577
lloretgalleg45220152019-10-29 11:53:49 +0100578 return image_list
579 except Exception as e:
580 self._format_vimconn_exception(e)
tiernodeb74b22019-05-27 10:24:50 +0000581
lloretgalleg45220152019-10-29 11:53:49 +0100582 def _get_offer_list(self, params, publisher):
583 """
584 Helper method to obtain offer list for defined publisher
585 """
586 if len(params) >= 2 and params[1]:
587 return [params[1]]
588 else:
589 try:
590 # get list of offers from azure
sousaedu80135b92021-02-17 15:05:18 +0100591 result_offers = self.conn_compute.virtual_machine_images.list_offers(
592 self.region, publisher
593 )
594
lloretgalleg45220152019-10-29 11:53:49 +0100595 return [offer.name for offer in result_offers]
596 except CloudError as e:
597 # azure raises CloudError when not found
sousaedu80135b92021-02-17 15:05:18 +0100598 self.logger.info(
599 "error listing offers for publisher {}, Error: {}".format(
600 publisher, e
601 )
602 )
603
lloretgalleg45220152019-10-29 11:53:49 +0100604 return []
605
606 def _get_sku_list(self, params, publisher, offer):
607 """
608 Helper method to obtain sku list for defined publisher and offer
609 """
610 if len(params) >= 3 and params[2]:
611 return [params[2]]
612 else:
613 try:
614 # get list of skus from azure
sousaedu80135b92021-02-17 15:05:18 +0100615 result_skus = self.conn_compute.virtual_machine_images.list_skus(
616 self.region, publisher, offer
617 )
618
lloretgalleg45220152019-10-29 11:53:49 +0100619 return [sku.name for sku in result_skus]
620 except CloudError as e:
621 # azure raises CloudError when not found
sousaedu80135b92021-02-17 15:05:18 +0100622 self.logger.info(
623 "error listing skus for publisher {}, offer {}, Error: {}".format(
624 publisher, offer, e
625 )
626 )
627
lloretgalleg45220152019-10-29 11:53:49 +0100628 return []
629
630 def _get_sku_image_list(self, publisher, offer, sku):
631 """
632 Helper method to obtain image list for publisher, offer and sku
633 """
634 image_list = []
635 try:
sousaedu80135b92021-02-17 15:05:18 +0100636 result_images = self.conn_compute.virtual_machine_images.list(
637 self.region, publisher, offer, sku
638 )
lloretgalleg45220152019-10-29 11:53:49 +0100639 for result_image in result_images:
sousaedu80135b92021-02-17 15:05:18 +0100640 image_list.append(
641 {
642 "id": str(result_image.id),
643 "name": ":".join([publisher, offer, sku, result_image.name]),
644 }
645 )
lloretgalleg45220152019-10-29 11:53:49 +0100646 except CloudError as e:
647 self.logger.info(
sousaedu80135b92021-02-17 15:05:18 +0100648 "error listing skus for publisher {}, offer {}, Error: {}".format(
649 publisher, offer, e
650 )
651 )
lloretgalleg45220152019-10-29 11:53:49 +0100652 image_list = []
sousaedu80135b92021-02-17 15:05:18 +0100653
lloretgalleg45220152019-10-29 11:53:49 +0100654 return image_list
655
656 def _get_version_image_list(self, publisher, offer, sku, version):
657 image_list = []
658 try:
sousaedu80135b92021-02-17 15:05:18 +0100659 result_image = self.conn_compute.virtual_machine_images.get(
660 self.region, publisher, offer, sku, version
661 )
662
lloretgalleg45220152019-10-29 11:53:49 +0100663 if result_image:
sousaedu80135b92021-02-17 15:05:18 +0100664 image_list.append(
665 {
666 "id": str(result_image.id),
667 "name": ":".join([publisher, offer, sku, version]),
668 }
669 )
lloretgalleg45220152019-10-29 11:53:49 +0100670 except CloudError as e:
671 # azure gives CloudError when not found
sousaedu80135b92021-02-17 15:05:18 +0100672 self.logger.info(
673 "error listing images for publisher {}, offer {}, sku {}, version {} Error: {}".format(
674 publisher, offer, sku, version, e
675 )
676 )
lloretgalleg45220152019-10-29 11:53:49 +0100677 image_list = []
sousaedu80135b92021-02-17 15:05:18 +0100678
tiernodeb74b22019-05-27 10:24:50 +0000679 return image_list
680
seryio34478552019-05-23 14:50:49 +0200681 def get_network_list(self, filter_dict={}):
tiernodeb74b22019-05-27 10:24:50 +0000682 """Obtain tenant networks of VIM
seryio34478552019-05-23 14:50:49 +0200683 Filter_dict can be:
684 name: network name
lloretgalleg45220152019-10-29 11:53:49 +0100685 id: network id
686 shared: boolean, not implemented in Azure
687 tenant_id: tenant, not used in Azure, all networks same tenants
688 admin_state_up: boolean, not implemented in Azure
689 status: 'ACTIVE', not implemented in Azure #
seryio34478552019-05-23 14:50:49 +0200690 Returns the network list of dictionaries
tiernodeb74b22019-05-27 10:24:50 +0000691 """
sousaedu80135b92021-02-17 15:05:18 +0100692 # self.logger.debug("getting network list for vim, filter %s", filter_dict)
seryio34478552019-05-23 14:50:49 +0200693 try:
694 self._reload_connection()
jamartinezv14a823d2019-08-01 11:45:15 +0200695
sousaedu80135b92021-02-17 15:05:18 +0100696 vnet = self.conn_vnet.virtual_networks.get(
697 self.resource_group, self.vnet_name
698 )
seryio34478552019-05-23 14:50:49 +0200699 subnet_list = []
jamartinezv14a823d2019-08-01 11:45:15 +0200700
seryio34478552019-05-23 14:50:49 +0200701 for subnet in vnet.subnets:
seryio34478552019-05-23 14:50:49 +0200702 if filter_dict:
703 if filter_dict.get("id") and str(subnet.id) != filter_dict["id"]:
704 continue
sousaedu80135b92021-02-17 15:05:18 +0100705
706 if (
707 filter_dict.get("name")
708 and str(subnet.name) != filter_dict["name"]
709 ):
seryio34478552019-05-23 14:50:49 +0200710 continue
711
jamartinezv14a823d2019-08-01 11:45:15 +0200712 name = self._get_resource_name_from_resource_id(subnet.id)
713
sousaedu80135b92021-02-17 15:05:18 +0100714 subnet_list.append(
715 {
716 "id": str(subnet.id),
717 "name": name,
718 "status": self.provision_state2osm[subnet.provisioning_state],
719 "cidr_block": str(subnet.address_prefix),
720 "type": "bridge",
721 "shared": False,
722 }
723 )
jamartinezv14a823d2019-08-01 11:45:15 +0200724
seryio34478552019-05-23 14:50:49 +0200725 return subnet_list
726 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +0100727 self._format_vimconn_exception(e)
seryio34478552019-05-23 14:50:49 +0200728
sousaedu80135b92021-02-17 15:05:18 +0100729 def new_vminstance(
730 self,
731 name,
732 description,
733 start,
734 image_id,
735 flavor_id,
736 net_list,
737 cloud_config=None,
738 disk_list=None,
739 availability_zone_index=None,
740 availability_zone_list=None,
741 ):
742 self.logger.debug(
743 "new vm instance name: %s, image_id: %s, flavor_id: %s, net_list: %s, cloud_config: %s, "
744 "disk_list: %s, availability_zone_index: %s, availability_zone_list: %s",
745 name,
746 image_id,
747 flavor_id,
748 net_list,
749 cloud_config,
750 disk_list,
751 availability_zone_index,
752 availability_zone_list,
753 )
lloretgalleg45220152019-10-29 11:53:49 +0100754 self._reload_connection()
755
756 # Validate input data is valid
757 # The virtual machine name must have less or 64 characters and it can not have the following
758 # characters: (~ ! @ # $ % ^ & * ( ) = + _ [ ] { } \ | ; : ' " , < > / ?.)
759 vm_name = self._check_vm_name(name)
760 # Obtain vm unused name
761 vm_name = self._get_unused_vm_name(vm_name)
762
763 # At least one network must be provided
764 if not net_list:
sousaedu80135b92021-02-17 15:05:18 +0100765 raise vimconn.VimConnException(
766 "At least one net must be provided to create a new VM"
767 )
lloretgalleg45220152019-10-29 11:53:49 +0100768
769 # image_id are several fields of the image_id
770 image_reference = self._get_image_reference(image_id)
jamartinezv14a823d2019-08-01 11:45:15 +0200771
seryio34478552019-05-23 14:50:49 +0200772 try:
lloretgalleg064b05a2019-11-29 14:46:31 +0100773 virtual_machine = None
774 created_items = {}
775
776 # Create nics for each subnet
777 self._check_subnets_for_vm(net_list)
778 vm_nics = []
sousaedu80135b92021-02-17 15:05:18 +0100779
lloretgalleg064b05a2019-11-29 14:46:31 +0100780 for idx, net in enumerate(net_list):
781 # Fault with subnet_id
sousaedu80135b92021-02-17 15:05:18 +0100782 # subnet_id=net["subnet_id"]
783 # subnet_id=net["net_id"]
784 nic_name = vm_name + "-nic-" + str(idx)
785 vm_nic, nic_items = self._create_nic(
786 net, nic_name, net.get("ip_address"), created_items
787 )
788 vm_nics.append({"id": str(vm_nic.id)})
789 net["vim_id"] = vm_nic.id
jamartinezv14a823d2019-08-01 11:45:15 +0200790
791 # cloud-init configuration
792 # cloud config
793 if cloud_config:
794 config_drive, userdata = self._create_user_data(cloud_config)
sousaedu80135b92021-02-17 15:05:18 +0100795 custom_data = base64.b64encode(userdata.encode("utf-8")).decode(
796 "latin-1"
797 )
lloretgalleg45220152019-10-29 11:53:49 +0100798 key_data = None
799 key_pairs = cloud_config.get("key-pairs")
800 if key_pairs:
801 key_data = key_pairs[0]
802
803 if cloud_config.get("users"):
804 user_name = cloud_config.get("users")[0].get("name", "osm")
805 else:
tiernob569e4b2019-11-21 16:10:32 +0000806 user_name = "osm" # DEFAULT USER IS OSM
lloretgalleg45220152019-10-29 11:53:49 +0100807
jamartinezv14a823d2019-08-01 11:45:15 +0200808 os_profile = {
sousaedu80135b92021-02-17 15:05:18 +0100809 "computer_name": vm_name,
810 "admin_username": user_name,
811 "linux_configuration": {
lloretgalleg45220152019-10-29 11:53:49 +0100812 "disable_password_authentication": True,
813 "ssh": {
sousaedu80135b92021-02-17 15:05:18 +0100814 "public_keys": [
815 {
816 "path": "/home/{}/.ssh/authorized_keys".format(
817 user_name
818 ),
819 "key_data": key_data,
820 }
821 ]
822 },
lloretgalleg45220152019-10-29 11:53:49 +0100823 },
sousaedu80135b92021-02-17 15:05:18 +0100824 "custom_data": custom_data,
jamartinezv14a823d2019-08-01 11:45:15 +0200825 }
826 else:
827 os_profile = {
sousaedu80135b92021-02-17 15:05:18 +0100828 "computer_name": vm_name,
829 "admin_username": "osm",
830 "admin_password": "Osm4u!",
jamartinezv14a823d2019-08-01 11:45:15 +0200831 }
832
seryio34478552019-05-23 14:50:49 +0200833 vm_parameters = {
sousaedu80135b92021-02-17 15:05:18 +0100834 "location": self.region,
835 "os_profile": os_profile,
836 "hardware_profile": {"vm_size": flavor_id},
837 "storage_profile": {"image_reference": image_reference},
seryio34478552019-05-23 14:50:49 +0200838 }
jamartinezv14a823d2019-08-01 11:45:15 +0200839
lloretgalleg45220152019-10-29 11:53:49 +0100840 # If the machine has several networks one must be marked as primary
841 # As it is not indicated in the interface the first interface will be marked as primary
842 if len(vm_nics) > 1:
843 for idx, vm_nic in enumerate(vm_nics):
844 if idx == 0:
sousaedu80135b92021-02-17 15:05:18 +0100845 vm_nics[0]["Primary"] = True
lloretgalleg45220152019-10-29 11:53:49 +0100846 else:
sousaedu80135b92021-02-17 15:05:18 +0100847 vm_nics[idx]["Primary"] = False
lloretgalleg45220152019-10-29 11:53:49 +0100848
sousaedu80135b92021-02-17 15:05:18 +0100849 vm_parameters["network_profile"] = {"network_interfaces": vm_nics}
lloretgalleg45220152019-10-29 11:53:49 +0100850
lloretgalleg064b05a2019-11-29 14:46:31 +0100851 # Obtain zone information
852 vm_zone = self._get_vm_zone(availability_zone_index, availability_zone_list)
853 if vm_zone:
sousaedu80135b92021-02-17 15:05:18 +0100854 vm_parameters["zones"] = [vm_zone]
lloretgalleg064b05a2019-11-29 14:46:31 +0100855
lloretgalleg45220152019-10-29 11:53:49 +0100856 self.logger.debug("create vm name: %s", vm_name)
seryio34478552019-05-23 14:50:49 +0200857 creation_result = self.conn_compute.virtual_machines.create_or_update(
sousaedu80135b92021-02-17 15:05:18 +0100858 self.resource_group, vm_name, vm_parameters
seryio34478552019-05-23 14:50:49 +0200859 )
lloretgalleg064b05a2019-11-29 14:46:31 +0100860 virtual_machine = creation_result.result()
lloretgallegbfc28b02019-11-21 09:31:16 +0100861 self.logger.debug("created vm name: %s", vm_name)
jamartinezv14a823d2019-08-01 11:45:15 +0200862
lloretgalleg064b05a2019-11-29 14:46:31 +0100863 # Add disks if they are provided
864 if disk_list:
865 for disk_index, disk in enumerate(disk_list):
sousaedu80135b92021-02-17 15:05:18 +0100866 self.logger.debug(
867 "add disk size: %s, image: %s",
868 disk.get("size"),
869 disk.get("image"),
870 )
871 self._add_newvm_disk(
872 virtual_machine, vm_name, disk_index, disk, created_items
873 )
lloretgalleg064b05a2019-11-29 14:46:31 +0100874
lloretgalleg45220152019-10-29 11:53:49 +0100875 if start:
sousaedu80135b92021-02-17 15:05:18 +0100876 self.conn_compute.virtual_machines.start(self.resource_group, vm_name)
tiernob569e4b2019-11-21 16:10:32 +0000877 # start_result.wait()
jamartinezv14a823d2019-08-01 11:45:15 +0200878
lloretgalleg064b05a2019-11-29 14:46:31 +0100879 return virtual_machine.id, created_items
sousaedu80135b92021-02-17 15:05:18 +0100880
tiernob569e4b2019-11-21 16:10:32 +0000881 # run_command_parameters = {
sousaedu80135b92021-02-17 15:05:18 +0100882 # "command_id": "RunShellScript", # For linux, don't change it
883 # "script": [
884 # "date > /tmp/test.txt"
tiernob569e4b2019-11-21 16:10:32 +0000885 # ]
886 # }
seryio34478552019-05-23 14:50:49 +0200887 except Exception as e:
lloretgalleg064b05a2019-11-29 14:46:31 +0100888 # Rollback vm creacion
889 vm_id = None
sousaedu80135b92021-02-17 15:05:18 +0100890
lloretgalleg064b05a2019-11-29 14:46:31 +0100891 if virtual_machine:
892 vm_id = virtual_machine.id
sousaedu80135b92021-02-17 15:05:18 +0100893
lloretgalleg064b05a2019-11-29 14:46:31 +0100894 try:
895 self.logger.debug("exception creating vm try to rollback")
896 self.delete_vminstance(vm_id, created_items)
897 except Exception as e2:
898 self.logger.error("new_vminstance rollback fail {}".format(e2))
899
sousaedu80135b92021-02-17 15:05:18 +0100900 self.logger.debug("Exception creating new vminstance: %s", e, exc_info=True)
lloretgalleg45220152019-10-29 11:53:49 +0100901 self._format_vimconn_exception(e)
902
903 def _get_unused_vm_name(self, vm_name):
904 """
905 Checks the vm name and in case it is used adds a suffix to the name to allow creation
906 :return:
907 """
908 all_vms = self.conn_compute.virtual_machines.list(self.resource_group)
909 # Filter to vms starting with the indicated name
910 vms = list(filter(lambda vm: (vm.name.startswith(vm_name)), all_vms))
911 vm_names = [str(vm.name) for vm in vms]
912
913 # get the name with the first not used suffix
914 name_suffix = 0
915 # name = subnet_name + "-" + str(name_suffix)
916 name = vm_name # first subnet created will have no prefix
sousaedu80135b92021-02-17 15:05:18 +0100917
lloretgalleg45220152019-10-29 11:53:49 +0100918 while name in vm_names:
919 name_suffix += 1
920 name = vm_name + "-" + str(name_suffix)
sousaedu80135b92021-02-17 15:05:18 +0100921
lloretgalleg45220152019-10-29 11:53:49 +0100922 return name
923
lloretgalleg064b05a2019-11-29 14:46:31 +0100924 def _get_vm_zone(self, availability_zone_index, availability_zone_list):
lloretgalleg064b05a2019-11-29 14:46:31 +0100925 if availability_zone_index is None:
926 return None
927
928 vim_availability_zones = self._get_azure_availability_zones()
929 # check if VIM offer enough availability zones describe in the VNFD
sousaedu80135b92021-02-17 15:05:18 +0100930 if vim_availability_zones and len(availability_zone_list) <= len(
931 vim_availability_zones
932 ):
lloretgalleg064b05a2019-11-29 14:46:31 +0100933 # check if all the names of NFV AV match VIM AV names
934 match_by_index = False
sousaedu80135b92021-02-17 15:05:18 +0100935
lloretgalleg064b05a2019-11-29 14:46:31 +0100936 if not availability_zone_list:
937 match_by_index = True
938 else:
939 for av in availability_zone_list:
940 if av not in vim_availability_zones:
941 match_by_index = True
942 break
sousaedu80135b92021-02-17 15:05:18 +0100943
lloretgalleg064b05a2019-11-29 14:46:31 +0100944 if match_by_index:
945 return vim_availability_zones[availability_zone_index]
946 else:
947 return availability_zone_list[availability_zone_index]
948 else:
sousaedu80135b92021-02-17 15:05:18 +0100949 raise vimconn.VimConnConflictException(
950 "No enough availability zones at VIM for this deployment"
951 )
lloretgalleg064b05a2019-11-29 14:46:31 +0100952
953 def _get_azure_availability_zones(self):
954 return self.AZURE_ZONES
955
sousaedu80135b92021-02-17 15:05:18 +0100956 def _add_newvm_disk(
957 self, virtual_machine, vm_name, disk_index, disk, created_items={}
958 ):
lloretgalleg064b05a2019-11-29 14:46:31 +0100959 disk_name = None
960 data_disk = None
961
962 # Check if must create empty disk or from image
sousaedu80135b92021-02-17 15:05:18 +0100963 if disk.get("vim_id"):
lloretgalleg064b05a2019-11-29 14:46:31 +0100964 # disk already exists, just get
sousaedu80135b92021-02-17 15:05:18 +0100965 parsed_id = azure_tools.parse_resource_id(disk.get("vim_id"))
lloretgalleg064b05a2019-11-29 14:46:31 +0100966 disk_name = parsed_id.get("name")
967 data_disk = self.conn_compute.disks.get(self.resource_group, disk_name)
968 else:
969 disk_name = vm_name + "_DataDisk_" + str(disk_index)
970 if not disk.get("image_id"):
971 self.logger.debug("create new data disk name: %s", disk_name)
972 async_disk_creation = self.conn_compute.disks.create_or_update(
973 self.resource_group,
974 disk_name,
975 {
sousaedu80135b92021-02-17 15:05:18 +0100976 "location": self.region,
977 "disk_size_gb": disk.get("size"),
978 "creation_data": {"create_option": DiskCreateOption.empty},
979 },
lloretgalleg064b05a2019-11-29 14:46:31 +0100980 )
981 data_disk = async_disk_creation.result()
982 created_items[data_disk.id] = True
983 else:
984 image_id = disk.get("image_id")
sousaedu80135b92021-02-17 15:05:18 +0100985
lloretgalleg064b05a2019-11-29 14:46:31 +0100986 if azure_tools.is_valid_resource_id(image_id):
987 parsed_id = azure_tools.parse_resource_id(image_id)
988
989 # Check if image is snapshot or disk
990 image_name = parsed_id.get("name")
991 type = parsed_id.get("resource_type")
lloretgalleg064b05a2019-11-29 14:46:31 +0100992
sousaedu80135b92021-02-17 15:05:18 +0100993 if type == "snapshots" or type == "disks":
lloretgalleg064b05a2019-11-29 14:46:31 +0100994 self.logger.debug("create disk from copy name: %s", image_name)
995 # ¿Should check that snapshot exists?
996 async_disk_creation = self.conn_compute.disks.create_or_update(
997 self.resource_group,
998 disk_name,
999 {
sousaedu80135b92021-02-17 15:05:18 +01001000 "location": self.region,
1001 "creation_data": {
1002 "create_option": "Copy",
1003 "source_uri": image_id,
1004 },
1005 },
lloretgalleg064b05a2019-11-29 14:46:31 +01001006 )
1007 data_disk = async_disk_creation.result()
1008 created_items[data_disk.id] = True
lloretgalleg064b05a2019-11-29 14:46:31 +01001009 else:
sousaedu80135b92021-02-17 15:05:18 +01001010 raise vimconn.VimConnNotFoundException(
1011 "Invalid image_id: %s ", image_id
1012 )
lloretgalleg064b05a2019-11-29 14:46:31 +01001013 else:
sousaedu80135b92021-02-17 15:05:18 +01001014 raise vimconn.VimConnNotFoundException(
1015 "Invalid image_id: %s ", image_id
1016 )
lloretgalleg064b05a2019-11-29 14:46:31 +01001017
1018 # Attach the disk created
sousaedu80135b92021-02-17 15:05:18 +01001019 virtual_machine.storage_profile.data_disks.append(
1020 {
1021 "lun": disk_index,
1022 "name": disk_name,
1023 "create_option": DiskCreateOption.attach,
1024 "managed_disk": {"id": data_disk.id},
1025 "disk_size_gb": disk.get("size"),
1026 }
1027 )
lloretgalleg064b05a2019-11-29 14:46:31 +01001028 self.logger.debug("attach disk name: %s", disk_name)
tierno1ec592d2020-06-16 15:29:47 +00001029 self.conn_compute.virtual_machines.create_or_update(
sousaedu80135b92021-02-17 15:05:18 +01001030 self.resource_group, virtual_machine.name, virtual_machine
lloretgalleg064b05a2019-11-29 14:46:31 +01001031 )
1032
jamartinezv14a823d2019-08-01 11:45:15 +02001033 # It is necesary extract from image_id data to create the VM with this format
sousaedu80135b92021-02-17 15:05:18 +01001034 # "image_reference": {
1035 # "publisher": vm_reference["publisher"],
1036 # "offer": vm_reference["offer"],
1037 # "sku": vm_reference["sku"],
1038 # "version": vm_reference["version"]
jamartinezv14a823d2019-08-01 11:45:15 +02001039 # },
lloretgalleg45220152019-10-29 11:53:49 +01001040 def _get_image_reference(self, image_id):
lloretgalleg45220152019-10-29 11:53:49 +01001041 try:
1042 # The data input format example:
1043 # /Subscriptions/ca3d18ab-d373-4afb-a5d6-7c44f098d16a/Providers/Microsoft.Compute/Locations/westeurope/
1044 # Publishers/Canonical/ArtifactTypes/VMImage/
1045 # Offers/UbuntuServer/
1046 # Skus/18.04-LTS/
1047 # Versions/18.04.201809110
sousaedu80135b92021-02-17 15:05:18 +01001048 publisher = str(image_id.split("/")[8])
1049 offer = str(image_id.split("/")[12])
1050 sku = str(image_id.split("/")[14])
1051 version = str(image_id.split("/")[16])
jamartinezv14a823d2019-08-01 11:45:15 +02001052
lloretgalleg45220152019-10-29 11:53:49 +01001053 return {
sousaedu80135b92021-02-17 15:05:18 +01001054 "publisher": publisher,
1055 "offer": offer,
1056 "sku": sku,
1057 "version": version,
lloretgalleg45220152019-10-29 11:53:49 +01001058 }
tierno1ec592d2020-06-16 15:29:47 +00001059 except Exception:
tierno72774862020-05-04 11:44:15 +00001060 raise vimconn.VimConnException(
sousaedu80135b92021-02-17 15:05:18 +01001061 "Unable to get image_reference from invalid image_id format: '{}'".format(
1062 image_id
1063 )
1064 )
jamartinezv14a823d2019-08-01 11:45:15 +02001065
1066 # Azure VM names can not have some special characters
lloretgalleg45220152019-10-29 11:53:49 +01001067 def _check_vm_name(self, vm_name):
1068 """
1069 Checks vm name, in case the vm has not allowed characters they are removed, not error raised
1070 """
jamartinezv14a823d2019-08-01 11:45:15 +02001071 chars_not_allowed_list = "~!@#$%^&*()=+_[]{}|;:<>/?."
1072
1073 # First: the VM name max length is 64 characters
1074 vm_name_aux = vm_name[:64]
1075
1076 # Second: replace not allowed characters
lloretgalleg45220152019-10-29 11:53:49 +01001077 for elem in chars_not_allowed_list:
jamartinezv14a823d2019-08-01 11:45:15 +02001078 # Check if string is in the main string
lloretgalleg45220152019-10-29 11:53:49 +01001079 if elem in vm_name_aux:
sousaedu80135b92021-02-17 15:05:18 +01001080 # self.logger.debug("Dentro del IF")
jamartinezv14a823d2019-08-01 11:45:15 +02001081 # Replace the string
sousaedu80135b92021-02-17 15:05:18 +01001082 vm_name_aux = vm_name_aux.replace(elem, "-")
jamartinezv14a823d2019-08-01 11:45:15 +02001083
1084 return vm_name_aux
seryio34478552019-05-23 14:50:49 +02001085
1086 def get_flavor_id_from_data(self, flavor_dict):
lloretgalleg45220152019-10-29 11:53:49 +01001087 self.logger.debug("getting flavor id from data, flavor_dict: %s", flavor_dict)
1088 filter_dict = flavor_dict or {}
sousaedu80135b92021-02-17 15:05:18 +01001089
jamartinezv14a823d2019-08-01 11:45:15 +02001090 try:
1091 self._reload_connection()
sousaedu80135b92021-02-17 15:05:18 +01001092 vm_sizes_list = [
1093 vm_size.serialize()
1094 for vm_size in self.conn_compute.virtual_machine_sizes.list(self.region)
1095 ]
tierno30d0d6d2019-05-27 08:14:01 +00001096
sousaedu80135b92021-02-17 15:05:18 +01001097 cpus = filter_dict.get("vcpus") or 0
1098 memMB = filter_dict.get("ram") or 0
tierno30d0d6d2019-05-27 08:14:01 +00001099
lloretgalleg45220152019-10-29 11:53:49 +01001100 # Filter
1101 if self._config.get("flavors_pattern"):
sousaedu80135b92021-02-17 15:05:18 +01001102 filtered_sizes = [
1103 size
1104 for size in vm_sizes_list
1105 if size["numberOfCores"] >= cpus
1106 and size["memoryInMB"] >= memMB
1107 and re.search(self._config.get("flavors_pattern"), size["name"])
1108 ]
lloretgalleg45220152019-10-29 11:53:49 +01001109 else:
sousaedu80135b92021-02-17 15:05:18 +01001110 filtered_sizes = [
1111 size
1112 for size in vm_sizes_list
1113 if size["numberOfCores"] >= cpus and size["memoryInMB"] >= memMB
1114 ]
lloretgalleg45220152019-10-29 11:53:49 +01001115
1116 # Sort
sousaedu80135b92021-02-17 15:05:18 +01001117 listedFilteredSizes = sorted(
1118 filtered_sizes,
1119 key=lambda k: (
1120 k["numberOfCores"],
1121 k["memoryInMB"],
1122 k["resourceDiskSizeInMB"],
1123 ),
1124 )
lloretgalleg45220152019-10-29 11:53:49 +01001125
1126 if listedFilteredSizes:
sousaedu80135b92021-02-17 15:05:18 +01001127 return listedFilteredSizes[0]["name"]
jamartinezv14a823d2019-08-01 11:45:15 +02001128
sousaedu80135b92021-02-17 15:05:18 +01001129 raise vimconn.VimConnNotFoundException(
1130 "Cannot find any flavor matching '{}'".format(str(flavor_dict))
1131 )
jamartinezv14a823d2019-08-01 11:45:15 +02001132 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +01001133 self._format_vimconn_exception(e)
jamartinezv14a823d2019-08-01 11:45:15 +02001134
1135 def _get_flavor_id_from_flavor_name(self, flavor_name):
tiernob569e4b2019-11-21 16:10:32 +00001136 # self.logger.debug("getting flavor id from flavor name {}".format(flavor_name))
jamartinezv14a823d2019-08-01 11:45:15 +02001137 try:
1138 self._reload_connection()
sousaedu80135b92021-02-17 15:05:18 +01001139 vm_sizes_list = [
1140 vm_size.serialize()
1141 for vm_size in self.conn_compute.virtual_machine_sizes.list(self.region)
1142 ]
jamartinezv14a823d2019-08-01 11:45:15 +02001143
1144 output_flavor = None
1145 for size in vm_sizes_list:
sousaedu80135b92021-02-17 15:05:18 +01001146 if size["name"] == flavor_name:
jamartinezv14a823d2019-08-01 11:45:15 +02001147 output_flavor = size
1148
tiernob569e4b2019-11-21 16:10:32 +00001149 # None is returned if not found anything
jamartinezv14a823d2019-08-01 11:45:15 +02001150 return output_flavor
jamartinezv14a823d2019-08-01 11:45:15 +02001151 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +01001152 self._format_vimconn_exception(e)
tierno30d0d6d2019-05-27 08:14:01 +00001153
1154 def check_vim_connectivity(self):
seryio34478552019-05-23 14:50:49 +02001155 try:
1156 self._reload_connection()
tierno30d0d6d2019-05-27 08:14:01 +00001157 return True
1158 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +01001159 raise vimconn.VimConnException(
1160 "Connectivity issue with Azure API: {}".format(e)
1161 )
seryio34478552019-05-23 14:50:49 +02001162
1163 def get_network(self, net_id):
sousaedu80135b92021-02-17 15:05:18 +01001164 # self.logger.debug("get network id: {}".format(net_id))
tiernob569e4b2019-11-21 16:10:32 +00001165 # res_name = self._get_resource_name_from_resource_id(net_id)
seryio34478552019-05-23 14:50:49 +02001166 self._reload_connection()
seryio34478552019-05-23 14:50:49 +02001167
sousaedu80135b92021-02-17 15:05:18 +01001168 filter_dict = {"name": net_id}
jamartinezv14a823d2019-08-01 11:45:15 +02001169 network_list = self.get_network_list(filter_dict)
1170
1171 if not network_list:
sousaedu80135b92021-02-17 15:05:18 +01001172 raise vimconn.VimConnNotFoundException(
1173 "network '{}' not found".format(net_id)
1174 )
jamartinezv14a823d2019-08-01 11:45:15 +02001175 else:
1176 return network_list[0]
1177
jamartinezv14a823d2019-08-01 11:45:15 +02001178 def delete_network(self, net_id, created_items=None):
sousaedu80135b92021-02-17 15:05:18 +01001179 self.logger.debug(
1180 "deleting network {} - {}".format(self.resource_group, net_id)
1181 )
jamartinezv14a823d2019-08-01 11:45:15 +02001182
seryio34478552019-05-23 14:50:49 +02001183 self._reload_connection()
lloretgalleg45220152019-10-29 11:53:49 +01001184 res_name = self._get_resource_name_from_resource_id(net_id)
sousaedu80135b92021-02-17 15:05:18 +01001185 filter_dict = {"name": res_name}
jamartinezv14a823d2019-08-01 11:45:15 +02001186 network_list = self.get_network_list(filter_dict)
1187 if not network_list:
sousaedu80135b92021-02-17 15:05:18 +01001188 raise vimconn.VimConnNotFoundException(
1189 "network '{}' not found".format(net_id)
1190 )
jamartinezv14a823d2019-08-01 11:45:15 +02001191
1192 try:
1193 # Subnet API fails (CloudError: Azure Error: ResourceNotFound)
1194 # Put the initial virtual_network API
sousaedu80135b92021-02-17 15:05:18 +01001195 async_delete = self.conn_vnet.subnets.delete(
1196 self.resource_group, self.vnet_name, res_name
1197 )
lloretgalleg45220152019-10-29 11:53:49 +01001198 async_delete.wait()
jamartinezv14a823d2019-08-01 11:45:15 +02001199 return net_id
1200
1201 except CloudError as e:
lloretgalleg45220152019-10-29 11:53:49 +01001202 if e.error.error and "notfound" in e.error.error.lower():
sousaedu80135b92021-02-17 15:05:18 +01001203 raise vimconn.VimConnNotFoundException(
1204 "network '{}' not found".format(net_id)
1205 )
jamartinezv14a823d2019-08-01 11:45:15 +02001206 else:
lloretgalleg45220152019-10-29 11:53:49 +01001207 self._format_vimconn_exception(e)
jamartinezv14a823d2019-08-01 11:45:15 +02001208 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +01001209 self._format_vimconn_exception(e)
jamartinezv14a823d2019-08-01 11:45:15 +02001210
jamartinezv14a823d2019-08-01 11:45:15 +02001211 def delete_vminstance(self, vm_id, created_items=None):
sousaedu80135b92021-02-17 15:05:18 +01001212 """Deletes a vm instance from the vim."""
1213 self.logger.debug(
1214 "deleting VM instance {} - {}".format(self.resource_group, vm_id)
1215 )
jamartinezv14a823d2019-08-01 11:45:15 +02001216 self._reload_connection()
1217
lloretgalleg064b05a2019-11-29 14:46:31 +01001218 created_items = created_items or {}
jamartinezv14a823d2019-08-01 11:45:15 +02001219 try:
lloretgalleg064b05a2019-11-29 14:46:31 +01001220 # Check vm exists, we can call delete_vm to clean created_items
1221 if vm_id:
1222 res_name = self._get_resource_name_from_resource_id(vm_id)
sousaedu80135b92021-02-17 15:05:18 +01001223 vm = self.conn_compute.virtual_machines.get(
1224 self.resource_group, res_name
1225 )
jamartinezv14a823d2019-08-01 11:45:15 +02001226
lloretgalleg064b05a2019-11-29 14:46:31 +01001227 # Shuts down the virtual machine and releases the compute resources
1228 # vm_stop = self.conn_compute.virtual_machines.power_off(self.resource_group, resName)
1229 # vm_stop.wait()
jamartinezv14a823d2019-08-01 11:45:15 +02001230
sousaedu80135b92021-02-17 15:05:18 +01001231 vm_delete = self.conn_compute.virtual_machines.delete(
1232 self.resource_group, res_name
1233 )
lloretgalleg064b05a2019-11-29 14:46:31 +01001234 vm_delete.wait()
sousaedu80135b92021-02-17 15:05:18 +01001235 self.logger.debug("deleted VM name: %s", res_name)
jamartinezv14a823d2019-08-01 11:45:15 +02001236
lloretgalleg064b05a2019-11-29 14:46:31 +01001237 # Delete OS Disk
1238 os_disk_name = vm.storage_profile.os_disk.name
sousaedu80135b92021-02-17 15:05:18 +01001239 self.logger.debug("delete OS DISK: %s", os_disk_name)
1240 async_disk_delete = self.conn_compute.disks.delete(
1241 self.resource_group, os_disk_name
1242 )
lloretgalleg064b05a2019-11-29 14:46:31 +01001243 async_disk_delete.wait()
1244 # os disks are created always with the machine
sousaedu80135b92021-02-17 15:05:18 +01001245 self.logger.debug("deleted OS DISK name: %s", os_disk_name)
jamartinezv14a823d2019-08-01 11:45:15 +02001246
lloretgalleg064b05a2019-11-29 14:46:31 +01001247 for data_disk in vm.storage_profile.data_disks:
sousaedu80135b92021-02-17 15:05:18 +01001248 self.logger.debug("delete data_disk: %s", data_disk.name)
1249 async_disk_delete = self.conn_compute.disks.delete(
1250 self.resource_group, data_disk.name
1251 )
lloretgalleg064b05a2019-11-29 14:46:31 +01001252 async_disk_delete.wait()
1253 self._markdel_created_item(data_disk.managed_disk.id, created_items)
sousaedu80135b92021-02-17 15:05:18 +01001254 self.logger.debug("deleted OS DISK name: %s", data_disk.name)
jamartinezv14a823d2019-08-01 11:45:15 +02001255
lloretgalleg064b05a2019-11-29 14:46:31 +01001256 # After deleting VM, it is necessary to delete NIC, because if is not deleted delete_network
1257 # does not work because Azure says that is in use the subnet
1258 network_interfaces = vm.network_profile.network_interfaces
lloretgalleg45220152019-10-29 11:53:49 +01001259
lloretgalleg064b05a2019-11-29 14:46:31 +01001260 for network_interface in network_interfaces:
sousaedu80135b92021-02-17 15:05:18 +01001261 nic_name = self._get_resource_name_from_resource_id(
1262 network_interface.id
1263 )
lloretgalleg064b05a2019-11-29 14:46:31 +01001264 nic_data = self.conn_vnet.network_interfaces.get(
sousaedu80135b92021-02-17 15:05:18 +01001265 self.resource_group, nic_name
1266 )
jamartinezv14a823d2019-08-01 11:45:15 +02001267
lloretgalleg064b05a2019-11-29 14:46:31 +01001268 public_ip_name = None
1269 exist_public_ip = nic_data.ip_configurations[0].public_ip_address
1270 if exist_public_ip:
sousaedu80135b92021-02-17 15:05:18 +01001271 public_ip_id = nic_data.ip_configurations[
1272 0
1273 ].public_ip_address.id
jamartinezv14a823d2019-08-01 11:45:15 +02001274
lloretgalleg064b05a2019-11-29 14:46:31 +01001275 # Delete public_ip
sousaedu80135b92021-02-17 15:05:18 +01001276 public_ip_name = self._get_resource_name_from_resource_id(
1277 public_ip_id
1278 )
jamartinezv14a823d2019-08-01 11:45:15 +02001279
lloretgalleg064b05a2019-11-29 14:46:31 +01001280 # Public ip must be deleted afterwards of nic that is attached
jamartinezv14a823d2019-08-01 11:45:15 +02001281
sousaedu80135b92021-02-17 15:05:18 +01001282 self.logger.debug("delete NIC name: %s", nic_name)
1283 nic_delete = self.conn_vnet.network_interfaces.delete(
1284 self.resource_group, nic_name
1285 )
lloretgalleg064b05a2019-11-29 14:46:31 +01001286 nic_delete.wait()
1287 self._markdel_created_item(network_interface.id, created_items)
sousaedu80135b92021-02-17 15:05:18 +01001288 self.logger.debug("deleted NIC name: %s", nic_name)
jamartinezv14a823d2019-08-01 11:45:15 +02001289
lloretgalleg064b05a2019-11-29 14:46:31 +01001290 # Delete list of public ips
1291 if public_ip_name:
sousaedu80135b92021-02-17 15:05:18 +01001292 self.logger.debug("delete PUBLIC IP - " + public_ip_name)
1293 ip_delete = self.conn_vnet.public_ip_addresses.delete(
1294 self.resource_group, public_ip_name
1295 )
lloretgalleg064b05a2019-11-29 14:46:31 +01001296 ip_delete.wait()
1297 self._markdel_created_item(public_ip_id, created_items)
lloretgalleg45220152019-10-29 11:53:49 +01001298
lloretgalleg064b05a2019-11-29 14:46:31 +01001299 # Delete created items
1300 self._delete_created_items(created_items)
lloretgalleg45220152019-10-29 11:53:49 +01001301
1302 except CloudError as e:
1303 if e.error.error and "notfound" in e.error.error.lower():
sousaedu80135b92021-02-17 15:05:18 +01001304 raise vimconn.VimConnNotFoundException(
1305 "No vm instance found '{}'".format(vm_id)
1306 )
lloretgalleg45220152019-10-29 11:53:49 +01001307 else:
1308 self._format_vimconn_exception(e)
1309 except Exception as e:
1310 self._format_vimconn_exception(e)
1311
lloretgalleg064b05a2019-11-29 14:46:31 +01001312 def _markdel_created_item(self, item_id, created_items):
1313 if item_id in created_items:
1314 created_items[item_id] = False
1315
1316 def _delete_created_items(self, created_items):
sousaedu80135b92021-02-17 15:05:18 +01001317 """Delete created_items elements that have not been deleted with the virtual machine
1318 Created_items may not be deleted correctly with the created machine if the
1319 virtual machine fails creating or in other cases of error
lloretgalleg064b05a2019-11-29 14:46:31 +01001320 """
1321 self.logger.debug("Created items: %s", created_items)
1322 # Must delete in order first nics, then public_ips
1323 # As dictionaries don't preserve order, first get items to be deleted then delete them
1324 nics_to_delete = []
1325 publics_ip_to_delete = []
1326 disks_to_delete = []
1327 for item_id, v in created_items.items():
1328 if not v: # skip already deleted
1329 continue
1330
tierno1ec592d2020-06-16 15:29:47 +00001331 # self.logger.debug("Must delete item id: %s", item_id)
lloretgalleg064b05a2019-11-29 14:46:31 +01001332 # Obtain type, supported nic, disk or public ip
1333 parsed_id = azure_tools.parse_resource_id(item_id)
1334 resource_type = parsed_id.get("resource_type")
1335 name = parsed_id.get("name")
1336
1337 if resource_type == "networkInterfaces":
1338 nics_to_delete.append(name)
1339 elif resource_type == "publicIPAddresses":
1340 publics_ip_to_delete.append(name)
1341 elif resource_type == "disks":
1342 disks_to_delete.append(name)
1343
1344 # Now delete
1345 for item_name in nics_to_delete:
1346 try:
1347 self.logger.debug("deleting nic name %s:", item_name)
sousaedu80135b92021-02-17 15:05:18 +01001348 nic_delete = self.conn_vnet.network_interfaces.delete(
1349 self.resource_group, item_name
1350 )
lloretgalleg064b05a2019-11-29 14:46:31 +01001351 nic_delete.wait()
1352 self.logger.debug("deleted nic name %s:", item_name)
1353 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +01001354 self.logger.error(
1355 "Error deleting item: {}: {}".format(type(e).__name__, e)
1356 )
lloretgalleg064b05a2019-11-29 14:46:31 +01001357
1358 for item_name in publics_ip_to_delete:
1359 try:
1360 self.logger.debug("deleting public ip name %s:", item_name)
sousaedu80135b92021-02-17 15:05:18 +01001361 ip_delete = self.conn_vnet.public_ip_addresses.delete(
1362 self.resource_group, name
1363 )
lloretgalleg064b05a2019-11-29 14:46:31 +01001364 ip_delete.wait()
1365 self.logger.debug("deleted public ip name %s:", item_name)
1366 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +01001367 self.logger.error(
1368 "Error deleting item: {}: {}".format(type(e).__name__, e)
1369 )
lloretgalleg064b05a2019-11-29 14:46:31 +01001370
1371 for item_name in disks_to_delete:
1372 try:
1373 self.logger.debug("deleting data disk name %s:", name)
sousaedu80135b92021-02-17 15:05:18 +01001374 async_disk_delete = self.conn_compute.disks.delete(
1375 self.resource_group, item_name
1376 )
lloretgalleg064b05a2019-11-29 14:46:31 +01001377 async_disk_delete.wait()
1378 self.logger.debug("deleted data disk name %s:", name)
1379 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +01001380 self.logger.error(
1381 "Error deleting item: {}: {}".format(type(e).__name__, e)
1382 )
lloretgalleg064b05a2019-11-29 14:46:31 +01001383
tiernob569e4b2019-11-21 16:10:32 +00001384 def action_vminstance(self, vm_id, action_dict, created_items={}):
jamartinezv14a823d2019-08-01 11:45:15 +02001385 """Send and action over a VM instance from VIM
lloretgalleg45220152019-10-29 11:53:49 +01001386 Returns the vm_id if the action was successfully sent to the VIM
1387 """
jamartinezv14a823d2019-08-01 11:45:15 +02001388 self.logger.debug("Action over VM '%s': %s", vm_id, str(action_dict))
sousaedu80135b92021-02-17 15:05:18 +01001389
jamartinezv14a823d2019-08-01 11:45:15 +02001390 try:
1391 self._reload_connection()
1392 resName = self._get_resource_name_from_resource_id(vm_id)
sousaedu80135b92021-02-17 15:05:18 +01001393
jamartinezv14a823d2019-08-01 11:45:15 +02001394 if "start" in action_dict:
lloretgalleg45220152019-10-29 11:53:49 +01001395 self.conn_compute.virtual_machines.start(self.resource_group, resName)
sousaedu80135b92021-02-17 15:05:18 +01001396 elif (
1397 "stop" in action_dict
1398 or "shutdown" in action_dict
1399 or "shutoff" in action_dict
1400 ):
1401 self.conn_compute.virtual_machines.power_off(
1402 self.resource_group, resName
1403 )
jamartinezv14a823d2019-08-01 11:45:15 +02001404 elif "terminate" in action_dict:
lloretgalleg45220152019-10-29 11:53:49 +01001405 self.conn_compute.virtual_machines.delete(self.resource_group, resName)
jamartinezv14a823d2019-08-01 11:45:15 +02001406 elif "reboot" in action_dict:
lloretgalleg45220152019-10-29 11:53:49 +01001407 self.conn_compute.virtual_machines.restart(self.resource_group, resName)
sousaedu80135b92021-02-17 15:05:18 +01001408
jamartinezv14a823d2019-08-01 11:45:15 +02001409 return None
1410 except CloudError as e:
lloretgalleg45220152019-10-29 11:53:49 +01001411 if e.error.error and "notfound" in e.error.error.lower():
tierno72774862020-05-04 11:44:15 +00001412 raise vimconn.VimConnNotFoundException("No vm found '{}'".format(vm_id))
jamartinezv14a823d2019-08-01 11:45:15 +02001413 else:
lloretgalleg45220152019-10-29 11:53:49 +01001414 self._format_vimconn_exception(e)
jamartinezv14a823d2019-08-01 11:45:15 +02001415 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +01001416 self._format_vimconn_exception(e)
jamartinezv14a823d2019-08-01 11:45:15 +02001417
1418 def delete_flavor(self, flavor_id):
sousaedu80135b92021-02-17 15:05:18 +01001419 raise vimconn.VimConnAuthException(
1420 "It is not possible to delete a FLAVOR in AZURE"
1421 )
jamartinezv14a823d2019-08-01 11:45:15 +02001422
sousaedu80135b92021-02-17 15:05:18 +01001423 def delete_tenant(self, tenant_id):
1424 raise vimconn.VimConnAuthException(
1425 "It is not possible to delete a TENANT in AZURE"
1426 )
jamartinezv14a823d2019-08-01 11:45:15 +02001427
1428 def delete_image(self, image_id):
sousaedu80135b92021-02-17 15:05:18 +01001429 raise vimconn.VimConnAuthException(
1430 "It is not possible to delete a IMAGE in AZURE"
1431 )
seryio34478552019-05-23 14:50:49 +02001432
1433 def get_vminstance(self, vm_id):
lloretgalleg45220152019-10-29 11:53:49 +01001434 """
1435 Obtaing the vm instance data from v_id
1436 """
1437 self.logger.debug("get vm instance: %s", vm_id)
seryio34478552019-05-23 14:50:49 +02001438 self._reload_connection()
jamartinezv14a823d2019-08-01 11:45:15 +02001439 try:
1440 resName = self._get_resource_name_from_resource_id(vm_id)
tiernob569e4b2019-11-21 16:10:32 +00001441 vm = self.conn_compute.virtual_machines.get(self.resource_group, resName)
jamartinezv14a823d2019-08-01 11:45:15 +02001442 except CloudError as e:
lloretgalleg45220152019-10-29 11:53:49 +01001443 if e.error.error and "notfound" in e.error.error.lower():
sousaedu80135b92021-02-17 15:05:18 +01001444 raise vimconn.VimConnNotFoundException(
1445 "No vminstance found '{}'".format(vm_id)
1446 )
jamartinezv14a823d2019-08-01 11:45:15 +02001447 else:
lloretgalleg45220152019-10-29 11:53:49 +01001448 self._format_vimconn_exception(e)
jamartinezv14a823d2019-08-01 11:45:15 +02001449 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +01001450 self._format_vimconn_exception(e)
seryio34478552019-05-23 14:50:49 +02001451
1452 return vm
1453
1454 def get_flavor(self, flavor_id):
lloretgalleg45220152019-10-29 11:53:49 +01001455 """
1456 Obtains the flavor_data from the flavor_id
1457 """
seryio34478552019-05-23 14:50:49 +02001458 self._reload_connection()
lloretgalleg45220152019-10-29 11:53:49 +01001459 self.logger.debug("get flavor from id: %s", flavor_id)
jamartinezv14a823d2019-08-01 11:45:15 +02001460 flavor_data = self._get_flavor_id_from_flavor_name(flavor_id)
sousaedu80135b92021-02-17 15:05:18 +01001461
jamartinezv14a823d2019-08-01 11:45:15 +02001462 if flavor_data:
1463 flavor = {
sousaedu80135b92021-02-17 15:05:18 +01001464 "id": flavor_id,
1465 "name": flavor_id,
1466 "ram": flavor_data["memoryInMB"],
1467 "vcpus": flavor_data["numberOfCores"],
1468 "disk": flavor_data["resourceDiskSizeInMB"] / 1024,
jamartinezv14a823d2019-08-01 11:45:15 +02001469 }
sousaedu80135b92021-02-17 15:05:18 +01001470
jamartinezv14a823d2019-08-01 11:45:15 +02001471 return flavor
1472 else:
sousaedu80135b92021-02-17 15:05:18 +01001473 raise vimconn.VimConnNotFoundException(
1474 "flavor '{}' not found".format(flavor_id)
1475 )
seryio34478552019-05-23 14:50:49 +02001476
jamartinezv14a823d2019-08-01 11:45:15 +02001477 def get_tenant_list(self, filter_dict={}):
sousaedu80135b92021-02-17 15:05:18 +01001478 """Obtains the list of tenants
1479 For the azure connector only the azure tenant will be returned if it is compatible
1480 with filter_dict
lloretgalleg45220152019-10-29 11:53:49 +01001481 """
sousaedu80135b92021-02-17 15:05:18 +01001482 tenants_azure = [{"name": self.tenant, "id": self.tenant}]
tiernob569e4b2019-11-21 16:10:32 +00001483 tenant_list = []
seryio34478552019-05-23 14:50:49 +02001484
lloretgalleg45220152019-10-29 11:53:49 +01001485 self.logger.debug("get tenant list: %s", filter_dict)
jamartinezv14a823d2019-08-01 11:45:15 +02001486 for tenant_azure in tenants_azure:
1487 if filter_dict:
sousaedu80135b92021-02-17 15:05:18 +01001488 if (
1489 filter_dict.get("id")
1490 and str(tenant_azure.get("id")) != filter_dict["id"]
1491 ):
jamartinezv14a823d2019-08-01 11:45:15 +02001492 continue
sousaedu80135b92021-02-17 15:05:18 +01001493
1494 if (
1495 filter_dict.get("name")
1496 and str(tenant_azure.get("name")) != filter_dict["name"]
1497 ):
jamartinezv14a823d2019-08-01 11:45:15 +02001498 continue
1499
1500 tenant_list.append(tenant_azure)
1501
1502 return tenant_list
seryio34478552019-05-23 14:50:49 +02001503
tierno84efdc12019-05-29 09:29:01 +00001504 def refresh_nets_status(self, net_list):
lloretgalleg45220152019-10-29 11:53:49 +01001505 """Get the status of the networks
sousaedu80135b92021-02-17 15:05:18 +01001506 Params: the list of network identifiers
1507 Returns a dictionary with:
1508 net_id: #VIM id of this network
1509 status: #Mandatory. Text with one of:
1510 # DELETED (not found at vim)
1511 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
1512 # OTHER (Vim reported other status not understood)
1513 # ERROR (VIM indicates an ERROR status)
1514 # ACTIVE, INACTIVE, DOWN (admin down),
1515 # BUILD (on building process)
1516 #
1517 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
1518 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
lloretgalleg45220152019-10-29 11:53:49 +01001519 """
tierno84efdc12019-05-29 09:29:01 +00001520 out_nets = {}
1521 self._reload_connection()
lloretgalleg45220152019-10-29 11:53:49 +01001522
1523 self.logger.debug("reload nets status net_list: %s", net_list)
tierno84efdc12019-05-29 09:29:01 +00001524 for net_id in net_list:
1525 try:
jamartinezv14a823d2019-08-01 11:45:15 +02001526 netName = self._get_net_name_from_resource_id(net_id)
tierno84efdc12019-05-29 09:29:01 +00001527 resName = self._get_resource_name_from_resource_id(net_id)
seryio34478552019-05-23 14:50:49 +02001528
jamartinezv14a823d2019-08-01 11:45:15 +02001529 net = self.conn_vnet.subnets.get(self.resource_group, netName, resName)
1530
lloretgalleg45220152019-10-29 11:53:49 +01001531 out_nets[net_id] = {
jamartinezv14a823d2019-08-01 11:45:15 +02001532 "status": self.provision_state2osm[net.provisioning_state],
sousaedu80135b92021-02-17 15:05:18 +01001533 "vim_info": str(net),
tierno84efdc12019-05-29 09:29:01 +00001534 }
1535 except CloudError as e:
lloretgalleg45220152019-10-29 11:53:49 +01001536 if e.error.error and "notfound" in e.error.error.lower():
sousaedu80135b92021-02-17 15:05:18 +01001537 self.logger.info(
1538 "Not found subnet net_name: %s, subnet_name: %s",
1539 netName,
1540 resName,
1541 )
1542 out_nets[net_id] = {"status": "DELETED", "error_msg": str(e)}
tierno84efdc12019-05-29 09:29:01 +00001543 else:
sousaedu80135b92021-02-17 15:05:18 +01001544 self.logger.error(
1545 "CloudError Exception %s when searching subnet", e
1546 )
lloretgalleg45220152019-10-29 11:53:49 +01001547 out_nets[net_id] = {
1548 "status": "VIM_ERROR",
sousaedu80135b92021-02-17 15:05:18 +01001549 "error_msg": str(e),
lloretgalleg45220152019-10-29 11:53:49 +01001550 }
tierno72774862020-05-04 11:44:15 +00001551 except vimconn.VimConnNotFoundException as e:
sousaedu80135b92021-02-17 15:05:18 +01001552 self.logger.error(
1553 "VimConnNotFoundException %s when searching subnet", e
1554 )
jamartinezv14a823d2019-08-01 11:45:15 +02001555 out_nets[net_id] = {
1556 "status": "DELETED",
sousaedu80135b92021-02-17 15:05:18 +01001557 "error_msg": str(e),
jamartinezv14a823d2019-08-01 11:45:15 +02001558 }
tierno84efdc12019-05-29 09:29:01 +00001559 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +01001560 self.logger.error(
1561 "Exception %s when searching subnet", e, exc_info=True
1562 )
tierno84efdc12019-05-29 09:29:01 +00001563 out_nets[net_id] = {
1564 "status": "VIM_ERROR",
sousaedu80135b92021-02-17 15:05:18 +01001565 "error_msg": str(e),
tierno84efdc12019-05-29 09:29:01 +00001566 }
sousaedu80135b92021-02-17 15:05:18 +01001567
tierno84efdc12019-05-29 09:29:01 +00001568 return out_nets
1569
1570 def refresh_vms_status(self, vm_list):
sousaedu80135b92021-02-17 15:05:18 +01001571 """Get the status of the virtual machines and their interfaces/ports
lloretgalleg45220152019-10-29 11:53:49 +01001572 Params: the list of VM identifiers
1573 Returns a dictionary with:
1574 vm_id: # VIM id of this Virtual Machine
1575 status: # Mandatory. Text with one of:
1576 # DELETED (not found at vim)
1577 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
1578 # OTHER (Vim reported other status not understood)
1579 # ERROR (VIM indicates an ERROR status)
1580 # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
1581 # BUILD (on building process), ERROR
1582 # ACTIVE:NoMgmtIP (Active but none of its interfaces has an IP address
1583 # (ACTIVE:NoMgmtIP is not returned for Azure)
1584 #
1585 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
1586 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
1587 interfaces: list with interface info. Each item a dictionary with:
1588 vim_interface_id - The ID of the interface
1589 mac_address - The MAC address of the interface.
1590 ip_address - The IP address of the interface within the subnet.
1591 """
tierno84efdc12019-05-29 09:29:01 +00001592 out_vms = {}
1593 self._reload_connection()
jamartinezv14a823d2019-08-01 11:45:15 +02001594
lloretgalleg45220152019-10-29 11:53:49 +01001595 self.logger.debug("refresh vm status vm_list: %s", vm_list)
1596 search_vm_list = vm_list or {}
1597
1598 for vm_id in search_vm_list:
1599 out_vm = {}
tierno84efdc12019-05-29 09:29:01 +00001600 try:
lloretgalleg45220152019-10-29 11:53:49 +01001601 res_name = self._get_resource_name_from_resource_id(vm_id)
jamartinezv14a823d2019-08-01 11:45:15 +02001602
sousaedu80135b92021-02-17 15:05:18 +01001603 vm = self.conn_compute.virtual_machines.get(
1604 self.resource_group, res_name
1605 )
1606 out_vm["vim_info"] = str(vm)
1607 out_vm["status"] = self.provision_state2osm.get(
1608 vm.provisioning_state, "OTHER"
1609 )
1610
1611 if vm.provisioning_state == "Succeeded":
lloretgalleg45220152019-10-29 11:53:49 +01001612 # check if machine is running or stopped
sousaedu80135b92021-02-17 15:05:18 +01001613 instance_view = self.conn_compute.virtual_machines.instance_view(
1614 self.resource_group, res_name
1615 )
1616
lloretgalleg45220152019-10-29 11:53:49 +01001617 for status in instance_view.statuses:
1618 splitted_status = status.code.split("/")
sousaedu80135b92021-02-17 15:05:18 +01001619 if (
1620 len(splitted_status) == 2
1621 and splitted_status[0] == "PowerState"
1622 ):
1623 out_vm["status"] = self.power_state2osm.get(
1624 splitted_status[1], "OTHER"
1625 )
jamartinezv14a823d2019-08-01 11:45:15 +02001626
1627 network_interfaces = vm.network_profile.network_interfaces
sousaedu80135b92021-02-17 15:05:18 +01001628 out_vm["interfaces"] = self._get_vm_interfaces_status(
1629 vm_id, network_interfaces
1630 )
jamartinezv14a823d2019-08-01 11:45:15 +02001631
lloretgalleg45220152019-10-29 11:53:49 +01001632 except CloudError as e:
1633 if e.error.error and "notfound" in e.error.error.lower():
1634 self.logger.debug("Not found vm id: %s", vm_id)
sousaedu80135b92021-02-17 15:05:18 +01001635 out_vm["status"] = "DELETED"
1636 out_vm["error_msg"] = str(e)
1637 out_vm["vim_info"] = None
lloretgalleg45220152019-10-29 11:53:49 +01001638 else:
1639 # maybe connection error or another type of error, return vim error
1640 self.logger.error("Exception %s refreshing vm_status", e)
sousaedu80135b92021-02-17 15:05:18 +01001641 out_vm["status"] = "VIM_ERROR"
1642 out_vm["error_msg"] = str(e)
1643 out_vm["vim_info"] = None
tierno84efdc12019-05-29 09:29:01 +00001644 except Exception as e:
lloretgalleg45220152019-10-29 11:53:49 +01001645 self.logger.error("Exception %s refreshing vm_status", e, exc_info=True)
sousaedu80135b92021-02-17 15:05:18 +01001646 out_vm["status"] = "VIM_ERROR"
1647 out_vm["error_msg"] = str(e)
1648 out_vm["vim_info"] = None
jamartinezv14a823d2019-08-01 11:45:15 +02001649
lloretgalleg45220152019-10-29 11:53:49 +01001650 out_vms[vm_id] = out_vm
tierno84efdc12019-05-29 09:29:01 +00001651
1652 return out_vms
seryio07ad1362019-05-29 09:16:24 +02001653
lloretgalleg45220152019-10-29 11:53:49 +01001654 def _get_vm_interfaces_status(self, vm_id, interfaces):
1655 """
1656 Gets the interfaces detail for a vm
1657 :param interfaces: List of interfaces.
1658 :return: Dictionary with list of interfaces including, vim_interface_id, mac_address and ip_address
1659 """
1660 try:
1661 interface_list = []
1662 for network_interface in interfaces:
1663 interface_dict = {}
sousaedu80135b92021-02-17 15:05:18 +01001664 nic_name = self._get_resource_name_from_resource_id(
1665 network_interface.id
1666 )
1667 interface_dict["vim_interface_id"] = network_interface.id
lloretgalleg45220152019-10-29 11:53:49 +01001668
1669 nic_data = self.conn_vnet.network_interfaces.get(
1670 self.resource_group,
sousaedu80135b92021-02-17 15:05:18 +01001671 nic_name,
1672 )
lloretgalleg45220152019-10-29 11:53:49 +01001673
lloretgallegbfc28b02019-11-21 09:31:16 +01001674 ips = []
1675 if nic_data.ip_configurations[0].public_ip_address:
1676 self.logger.debug("Obtain public ip address")
tiernob569e4b2019-11-21 16:10:32 +00001677 public_ip_name = self._get_resource_name_from_resource_id(
sousaedu80135b92021-02-17 15:05:18 +01001678 nic_data.ip_configurations[0].public_ip_address.id
1679 )
1680 public_ip = self.conn_vnet.public_ip_addresses.get(
1681 self.resource_group, public_ip_name
1682 )
lloretgallegbfc28b02019-11-21 09:31:16 +01001683 self.logger.debug("Public ip address is: %s", public_ip.ip_address)
1684 ips.append(public_ip.ip_address)
1685
lloretgalleg45220152019-10-29 11:53:49 +01001686 private_ip = nic_data.ip_configurations[0].private_ip_address
lloretgallegbfc28b02019-11-21 09:31:16 +01001687 ips.append(private_ip)
lloretgalleg45220152019-10-29 11:53:49 +01001688
sousaedu80135b92021-02-17 15:05:18 +01001689 interface_dict["mac_address"] = nic_data.mac_address
1690 interface_dict["ip_address"] = ";".join(ips)
lloretgalleg45220152019-10-29 11:53:49 +01001691 interface_list.append(interface_dict)
1692
1693 return interface_list
1694 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +01001695 self.logger.error(
1696 "Exception %s obtaining interface data for vm: %s, error: %s",
1697 vm_id,
1698 e,
1699 exc_info=True,
1700 )
lloretgalleg45220152019-10-29 11:53:49 +01001701 self._format_vimconn_exception(e)
1702
seryio34478552019-05-23 14:50:49 +02001703
1704if __name__ == "__main__":
seryio34478552019-05-23 14:50:49 +02001705 # Making some basic test
sousaedu80135b92021-02-17 15:05:18 +01001706 vim_id = "azure"
1707 vim_name = "azure"
seryio34478552019-05-23 14:50:49 +02001708 needed_test_params = {
tiernodeb74b22019-05-27 10:24:50 +00001709 "client_id": "AZURE_CLIENT_ID",
1710 "secret": "AZURE_SECRET",
1711 "tenant": "AZURE_TENANT",
1712 "resource_group": "AZURE_RESOURCE_GROUP",
1713 "subscription_id": "AZURE_SUBSCRIPTION_ID",
tierno30d0d6d2019-05-27 08:14:01 +00001714 "vnet_name": "AZURE_VNET_NAME",
seryio34478552019-05-23 14:50:49 +02001715 }
1716 test_params = {}
1717
1718 for param, env_var in needed_test_params.items():
1719 value = getenv(env_var)
sousaedu80135b92021-02-17 15:05:18 +01001720
seryio34478552019-05-23 14:50:49 +02001721 if not value:
1722 raise Exception("Provide a valid value for env '{}'".format(env_var))
sousaedu80135b92021-02-17 15:05:18 +01001723
seryio34478552019-05-23 14:50:49 +02001724 test_params[param] = value
1725
1726 config = {
sousaedu80135b92021-02-17 15:05:18 +01001727 "region_name": getenv("AZURE_REGION_NAME", "westeurope"),
1728 "resource_group": getenv("AZURE_RESOURCE_GROUP"),
1729 "subscription_id": getenv("AZURE_SUBSCRIPTION_ID"),
1730 "pub_key": getenv("AZURE_PUB_KEY", None),
1731 "vnet_name": getenv("AZURE_VNET_NAME", "myNetwork"),
seryio34478552019-05-23 14:50:49 +02001732 }
tierno30d0d6d2019-05-27 08:14:01 +00001733
seryio34478552019-05-23 14:50:49 +02001734 virtualMachine = {
sousaedu80135b92021-02-17 15:05:18 +01001735 "name": "sergio",
1736 "description": "new VM",
1737 "status": "running",
1738 "image": {
1739 "publisher": "Canonical",
1740 "offer": "UbuntuServer",
1741 "sku": "16.04.0-LTS",
1742 "version": "latest",
seryio34478552019-05-23 14:50:49 +02001743 },
sousaedu80135b92021-02-17 15:05:18 +01001744 "hardware_profile": {"vm_size": "Standard_DS1_v2"},
1745 "networks": ["sergio"],
seryio34478552019-05-23 14:50:49 +02001746 }
1747
1748 vnet_config = {
sousaedu80135b92021-02-17 15:05:18 +01001749 "subnet_address": "10.1.2.0/24",
1750 # "subnet_name": "subnet-oam"
seryio34478552019-05-23 14:50:49 +02001751 }
1752 ###########################
1753
sousaedu80135b92021-02-17 15:05:18 +01001754 azure = vimconnector(
1755 vim_id,
1756 vim_name,
1757 tenant_id=test_params["tenant"],
1758 tenant_name=None,
1759 url=None,
1760 url_admin=None,
1761 user=test_params["client_id"],
1762 passwd=test_params["secret"],
1763 log_level=None,
1764 config=config,
1765 )
seryio34478552019-05-23 14:50:49 +02001766
tiernodeb74b22019-05-27 10:24:50 +00001767 # azure.get_flavor_id_from_data("here")
1768 # subnets=azure.get_network_list()
sousaedu80135b92021-02-17 15:05:18 +01001769 # azure.new_vminstance(virtualMachine["name"], virtualMachine["description"], virtualMachine["status"],
1770 # virtualMachine["image"], virtualMachine["hardware_profile"]["vm_size"], subnets)
tiernodeb74b22019-05-27 10:24:50 +00001771
tierno24620412019-06-03 14:05:08 +00001772 azure.new_network("mynet", None)
sousaedu80135b92021-02-17 15:05:18 +01001773 net_id = (
1774 "/subscriptions/82f80cc1-876b-4591-9911-1fb5788384fd/resourceGroups/osmRG/providers/Microsoft."
1775 "Network/virtualNetworks/test"
1776 )
1777 net_id_not_found = (
1778 "/subscriptions/82f80cc1-876b-4591-9911-1fb5788384fd/resourceGroups/osmRG/providers/"
1779 "Microsoft.Network/virtualNetworks/testALF"
1780 )
tierno84efdc12019-05-29 09:29:01 +00001781 azure.refresh_nets_status([net_id, net_id_not_found])