| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 1 | # -*- coding: utf-8 -*- |
| 2 | |
| 3 | ## |
| tierno | 9202102 | 2018-09-12 16:29:23 +0200 | [diff] [blame] | 4 | # Copyright 2017 Telefonica Digital Spain S.L.U. |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 5 | # This file is part of ETSI OSM |
| 6 | # All Rights Reserved. |
| 7 | # |
| 8 | # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 9 | # not use this file except in compliance with the License. You may obtain |
| 10 | # a copy of the License at |
| 11 | # |
| 12 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 13 | # |
| 14 | # Unless required by applicable law or agreed to in writing, software |
| 15 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 16 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 17 | |
| 18 | # License for the specific language governing permissions and limitations |
| 19 | # under the License. |
| 20 | # |
| 21 | # For those usages not covered by the Apache License, Version 2.0 please |
| 22 | # contact with: patent-office@telefonica.com |
| 23 | ## |
| 24 | |
| 25 | """ |
| 26 | vimconnector implements all the methods to interact with OpenNebula using the XML-RPC API. |
| 27 | """ |
| 28 | __author__ = "Jose Maria Carmona Perez,Juan Antonio Hernando Labajo, Emilio Abraham Garrido Garcia,Alberto Florez " \ |
| tierno | 9202102 | 2018-09-12 16:29:23 +0200 | [diff] [blame] | 29 | "Pages, Andres Pozo Munoz, Santiago Perez Marin, Onlife Networks Telefonica I+D Product Innovation " |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 30 | __date__ = "$13-dec-2017 11:09:29$" |
| sousaedu | e493e9b | 2021-02-09 15:30:01 +0100 | [diff] [blame^] | 31 | |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 32 | from osm_ro_plugin import vimconn |
| sousaedu | e493e9b | 2021-02-09 15:30:01 +0100 | [diff] [blame^] | 33 | import logging |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 34 | import requests |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 35 | # import logging |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 36 | import oca |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 37 | # import untangle |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 38 | import math |
| 39 | import random |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 40 | import pyone |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 41 | |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 42 | |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 43 | class vimconnector(vimconn.VimConnector): |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 44 | def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, |
| 45 | log_level="DEBUG", config={}, persistent_info={}): |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 46 | |
| 47 | """Constructor of VIM |
| 48 | Params: |
| 49 | 'uuid': id asigned to this VIM |
| 50 | 'name': name assigned to this VIM, can be used for logging |
| 51 | 'tenant_id', 'tenant_name': (only one of them is mandatory) VIM tenant to be used |
| 52 | 'url_admin': (optional), url used for administrative tasks |
| 53 | 'user', 'passwd': credentials of the VIM user |
| 54 | 'log_level': provider if it should use a different log_level than the general one |
| 55 | 'config': dictionary with extra VIM information. This contains a consolidate version of general VIM config |
| 56 | at creation and particular VIM config at teh attachment |
| 57 | 'persistent_info': dict where the class can store information that will be available among class |
| 58 | destroy/creation cycles. This info is unique per VIM/credential. At first call it will contain an |
| 59 | empty dict. Useful to store login/tokens information for speed up communication |
| 60 | |
| 61 | Returns: Raise an exception is some needed parameter is missing, but it must not do any connectivity |
| 62 | check against the VIM |
| 63 | """ |
| 64 | |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 65 | vimconn.VimConnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, log_level, |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 66 | config) |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 67 | |
| sousaedu | e493e9b | 2021-02-09 15:30:01 +0100 | [diff] [blame^] | 68 | self.logger = logging.getLogger('ro.vim.openstack') |
| 69 | |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 70 | def _new_one_connection(self): |
| 71 | return pyone.OneServer(self.url, session=self.user + ':' + self.passwd) |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 72 | |
| 73 | def new_tenant(self, tenant_name, tenant_description): |
| 74 | # '''Adds a new tenant to VIM with this name and description, returns the tenant identifier''' |
| 75 | try: |
| 76 | client = oca.Client(self.user + ':' + self.passwd, self.url) |
| 77 | group_list = oca.GroupPool(client) |
| 78 | user_list = oca.UserPool(client) |
| 79 | group_list.info() |
| 80 | user_list.info() |
| 81 | create_primarygroup = 1 |
| 82 | # create group-tenant |
| 83 | for group in group_list: |
| 84 | if str(group.name) == str(tenant_name): |
| 85 | create_primarygroup = 0 |
| 86 | break |
| 87 | if create_primarygroup == 1: |
| 88 | oca.Group.allocate(client, tenant_name) |
| 89 | group_list.info() |
| 90 | # set to primary_group the tenant_group and oneadmin to secondary_group |
| 91 | for group in group_list: |
| 92 | if str(group.name) == str(tenant_name): |
| 93 | for user in user_list: |
| 94 | if str(user.name) == str(self.user): |
| 95 | if user.name == "oneadmin": |
| 96 | return str(0) |
| 97 | else: |
| 98 | self._add_secondarygroup(user.id, group.id) |
| 99 | user.chgrp(group.id) |
| 100 | return str(group.id) |
| 101 | except Exception as e: |
| 102 | self.logger.error("Create new tenant error: " + str(e)) |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 103 | raise vimconn.VimConnException(e) |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 104 | |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 105 | def delete_tenant(self, tenant_id): |
| 106 | """Delete a tenant from VIM. Returns the old tenant identifier""" |
| 107 | try: |
| 108 | client = oca.Client(self.user + ':' + self.passwd, self.url) |
| 109 | group_list = oca.GroupPool(client) |
| 110 | user_list = oca.UserPool(client) |
| 111 | group_list.info() |
| 112 | user_list.info() |
| 113 | for group in group_list: |
| 114 | if str(group.id) == str(tenant_id): |
| 115 | for user in user_list: |
| 116 | if str(user.name) == str(self.user): |
| 117 | self._delete_secondarygroup(user.id, group.id) |
| 118 | group.delete(client) |
| 119 | return None |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 120 | raise vimconn.VimConnNotFoundException("Group {} not found".format(tenant_id)) |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 121 | except Exception as e: |
| 122 | self.logger.error("Delete tenant " + str(tenant_id) + " error: " + str(e)) |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 123 | raise vimconn.VimConnException(e) |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 124 | |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 125 | def _add_secondarygroup(self, id_user, id_group): |
| 126 | # change secondary_group to primary_group |
| 127 | params = '<?xml version="1.0"?> \ |
| 128 | <methodCall>\ |
| 129 | <methodName>one.user.addgroup</methodName>\ |
| 130 | <params>\ |
| 131 | <param>\ |
| 132 | <value><string>{}:{}</string></value>\ |
| 133 | </param>\ |
| 134 | <param>\ |
| 135 | <value><int>{}</int></value>\ |
| 136 | </param>\ |
| 137 | <param>\ |
| 138 | <value><int>{}</int></value>\ |
| 139 | </param>\ |
| 140 | </params>\ |
| 141 | </methodCall>'.format(self.user, self.passwd, (str(id_user)), (str(id_group))) |
| 142 | requests.post(self.url, params) |
| 143 | |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 144 | def _delete_secondarygroup(self, id_user, id_group): |
| 145 | params = '<?xml version="1.0"?> \ |
| 146 | <methodCall>\ |
| 147 | <methodName>one.user.delgroup</methodName>\ |
| 148 | <params>\ |
| 149 | <param>\ |
| 150 | <value><string>{}:{}</string></value>\ |
| 151 | </param>\ |
| 152 | <param>\ |
| 153 | <value><int>{}</int></value>\ |
| 154 | </param>\ |
| 155 | <param>\ |
| 156 | <value><int>{}</int></value>\ |
| 157 | </param>\ |
| 158 | </params>\ |
| 159 | </methodCall>'.format(self.user, self.passwd, (str(id_user)), (str(id_group))) |
| 160 | requests.post(self.url, params) |
| 161 | |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 162 | def new_network(self, net_name, net_type, ip_profile=None, shared=False, provider_network_profile=None): |
| garciadeblas | ebd6672 | 2019-01-31 16:01:31 +0000 | [diff] [blame] | 163 | """Adds a tenant network to VIM |
| 164 | Params: |
| 165 | 'net_name': name of the network |
| 166 | 'net_type': one of: |
| 167 | 'bridge': overlay isolated network |
| 168 | 'data': underlay E-LAN network for Passthrough and SRIOV interfaces |
| 169 | 'ptp': underlay E-LINE network for Passthrough and SRIOV interfaces. |
| 170 | 'ip_profile': is a dict containing the IP parameters of the network |
| 171 | 'ip_version': can be "IPv4" or "IPv6" (Currently only IPv4 is implemented) |
| 172 | 'subnet_address': ip_prefix_schema, that is X.X.X.X/Y |
| 173 | 'gateway_address': (Optional) ip_schema, that is X.X.X.X |
| 174 | 'dns_address': (Optional) comma separated list of ip_schema, e.g. X.X.X.X[,X,X,X,X] |
| 175 | 'dhcp_enabled': True or False |
| 176 | 'dhcp_start_address': ip_schema, first IP to grant |
| 177 | 'dhcp_count': number of IPs to grant. |
| 178 | 'shared': if this network can be seen/use by other tenants/organization |
| kbsub | a85c54d | 2019-10-17 16:30:32 +0000 | [diff] [blame] | 179 | 'provider_network_profile': (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk} |
| garciadeblas | ebd6672 | 2019-01-31 16:01:31 +0000 | [diff] [blame] | 180 | Returns a tuple with the network identifier and created_items, or raises an exception on error |
| 181 | created_items can be None or a dictionary where this method can include key-values that will be passed to |
| 182 | the method delete_network. Can be used to store created segments, created l2gw connections, etc. |
| 183 | Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same |
| 184 | as not present. |
| 185 | """ |
| 186 | |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 187 | # oca library method cannot be used in this case (problem with cluster parameters) |
| 188 | try: |
| kbsub | a85c54d | 2019-10-17 16:30:32 +0000 | [diff] [blame] | 189 | vlan = None |
| 190 | if provider_network_profile: |
| 191 | vlan = provider_network_profile.get("segmentation-id") |
| albertoflorez | 3ade00b | 2019-07-08 13:16:21 +0200 | [diff] [blame] | 192 | created_items = {} |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 193 | one = self._new_one_connection() |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 194 | size = "254" |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 195 | if ip_profile is None: |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 196 | subnet_rand = random.randint(0, 255) |
| 197 | ip_start = "192.168.{}.1".format(subnet_rand) |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 198 | else: |
| 199 | index = ip_profile["subnet_address"].find("/") |
| 200 | ip_start = ip_profile["subnet_address"][:index] |
| tierno | 7d782ef | 2019-10-04 12:56:31 +0000 | [diff] [blame] | 201 | if "dhcp_count" in ip_profile and ip_profile["dhcp_count"] is not None: |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 202 | size = str(ip_profile["dhcp_count"]) |
| tierno | 7d782ef | 2019-10-04 12:56:31 +0000 | [diff] [blame] | 203 | elif "dhcp_count" not in ip_profile and ip_profile["ip_version"] == "IPv4": |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 204 | prefix = ip_profile["subnet_address"][index + 1:] |
| 205 | size = int(math.pow(2, 32 - prefix)) |
| tierno | 7d782ef | 2019-10-04 12:56:31 +0000 | [diff] [blame] | 206 | if "dhcp_start_address" in ip_profile and ip_profile["dhcp_start_address"] is not None: |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 207 | ip_start = str(ip_profile["dhcp_start_address"]) |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 208 | # if ip_profile["ip_version"] == "IPv6": |
| 209 | # ip_prefix_type = "GLOBAL_PREFIX" |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 210 | |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 211 | if vlan is not None: |
| 212 | vlan_id = vlan |
| 213 | else: |
| 214 | vlan_id = str(random.randint(100, 4095)) |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 215 | # if "internal" in net_name: |
| albertoflorez | 3ade00b | 2019-07-08 13:16:21 +0200 | [diff] [blame] | 216 | # OpenNebula not support two networks with same name |
| 217 | random_net_name = str(random.randint(1, 1000000)) |
| 218 | net_name = net_name + random_net_name |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 219 | net_id = one.vn.allocate({ |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 220 | 'NAME': net_name, |
| 221 | 'VN_MAD': '802.1Q', |
| 222 | 'PHYDEV': self.config["network"]["phydev"], |
| 223 | 'VLAN_ID': vlan_id |
| 224 | }, self.config["cluster"]["id"]) |
| 225 | arpool = { |
| 226 | 'AR_POOL': { |
| 227 | 'AR': { |
| 228 | 'TYPE': 'IP4', |
| 229 | 'IP': ip_start, |
| 230 | 'SIZE': size |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 231 | } |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 232 | } |
| albertoflorez | 3ade00b | 2019-07-08 13:16:21 +0200 | [diff] [blame] | 233 | } |
| 234 | one.vn.add_ar(net_id, arpool) |
| 235 | return net_id, created_items |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 236 | except Exception as e: |
| 237 | self.logger.error("Create new network error: " + str(e)) |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 238 | raise vimconn.VimConnException(e) |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 239 | |
| 240 | def get_network_list(self, filter_dict={}): |
| 241 | """Obtain tenant networks of VIM |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 242 | :params filter_dict: (optional) contains entries to return only networks that matches ALL entries: |
| 243 | name: string => returns only networks with this name |
| 244 | id: string => returns networks with this VIM id, this imply returns one network at most |
| 245 | shared: boolean >= returns only networks that are (or are not) shared |
| 246 | tenant_id: sting => returns only networks that belong to this tenant/project |
| 247 | (not used yet) admin_state_up: boolean => returns only networks that are (or are not) in admin state active |
| 248 | (not used yet) status: 'ACTIVE','ERROR',... => filter networks that are on this status |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 249 | Returns the network list of dictionaries. each dictionary contains: |
| 250 | 'id': (mandatory) VIM network id |
| 251 | 'name': (mandatory) VIM network name |
| 252 | 'status': (mandatory) can be 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER' |
| 253 | 'network_type': (optional) can be 'vxlan', 'vlan' or 'flat' |
| 254 | 'segmentation_id': (optional) in case network_type is vlan or vxlan this field contains the segmentation id |
| 255 | 'error_msg': (optional) text that explains the ERROR status |
| 256 | other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param |
| 257 | List can be empty if no network map the filter_dict. Raise an exception only upon VIM connectivity, |
| 258 | authorization, or some other unspecific error |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 259 | """ |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 260 | |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 261 | try: |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 262 | one = self._new_one_connection() |
| 263 | net_pool = one.vnpool.info(-2, -1, -1).VNET |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 264 | response = [] |
| tierno | 7d782ef | 2019-10-04 12:56:31 +0000 | [diff] [blame] | 265 | if "name" in filter_dict: |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 266 | network_name_filter = filter_dict["name"] |
| 267 | else: |
| 268 | network_name_filter = None |
| tierno | 7d782ef | 2019-10-04 12:56:31 +0000 | [diff] [blame] | 269 | if "id" in filter_dict: |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 270 | network_id_filter = filter_dict["id"] |
| 271 | else: |
| 272 | network_id_filter = None |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 273 | for network in net_pool: |
| 274 | if network.NAME == network_name_filter or str(network.ID) == str(network_id_filter): |
| 275 | net_dict = {"name": network.NAME, "id": str(network.ID), "status": "ACTIVE"} |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 276 | response.append(net_dict) |
| 277 | return response |
| 278 | except Exception as e: |
| 279 | self.logger.error("Get network list error: " + str(e)) |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 280 | raise vimconn.VimConnException(e) |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 281 | |
| 282 | def get_network(self, net_id): |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 283 | """Obtain network details from the 'net_id' VIM network |
| 284 | Return a dict that contains: |
| 285 | 'id': (mandatory) VIM network id, that is, net_id |
| 286 | 'name': (mandatory) VIM network name |
| 287 | 'status': (mandatory) can be 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER' |
| 288 | 'error_msg': (optional) text that explains the ERROR status |
| 289 | other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param |
| 290 | Raises an exception upon error or when network is not found |
| 291 | """ |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 292 | try: |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 293 | one = self._new_one_connection() |
| 294 | net_pool = one.vnpool.info(-2, -1, -1).VNET |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 295 | net = {} |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 296 | for network in net_pool: |
| 297 | if str(network.ID) == str(net_id): |
| 298 | net['id'] = network.ID |
| 299 | net['name'] = network.NAME |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 300 | net['status'] = "ACTIVE" |
| 301 | break |
| 302 | if net: |
| 303 | return net |
| 304 | else: |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 305 | raise vimconn.VimConnNotFoundException("Network {} not found".format(net_id)) |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 306 | except Exception as e: |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 307 | self.logger.error("Get network " + str(net_id) + " error): " + str(e)) |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 308 | raise vimconn.VimConnException(e) |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 309 | |
| garciadeblas | ebd6672 | 2019-01-31 16:01:31 +0000 | [diff] [blame] | 310 | def delete_network(self, net_id, created_items=None): |
| 311 | """ |
| 312 | Removes a tenant network from VIM and its associated elements |
| 313 | :param net_id: VIM identifier of the network, provided by method new_network |
| 314 | :param created_items: dictionary with extra items to be deleted. provided by method new_network |
| 315 | Returns the network identifier or raises an exception upon error or when network is not found |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 316 | """ |
| 317 | try: |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 318 | |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 319 | one = self._new_one_connection() |
| 320 | one.vn.delete(int(net_id)) |
| 321 | return net_id |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 322 | except Exception as e: |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 323 | self.logger.error("Delete network " + str(net_id) + "error: network not found" + str(e)) |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 324 | raise vimconn.VimConnException(e) |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 325 | |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 326 | def refresh_nets_status(self, net_list): |
| 327 | """Get the status of the networks |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 328 | Params: |
| 329 | 'net_list': a list with the VIM network id to be get the status |
| 330 | Returns a dictionary with: |
| 331 | 'net_id': #VIM id of this network |
| 332 | status: #Mandatory. Text with one of: |
| 333 | # DELETED (not found at vim) |
| 334 | # VIM_ERROR (Cannot connect to VIM, authentication problems, VIM response error, ...) |
| 335 | # OTHER (Vim reported other status not understood) |
| 336 | # ERROR (VIM indicates an ERROR status) |
| 337 | # ACTIVE, INACTIVE, DOWN (admin down), |
| 338 | # BUILD (on building process) |
| 339 | error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR |
| 340 | vim_info: #Text with plain information obtained from vim (yaml.safe_dump) |
| 341 | 'net_id2': ... |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 342 | """ |
| 343 | net_dict = {} |
| 344 | try: |
| 345 | for net_id in net_list: |
| 346 | net = {} |
| 347 | try: |
| 348 | net_vim = self.get_network(net_id) |
| 349 | net["status"] = net_vim["status"] |
| 350 | net["vim_info"] = None |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 351 | except vimconn.VimConnNotFoundException as e: |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 352 | self.logger.error("Exception getting net status: {}".format(str(e))) |
| 353 | net['status'] = "DELETED" |
| 354 | net['error_msg'] = str(e) |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 355 | except vimconn.VimConnException as e: |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 356 | self.logger.error(e) |
| 357 | net["status"] = "VIM_ERROR" |
| 358 | net["error_msg"] = str(e) |
| 359 | net_dict[net_id] = net |
| 360 | return net_dict |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 361 | except vimconn.VimConnException as e: |
| jomacarpe | ea2a73e | 2018-02-27 13:48:22 +0100 | [diff] [blame] | 362 | self.logger.error(e) |
| 363 | for k in net_dict: |
| 364 | net_dict[k]["status"] = "VIM_ERROR" |
| 365 | net_dict[k]["error_msg"] = str(e) |
| 366 | return net_dict |
| 367 | |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 368 | def get_flavor(self, flavor_id): # Esta correcto |
| 369 | """Obtain flavor details from the VIM |
| 370 | Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } |
| 371 | Raises an exception upon error or if not found |
| 372 | """ |
| 373 | try: |
| 374 | |
| 375 | one = self._new_one_connection() |
| 376 | template = one.template.info(int(flavor_id)) |
| 377 | if template is not None: |
| 378 | return {'id': template.ID, 'name': template.NAME} |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 379 | raise vimconn.VimConnNotFoundException("Flavor {} not found".format(flavor_id)) |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 380 | except Exception as e: |
| 381 | self.logger.error("get flavor " + str(flavor_id) + " error: " + str(e)) |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 382 | raise vimconn.VimConnException(e) |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 383 | |
| 384 | def new_flavor(self, flavor_data): |
| 385 | """Adds a tenant flavor to VIM |
| 386 | flavor_data contains a dictionary with information, keys: |
| 387 | name: flavor name |
| 388 | ram: memory (cloud type) in MBytes |
| 389 | vpcus: cpus (cloud type) |
| 390 | extended: EPA parameters |
| 391 | - numas: #items requested in same NUMA |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 392 | memory: number of 1G huge pages memory |
| 393 | paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads |
| 394 | interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 395 | - name: interface name |
| 396 | dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC |
| 397 | bandwidth: X Gbps; requested guarantee bandwidth |
| 398 | vpci: requested virtual PCI address |
| 399 | disk: disk size |
| 400 | is_public: |
| 401 | #TODO to concrete |
| 402 | Returns the flavor identifier""" |
| 403 | |
| 404 | disk_size = str(int(flavor_data["disk"])*1024) |
| 405 | |
| 406 | try: |
| 407 | one = self._new_one_connection() |
| 408 | template_id = one.template.allocate({ |
| 409 | 'TEMPLATE': { |
| 410 | 'NAME': flavor_data["name"], |
| 411 | 'CPU': flavor_data["vcpus"], |
| 412 | 'VCPU': flavor_data["vcpus"], |
| 413 | 'MEMORY': flavor_data["ram"], |
| 414 | 'DISK': { |
| 415 | 'SIZE': disk_size |
| 416 | }, |
| 417 | 'CONTEXT': { |
| 418 | 'NETWORK': "YES", |
| 419 | 'SSH_PUBLIC_KEY': '$USER[SSH_PUBLIC_KEY]' |
| 420 | }, |
| 421 | 'GRAPHICS': { |
| 422 | 'LISTEN': '0.0.0.0', |
| 423 | 'TYPE': 'VNC' |
| 424 | }, |
| 425 | 'CLUSTER_ID': self.config["cluster"]["id"] |
| 426 | } |
| 427 | }) |
| 428 | return template_id |
| 429 | |
| 430 | except Exception as e: |
| 431 | self.logger.error("Create new flavor error: " + str(e)) |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 432 | raise vimconn.VimConnException(e) |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 433 | |
| 434 | def delete_flavor(self, flavor_id): |
| 435 | """ Deletes a tenant flavor from VIM |
| 436 | Returns the old flavor_id |
| 437 | """ |
| 438 | try: |
| 439 | one = self._new_one_connection() |
| 440 | one.template.delete(int(flavor_id), False) |
| 441 | return flavor_id |
| 442 | except Exception as e: |
| 443 | self.logger.error("Error deleting flavor " + str(flavor_id) + ". Flavor not found") |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 444 | raise vimconn.VimConnException(e) |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 445 | |
| 446 | def get_image_list(self, filter_dict={}): |
| 447 | """Obtain tenant images from VIM |
| 448 | Filter_dict can be: |
| 449 | name: image name |
| 450 | id: image uuid |
| 451 | checksum: image checksum |
| 452 | location: image path |
| 453 | Returns the image list of dictionaries: |
| 454 | [{<the fields at Filter_dict plus some VIM specific>}, ...] |
| 455 | List can be empty |
| 456 | """ |
| 457 | try: |
| 458 | one = self._new_one_connection() |
| 459 | image_pool = one.imagepool.info(-2, -1, -1).IMAGE |
| 460 | images = [] |
| tierno | 7d782ef | 2019-10-04 12:56:31 +0000 | [diff] [blame] | 461 | if "name" in filter_dict: |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 462 | image_name_filter = filter_dict["name"] |
| 463 | else: |
| 464 | image_name_filter = None |
| tierno | 7d782ef | 2019-10-04 12:56:31 +0000 | [diff] [blame] | 465 | if "id" in filter_dict: |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 466 | image_id_filter = filter_dict["id"] |
| 467 | else: |
| 468 | image_id_filter = None |
| 469 | for image in image_pool: |
| 470 | if str(image_name_filter) == str(image.NAME) or str(image.ID) == str(image_id_filter): |
| 471 | images_dict = {"name": image.NAME, "id": str(image.ID)} |
| 472 | images.append(images_dict) |
| 473 | return images |
| 474 | except Exception as e: |
| 475 | self.logger.error("Get image list error: " + str(e)) |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 476 | raise vimconn.VimConnException(e) |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 477 | |
| 478 | def new_vminstance(self, name, description, start, image_id, flavor_id, net_list, cloud_config=None, disk_list=None, |
| 479 | availability_zone_index=None, availability_zone_list=None): |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 480 | """ |
| 481 | Adds a VM instance to VIM |
| 482 | :param name: |
| 483 | :param description: |
| 484 | :param start: (boolean) indicates if VM must start or created in pause mode. |
| 485 | :param image_id: image VIM id to use for the VM |
| 486 | :param flavor_id: flavor VIM id to use for the VM |
| 487 | :param net_list: list of interfaces, each one is a dictionary with: |
| 488 | 'name': (optional) name for the interface. |
| 489 | 'net_id': VIM network id where this interface must be connect to. Mandatory for type==virtual |
| 490 | 'vpci': (optional) virtual vPCI address to assign at the VM. Can be ignored depending on VIM |
| 491 | capabilities |
| 492 | 'model': (optional and only have sense for type==virtual) interface model: virtio, e1000, ... |
| 493 | 'mac_address': (optional) mac address to assign to this interface |
| 494 | 'ip_address': (optional) IP address to assign to this interface |
| 495 | #TODO: CHECK if an optional 'vlan' parameter is needed for VIMs when type if VF and net_id is not |
| 496 | provided, the VLAN tag to be used. In case net_id is provided, the internal network vlan is |
| 497 | used for tagging VF |
| 498 | 'type': (mandatory) can be one of: |
| 499 | 'virtual', in this case always connected to a network of type 'net_type=bridge' |
| 500 | 'PCI-PASSTHROUGH' or 'PF' (passthrough): depending on VIM capabilities it can be connected to |
| 501 | a data/ptp network ot itcan created unconnected |
| 502 | 'SR-IOV' or 'VF' (SRIOV with VLAN tag): same as PF for network connectivity. |
| 503 | 'VFnotShared'(SRIOV without VLAN tag) same as PF for network connectivity. VF where no other VFs |
| 504 | are allocated on the same physical NIC |
| 505 | 'bw': (optional) only for PF/VF/VFnotShared. Minimal Bandwidth required for the interface in GBPS |
| 506 | 'port_security': (optional) If False it must avoid any traffic filtering at this interface. If missing |
| 507 | or True, it must apply the default VIM behaviour |
| 508 | After execution the method will add the key: |
| 509 | 'vim_id': must be filled/added by this method with the VIM identifier generated by the VIM for this |
| 510 | interface. 'net_list' is modified |
| 511 | :param cloud_config: (optional) dictionary with: |
| 512 | 'key-pairs': (optional) list of strings with the public key to be inserted to the default user |
| 513 | 'users': (optional) list of users to be inserted, each item is a dict with: |
| 514 | 'name': (mandatory) user name, |
| 515 | 'key-pairs': (optional) list of strings with the public key to be inserted to the user |
| 516 | 'user-data': (optional) can be a string with the text script to be passed directly to cloud-init, |
| 517 | or a list of strings, each one contains a script to be passed, usually with a MIMEmultipart file |
| 518 | 'config-files': (optional). List of files to be transferred. Each item is a dict with: |
| 519 | 'dest': (mandatory) string with the destination absolute path |
| 520 | 'encoding': (optional, by default text). Can be one of: |
| 521 | 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64' |
| 522 | 'content' (mandatory): string with the content of the file |
| 523 | 'permissions': (optional) string with file permissions, typically octal notation '0644' |
| 524 | 'owner': (optional) file owner, string with the format 'owner:group' |
| 525 | 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk) |
| 526 | :param disk_list: (optional) list with additional disks to the VM. Each item is a dict with: |
| 527 | 'image_id': (optional). VIM id of an existing image. If not provided an empty disk must be mounted |
| 528 | 'size': (mandatory) string with the size of the disk in GB |
| 529 | :param availability_zone_index: Index of availability_zone_list to use for this this VM. None if not AV |
| 530 | required |
| 531 | :param availability_zone_list: list of availability zones given by user in the VNFD descriptor. Ignore if |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 532 | availability_zone_index is None |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 533 | :return: a tuple with the instance identifier and created_items or raises an exception on error |
| 534 | created_items can be None or a dictionary where this method can include key-values that will be passed to |
| 535 | the method delete_vminstance and action_vminstance. Can be used to store created ports, volumes, etc. |
| 536 | Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same |
| 537 | as not present. |
| 538 | """ |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 539 | self.logger.debug( |
| 540 | "new_vminstance input: image='{}' flavor='{}' nics='{}'".format(image_id, flavor_id, str(net_list))) |
| 541 | try: |
| 542 | one = self._new_one_connection() |
| 543 | template_vim = one.template.info(int(flavor_id), True) |
| 544 | disk_size = str(template_vim.TEMPLATE["DISK"]["SIZE"]) |
| 545 | |
| 546 | one = self._new_one_connection() |
| 547 | template_updated = "" |
| 548 | for net in net_list: |
| 549 | net_in_vim = one.vn.info(int(net["net_id"])) |
| 550 | net["vim_id"] = str(net_in_vim.ID) |
| 551 | network = 'NIC = [NETWORK = "{}",NETWORK_UNAME = "{}" ]'.format( |
| 552 | net_in_vim.NAME, net_in_vim.UNAME) |
| 553 | template_updated += network |
| 554 | |
| 555 | template_updated += "DISK = [ IMAGE_ID = {},\n SIZE = {}]".format(image_id, disk_size) |
| 556 | |
| 557 | if isinstance(cloud_config, dict): |
| 558 | if cloud_config.get("key-pairs"): |
| 559 | context = 'CONTEXT = [\n NETWORK = "YES",\n SSH_PUBLIC_KEY = "' |
| 560 | for key in cloud_config["key-pairs"]: |
| 561 | context += key + '\n' |
| 562 | # if False: |
| 563 | # context += '"\n USERNAME = ' |
| 564 | context += '"]' |
| 565 | template_updated += context |
| 566 | |
| 567 | vm_instance_id = one.template.instantiate(int(flavor_id), name, False, template_updated) |
| 568 | self.logger.info( |
| 569 | "Instanciating in OpenNebula a new VM name:{} id:{}".format(name, flavor_id)) |
| 570 | return str(vm_instance_id), None |
| 571 | except pyone.OneNoExistsException as e: |
| 572 | self.logger.error("Network with id " + str(e) + " not found: " + str(e)) |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 573 | raise vimconn.VimConnNotFoundException(e) |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 574 | except Exception as e: |
| 575 | self.logger.error("Create new vm instance error: " + str(e)) |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 576 | raise vimconn.VimConnException(e) |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 577 | |
| 578 | def get_vminstance(self, vm_id): |
| 579 | """Returns the VM instance information from VIM""" |
| 580 | try: |
| 581 | one = self._new_one_connection() |
| 582 | vm = one.vm.info(int(vm_id)) |
| 583 | return vm |
| 584 | except Exception as e: |
| 585 | self.logger.error("Getting vm instance error: " + str(e) + ": VM Instance not found") |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 586 | raise vimconn.VimConnException(e) |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 587 | |
| 588 | def delete_vminstance(self, vm_id, created_items=None): |
| 589 | """ |
| 590 | Removes a VM instance from VIM and its associated elements |
| 591 | :param vm_id: VIM identifier of the VM, provided by method new_vminstance |
| 592 | :param created_items: dictionary with extra items to be deleted. provided by method new_vminstance and/or method |
| 593 | action_vminstance |
| 594 | :return: None or the same vm_id. Raises an exception on fail |
| 595 | """ |
| 596 | try: |
| 597 | one = self._new_one_connection() |
| 598 | one.vm.recover(int(vm_id), 3) |
| 599 | vm = None |
| 600 | while True: |
| 601 | if vm is not None and vm.LCM_STATE == 0: |
| 602 | break |
| 603 | else: |
| 604 | vm = one.vm.info(int(vm_id)) |
| 605 | |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 606 | except pyone.OneNoExistsException: |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 607 | self.logger.info("The vm " + str(vm_id) + " does not exist or is already deleted") |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 608 | raise vimconn.VimConnNotFoundException("The vm {} does not exist or is already deleted".format(vm_id)) |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 609 | except Exception as e: |
| 610 | self.logger.error("Delete vm instance " + str(vm_id) + " error: " + str(e)) |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 611 | raise vimconn.VimConnException(e) |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 612 | |
| 613 | def refresh_vms_status(self, vm_list): |
| 614 | """Get the status of the virtual machines and their interfaces/ports |
| 615 | Params: the list of VM identifiers |
| 616 | Returns a dictionary with: |
| 617 | vm_id: #VIM id of this Virtual Machine |
| 618 | status: #Mandatory. Text with one of: |
| 619 | # DELETED (not found at vim) |
| 620 | # VIM_ERROR (Cannot connect to VIM, VIM response error, ...) |
| 621 | # OTHER (Vim reported other status not understood) |
| 622 | # ERROR (VIM indicates an ERROR status) |
| 623 | # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running), |
| 624 | # BUILD (on building process), ERROR |
| 625 | # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address |
| 626 | # |
| 627 | error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR |
| 628 | vim_info: #Text with plain information obtained from vim (yaml.safe_dump) |
| 629 | interfaces: list with interface info. Each item a dictionary with: |
| 630 | vim_info: #Text with plain information obtained from vim (yaml.safe_dump) |
| 631 | mac_address: #Text format XX:XX:XX:XX:XX:XX |
| 632 | vim_net_id: #network id where this interface is connected, if provided at creation |
| 633 | vim_interface_id: #interface/port VIM id |
| 634 | ip_address: #null, or text with IPv4, IPv6 address |
| 635 | compute_node: #identification of compute node where PF,VF interface is allocated |
| 636 | pci: #PCI address of the NIC that hosts the PF,VF |
| 637 | vlan: #physical VLAN used for VF |
| 638 | """ |
| 639 | vm_dict = {} |
| 640 | try: |
| 641 | for vm_id in vm_list: |
| 642 | vm = {} |
| 643 | if self.get_vminstance(vm_id) is not None: |
| 644 | vm_element = self.get_vminstance(vm_id) |
| 645 | else: |
| 646 | self.logger.info("The vm " + str(vm_id) + " does not exist.") |
| 647 | vm['status'] = "DELETED" |
| 648 | vm['error_msg'] = ("The vm " + str(vm_id) + " does not exist.") |
| 649 | continue |
| 650 | vm["vim_info"] = None |
| 651 | vm_status = vm_element.LCM_STATE |
| 652 | if vm_status == 3: |
| 653 | vm['status'] = "ACTIVE" |
| 654 | elif vm_status == 36: |
| 655 | vm['status'] = "ERROR" |
| 656 | vm['error_msg'] = "VM failure" |
| 657 | else: |
| 658 | vm['status'] = "BUILD" |
| 659 | |
| 660 | if vm_element is not None: |
| 661 | interfaces = self._get_networks_vm(vm_element) |
| 662 | vm["interfaces"] = interfaces |
| 663 | vm_dict[vm_id] = vm |
| 664 | return vm_dict |
| 665 | except Exception as e: |
| 666 | self.logger.error(e) |
| 667 | for k in vm_dict: |
| 668 | vm_dict[k]["status"] = "VIM_ERROR" |
| 669 | vm_dict[k]["error_msg"] = str(e) |
| 670 | return vm_dict |
| 671 | |
| 672 | def _get_networks_vm(self, vm_element): |
| 673 | interfaces = [] |
| 674 | try: |
| 675 | if isinstance(vm_element.TEMPLATE["NIC"], list): |
| 676 | for net in vm_element.TEMPLATE["NIC"]: |
| 677 | interface = {'vim_info': None, "mac_address": str(net["MAC"]), "vim_net_id": str(net["NETWORK_ID"]), |
| 678 | "vim_interface_id": str(net["NETWORK_ID"])} |
| 679 | # maybe it should be 2 different keys for ip_address if an interface has ipv4 and ipv6 |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 680 | if 'IP' in net: |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 681 | interface["ip_address"] = str(net["IP"]) |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 682 | if 'IP6_GLOBAL' in net: |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 683 | interface["ip_address"] = str(net["IP6_GLOBAL"]) |
| 684 | interfaces.append(interface) |
| 685 | else: |
| 686 | net = vm_element.TEMPLATE["NIC"] |
| 687 | interface = {'vim_info': None, "mac_address": str(net["MAC"]), "vim_net_id": str(net["NETWORK_ID"]), |
| 688 | "vim_interface_id": str(net["NETWORK_ID"])} |
| 689 | # maybe it should be 2 different keys for ip_address if an interface has ipv4 and ipv6 |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 690 | if 'IP' in net: |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 691 | interface["ip_address"] = str(net["IP"]) |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 692 | if 'IP6_GLOBAL' in net: |
| jomacarpe | 20c1323 | 2019-06-12 21:20:51 +0000 | [diff] [blame] | 693 | interface["ip_address"] = str(net["IP6_GLOBAL"]) |
| 694 | interfaces.append(interface) |
| 695 | return interfaces |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 696 | except Exception: |
| albertoflorez | 3ade00b | 2019-07-08 13:16:21 +0200 | [diff] [blame] | 697 | self.logger.error("Error getting vm interface_information of vm_id: " + str(vm_element.ID)) |