| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1 | # -*- coding: utf-8 -*- |
| tierno | b569e4b | 2019-11-21 16:10:32 +0000 | [diff] [blame] | 2 | ## |
| 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 | ## |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 15 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 16 | import base64 |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 17 | import logging |
| sousaedu | 049cbb1 | 2022-01-05 11:39:35 +0000 | [diff] [blame] | 18 | from os import getenv |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 19 | import re |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 20 | |
| sousaedu | 049cbb1 | 2022-01-05 11:39:35 +0000 | [diff] [blame] | 21 | from azure.core.exceptions import ResourceNotFoundError |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 22 | from azure.identity import ClientSecretCredential |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 23 | from azure.mgmt.compute import ComputeManagementClient |
| sousaedu | 049cbb1 | 2022-01-05 11:39:35 +0000 | [diff] [blame] | 24 | from azure.mgmt.network import NetworkManagementClient |
| 25 | from azure.mgmt.resource import ResourceManagementClient |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 26 | from azure.profiles import ProfileDefinition |
| sousaedu | 049cbb1 | 2022-01-05 11:39:35 +0000 | [diff] [blame] | 27 | from cryptography.hazmat.backends import default_backend as crypto_default_backend |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 28 | from cryptography.hazmat.primitives import serialization as crypto_serialization |
| 29 | from cryptography.hazmat.primitives.asymmetric import rsa |
| sousaedu | 049cbb1 | 2022-01-05 11:39:35 +0000 | [diff] [blame] | 30 | from msrest.exceptions import AuthenticationError |
| 31 | from msrestazure.azure_exceptions import CloudError |
| 32 | import msrestazure.tools as azure_tools |
| 33 | import netaddr |
| 34 | from osm_ro_plugin import vimconn |
| 35 | from requests.exceptions import ConnectionError |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 36 | |
| 37 | __author__ = "Isabel Lloret, Sergio Gonzalez, Alfonso Tierno, Gerardo Garcia" |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 38 | __date__ = "$18-apr-2019 23:59:59$" |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 39 | |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 40 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 41 | if getenv("OSMRO_PDB_DEBUG"): |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 42 | import sys |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 43 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 44 | print(sys.path) |
| 45 | import pdb |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 46 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 47 | pdb.set_trace() |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 48 | |
| 49 | |
| garciadeblas | c878ac4 | 2021-05-27 12:00:30 +0200 | [diff] [blame] | 50 | def find_in_list(the_list, condition_lambda): |
| 51 | for item in the_list: |
| 52 | if condition_lambda(item): |
| 53 | return item |
| 54 | else: |
| 55 | return None |
| 56 | |
| 57 | |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 58 | class vimconnector(vimconn.VimConnector): |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 59 | # Translate azure provisioning state to OSM provision state |
| 60 | # The first three ones are the transitional status once a user initiated action has been requested |
| 61 | # Once the operation is complete, it will transition into the states Succeeded or Failed |
| 62 | # https://docs.microsoft.com/en-us/azure/virtual-machines/windows/states-lifecycle |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 63 | provision_state2osm = { |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 64 | "Creating": "BUILD", |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 65 | "Updating": "BUILD", |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 66 | "Deleting": "INACTIVE", |
| 67 | "Succeeded": "ACTIVE", |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 68 | "Failed": "ERROR", |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 69 | } |
| 70 | |
| 71 | # Translate azure power state to OSM provision state |
| 72 | power_state2osm = { |
| 73 | "starting": "INACTIVE", |
| 74 | "running": "ACTIVE", |
| 75 | "stopping": "INACTIVE", |
| 76 | "stopped": "INACTIVE", |
| 77 | "unknown": "OTHER", |
| 78 | "deallocated": "BUILD", |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 79 | "deallocating": "BUILD", |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 80 | } |
| 81 | |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 82 | # TODO - review availability zones |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 83 | AZURE_ZONES = ["1", "2", "3"] |
| 84 | |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 85 | AZURE_COMPUTE_MGMT_CLIENT_API_VERSION = "2021-03-01" |
| 86 | AZURE_COMPUTE_MGMT_PROFILE_TAG = "azure.mgmt.compute.ComputeManagementClient" |
| 87 | AZURE_COMPUTE_MGMT_PROFILE = ProfileDefinition( |
| 88 | { |
| 89 | AZURE_COMPUTE_MGMT_PROFILE_TAG: { |
| 90 | None: AZURE_COMPUTE_MGMT_CLIENT_API_VERSION, |
| 91 | "availability_sets": "2020-12-01", |
| 92 | "dedicated_host_groups": "2020-12-01", |
| 93 | "dedicated_hosts": "2020-12-01", |
| 94 | "disk_accesses": "2020-12-01", |
| 95 | "disk_encryption_sets": "2020-12-01", |
| 96 | "disk_restore_point": "2020-12-01", |
| 97 | "disks": "2020-12-01", |
| 98 | "galleries": "2020-09-30", |
| 99 | "gallery_application_versions": "2020-09-30", |
| 100 | "gallery_applications": "2020-09-30", |
| 101 | "gallery_image_versions": "2020-09-30", |
| 102 | "gallery_images": "2020-09-30", |
| 103 | "gallery_sharing_profile": "2020-09-30", |
| 104 | "images": "2020-12-01", |
| 105 | "log_analytics": "2020-12-01", |
| 106 | "operations": "2020-12-01", |
| 107 | "proximity_placement_groups": "2020-12-01", |
| 108 | "resource_skus": "2019-04-01", |
| 109 | "shared_galleries": "2020-09-30", |
| 110 | "shared_gallery_image_versions": "2020-09-30", |
| 111 | "shared_gallery_images": "2020-09-30", |
| 112 | "snapshots": "2020-12-01", |
| 113 | "ssh_public_keys": "2020-12-01", |
| 114 | "usage": "2020-12-01", |
| 115 | "virtual_machine_extension_images": "2020-12-01", |
| 116 | "virtual_machine_extensions": "2020-12-01", |
| 117 | "virtual_machine_images": "2020-12-01", |
| 118 | "virtual_machine_images_edge_zone": "2020-12-01", |
| 119 | "virtual_machine_run_commands": "2020-12-01", |
| 120 | "virtual_machine_scale_set_extensions": "2020-12-01", |
| 121 | "virtual_machine_scale_set_rolling_upgrades": "2020-12-01", |
| 122 | "virtual_machine_scale_set_vm_extensions": "2020-12-01", |
| 123 | "virtual_machine_scale_set_vm_run_commands": "2020-12-01", |
| 124 | "virtual_machine_scale_set_vms": "2020-12-01", |
| 125 | "virtual_machine_scale_sets": "2020-12-01", |
| 126 | "virtual_machine_sizes": "2020-12-01", |
| 127 | "virtual_machines": "2020-12-01", |
| 128 | } |
| 129 | }, |
| 130 | AZURE_COMPUTE_MGMT_PROFILE_TAG + " osm", |
| 131 | ) |
| 132 | |
| 133 | AZURE_RESOURCE_MGMT_CLIENT_API_VERSION = "2020-10-01" |
| 134 | AZURE_RESOURCE_MGMT_PROFILE_TAG = ( |
| 135 | "azure.mgmt.resource.resources.ResourceManagementClient" |
| 136 | ) |
| 137 | AZURE_RESOURCE_MGMT_PROFILE = ProfileDefinition( |
| 138 | { |
| 139 | AZURE_RESOURCE_MGMT_PROFILE_TAG: { |
| 140 | None: AZURE_RESOURCE_MGMT_CLIENT_API_VERSION, |
| 141 | } |
| 142 | }, |
| 143 | AZURE_RESOURCE_MGMT_PROFILE_TAG + " osm", |
| 144 | ) |
| 145 | |
| 146 | AZURE_NETWORK_MGMT_CLIENT_API_VERSION = "2020-11-01" |
| 147 | AZURE_NETWORK_MGMT_PROFILE_TAG = "azure.mgmt.network.NetworkManagementClient" |
| 148 | AZURE_NETWORK_MGMT_PROFILE = ProfileDefinition( |
| 149 | { |
| 150 | AZURE_NETWORK_MGMT_PROFILE_TAG: { |
| 151 | None: AZURE_NETWORK_MGMT_CLIENT_API_VERSION, |
| 152 | "firewall_policy_rule_groups": "2020-04-01", |
| 153 | "interface_endpoints": "2019-02-01", |
| 154 | "p2_svpn_server_configurations": "2019-07-01", |
| 155 | } |
| 156 | }, |
| 157 | AZURE_NETWORK_MGMT_PROFILE_TAG + " osm", |
| 158 | ) |
| 159 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 160 | def __init__( |
| 161 | self, |
| 162 | uuid, |
| 163 | name, |
| 164 | tenant_id, |
| 165 | tenant_name, |
| 166 | url, |
| 167 | url_admin=None, |
| 168 | user=None, |
| 169 | passwd=None, |
| 170 | log_level=None, |
| 171 | config={}, |
| 172 | persistent_info={}, |
| 173 | ): |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 174 | """ |
| 175 | Constructor of VIM. Raise an exception is some needed parameter is missing, but it must not do any connectivity |
| 176 | checking against the VIM |
| 177 | Using common constructor parameters. |
| 178 | In this case: config must include the following parameters: |
| 179 | subscription_id: assigned azure subscription identifier |
| 180 | region_name: current region for azure network |
| 181 | resource_group: used for all azure created resources |
| 182 | vnet_name: base vnet for azure, created networks will be subnets from this base network |
| 183 | config may also include the following parameter: |
| 184 | flavors_pattern: pattern that will be used to select a range of vm sizes, for example |
| 185 | "^((?!Standard_B).)*$" will filter out Standard_B range that is cheap but is very overused |
| 186 | "^Standard_B" will select a serie B maybe for test environment |
| 187 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 188 | vimconn.VimConnector.__init__( |
| 189 | self, |
| 190 | uuid, |
| 191 | name, |
| 192 | tenant_id, |
| 193 | tenant_name, |
| 194 | url, |
| 195 | url_admin, |
| 196 | user, |
| 197 | passwd, |
| 198 | log_level, |
| 199 | config, |
| 200 | persistent_info, |
| 201 | ) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 202 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 203 | # Variable that indicates if client must be reloaded or initialized |
| 204 | self.reload_client = True |
| 205 | |
| aguilard | 5d27a33 | 2023-11-02 16:52:56 +0000 | [diff] [blame] | 206 | self.vnet_address_space = [] |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 207 | |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 208 | # LOGGER |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 209 | self.logger = logging.getLogger("ro.vim.azure") |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 210 | if log_level: |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 211 | self.logger.setLevel(getattr(logging, log_level)) |
| 212 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 213 | self.tenant = tenant_id or tenant_name |
| tierno | 30d0d6d | 2019-05-27 08:14:01 +0000 | [diff] [blame] | 214 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 215 | # Store config to create azure subscription later |
| tierno | b569e4b | 2019-11-21 16:10:32 +0000 | [diff] [blame] | 216 | self._config = { |
| 217 | "user": user, |
| 218 | "passwd": passwd, |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 219 | "tenant": tenant_id or tenant_name, |
| tierno | b569e4b | 2019-11-21 16:10:32 +0000 | [diff] [blame] | 220 | } |
| tierno | 30d0d6d | 2019-05-27 08:14:01 +0000 | [diff] [blame] | 221 | |
| 222 | # SUBSCRIPTION |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 223 | if "subscription_id" in config: |
| 224 | self._config["subscription_id"] = config.get("subscription_id") |
| 225 | # self.logger.debug("Setting subscription to: %s", self.config["subscription_id"]) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 226 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 227 | raise vimconn.VimConnException("Subscription not specified") |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 228 | |
| tierno | 30d0d6d | 2019-05-27 08:14:01 +0000 | [diff] [blame] | 229 | # RESOURCE_GROUP |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 230 | if "resource_group" in config: |
| 231 | self.resource_group = config.get("resource_group") |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 232 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 233 | raise vimconn.VimConnException( |
| 234 | "Azure resource_group is not specified at config" |
| 235 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 236 | |
| garciadeblas | 66af694 | 2021-10-26 18:38:49 +0200 | [diff] [blame] | 237 | # REGION |
| 238 | if "region_name" in config: |
| 239 | self.region = config.get("region_name") |
| 240 | else: |
| 241 | raise vimconn.VimConnException( |
| 242 | "Azure region_name is not specified at config" |
| 243 | ) |
| 244 | |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 245 | # VNET_NAME |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 246 | if "vnet_name" in config: |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 247 | self.vnet_name = config["vnet_name"] |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 248 | |
| gallardo | dd82175 | 2022-01-17 17:37:51 +0000 | [diff] [blame] | 249 | # VNET_RESOURCE_GROUP |
| 250 | self.vnet_resource_group = config.get("vnet_resource_group") |
| 251 | |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 252 | # TODO - not used, do anything about it? |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 253 | # public ssh key |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 254 | self.pub_key = config.get("pub_key") |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 255 | |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 256 | # TODO - check default user for azure |
| 257 | # default admin user |
| 258 | self._default_admin_user = "azureuser" |
| 259 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 260 | # flavor pattern regex |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 261 | if "flavors_pattern" in config: |
| 262 | self._config["flavors_pattern"] = config["flavors_pattern"] |
| 263 | |
| garciadeblas | c878ac4 | 2021-05-27 12:00:30 +0200 | [diff] [blame] | 264 | def _find_in_capabilities(self, capabilities, name): |
| 265 | cap = find_in_list(capabilities, lambda c: c["name"] == name) |
| 266 | if cap: |
| 267 | return cap.get("value") |
| 268 | else: |
| 269 | return None |
| 270 | |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 271 | def _reload_connection(self): |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 272 | """ |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 273 | Called before any operation, checks python azure clients |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 274 | """ |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 275 | if self.reload_client: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 276 | self.logger.debug("reloading azure client") |
| 277 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 278 | try: |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 279 | self.credentials = ClientSecretCredential( |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 280 | client_id=self._config["user"], |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 281 | client_secret=self._config["passwd"], |
| 282 | tenant_id=self._config["tenant"], |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 283 | ) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 284 | self.conn = ResourceManagementClient( |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 285 | self.credentials, |
| 286 | self._config["subscription_id"], |
| 287 | profile=self.AZURE_RESOURCE_MGMT_PROFILE, |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 288 | ) |
| 289 | self.conn_compute = ComputeManagementClient( |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 290 | self.credentials, |
| 291 | self._config["subscription_id"], |
| 292 | profile=self.AZURE_COMPUTE_MGMT_PROFILE, |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 293 | ) |
| 294 | self.conn_vnet = NetworkManagementClient( |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 295 | self.credentials, |
| 296 | self._config["subscription_id"], |
| 297 | profile=self.AZURE_NETWORK_MGMT_PROFILE, |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 298 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 299 | self._check_or_create_resource_group() |
| 300 | self._check_or_create_vnet() |
| 301 | |
| 302 | # Set to client created |
| 303 | self.reload_client = False |
| 304 | except Exception as e: |
| 305 | self._format_vimconn_exception(e) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 306 | |
| 307 | def _get_resource_name_from_resource_id(self, resource_id): |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 308 | """ |
| 309 | Obtains resource_name from the azure complete identifier: resource_name will always be last item |
| 310 | """ |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 311 | try: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 312 | resource = str(resource_id.split("/")[-1]) |
| 313 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 314 | return resource |
| 315 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 316 | raise vimconn.VimConnException( |
| 317 | "Unable to get resource name from resource_id '{}' Error: '{}'".format( |
| 318 | resource_id, e |
| 319 | ) |
| 320 | ) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 321 | |
| 322 | def _get_location_from_resource_group(self, resource_group_name): |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 323 | try: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 324 | location = self.conn.resource_groups.get(resource_group_name).location |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 325 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 326 | return location |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 327 | except Exception: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 328 | raise vimconn.VimConnNotFoundException( |
| 329 | "Location '{}' not found".format(resource_group_name) |
| 330 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 331 | |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 332 | def _get_resource_group_name_from_resource_id(self, resource_id): |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 333 | try: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 334 | rg = str(resource_id.split("/")[4]) |
| 335 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 336 | return rg |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 337 | except Exception: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 338 | raise vimconn.VimConnException( |
| 339 | "Unable to get resource group from invalid resource_id format '{}'".format( |
| 340 | resource_id |
| 341 | ) |
| 342 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 343 | |
| 344 | def _get_net_name_from_resource_id(self, resource_id): |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 345 | try: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 346 | net_name = str(resource_id.split("/")[8]) |
| 347 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 348 | return net_name |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 349 | except Exception: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 350 | raise vimconn.VimConnException( |
| 351 | "Unable to get azure net_name from invalid resource_id format '{}'".format( |
| 352 | resource_id |
| 353 | ) |
| 354 | ) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 355 | |
| 356 | def _check_subnets_for_vm(self, net_list): |
| tierno | 30d0d6d | 2019-05-27 08:14:01 +0000 | [diff] [blame] | 357 | # All subnets must belong to the same resource group and vnet |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 358 | # All subnets must belong to the same resource group anded vnet |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 359 | rg_vnet = set( |
| 360 | self._get_resource_group_name_from_resource_id(net["net_id"]) |
| 361 | + self._get_net_name_from_resource_id(net["net_id"]) |
| 362 | for net in net_list |
| 363 | ) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 364 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 365 | if len(rg_vnet) != 1: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 366 | raise self._format_vimconn_exception( |
| 367 | "Azure VMs can only attach to subnets in same VNET" |
| 368 | ) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 369 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 370 | def _format_vimconn_exception(self, e): |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 371 | """ |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 372 | Transforms a generic or azure exception to a vimcommException |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 373 | """ |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 374 | self.logger.error("Azure plugin error: {}".format(e)) |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 375 | if isinstance(e, vimconn.VimConnException): |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 376 | raise e |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 377 | elif isinstance(e, AuthenticationError): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 378 | raise vimconn.VimConnAuthException(type(e).__name__ + ": " + str(e)) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 379 | elif isinstance(e, ConnectionError): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 380 | raise vimconn.VimConnConnectionException(type(e).__name__ + ": " + str(e)) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 381 | else: |
| 382 | # In case of generic error recreate client |
| 383 | self.reload_client = True |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 384 | |
| 385 | raise vimconn.VimConnException(type(e).__name__ + ": " + str(e)) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 386 | |
| 387 | def _check_or_create_resource_group(self): |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 388 | """ |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 389 | Creates the base resource group if it does not exist |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 390 | """ |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 391 | try: |
| 392 | rg_exists = self.conn.resource_groups.check_existence(self.resource_group) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 393 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 394 | if not rg_exists: |
| 395 | self.logger.debug("create base rgroup: %s", self.resource_group) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 396 | self.conn.resource_groups.create_or_update( |
| 397 | self.resource_group, {"location": self.region} |
| 398 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 399 | except Exception as e: |
| 400 | self._format_vimconn_exception(e) |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 401 | |
| 402 | def _check_or_create_vnet(self): |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 403 | """ |
| 404 | Try to get existent base vnet, in case it does not exist it creates it |
| 405 | """ |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 406 | try: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 407 | vnet = self.conn_vnet.virtual_networks.get( |
| gallardo | dd82175 | 2022-01-17 17:37:51 +0000 | [diff] [blame] | 408 | self.vnet_resource_group or self.resource_group, self.vnet_name |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 409 | ) |
| aguilard | 5d27a33 | 2023-11-02 16:52:56 +0000 | [diff] [blame] | 410 | self.vnet_address_space = vnet.address_space.address_prefixes |
| tierno | 2462041 | 2019-06-03 14:05:08 +0000 | [diff] [blame] | 411 | self.vnet_id = vnet.id |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 412 | |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 413 | return |
| 414 | except CloudError as e: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 415 | if e.error.error and "notfound" in e.error.error.lower(): |
| aticig | 7b521f7 | 2022-07-15 00:43:09 +0300 | [diff] [blame] | 416 | self.logger.exception("CloudError Exception occured.") |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 417 | # continue and create it |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 418 | else: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 419 | self._format_vimconn_exception(e) |
| 420 | |
| 421 | # if it does not exist, create it |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 422 | try: |
| 423 | vnet_params = { |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 424 | "location": self.region, |
| 425 | "address_space": {"address_prefixes": ["10.0.0.0/8"]}, |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 426 | } |
| aguilard | 5d27a33 | 2023-11-02 16:52:56 +0000 | [diff] [blame] | 427 | self.vnet_address_space = ["10.0.0.0/8"] |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 428 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 429 | self.logger.debug("create base vnet: %s", self.vnet_name) |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 430 | self.conn_vnet.virtual_networks.begin_create_or_update( |
| gallardo | dd82175 | 2022-01-17 17:37:51 +0000 | [diff] [blame] | 431 | self.vnet_resource_group or self.resource_group, |
| 432 | self.vnet_name, |
| 433 | vnet_params, |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 434 | ) |
| 435 | vnet = self.conn_vnet.virtual_networks.get( |
| gallardo | dd82175 | 2022-01-17 17:37:51 +0000 | [diff] [blame] | 436 | self.vnet_resource_group or self.resource_group, self.vnet_name |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 437 | ) |
| tierno | 2462041 | 2019-06-03 14:05:08 +0000 | [diff] [blame] | 438 | self.vnet_id = vnet.id |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 439 | except Exception as e: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 440 | self._format_vimconn_exception(e) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 441 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 442 | def new_network( |
| 443 | self, |
| 444 | net_name, |
| 445 | net_type, |
| 446 | ip_profile=None, |
| 447 | shared=False, |
| 448 | provider_network_profile=None, |
| 449 | ): |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 450 | """ |
| 451 | Adds a tenant network to VIM |
| 452 | :param net_name: name of the network |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 453 | :param net_type: not used for azure networks |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 454 | :param ip_profile: is a dict containing the IP parameters of the network (Currently only IPv4 is implemented) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 455 | 'ip-version': can be one of ['IPv4','IPv6'] |
| 456 | 'subnet-address': ip_prefix_schema, that is X.X.X.X/Y |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 457 | 'gateway-address': (Optional) ip_schema, that is X.X.X.X, not implemented for azure connector |
| 458 | 'dns-address': (Optional) ip_schema, not implemented for azure connector |
| 459 | 'dhcp': (Optional) dict containing, not implemented for azure connector |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 460 | 'enabled': {'type': 'boolean'}, |
| 461 | 'start-address': ip_schema, first IP to grant |
| 462 | 'count': number of IPs to grant. |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 463 | :param shared: Not allowed for Azure Connector |
| kbsub | a85c54d | 2019-10-17 16:30:32 +0000 | [diff] [blame] | 464 | :param provider_network_profile: (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk} |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 465 | :return: a tuple with the network identifier and created_items, or raises an exception on error |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 466 | created_items can be None or a dictionary where this method can include key-values that will be passed to |
| 467 | the method delete_network. Can be used to store created segments, created l2gw connections, etc. |
| 468 | Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same |
| 469 | as not present. |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 470 | """ |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 471 | return self._new_subnet(net_name, ip_profile) |
| 472 | |
| 473 | def _new_subnet(self, net_name, ip_profile): |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 474 | """ |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 475 | Adds a tenant network to VIM. It creates a new subnet at existing base vnet |
| 476 | :param net_name: subnet name |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 477 | :param ip_profile: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 478 | subnet-address: if it is not provided a subnet/24 in the default vnet is created, |
| 479 | otherwise it creates a subnet in the indicated address |
| 480 | :return: a tuple with the network identifier and created_items, or raises an exception on error |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 481 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 482 | self.logger.debug("create subnet name %s, ip_profile %s", net_name, ip_profile) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 483 | self._reload_connection() |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 484 | |
| 485 | if ip_profile is None: |
| tierno | 2462041 | 2019-06-03 14:05:08 +0000 | [diff] [blame] | 486 | # get a non used vnet ip range /24 and allocate automatically inside the range self.vnet_address_space |
| 487 | used_subnets = self.get_network_list() |
| aguilard | 5d27a33 | 2023-11-02 16:52:56 +0000 | [diff] [blame] | 488 | for space in self.vnet_address_space: |
| 489 | for ip_range in netaddr.IPNetwork(space).subnet(24): |
| 490 | for used_subnet in used_subnets: |
| 491 | subnet_range = netaddr.IPNetwork(used_subnet["cidr_block"]) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 492 | |
| aguilard | 5d27a33 | 2023-11-02 16:52:56 +0000 | [diff] [blame] | 493 | if subnet_range in ip_range or ip_range in subnet_range: |
| 494 | # this range overlaps with an existing subnet ip range. Breaks and look for another |
| 495 | break |
| 496 | else: |
| 497 | ip_profile = {"subnet_address": str(ip_range)} |
| 498 | self.logger.debug( |
| 499 | "dinamically obtained ip_profile: %s", ip_range |
| 500 | ) |
| tierno | 2462041 | 2019-06-03 14:05:08 +0000 | [diff] [blame] | 501 | break |
| aguilard | 5d27a33 | 2023-11-02 16:52:56 +0000 | [diff] [blame] | 502 | if ip_profile is not None: |
| tierno | 2462041 | 2019-06-03 14:05:08 +0000 | [diff] [blame] | 503 | break |
| 504 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 505 | raise vimconn.VimConnException( |
| 506 | "Cannot find a non-used subnet range in {}".format( |
| 507 | self.vnet_address_space |
| 508 | ) |
| 509 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 510 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 511 | ip_profile = {"subnet_address": ip_profile["subnet_address"]} |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 512 | |
| 513 | try: |
| tierno | b569e4b | 2019-11-21 16:10:32 +0000 | [diff] [blame] | 514 | # subnet_name = "{}-{}".format(net_name[:24], uuid4()) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 515 | subnet_params = {"address_prefix": ip_profile["subnet_address"]} |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 516 | # Assign a not duplicated net name |
| 517 | subnet_name = self._get_unused_subnet_name(net_name) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 518 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 519 | self.logger.debug("creating subnet_name: {}".format(subnet_name)) |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 520 | async_creation = self.conn_vnet.subnets.begin_create_or_update( |
| gallardo | dd82175 | 2022-01-17 17:37:51 +0000 | [diff] [blame] | 521 | self.vnet_resource_group or self.resource_group, |
| 522 | self.vnet_name, |
| 523 | subnet_name, |
| 524 | subnet_params, |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 525 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 526 | async_creation.wait() |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 527 | # TODO - do not wait here, check where it is used |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 528 | self.logger.debug("created subnet_name: {}".format(subnet_name)) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 529 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 530 | return "{}/subnets/{}".format(self.vnet_id, subnet_name), None |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 531 | except Exception as e: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 532 | self._format_vimconn_exception(e) |
| 533 | |
| 534 | def _get_unused_subnet_name(self, subnet_name): |
| 535 | """ |
| 536 | Adds a prefix to the subnet_name with a number in case the indicated name is repeated |
| 537 | Checks subnets with the indicated name (without suffix) and adds a suffix with a number |
| 538 | """ |
| gallardo | dd82175 | 2022-01-17 17:37:51 +0000 | [diff] [blame] | 539 | all_subnets = self.conn_vnet.subnets.list( |
| 540 | self.vnet_resource_group or self.resource_group, self.vnet_name |
| 541 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 542 | # Filter to subnets starting with the indicated name |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 543 | subnets = list( |
| 544 | filter(lambda subnet: (subnet.name.startswith(subnet_name)), all_subnets) |
| 545 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 546 | net_names = [str(subnet.name) for subnet in subnets] |
| 547 | |
| 548 | # get the name with the first not used suffix |
| 549 | name_suffix = 0 |
| tierno | b569e4b | 2019-11-21 16:10:32 +0000 | [diff] [blame] | 550 | # name = subnet_name + "-" + str(name_suffix) |
| 551 | name = subnet_name # first subnet created will have no prefix |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 552 | while name in net_names: |
| 553 | name_suffix += 1 |
| 554 | name = subnet_name + "-" + str(name_suffix) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 555 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 556 | return name |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 557 | |
| garciadeblas | 66af694 | 2021-10-26 18:38:49 +0200 | [diff] [blame] | 558 | def _create_nic(self, net, nic_name, region=None, static_ip=None, created_items={}): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 559 | self.logger.debug("create nic name %s, net_name %s", nic_name, net) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 560 | self._reload_connection() |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 561 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 562 | subnet_id = net["net_id"] |
| sousaedu | 89278b8 | 2021-11-19 01:01:32 +0000 | [diff] [blame] | 563 | location = self.region or self._get_location_from_resource_group( |
| 564 | self.resource_group |
| 565 | ) |
| gallardo | dd82175 | 2022-01-17 17:37:51 +0000 | [diff] [blame] | 566 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 567 | try: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 568 | net_ifz = {"location": location} |
| 569 | net_ip_config = { |
| 570 | "name": nic_name + "-ipconfiguration", |
| 571 | "subnet": {"id": subnet_id}, |
| 572 | } |
| lloretgalleg | bfc28b0 | 2019-11-21 09:31:16 +0100 | [diff] [blame] | 573 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 574 | if static_ip: |
| 575 | net_ip_config["privateIPAddress"] = static_ip |
| 576 | net_ip_config["privateIPAllocationMethod"] = "Static" |
| 577 | |
| 578 | net_ifz["ip_configurations"] = [net_ip_config] |
| 579 | mac_address = net.get("mac_address") |
| 580 | |
| 581 | if mac_address: |
| 582 | net_ifz["mac_address"] = mac_address |
| 583 | |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 584 | async_nic_creation = ( |
| 585 | self.conn_vnet.network_interfaces.begin_create_or_update( |
| 586 | self.resource_group, nic_name, net_ifz |
| 587 | ) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 588 | ) |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 589 | nic_data = async_nic_creation.result() |
| 590 | created_items[nic_data.id] = True |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 591 | self.logger.debug("created nic name %s", nic_name) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 592 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 593 | public_ip = net.get("floating_ip") |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 594 | if public_ip: |
| 595 | public_ip_address_params = { |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 596 | "location": location, |
| 597 | "public_ip_allocation_method": "Dynamic", |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 598 | } |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 599 | public_ip_name = nic_name + "-public-ip" |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 600 | async_public_ip = ( |
| 601 | self.conn_vnet.public_ip_addresses.begin_create_or_update( |
| 602 | self.resource_group, public_ip_name, public_ip_address_params |
| 603 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 604 | ) |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 605 | public_ip = async_public_ip.result() |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 606 | self.logger.debug("created public IP: {}".format(public_ip)) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 607 | |
| tierno | b569e4b | 2019-11-21 16:10:32 +0000 | [diff] [blame] | 608 | # Associate NIC to Public IP |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 609 | nic_data = self.conn_vnet.network_interfaces.get( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 610 | self.resource_group, nic_name |
| 611 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 612 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 613 | nic_data.ip_configurations[0].public_ip_address = public_ip |
| 614 | created_items[public_ip.id] = True |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 615 | |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 616 | self.conn_vnet.network_interfaces.begin_create_or_update( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 617 | self.resource_group, nic_name, nic_data |
| 618 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 619 | |
| 620 | except Exception as e: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 621 | self._format_vimconn_exception(e) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 622 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 623 | return nic_data, created_items |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 624 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 625 | def new_flavor(self, flavor_data): |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 626 | """ |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 627 | It is not allowed to create new flavors in Azure, must always use an existing one |
| 628 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 629 | raise vimconn.VimConnAuthException( |
| 630 | "It is not possible to create new flavors in AZURE" |
| 631 | ) |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 632 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 633 | def new_tenant(self, tenant_name, tenant_description): |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 634 | """ |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 635 | It is not allowed to create new tenants in azure |
| 636 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 637 | raise vimconn.VimConnAuthException( |
| 638 | "It is not possible to create a TENANT in AZURE" |
| 639 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 640 | |
| 641 | def new_image(self, image_dict): |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 642 | """ |
| 643 | It is not allowed to create new images in Azure, must always use an existing one |
| 644 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 645 | raise vimconn.VimConnAuthException( |
| 646 | "It is not possible to create new images in AZURE" |
| 647 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 648 | |
| 649 | def get_image_id_from_path(self, path): |
| 650 | """Get the image id from image path in the VIM database. |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 651 | Returns the image_id or raises a vimconnNotFoundException |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 652 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 653 | raise vimconn.VimConnAuthException( |
| 654 | "It is not possible to obtain image from path in AZURE" |
| 655 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 656 | |
| 657 | def get_image_list(self, filter_dict={}): |
| 658 | """Obtain tenant images from VIM |
| 659 | Filter_dict can be: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 660 | name: image name with the format: publisher:offer:sku:version |
| 661 | If some part of the name is provide ex: publisher:offer it will search all availables skus and version |
| 662 | for the provided publisher and offer |
| 663 | id: image uuid, currently not supported for azure |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 664 | Returns the image list of dictionaries: |
| 665 | [{<the fields at Filter_dict plus some VIM specific>}, ...] |
| 666 | List can be empty |
| 667 | """ |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 668 | self.logger.debug("get_image_list filter {}".format(filter_dict)) |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 669 | |
| 670 | self._reload_connection() |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 671 | try: |
| 672 | image_list = [] |
| 673 | if filter_dict.get("name"): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 674 | # name will have the format "publisher:offer:sku:version" |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 675 | # publisher is required, offer sku and version will be searched if not provided |
| 676 | params = filter_dict["name"].split(":") |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 677 | publisher = params[0] |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 678 | if publisher: |
| 679 | # obtain offer list |
| 680 | offer_list = self._get_offer_list(params, publisher) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 681 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 682 | for offer in offer_list: |
| 683 | # obtain skus |
| 684 | sku_list = self._get_sku_list(params, publisher, offer) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 685 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 686 | for sku in sku_list: |
| 687 | # if version is defined get directly version, else list images |
| 688 | if len(params) == 4 and params[3]: |
| 689 | version = params[3] |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 690 | if version == "latest": |
| 691 | image_list = self._get_sku_image_list( |
| 692 | publisher, offer, sku |
| 693 | ) |
| 694 | image_list = [image_list[-1]] |
| 695 | else: |
| 696 | image_list = self._get_version_image_list( |
| 697 | publisher, offer, sku, version |
| 698 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 699 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 700 | image_list = self._get_sku_image_list( |
| 701 | publisher, offer, sku |
| 702 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 703 | else: |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 704 | raise vimconn.VimConnAuthException( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 705 | "List images in Azure must include name param with at least publisher" |
| 706 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 707 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 708 | raise vimconn.VimConnAuthException( |
| 709 | "List images in Azure must include name param with at" |
| 710 | " least publisher" |
| 711 | ) |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 712 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 713 | return image_list |
| 714 | except Exception as e: |
| 715 | self._format_vimconn_exception(e) |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 716 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 717 | def _get_offer_list(self, params, publisher): |
| 718 | """ |
| 719 | Helper method to obtain offer list for defined publisher |
| 720 | """ |
| 721 | if len(params) >= 2 and params[1]: |
| 722 | return [params[1]] |
| 723 | else: |
| 724 | try: |
| 725 | # get list of offers from azure |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 726 | result_offers = self.conn_compute.virtual_machine_images.list_offers( |
| 727 | self.region, publisher |
| 728 | ) |
| 729 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 730 | return [offer.name for offer in result_offers] |
| 731 | except CloudError as e: |
| 732 | # azure raises CloudError when not found |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 733 | self.logger.info( |
| 734 | "error listing offers for publisher {}, Error: {}".format( |
| 735 | publisher, e |
| 736 | ) |
| 737 | ) |
| 738 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 739 | return [] |
| 740 | |
| 741 | def _get_sku_list(self, params, publisher, offer): |
| 742 | """ |
| 743 | Helper method to obtain sku list for defined publisher and offer |
| 744 | """ |
| 745 | if len(params) >= 3 and params[2]: |
| 746 | return [params[2]] |
| 747 | else: |
| 748 | try: |
| 749 | # get list of skus from azure |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 750 | result_skus = self.conn_compute.virtual_machine_images.list_skus( |
| 751 | self.region, publisher, offer |
| 752 | ) |
| 753 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 754 | return [sku.name for sku in result_skus] |
| 755 | except CloudError as e: |
| 756 | # azure raises CloudError when not found |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 757 | self.logger.info( |
| 758 | "error listing skus for publisher {}, offer {}, Error: {}".format( |
| 759 | publisher, offer, e |
| 760 | ) |
| 761 | ) |
| 762 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 763 | return [] |
| 764 | |
| 765 | def _get_sku_image_list(self, publisher, offer, sku): |
| 766 | """ |
| 767 | Helper method to obtain image list for publisher, offer and sku |
| 768 | """ |
| 769 | image_list = [] |
| 770 | try: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 771 | result_images = self.conn_compute.virtual_machine_images.list( |
| 772 | self.region, publisher, offer, sku |
| 773 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 774 | for result_image in result_images: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 775 | image_list.append( |
| 776 | { |
| 777 | "id": str(result_image.id), |
| 778 | "name": ":".join([publisher, offer, sku, result_image.name]), |
| 779 | } |
| 780 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 781 | except CloudError as e: |
| 782 | self.logger.info( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 783 | "error listing skus for publisher {}, offer {}, Error: {}".format( |
| 784 | publisher, offer, e |
| 785 | ) |
| 786 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 787 | image_list = [] |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 788 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 789 | return image_list |
| 790 | |
| 791 | def _get_version_image_list(self, publisher, offer, sku, version): |
| 792 | image_list = [] |
| 793 | try: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 794 | result_image = self.conn_compute.virtual_machine_images.get( |
| 795 | self.region, publisher, offer, sku, version |
| 796 | ) |
| 797 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 798 | if result_image: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 799 | image_list.append( |
| 800 | { |
| 801 | "id": str(result_image.id), |
| 802 | "name": ":".join([publisher, offer, sku, version]), |
| 803 | } |
| 804 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 805 | except CloudError as e: |
| 806 | # azure gives CloudError when not found |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 807 | self.logger.info( |
| 808 | "error listing images for publisher {}, offer {}, sku {}, version {} Error: {}".format( |
| 809 | publisher, offer, sku, version, e |
| 810 | ) |
| 811 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 812 | image_list = [] |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 813 | |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 814 | return image_list |
| 815 | |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 816 | def get_network_list(self, filter_dict={}): |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 817 | """Obtain tenant networks of VIM |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 818 | Filter_dict can be: |
| 819 | name: network name |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 820 | id: network id |
| 821 | shared: boolean, not implemented in Azure |
| 822 | tenant_id: tenant, not used in Azure, all networks same tenants |
| 823 | admin_state_up: boolean, not implemented in Azure |
| 824 | status: 'ACTIVE', not implemented in Azure # |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 825 | Returns the network list of dictionaries |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 826 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 827 | # self.logger.debug("getting network list for vim, filter %s", filter_dict) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 828 | try: |
| 829 | self._reload_connection() |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 830 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 831 | vnet = self.conn_vnet.virtual_networks.get( |
| gallardo | dd82175 | 2022-01-17 17:37:51 +0000 | [diff] [blame] | 832 | self.vnet_resource_group or self.resource_group, self.vnet_name |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 833 | ) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 834 | subnet_list = [] |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 835 | |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 836 | for subnet in vnet.subnets: |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 837 | if filter_dict: |
| 838 | if filter_dict.get("id") and str(subnet.id) != filter_dict["id"]: |
| 839 | continue |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 840 | |
| 841 | if ( |
| 842 | filter_dict.get("name") |
| 843 | and str(subnet.name) != filter_dict["name"] |
| 844 | ): |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 845 | continue |
| 846 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 847 | name = self._get_resource_name_from_resource_id(subnet.id) |
| 848 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 849 | subnet_list.append( |
| 850 | { |
| 851 | "id": str(subnet.id), |
| 852 | "name": name, |
| 853 | "status": self.provision_state2osm[subnet.provisioning_state], |
| 854 | "cidr_block": str(subnet.address_prefix), |
| 855 | "type": "bridge", |
| 856 | "shared": False, |
| 857 | } |
| 858 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 859 | |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 860 | return subnet_list |
| 861 | except Exception as e: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 862 | self._format_vimconn_exception(e) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 863 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 864 | def new_vminstance( |
| 865 | self, |
| 866 | name, |
| 867 | description, |
| 868 | start, |
| 869 | image_id, |
| 870 | flavor_id, |
| Alexis Romero | b70f4ed | 2022-03-11 18:00:49 +0100 | [diff] [blame] | 871 | affinity_group_list, |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 872 | net_list, |
| 873 | cloud_config=None, |
| 874 | disk_list=None, |
| 875 | availability_zone_index=None, |
| 876 | availability_zone_list=None, |
| 877 | ): |
| 878 | self.logger.debug( |
| 879 | "new vm instance name: %s, image_id: %s, flavor_id: %s, net_list: %s, cloud_config: %s, " |
| 880 | "disk_list: %s, availability_zone_index: %s, availability_zone_list: %s", |
| 881 | name, |
| 882 | image_id, |
| 883 | flavor_id, |
| 884 | net_list, |
| 885 | cloud_config, |
| 886 | disk_list, |
| 887 | availability_zone_index, |
| 888 | availability_zone_list, |
| 889 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 890 | self._reload_connection() |
| 891 | |
| 892 | # Validate input data is valid |
| 893 | # The virtual machine name must have less or 64 characters and it can not have the following |
| 894 | # characters: (~ ! @ # $ % ^ & * ( ) = + _ [ ] { } \ | ; : ' " , < > / ?.) |
| 895 | vm_name = self._check_vm_name(name) |
| 896 | # Obtain vm unused name |
| 897 | vm_name = self._get_unused_vm_name(vm_name) |
| 898 | |
| 899 | # At least one network must be provided |
| 900 | if not net_list: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 901 | raise vimconn.VimConnException( |
| 902 | "At least one net must be provided to create a new VM" |
| 903 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 904 | |
| 905 | # image_id are several fields of the image_id |
| 906 | image_reference = self._get_image_reference(image_id) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 907 | |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 908 | try: |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 909 | virtual_machine = None |
| 910 | created_items = {} |
| 911 | |
| 912 | # Create nics for each subnet |
| 913 | self._check_subnets_for_vm(net_list) |
| 914 | vm_nics = [] |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 915 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 916 | for idx, net in enumerate(net_list): |
| 917 | # Fault with subnet_id |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 918 | # subnet_id=net["subnet_id"] |
| 919 | # subnet_id=net["net_id"] |
| 920 | nic_name = vm_name + "-nic-" + str(idx) |
| 921 | vm_nic, nic_items = self._create_nic( |
| garciadeblas | 66af694 | 2021-10-26 18:38:49 +0200 | [diff] [blame] | 922 | net, nic_name, self.region, net.get("ip_address"), created_items |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 923 | ) |
| 924 | vm_nics.append({"id": str(vm_nic.id)}) |
| 925 | net["vim_id"] = vm_nic.id |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 926 | |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 927 | vm_parameters = { |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 928 | "location": self.region, |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 929 | "os_profile": self._build_os_profile(vm_name, cloud_config, image_id), |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 930 | "hardware_profile": {"vm_size": flavor_id}, |
| 931 | "storage_profile": {"image_reference": image_reference}, |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 932 | } |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 933 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 934 | # If the machine has several networks one must be marked as primary |
| 935 | # As it is not indicated in the interface the first interface will be marked as primary |
| 936 | if len(vm_nics) > 1: |
| 937 | for idx, vm_nic in enumerate(vm_nics): |
| 938 | if idx == 0: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 939 | vm_nics[0]["Primary"] = True |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 940 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 941 | vm_nics[idx]["Primary"] = False |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 942 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 943 | vm_parameters["network_profile"] = {"network_interfaces": vm_nics} |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 944 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 945 | # Obtain zone information |
| 946 | vm_zone = self._get_vm_zone(availability_zone_index, availability_zone_list) |
| 947 | if vm_zone: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 948 | vm_parameters["zones"] = [vm_zone] |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 949 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 950 | self.logger.debug("create vm name: %s", vm_name) |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 951 | creation_result = self.conn_compute.virtual_machines.begin_create_or_update( |
| 952 | self.resource_group, vm_name, vm_parameters, polling=False |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 953 | ) |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 954 | self.logger.debug("obtained creation result: %s", creation_result) |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 955 | virtual_machine = creation_result.result() |
| lloretgalleg | bfc28b0 | 2019-11-21 09:31:16 +0100 | [diff] [blame] | 956 | self.logger.debug("created vm name: %s", vm_name) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 957 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 958 | return virtual_machine.id, created_items |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 959 | |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 960 | except Exception as e: |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 961 | # Rollback vm creacion |
| 962 | vm_id = None |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 963 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 964 | if virtual_machine: |
| 965 | vm_id = virtual_machine.id |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 966 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 967 | try: |
| 968 | self.logger.debug("exception creating vm try to rollback") |
| 969 | self.delete_vminstance(vm_id, created_items) |
| 970 | except Exception as e2: |
| 971 | self.logger.error("new_vminstance rollback fail {}".format(e2)) |
| 972 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 973 | self.logger.debug("Exception creating new vminstance: %s", e, exc_info=True) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 974 | self._format_vimconn_exception(e) |
| 975 | |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 976 | def _build_os_profile(self, vm_name, cloud_config, image_id): |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 977 | # initial os_profile |
| 978 | os_profile = {"computer_name": vm_name} |
| 979 | |
| 980 | # for azure os_profile admin_username is required |
| 981 | if cloud_config and cloud_config.get("users"): |
| 982 | admin_username = cloud_config.get("users")[0].get( |
| 983 | "name", self._get_default_admin_user(image_id) |
| 984 | ) |
| 985 | else: |
| 986 | admin_username = self._get_default_admin_user(image_id) |
| 987 | os_profile["admin_username"] = admin_username |
| 988 | |
| 989 | # if there is a cloud-init load it |
| 990 | if cloud_config: |
| 991 | _, userdata = self._create_user_data(cloud_config) |
| 992 | custom_data = base64.b64encode(userdata.encode("utf-8")).decode("latin-1") |
| 993 | os_profile["custom_data"] = custom_data |
| 994 | |
| 995 | # either password of ssh-keys are required |
| 996 | # we will always use ssh-keys, in case it is not available we will generate it |
| 997 | if cloud_config and cloud_config.get("key-pairs"): |
| 998 | key_data = cloud_config.get("key-pairs")[0] |
| 999 | else: |
| 1000 | _, key_data = self._generate_keys() |
| 1001 | |
| 1002 | os_profile["linux_configuration"] = { |
| 1003 | "ssh": { |
| 1004 | "public_keys": [ |
| 1005 | { |
| 1006 | "path": "/home/{}/.ssh/authorized_keys".format(admin_username), |
| 1007 | "key_data": key_data, |
| 1008 | } |
| 1009 | ] |
| 1010 | }, |
| 1011 | } |
| 1012 | |
| 1013 | return os_profile |
| 1014 | |
| 1015 | def _generate_keys(self): |
| 1016 | """Method used to generate a pair of private/public keys. |
| 1017 | This method is used because to create a vm in Azure we always need a key or a password |
| 1018 | In some cases we may have a password in a cloud-init file but it may not be available |
| 1019 | """ |
| 1020 | key = rsa.generate_private_key( |
| 1021 | backend=crypto_default_backend(), public_exponent=65537, key_size=2048 |
| 1022 | ) |
| 1023 | private_key = key.private_bytes( |
| 1024 | crypto_serialization.Encoding.PEM, |
| 1025 | crypto_serialization.PrivateFormat.PKCS8, |
| 1026 | crypto_serialization.NoEncryption(), |
| 1027 | ) |
| 1028 | public_key = key.public_key().public_bytes( |
| 1029 | crypto_serialization.Encoding.OpenSSH, |
| 1030 | crypto_serialization.PublicFormat.OpenSSH, |
| 1031 | ) |
| 1032 | private_key = private_key.decode("utf8") |
| 1033 | # Change first line because Paramiko needs a explicit start with 'BEGIN RSA PRIVATE KEY' |
| 1034 | i = private_key.find("\n") |
| 1035 | private_key = "-----BEGIN RSA PRIVATE KEY-----" + private_key[i:] |
| 1036 | public_key = public_key.decode("utf8") |
| 1037 | |
| 1038 | return private_key, public_key |
| 1039 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1040 | def _get_unused_vm_name(self, vm_name): |
| 1041 | """ |
| 1042 | Checks the vm name and in case it is used adds a suffix to the name to allow creation |
| 1043 | :return: |
| 1044 | """ |
| 1045 | all_vms = self.conn_compute.virtual_machines.list(self.resource_group) |
| 1046 | # Filter to vms starting with the indicated name |
| 1047 | vms = list(filter(lambda vm: (vm.name.startswith(vm_name)), all_vms)) |
| 1048 | vm_names = [str(vm.name) for vm in vms] |
| 1049 | |
| 1050 | # get the name with the first not used suffix |
| 1051 | name_suffix = 0 |
| 1052 | # name = subnet_name + "-" + str(name_suffix) |
| 1053 | name = vm_name # first subnet created will have no prefix |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1054 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1055 | while name in vm_names: |
| 1056 | name_suffix += 1 |
| 1057 | name = vm_name + "-" + str(name_suffix) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1058 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1059 | return name |
| 1060 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1061 | def _get_vm_zone(self, availability_zone_index, availability_zone_list): |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1062 | if availability_zone_index is None: |
| 1063 | return None |
| 1064 | |
| 1065 | vim_availability_zones = self._get_azure_availability_zones() |
| 1066 | # check if VIM offer enough availability zones describe in the VNFD |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1067 | if vim_availability_zones and len(availability_zone_list) <= len( |
| 1068 | vim_availability_zones |
| 1069 | ): |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1070 | # check if all the names of NFV AV match VIM AV names |
| 1071 | match_by_index = False |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1072 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1073 | if not availability_zone_list: |
| 1074 | match_by_index = True |
| 1075 | else: |
| 1076 | for av in availability_zone_list: |
| 1077 | if av not in vim_availability_zones: |
| 1078 | match_by_index = True |
| 1079 | break |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1080 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1081 | if match_by_index: |
| 1082 | return vim_availability_zones[availability_zone_index] |
| 1083 | else: |
| 1084 | return availability_zone_list[availability_zone_index] |
| 1085 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1086 | raise vimconn.VimConnConflictException( |
| 1087 | "No enough availability zones at VIM for this deployment" |
| 1088 | ) |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1089 | |
| 1090 | def _get_azure_availability_zones(self): |
| 1091 | return self.AZURE_ZONES |
| 1092 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1093 | def _get_image_reference(self, image_id): |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1094 | try: |
| 1095 | # The data input format example: |
| 1096 | # /Subscriptions/ca3d18ab-d373-4afb-a5d6-7c44f098d16a/Providers/Microsoft.Compute/Locations/westeurope/ |
| 1097 | # Publishers/Canonical/ArtifactTypes/VMImage/ |
| 1098 | # Offers/UbuntuServer/ |
| 1099 | # Skus/18.04-LTS/ |
| 1100 | # Versions/18.04.201809110 |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1101 | publisher = str(image_id.split("/")[8]) |
| 1102 | offer = str(image_id.split("/")[12]) |
| 1103 | sku = str(image_id.split("/")[14]) |
| 1104 | version = str(image_id.split("/")[16]) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1105 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1106 | return { |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1107 | "publisher": publisher, |
| 1108 | "offer": offer, |
| 1109 | "sku": sku, |
| 1110 | "version": version, |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1111 | } |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 1112 | except Exception: |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 1113 | raise vimconn.VimConnException( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1114 | "Unable to get image_reference from invalid image_id format: '{}'".format( |
| 1115 | image_id |
| 1116 | ) |
| 1117 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1118 | |
| 1119 | # Azure VM names can not have some special characters |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1120 | def _check_vm_name(self, vm_name): |
| 1121 | """ |
| 1122 | Checks vm name, in case the vm has not allowed characters they are removed, not error raised |
| 1123 | """ |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1124 | chars_not_allowed_list = "~!@#$%^&*()=+_[]{}|;:<>/?." |
| 1125 | |
| 1126 | # First: the VM name max length is 64 characters |
| 1127 | vm_name_aux = vm_name[:64] |
| 1128 | |
| 1129 | # Second: replace not allowed characters |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1130 | for elem in chars_not_allowed_list: |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1131 | # Check if string is in the main string |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1132 | if elem in vm_name_aux: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1133 | # self.logger.debug("Dentro del IF") |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1134 | # Replace the string |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1135 | vm_name_aux = vm_name_aux.replace(elem, "-") |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1136 | |
| 1137 | return vm_name_aux |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1138 | |
| 1139 | def get_flavor_id_from_data(self, flavor_dict): |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1140 | self.logger.debug("getting flavor id from data, flavor_dict: %s", flavor_dict) |
| 1141 | filter_dict = flavor_dict or {} |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1142 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1143 | try: |
| 1144 | self._reload_connection() |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1145 | vm_sizes_list = [ |
| garciadeblas | c878ac4 | 2021-05-27 12:00:30 +0200 | [diff] [blame] | 1146 | vm_size.as_dict() |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1147 | for vm_size in self.conn_compute.resource_skus.list( |
| aguilard | b1aa422 | 2023-10-09 14:05:53 +0000 | [diff] [blame] | 1148 | filter="location eq '{}'".format(self.region) |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1149 | ) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1150 | ] |
| tierno | 30d0d6d | 2019-05-27 08:14:01 +0000 | [diff] [blame] | 1151 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1152 | cpus = filter_dict.get("vcpus") or 0 |
| 1153 | memMB = filter_dict.get("ram") or 0 |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1154 | numberInterfaces = len(filter_dict.get("interfaces", [])) or 0 |
| tierno | 30d0d6d | 2019-05-27 08:14:01 +0000 | [diff] [blame] | 1155 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1156 | # Filter |
| garciadeblas | c878ac4 | 2021-05-27 12:00:30 +0200 | [diff] [blame] | 1157 | filtered_sizes = [] |
| 1158 | for size in vm_sizes_list: |
| 1159 | if size["resource_type"] == "virtualMachines": |
| 1160 | size_cpus = int( |
| 1161 | self._find_in_capabilities(size["capabilities"], "vCPUs") |
| 1162 | ) |
| 1163 | size_memory = float( |
| 1164 | self._find_in_capabilities(size["capabilities"], "MemoryGB") |
| 1165 | ) |
| 1166 | size_interfaces = self._find_in_capabilities( |
| 1167 | size["capabilities"], "MaxNetworkInterfaces" |
| 1168 | ) |
| 1169 | if size_interfaces: |
| 1170 | size_interfaces = int(size_interfaces) |
| 1171 | else: |
| 1172 | self.logger.debug( |
| 1173 | "Flavor with no defined MaxNetworkInterfaces: {}".format( |
| 1174 | size["name"] |
| 1175 | ) |
| 1176 | ) |
| 1177 | continue |
| 1178 | if ( |
| 1179 | size_cpus >= cpus |
| 1180 | and size_memory >= memMB / 1024 |
| 1181 | and size_interfaces >= numberInterfaces |
| 1182 | ): |
| 1183 | if self._config.get("flavors_pattern"): |
| 1184 | if re.search( |
| 1185 | self._config.get("flavors_pattern"), size["name"] |
| 1186 | ): |
| 1187 | new_size = { |
| 1188 | e["name"]: e["value"] for e in size["capabilities"] |
| 1189 | } |
| 1190 | new_size["name"] = size["name"] |
| 1191 | filtered_sizes.append(new_size) |
| 1192 | else: |
| 1193 | new_size = { |
| 1194 | e["name"]: e["value"] for e in size["capabilities"] |
| 1195 | } |
| 1196 | new_size["name"] = size["name"] |
| 1197 | filtered_sizes.append(new_size) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1198 | |
| 1199 | # Sort |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1200 | listedFilteredSizes = sorted( |
| 1201 | filtered_sizes, |
| 1202 | key=lambda k: ( |
| garciadeblas | c878ac4 | 2021-05-27 12:00:30 +0200 | [diff] [blame] | 1203 | int(k["vCPUs"]), |
| 1204 | float(k["MemoryGB"]), |
| 1205 | int(k["MaxNetworkInterfaces"]), |
| 1206 | int(k["MaxResourceVolumeMB"]), |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1207 | ), |
| 1208 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1209 | |
| 1210 | if listedFilteredSizes: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1211 | return listedFilteredSizes[0]["name"] |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1212 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1213 | raise vimconn.VimConnNotFoundException( |
| 1214 | "Cannot find any flavor matching '{}'".format(str(flavor_dict)) |
| 1215 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1216 | except Exception as e: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1217 | self._format_vimconn_exception(e) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1218 | |
| 1219 | def _get_flavor_id_from_flavor_name(self, flavor_name): |
| tierno | b569e4b | 2019-11-21 16:10:32 +0000 | [diff] [blame] | 1220 | # self.logger.debug("getting flavor id from flavor name {}".format(flavor_name)) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1221 | try: |
| 1222 | self._reload_connection() |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1223 | vm_sizes_list = [ |
| garciadeblas | c878ac4 | 2021-05-27 12:00:30 +0200 | [diff] [blame] | 1224 | vm_size.as_dict() |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1225 | for vm_size in self.conn_compute.resource_skus.list( |
| aguilard | b1aa422 | 2023-10-09 14:05:53 +0000 | [diff] [blame] | 1226 | filter="location eq '{}'".format(self.region) |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1227 | ) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1228 | ] |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1229 | |
| 1230 | output_flavor = None |
| 1231 | for size in vm_sizes_list: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1232 | if size["name"] == flavor_name: |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1233 | output_flavor = size |
| 1234 | |
| tierno | b569e4b | 2019-11-21 16:10:32 +0000 | [diff] [blame] | 1235 | # None is returned if not found anything |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1236 | return output_flavor |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1237 | except Exception as e: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1238 | self._format_vimconn_exception(e) |
| tierno | 30d0d6d | 2019-05-27 08:14:01 +0000 | [diff] [blame] | 1239 | |
| 1240 | def check_vim_connectivity(self): |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1241 | try: |
| 1242 | self._reload_connection() |
| tierno | 30d0d6d | 2019-05-27 08:14:01 +0000 | [diff] [blame] | 1243 | return True |
| 1244 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1245 | raise vimconn.VimConnException( |
| 1246 | "Connectivity issue with Azure API: {}".format(e) |
| 1247 | ) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1248 | |
| 1249 | def get_network(self, net_id): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1250 | # self.logger.debug("get network id: {}".format(net_id)) |
| tierno | b569e4b | 2019-11-21 16:10:32 +0000 | [diff] [blame] | 1251 | # res_name = self._get_resource_name_from_resource_id(net_id) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1252 | self._reload_connection() |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1253 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1254 | filter_dict = {"name": net_id} |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1255 | network_list = self.get_network_list(filter_dict) |
| 1256 | |
| 1257 | if not network_list: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1258 | raise vimconn.VimConnNotFoundException( |
| 1259 | "network '{}' not found".format(net_id) |
| 1260 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1261 | else: |
| 1262 | return network_list[0] |
| 1263 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1264 | def delete_network(self, net_id, created_items=None): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1265 | self.logger.debug( |
| gallardo | dd82175 | 2022-01-17 17:37:51 +0000 | [diff] [blame] | 1266 | "deleting network {} - {}".format( |
| 1267 | self.vnet_resource_group or self.resource_group, net_id |
| 1268 | ) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1269 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1270 | |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1271 | self._reload_connection() |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1272 | res_name = self._get_resource_name_from_resource_id(net_id) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1273 | |
| 1274 | try: |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1275 | # Obtain subnets ant try to delete nic first |
| 1276 | subnet = self.conn_vnet.subnets.get( |
| gallardo | dd82175 | 2022-01-17 17:37:51 +0000 | [diff] [blame] | 1277 | self.vnet_resource_group or self.resource_group, |
| 1278 | self.vnet_name, |
| 1279 | res_name, |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1280 | ) |
| 1281 | if not subnet: |
| 1282 | raise vimconn.VimConnNotFoundException( |
| 1283 | "network '{}' not found".format(net_id) |
| 1284 | ) |
| 1285 | |
| 1286 | # TODO - for a quick-fix delete nics sequentially but should not wait |
| 1287 | # for each in turn |
| 1288 | if subnet.ip_configurations: |
| 1289 | for ip_configuration in subnet.ip_configurations: |
| 1290 | # obtain nic_name from ip_configuration |
| 1291 | parsed_id = azure_tools.parse_resource_id(ip_configuration.id) |
| 1292 | nic_name = parsed_id["name"] |
| 1293 | self.delete_inuse_nic(nic_name) |
| 1294 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1295 | # Subnet API fails (CloudError: Azure Error: ResourceNotFound) |
| 1296 | # Put the initial virtual_network API |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1297 | async_delete = self.conn_vnet.subnets.begin_delete( |
| gallardo | dd82175 | 2022-01-17 17:37:51 +0000 | [diff] [blame] | 1298 | self.vnet_resource_group or self.resource_group, |
| 1299 | self.vnet_name, |
| 1300 | res_name, |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1301 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1302 | async_delete.wait() |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1303 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1304 | return net_id |
| 1305 | |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1306 | except ResourceNotFoundError: |
| 1307 | raise vimconn.VimConnNotFoundException( |
| 1308 | "network '{}' not found".format(net_id) |
| 1309 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1310 | except CloudError as e: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1311 | if e.error.error and "notfound" in e.error.error.lower(): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1312 | raise vimconn.VimConnNotFoundException( |
| 1313 | "network '{}' not found".format(net_id) |
| 1314 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1315 | else: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1316 | self._format_vimconn_exception(e) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1317 | except Exception as e: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1318 | self._format_vimconn_exception(e) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1319 | |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1320 | def delete_inuse_nic(self, nic_name): |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1321 | # Obtain nic data |
| 1322 | nic_data = self.conn_vnet.network_interfaces.get(self.resource_group, nic_name) |
| 1323 | |
| 1324 | # Obtain vm associated to nic in case it exists |
| 1325 | if nic_data.virtual_machine: |
| 1326 | vm_name = azure_tools.parse_resource_id(nic_data.virtual_machine.id)["name"] |
| 1327 | self.logger.debug("vm_name: {}".format(vm_name)) |
| 1328 | virtual_machine = self.conn_compute.virtual_machines.get( |
| 1329 | self.resource_group, vm_name |
| 1330 | ) |
| 1331 | self.logger.debug("obtained vm") |
| 1332 | |
| 1333 | # Deattach nic from vm if it has netwolk machines attached |
| 1334 | network_interfaces = virtual_machine.network_profile.network_interfaces |
| 1335 | network_interfaces[:] = [ |
| 1336 | interface |
| 1337 | for interface in network_interfaces |
| 1338 | if self._get_resource_name_from_resource_id(interface.id) != nic_name |
| 1339 | ] |
| 1340 | |
| 1341 | # TODO - check if there is a public ip to delete and delete it |
| 1342 | if network_interfaces: |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1343 | # Deallocate the vm |
| 1344 | async_vm_deallocate = ( |
| 1345 | self.conn_compute.virtual_machines.begin_deallocate( |
| 1346 | self.resource_group, vm_name |
| 1347 | ) |
| 1348 | ) |
| 1349 | self.logger.debug("deallocating vm") |
| 1350 | async_vm_deallocate.wait() |
| 1351 | self.logger.debug("vm deallocated") |
| 1352 | |
| 1353 | async_vm_update = ( |
| 1354 | self.conn_compute.virtual_machines.begin_create_or_update( |
| 1355 | self.resource_group, vm_name, virtual_machine |
| 1356 | ) |
| 1357 | ) |
| 1358 | virtual_machine = async_vm_update.result() |
| 1359 | self.logger.debug("nic removed from interface") |
| 1360 | |
| 1361 | else: |
| 1362 | self.logger.debug("There are no interfaces left, delete vm") |
| 1363 | self.delete_vminstance(virtual_machine.id) |
| 1364 | self.logger.debug("Delete vm") |
| 1365 | |
| 1366 | # Delete nic |
| 1367 | self.logger.debug("delete NIC name: %s", nic_name) |
| 1368 | nic_delete = self.conn_vnet.network_interfaces.begin_delete( |
| 1369 | self.resource_group, nic_name |
| 1370 | ) |
| 1371 | nic_delete.wait() |
| 1372 | self.logger.debug("deleted NIC name: %s", nic_name) |
| 1373 | |
| garciadeblas | 89598d4 | 2022-06-30 13:57:43 +0200 | [diff] [blame] | 1374 | def delete_vminstance(self, vm_id, created_items=None, volumes_to_hold=None): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1375 | """Deletes a vm instance from the vim.""" |
| 1376 | self.logger.debug( |
| 1377 | "deleting VM instance {} - {}".format(self.resource_group, vm_id) |
| 1378 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1379 | self._reload_connection() |
| 1380 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1381 | created_items = created_items or {} |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1382 | try: |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1383 | # Check vm exists, we can call delete_vm to clean created_items |
| 1384 | if vm_id: |
| 1385 | res_name = self._get_resource_name_from_resource_id(vm_id) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1386 | vm = self.conn_compute.virtual_machines.get( |
| 1387 | self.resource_group, res_name |
| 1388 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1389 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1390 | # Shuts down the virtual machine and releases the compute resources |
| 1391 | # vm_stop = self.conn_compute.virtual_machines.power_off(self.resource_group, resName) |
| 1392 | # vm_stop.wait() |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1393 | |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1394 | vm_delete = self.conn_compute.virtual_machines.begin_delete( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1395 | self.resource_group, res_name |
| 1396 | ) |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1397 | vm_delete.wait() |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1398 | self.logger.debug("deleted VM name: %s", res_name) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1399 | |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1400 | # Delete OS Disk, check if exists, in case of error creating |
| 1401 | # it may not be fully created |
| 1402 | if vm.storage_profile.os_disk: |
| 1403 | os_disk_name = vm.storage_profile.os_disk.name |
| 1404 | self.logger.debug("delete OS DISK: %s", os_disk_name) |
| 1405 | async_disk_delete = self.conn_compute.disks.begin_delete( |
| 1406 | self.resource_group, os_disk_name |
| 1407 | ) |
| 1408 | async_disk_delete.wait() |
| 1409 | # os disks are created always with the machine |
| 1410 | self.logger.debug("deleted OS DISK name: %s", os_disk_name) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1411 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1412 | for data_disk in vm.storage_profile.data_disks: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1413 | self.logger.debug("delete data_disk: %s", data_disk.name) |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1414 | async_disk_delete = self.conn_compute.disks.begin_delete( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1415 | self.resource_group, data_disk.name |
| 1416 | ) |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1417 | async_disk_delete.wait() |
| 1418 | self._markdel_created_item(data_disk.managed_disk.id, created_items) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1419 | self.logger.debug("deleted OS DISK name: %s", data_disk.name) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1420 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1421 | # After deleting VM, it is necessary to delete NIC, because if is not deleted delete_network |
| 1422 | # does not work because Azure says that is in use the subnet |
| 1423 | network_interfaces = vm.network_profile.network_interfaces |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1424 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1425 | for network_interface in network_interfaces: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1426 | nic_name = self._get_resource_name_from_resource_id( |
| 1427 | network_interface.id |
| 1428 | ) |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1429 | nic_data = self.conn_vnet.network_interfaces.get( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1430 | self.resource_group, nic_name |
| 1431 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1432 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1433 | public_ip_name = None |
| 1434 | exist_public_ip = nic_data.ip_configurations[0].public_ip_address |
| 1435 | if exist_public_ip: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1436 | public_ip_id = nic_data.ip_configurations[ |
| 1437 | 0 |
| 1438 | ].public_ip_address.id |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1439 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1440 | # Delete public_ip |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1441 | public_ip_name = self._get_resource_name_from_resource_id( |
| 1442 | public_ip_id |
| 1443 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1444 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1445 | # Public ip must be deleted afterwards of nic that is attached |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1446 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1447 | self.logger.debug("delete NIC name: %s", nic_name) |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1448 | nic_delete = self.conn_vnet.network_interfaces.begin_delete( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1449 | self.resource_group, nic_name |
| 1450 | ) |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1451 | nic_delete.wait() |
| 1452 | self._markdel_created_item(network_interface.id, created_items) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1453 | self.logger.debug("deleted NIC name: %s", nic_name) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1454 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1455 | # Delete list of public ips |
| 1456 | if public_ip_name: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1457 | self.logger.debug("delete PUBLIC IP - " + public_ip_name) |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1458 | ip_delete = self.conn_vnet.public_ip_addresses.begin_delete( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1459 | self.resource_group, public_ip_name |
| 1460 | ) |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1461 | ip_delete.wait() |
| 1462 | self._markdel_created_item(public_ip_id, created_items) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1463 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1464 | # Delete created items |
| 1465 | self._delete_created_items(created_items) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1466 | |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1467 | except ResourceNotFoundError: |
| 1468 | raise vimconn.VimConnNotFoundException( |
| 1469 | "No vm instance found '{}'".format(vm_id) |
| 1470 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1471 | except CloudError as e: |
| 1472 | if e.error.error and "notfound" in e.error.error.lower(): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1473 | raise vimconn.VimConnNotFoundException( |
| 1474 | "No vm instance found '{}'".format(vm_id) |
| 1475 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1476 | else: |
| 1477 | self._format_vimconn_exception(e) |
| 1478 | except Exception as e: |
| 1479 | self._format_vimconn_exception(e) |
| 1480 | |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1481 | def _markdel_created_item(self, item_id, created_items): |
| 1482 | if item_id in created_items: |
| 1483 | created_items[item_id] = False |
| 1484 | |
| 1485 | def _delete_created_items(self, created_items): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1486 | """Delete created_items elements that have not been deleted with the virtual machine |
| 1487 | Created_items may not be deleted correctly with the created machine if the |
| 1488 | virtual machine fails creating or in other cases of error |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1489 | """ |
| 1490 | self.logger.debug("Created items: %s", created_items) |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1491 | # TODO - optimize - should not wait until it is deleted |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1492 | # Must delete in order first nics, then public_ips |
| 1493 | # As dictionaries don't preserve order, first get items to be deleted then delete them |
| 1494 | nics_to_delete = [] |
| 1495 | publics_ip_to_delete = [] |
| 1496 | disks_to_delete = [] |
| 1497 | for item_id, v in created_items.items(): |
| 1498 | if not v: # skip already deleted |
| 1499 | continue |
| 1500 | |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 1501 | # self.logger.debug("Must delete item id: %s", item_id) |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1502 | # Obtain type, supported nic, disk or public ip |
| 1503 | parsed_id = azure_tools.parse_resource_id(item_id) |
| 1504 | resource_type = parsed_id.get("resource_type") |
| 1505 | name = parsed_id.get("name") |
| 1506 | |
| 1507 | if resource_type == "networkInterfaces": |
| 1508 | nics_to_delete.append(name) |
| 1509 | elif resource_type == "publicIPAddresses": |
| 1510 | publics_ip_to_delete.append(name) |
| 1511 | elif resource_type == "disks": |
| 1512 | disks_to_delete.append(name) |
| 1513 | |
| 1514 | # Now delete |
| 1515 | for item_name in nics_to_delete: |
| 1516 | try: |
| 1517 | self.logger.debug("deleting nic name %s:", item_name) |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1518 | nic_delete = self.conn_vnet.network_interfaces.begin_delete( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1519 | self.resource_group, item_name |
| 1520 | ) |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1521 | nic_delete.wait() |
| 1522 | self.logger.debug("deleted nic name %s:", item_name) |
| 1523 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1524 | self.logger.error( |
| 1525 | "Error deleting item: {}: {}".format(type(e).__name__, e) |
| 1526 | ) |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1527 | |
| 1528 | for item_name in publics_ip_to_delete: |
| 1529 | try: |
| 1530 | self.logger.debug("deleting public ip name %s:", item_name) |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1531 | ip_delete = self.conn_vnet.public_ip_addresses.begin_delete( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1532 | self.resource_group, name |
| 1533 | ) |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1534 | ip_delete.wait() |
| 1535 | self.logger.debug("deleted public ip name %s:", item_name) |
| 1536 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1537 | self.logger.error( |
| 1538 | "Error deleting item: {}: {}".format(type(e).__name__, e) |
| 1539 | ) |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1540 | |
| 1541 | for item_name in disks_to_delete: |
| 1542 | try: |
| 1543 | self.logger.debug("deleting data disk name %s:", name) |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1544 | async_disk_delete = self.conn_compute.disks.begin_delete( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1545 | self.resource_group, item_name |
| 1546 | ) |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1547 | async_disk_delete.wait() |
| 1548 | self.logger.debug("deleted data disk name %s:", name) |
| 1549 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1550 | self.logger.error( |
| 1551 | "Error deleting item: {}: {}".format(type(e).__name__, e) |
| 1552 | ) |
| lloretgalleg | 064b05a | 2019-11-29 14:46:31 +0100 | [diff] [blame] | 1553 | |
| tierno | b569e4b | 2019-11-21 16:10:32 +0000 | [diff] [blame] | 1554 | def action_vminstance(self, vm_id, action_dict, created_items={}): |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1555 | """Send and action over a VM instance from VIM |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1556 | Returns the vm_id if the action was successfully sent to the VIM |
| 1557 | """ |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1558 | self.logger.debug("Action over VM '%s': %s", vm_id, str(action_dict)) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1559 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1560 | try: |
| 1561 | self._reload_connection() |
| 1562 | resName = self._get_resource_name_from_resource_id(vm_id) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1563 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1564 | if "start" in action_dict: |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1565 | self.conn_compute.virtual_machines.begin_start( |
| 1566 | self.resource_group, resName |
| 1567 | ) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1568 | elif ( |
| 1569 | "stop" in action_dict |
| 1570 | or "shutdown" in action_dict |
| 1571 | or "shutoff" in action_dict |
| 1572 | ): |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1573 | self.conn_compute.virtual_machines.begin_power_off( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1574 | self.resource_group, resName |
| 1575 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1576 | elif "terminate" in action_dict: |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1577 | self.conn_compute.virtual_machines.begin_delete( |
| 1578 | self.resource_group, resName |
| 1579 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1580 | elif "reboot" in action_dict: |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1581 | self.conn_compute.virtual_machines.begin_restart( |
| 1582 | self.resource_group, resName |
| 1583 | ) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1584 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1585 | return None |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1586 | except ResourceNotFoundError: |
| 1587 | raise vimconn.VimConnNotFoundException("No vm found '{}'".format(vm_id)) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1588 | except CloudError as e: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1589 | if e.error.error and "notfound" in e.error.error.lower(): |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 1590 | raise vimconn.VimConnNotFoundException("No vm found '{}'".format(vm_id)) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1591 | else: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1592 | self._format_vimconn_exception(e) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1593 | except Exception as e: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1594 | self._format_vimconn_exception(e) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1595 | |
| 1596 | def delete_flavor(self, flavor_id): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1597 | raise vimconn.VimConnAuthException( |
| 1598 | "It is not possible to delete a FLAVOR in AZURE" |
| 1599 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1600 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1601 | def delete_tenant(self, tenant_id): |
| 1602 | raise vimconn.VimConnAuthException( |
| 1603 | "It is not possible to delete a TENANT in AZURE" |
| 1604 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1605 | |
| 1606 | def delete_image(self, image_id): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1607 | raise vimconn.VimConnAuthException( |
| 1608 | "It is not possible to delete a IMAGE in AZURE" |
| 1609 | ) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1610 | |
| 1611 | def get_vminstance(self, vm_id): |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1612 | """ |
| 1613 | Obtaing the vm instance data from v_id |
| 1614 | """ |
| 1615 | self.logger.debug("get vm instance: %s", vm_id) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1616 | self._reload_connection() |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1617 | try: |
| 1618 | resName = self._get_resource_name_from_resource_id(vm_id) |
| tierno | b569e4b | 2019-11-21 16:10:32 +0000 | [diff] [blame] | 1619 | vm = self.conn_compute.virtual_machines.get(self.resource_group, resName) |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1620 | except ResourceNotFoundError: |
| 1621 | raise vimconn.VimConnNotFoundException( |
| 1622 | "No vminstance found '{}'".format(vm_id) |
| 1623 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1624 | except CloudError as e: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1625 | if e.error.error and "notfound" in e.error.error.lower(): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1626 | raise vimconn.VimConnNotFoundException( |
| 1627 | "No vminstance found '{}'".format(vm_id) |
| 1628 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1629 | else: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1630 | self._format_vimconn_exception(e) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1631 | except Exception as e: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1632 | self._format_vimconn_exception(e) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1633 | |
| 1634 | return vm |
| 1635 | |
| 1636 | def get_flavor(self, flavor_id): |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1637 | """ |
| 1638 | Obtains the flavor_data from the flavor_id |
| 1639 | """ |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1640 | self._reload_connection() |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1641 | self.logger.debug("get flavor from id: %s", flavor_id) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1642 | flavor_data = self._get_flavor_id_from_flavor_name(flavor_id) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1643 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1644 | if flavor_data: |
| 1645 | flavor = { |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1646 | "id": flavor_id, |
| 1647 | "name": flavor_id, |
| 1648 | "ram": flavor_data["memoryInMB"], |
| 1649 | "vcpus": flavor_data["numberOfCores"], |
| 1650 | "disk": flavor_data["resourceDiskSizeInMB"] / 1024, |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1651 | } |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1652 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1653 | return flavor |
| 1654 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1655 | raise vimconn.VimConnNotFoundException( |
| 1656 | "flavor '{}' not found".format(flavor_id) |
| 1657 | ) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1658 | |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1659 | def get_tenant_list(self, filter_dict={}): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1660 | """Obtains the list of tenants |
| 1661 | For the azure connector only the azure tenant will be returned if it is compatible |
| 1662 | with filter_dict |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1663 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1664 | tenants_azure = [{"name": self.tenant, "id": self.tenant}] |
| tierno | b569e4b | 2019-11-21 16:10:32 +0000 | [diff] [blame] | 1665 | tenant_list = [] |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1666 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1667 | self.logger.debug("get tenant list: %s", filter_dict) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1668 | for tenant_azure in tenants_azure: |
| 1669 | if filter_dict: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1670 | if ( |
| 1671 | filter_dict.get("id") |
| 1672 | and str(tenant_azure.get("id")) != filter_dict["id"] |
| 1673 | ): |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1674 | continue |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1675 | |
| 1676 | if ( |
| 1677 | filter_dict.get("name") |
| 1678 | and str(tenant_azure.get("name")) != filter_dict["name"] |
| 1679 | ): |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1680 | continue |
| 1681 | |
| 1682 | tenant_list.append(tenant_azure) |
| 1683 | |
| 1684 | return tenant_list |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1685 | |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 1686 | def refresh_nets_status(self, net_list): |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1687 | """Get the status of the networks |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1688 | Params: the list of network identifiers |
| 1689 | Returns a dictionary with: |
| 1690 | net_id: #VIM id of this network |
| 1691 | status: #Mandatory. Text with one of: |
| 1692 | # DELETED (not found at vim) |
| 1693 | # VIM_ERROR (Cannot connect to VIM, VIM response error, ...) |
| 1694 | # OTHER (Vim reported other status not understood) |
| 1695 | # ERROR (VIM indicates an ERROR status) |
| 1696 | # ACTIVE, INACTIVE, DOWN (admin down), |
| 1697 | # BUILD (on building process) |
| 1698 | # |
| 1699 | error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR |
| 1700 | vim_info: #Text with plain information obtained from vim (yaml.safe_dump) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1701 | """ |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 1702 | out_nets = {} |
| 1703 | self._reload_connection() |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1704 | |
| 1705 | self.logger.debug("reload nets status net_list: %s", net_list) |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 1706 | for net_id in net_list: |
| 1707 | try: |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1708 | netName = self._get_net_name_from_resource_id(net_id) |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 1709 | resName = self._get_resource_name_from_resource_id(net_id) |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1710 | |
| gallardo | dd82175 | 2022-01-17 17:37:51 +0000 | [diff] [blame] | 1711 | net = self.conn_vnet.subnets.get( |
| 1712 | self.vnet_resource_group or self.resource_group, netName, resName |
| 1713 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1714 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1715 | out_nets[net_id] = { |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1716 | "status": self.provision_state2osm[net.provisioning_state], |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1717 | "vim_info": str(net), |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 1718 | } |
| 1719 | except CloudError as e: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1720 | if e.error.error and "notfound" in e.error.error.lower(): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1721 | self.logger.info( |
| 1722 | "Not found subnet net_name: %s, subnet_name: %s", |
| 1723 | netName, |
| 1724 | resName, |
| 1725 | ) |
| 1726 | out_nets[net_id] = {"status": "DELETED", "error_msg": str(e)} |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 1727 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1728 | self.logger.error( |
| 1729 | "CloudError Exception %s when searching subnet", e |
| 1730 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1731 | out_nets[net_id] = { |
| 1732 | "status": "VIM_ERROR", |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1733 | "error_msg": str(e), |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1734 | } |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 1735 | except vimconn.VimConnNotFoundException as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1736 | self.logger.error( |
| 1737 | "VimConnNotFoundException %s when searching subnet", e |
| 1738 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1739 | out_nets[net_id] = { |
| 1740 | "status": "DELETED", |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1741 | "error_msg": str(e), |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1742 | } |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 1743 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1744 | self.logger.error( |
| 1745 | "Exception %s when searching subnet", e, exc_info=True |
| 1746 | ) |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 1747 | out_nets[net_id] = { |
| 1748 | "status": "VIM_ERROR", |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1749 | "error_msg": str(e), |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 1750 | } |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1751 | |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 1752 | return out_nets |
| 1753 | |
| 1754 | def refresh_vms_status(self, vm_list): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1755 | """Get the status of the virtual machines and their interfaces/ports |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1756 | Params: the list of VM identifiers |
| 1757 | Returns a dictionary with: |
| 1758 | vm_id: # VIM id of this Virtual Machine |
| 1759 | status: # Mandatory. Text with one of: |
| 1760 | # DELETED (not found at vim) |
| 1761 | # VIM_ERROR (Cannot connect to VIM, VIM response error, ...) |
| 1762 | # OTHER (Vim reported other status not understood) |
| 1763 | # ERROR (VIM indicates an ERROR status) |
| 1764 | # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running), |
| 1765 | # BUILD (on building process), ERROR |
| 1766 | # ACTIVE:NoMgmtIP (Active but none of its interfaces has an IP address |
| 1767 | # (ACTIVE:NoMgmtIP is not returned for Azure) |
| 1768 | # |
| 1769 | error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR |
| 1770 | vim_info: #Text with plain information obtained from vim (yaml.safe_dump) |
| 1771 | interfaces: list with interface info. Each item a dictionary with: |
| 1772 | vim_interface_id - The ID of the interface |
| 1773 | mac_address - The MAC address of the interface. |
| 1774 | ip_address - The IP address of the interface within the subnet. |
| 1775 | """ |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 1776 | out_vms = {} |
| 1777 | self._reload_connection() |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1778 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1779 | self.logger.debug("refresh vm status vm_list: %s", vm_list) |
| 1780 | search_vm_list = vm_list or {} |
| 1781 | |
| 1782 | for vm_id in search_vm_list: |
| 1783 | out_vm = {} |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 1784 | try: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1785 | res_name = self._get_resource_name_from_resource_id(vm_id) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1786 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1787 | vm = self.conn_compute.virtual_machines.get( |
| 1788 | self.resource_group, res_name |
| 1789 | ) |
| aguilard | 309b5bf | 2023-10-05 14:13:23 +0000 | [diff] [blame] | 1790 | img = vm.storage_profile.image_reference |
| 1791 | images = self._get_version_image_list( |
| 1792 | img.publisher, img.offer, img.sku, img.version |
| 1793 | ) |
| 1794 | vim_info = { |
| 1795 | "id": vm.id, |
| 1796 | "name": vm.name, |
| 1797 | "location": vm.location, |
| 1798 | "provisioning_state": vm.provisioning_state, |
| 1799 | "vm_id": vm.vm_id, |
| 1800 | "type": vm.type, |
| 1801 | "flavor": {"id": vm.hardware_profile.vm_size}, |
| 1802 | "image": images[0], |
| 1803 | } |
| 1804 | out_vm["vim_info"] = str(vim_info) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1805 | out_vm["status"] = self.provision_state2osm.get( |
| 1806 | vm.provisioning_state, "OTHER" |
| 1807 | ) |
| 1808 | |
| 1809 | if vm.provisioning_state == "Succeeded": |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1810 | # check if machine is running or stopped |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1811 | instance_view = self.conn_compute.virtual_machines.instance_view( |
| 1812 | self.resource_group, res_name |
| 1813 | ) |
| 1814 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1815 | for status in instance_view.statuses: |
| 1816 | splitted_status = status.code.split("/") |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1817 | if ( |
| 1818 | len(splitted_status) == 2 |
| 1819 | and splitted_status[0] == "PowerState" |
| 1820 | ): |
| 1821 | out_vm["status"] = self.power_state2osm.get( |
| 1822 | splitted_status[1], "OTHER" |
| 1823 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1824 | |
| 1825 | network_interfaces = vm.network_profile.network_interfaces |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1826 | out_vm["interfaces"] = self._get_vm_interfaces_status( |
| 1827 | vm_id, network_interfaces |
| 1828 | ) |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1829 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1830 | except CloudError as e: |
| 1831 | if e.error.error and "notfound" in e.error.error.lower(): |
| 1832 | self.logger.debug("Not found vm id: %s", vm_id) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1833 | out_vm["status"] = "DELETED" |
| 1834 | out_vm["error_msg"] = str(e) |
| 1835 | out_vm["vim_info"] = None |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1836 | else: |
| 1837 | # maybe connection error or another type of error, return vim error |
| 1838 | self.logger.error("Exception %s refreshing vm_status", e) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1839 | out_vm["status"] = "VIM_ERROR" |
| 1840 | out_vm["error_msg"] = str(e) |
| 1841 | out_vm["vim_info"] = None |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 1842 | except Exception as e: |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1843 | self.logger.error("Exception %s refreshing vm_status", e, exc_info=True) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1844 | out_vm["status"] = "VIM_ERROR" |
| 1845 | out_vm["error_msg"] = str(e) |
| 1846 | out_vm["vim_info"] = None |
| jamartinezv | 14a823d | 2019-08-01 11:45:15 +0200 | [diff] [blame] | 1847 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1848 | out_vms[vm_id] = out_vm |
| tierno | 84efdc1 | 2019-05-29 09:29:01 +0000 | [diff] [blame] | 1849 | |
| 1850 | return out_vms |
| seryio | 07ad136 | 2019-05-29 09:16:24 +0200 | [diff] [blame] | 1851 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1852 | def _get_vm_interfaces_status(self, vm_id, interfaces): |
| 1853 | """ |
| 1854 | Gets the interfaces detail for a vm |
| 1855 | :param interfaces: List of interfaces. |
| 1856 | :return: Dictionary with list of interfaces including, vim_interface_id, mac_address and ip_address |
| 1857 | """ |
| 1858 | try: |
| 1859 | interface_list = [] |
| 1860 | for network_interface in interfaces: |
| 1861 | interface_dict = {} |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1862 | nic_name = self._get_resource_name_from_resource_id( |
| 1863 | network_interface.id |
| 1864 | ) |
| 1865 | interface_dict["vim_interface_id"] = network_interface.id |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1866 | |
| 1867 | nic_data = self.conn_vnet.network_interfaces.get( |
| 1868 | self.resource_group, |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1869 | nic_name, |
| 1870 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1871 | |
| lloretgalleg | bfc28b0 | 2019-11-21 09:31:16 +0100 | [diff] [blame] | 1872 | ips = [] |
| 1873 | if nic_data.ip_configurations[0].public_ip_address: |
| 1874 | self.logger.debug("Obtain public ip address") |
| tierno | b569e4b | 2019-11-21 16:10:32 +0000 | [diff] [blame] | 1875 | public_ip_name = self._get_resource_name_from_resource_id( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1876 | nic_data.ip_configurations[0].public_ip_address.id |
| 1877 | ) |
| 1878 | public_ip = self.conn_vnet.public_ip_addresses.get( |
| 1879 | self.resource_group, public_ip_name |
| 1880 | ) |
| lloretgalleg | bfc28b0 | 2019-11-21 09:31:16 +0100 | [diff] [blame] | 1881 | self.logger.debug("Public ip address is: %s", public_ip.ip_address) |
| 1882 | ips.append(public_ip.ip_address) |
| 1883 | |
| aguilard | 309b5bf | 2023-10-05 14:13:23 +0000 | [diff] [blame] | 1884 | subnet = nic_data.ip_configurations[0].subnet.id |
| 1885 | if subnet: |
| 1886 | interface_dict["vim_net_id"] = subnet |
| 1887 | |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1888 | private_ip = nic_data.ip_configurations[0].private_ip_address |
| lloretgalleg | bfc28b0 | 2019-11-21 09:31:16 +0100 | [diff] [blame] | 1889 | ips.append(private_ip) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1890 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1891 | interface_dict["mac_address"] = nic_data.mac_address |
| 1892 | interface_dict["ip_address"] = ";".join(ips) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1893 | interface_list.append(interface_dict) |
| 1894 | |
| 1895 | return interface_list |
| 1896 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1897 | self.logger.error( |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1898 | "Exception %s obtaining interface data for vm: %s", |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1899 | e, |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1900 | vm_id, |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1901 | exc_info=True, |
| 1902 | ) |
| lloretgalleg | 4522015 | 2019-10-29 11:53:49 +0100 | [diff] [blame] | 1903 | self._format_vimconn_exception(e) |
| 1904 | |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1905 | def _get_default_admin_user(self, image_id): |
| 1906 | if "ubuntu" in image_id.lower(): |
| 1907 | return "ubuntu" |
| 1908 | else: |
| 1909 | return self._default_admin_user |
| 1910 | |
| elumalai | 8658c2c | 2022-04-28 19:09:31 +0530 | [diff] [blame] | 1911 | def migrate_instance(self, vm_id, compute_host=None): |
| 1912 | """ |
| 1913 | Migrate a vdu |
| 1914 | param: |
| 1915 | vm_id: ID of an instance |
| 1916 | compute_host: Host to migrate the vdu to |
| 1917 | """ |
| 1918 | # TODO: Add support for migration |
| 1919 | raise vimconn.VimConnNotImplemented("Not implemented") |
| 1920 | |
| sritharan | 29a4c1a | 2022-05-05 12:15:04 +0000 | [diff] [blame] | 1921 | def resize_instance(self, vm_id, flavor_id=None): |
| 1922 | """ |
| 1923 | resize a vdu |
| 1924 | param: |
| 1925 | vm_id: ID of an instance |
| 1926 | flavor_id: flavor id to resize the vdu |
| 1927 | """ |
| 1928 | # TODO: Add support for resize |
| 1929 | raise vimconn.VimConnNotImplemented("Not implemented") |
| 1930 | |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1931 | |
| 1932 | if __name__ == "__main__": |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1933 | # Init logger |
| 1934 | log_format = "%(asctime)s %(levelname)s %(name)s %(filename)s:%(lineno)s %(funcName)s(): %(message)s" |
| 1935 | log_formatter = logging.Formatter(log_format, datefmt="%Y-%m-%dT%H:%M:%S") |
| 1936 | handler = logging.StreamHandler() |
| 1937 | handler.setFormatter(log_formatter) |
| 1938 | logger = logging.getLogger("ro.vim.azure") |
| 1939 | # logger.setLevel(level=logging.ERROR) |
| 1940 | # logger.setLevel(level=logging.INFO) |
| 1941 | logger.setLevel(level=logging.DEBUG) |
| 1942 | logger.addHandler(handler) |
| 1943 | |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1944 | # Making some basic test |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1945 | vim_id = "azure" |
| 1946 | vim_name = "azure" |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1947 | needed_test_params = { |
| tierno | deb74b2 | 2019-05-27 10:24:50 +0000 | [diff] [blame] | 1948 | "client_id": "AZURE_CLIENT_ID", |
| 1949 | "secret": "AZURE_SECRET", |
| 1950 | "tenant": "AZURE_TENANT", |
| 1951 | "resource_group": "AZURE_RESOURCE_GROUP", |
| 1952 | "subscription_id": "AZURE_SUBSCRIPTION_ID", |
| tierno | 30d0d6d | 2019-05-27 08:14:01 +0000 | [diff] [blame] | 1953 | "vnet_name": "AZURE_VNET_NAME", |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1954 | } |
| 1955 | test_params = {} |
| 1956 | |
| 1957 | for param, env_var in needed_test_params.items(): |
| 1958 | value = getenv(env_var) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1959 | |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1960 | if not value: |
| 1961 | raise Exception("Provide a valid value for env '{}'".format(env_var)) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1962 | |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1963 | test_params[param] = value |
| 1964 | |
| 1965 | config = { |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1966 | "region_name": getenv("AZURE_REGION_NAME", "northeurope"), |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1967 | "resource_group": getenv("AZURE_RESOURCE_GROUP"), |
| 1968 | "subscription_id": getenv("AZURE_SUBSCRIPTION_ID"), |
| 1969 | "pub_key": getenv("AZURE_PUB_KEY", None), |
| lloretgalleg | c8138e8 | 2021-03-31 07:12:06 +0000 | [diff] [blame] | 1970 | "vnet_name": getenv("AZURE_VNET_NAME", "osm_vnet"), |
| seryio | 3447855 | 2019-05-23 14:50:49 +0200 | [diff] [blame] | 1971 | } |
| tierno | 30d0d6d | 2019-05-27 08:14:01 +0000 | [diff] [blame] | 1972 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1973 | azure = vimconnector( |
| 1974 | vim_id, |
| 1975 | vim_name, |
| 1976 | tenant_id=test_params["tenant"], |
| 1977 | tenant_name=None, |
| 1978 | url=None, |
| 1979 | url_admin=None, |
| 1980 | user=test_params["client_id"], |
| 1981 | passwd=test_params["secret"], |
| 1982 | log_level=None, |
| 1983 | config=config, |
| 1984 | ) |