| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 1 | # -*- coding: utf-8 -*- |
| 2 | |
| 3 | ## |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 4 | # Copyright 2020 ADLINK Technology Inc. |
| baldoni | 1075715 | 2019-03-27 10:46:08 +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 | # License for the specific language governing permissions and limitations |
| 18 | # under the License. |
| 19 | # |
| 20 | # |
| 21 | |
| 22 | """ |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 23 | Eclipse fog05 connector, implements methods to interact with Eclipse fog05 |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 24 | |
| 25 | Manages LXD containers on x86_64 by default, currently missing EPA and VF/PF |
| 26 | Support config dict: |
| 27 | - arch : cpu architecture for the VIM |
| 28 | - hypervisor: virtualization technology supported by the VIM, can |
| 29 | can be one of: LXD, KVM, BARE, XEN, DOCKER, MCU |
| 30 | the selected VIM need to have at least a node with support |
| 31 | for the selected hypervisor |
| 32 | |
| 33 | """ |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 34 | |
| sousaedu | e493e9b | 2021-02-09 15:30:01 +0100 | [diff] [blame] | 35 | import logging |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 36 | import uuid |
| 37 | import socket |
| 38 | import struct |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 39 | from osm_ro_plugin import vimconn |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 40 | |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 41 | # import json |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 42 | from functools import partial |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 43 | from fog05 import FIMAPI |
| 44 | from fog05 import fimapi |
| 45 | from fog05_sdk.interfaces.FDU import FDU |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 46 | |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 47 | __author__ = "Gabriele Baldoni" |
| 48 | __date__ = "$2-june-2020 10:35:12$" |
| 49 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 50 | |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 51 | class vimconnector(vimconn.VimConnector): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 52 | def __init__( |
| 53 | self, |
| 54 | uuid, |
| 55 | name, |
| 56 | tenant_id, |
| 57 | tenant_name, |
| 58 | url, |
| 59 | url_admin=None, |
| 60 | user=None, |
| 61 | passwd=None, |
| 62 | log_level=None, |
| 63 | config={}, |
| 64 | persistent_info={}, |
| 65 | ): |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 66 | """Constructor of VIM |
| 67 | Params: |
| 68 | 'uuid': id asigned to this VIM |
| 69 | 'name': name assigned to this VIM, can be used for logging |
| 70 | 'tenant_id', 'tenant_name': (only one of them is mandatory) VIM tenant to be used |
| 71 | 'url_admin': (optional), url used for administrative tasks |
| 72 | 'user', 'passwd': credentials of the VIM user |
| 73 | 'log_level': provider if it should use a different log_level than the general one |
| 74 | 'config': dictionary with extra VIM information. This contains a consolidate version of general VIM config |
| 75 | at creation and particular VIM config at teh attachment |
| 76 | 'persistent_info': dict where the class can store information that will be available among class |
| 77 | destroy/creation cycles. This info is unique per VIM/credential. At first call it will contain an |
| 78 | empty dict. Useful to store login/tokens information for speed up communication |
| 79 | |
| 80 | Returns: Raise an exception is some needed parameter is missing, but it must not do any connectivity |
| 81 | check against the VIM |
| 82 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 83 | vimconn.VimConnector.__init__( |
| 84 | self, |
| 85 | uuid, |
| 86 | name, |
| 87 | tenant_id, |
| 88 | tenant_name, |
| 89 | url, |
| 90 | url_admin, |
| 91 | user, |
| 92 | passwd, |
| 93 | log_level, |
| 94 | config, |
| 95 | persistent_info, |
| 96 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 97 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 98 | self.logger = logging.getLogger("ro.vim.fos") |
| 99 | self.logger.debug("vimconn_fos init with config: {}".format(config)) |
| 100 | self.arch = config.get("arch", "x86_64") |
| 101 | self.hv = config.get("hypervisor", "LXD") |
| 102 | self.nodes = config.get("nodes", []) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 103 | self.fdu_node_map = {} |
| 104 | self.fos_api = FIMAPI(locator=self.url) |
| 105 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 106 | def __get_ip_range(self, first, count): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 107 | int_first = struct.unpack("!L", socket.inet_aton(first))[0] |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 108 | int_last = int_first + count |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 109 | last = socket.inet_ntoa(struct.pack("!L", int_last)) |
| 110 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 111 | return (first, last) |
| 112 | |
| 113 | def __name_filter(self, desc, filter_name=None): |
| 114 | if filter_name is None: |
| 115 | return True |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 116 | |
| 117 | return desc.get("name") == filter_name |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 118 | |
| 119 | def __id_filter(self, desc, filter_id=None): |
| 120 | if filter_id is None: |
| 121 | return True |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 122 | |
| 123 | return desc.get("uuid") == filter_id |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 124 | |
| 125 | def __checksum_filter(self, desc, filter_checksum=None): |
| 126 | if filter_checksum is None: |
| 127 | return True |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 128 | |
| 129 | return desc.get("checksum") == filter_checksum |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 130 | |
| 131 | def check_vim_connectivity(self): |
| 132 | """Checks VIM can be reached and user credentials are ok. |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 133 | Returns None if success or raised VimConnConnectionException, VimConnAuthException, ... |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 134 | """ |
| 135 | try: |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 136 | self.fos_api.node.list() |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 137 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 138 | return None |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 139 | except fimapi.FIMAuthExcetpion as fae: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 140 | raise vimconn.VimConnAuthException( |
| 141 | "Unable to authenticate to the VIM. Error {}".format(fae) |
| 142 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 143 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 144 | raise vimconn.VimConnConnectionException( |
| 145 | "VIM not reachable. Error {}".format(e) |
| 146 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 147 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 148 | def new_network( |
| 149 | self, |
| 150 | net_name, |
| 151 | net_type, |
| 152 | ip_profile=None, |
| 153 | shared=False, |
| 154 | provider_network_profile=None, |
| 155 | ): |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 156 | """Adds a tenant network to VIM |
| 157 | Params: |
| 158 | 'net_name': name of the network |
| 159 | 'net_type': one of: |
| 160 | 'bridge': overlay isolated network |
| 161 | 'data': underlay E-LAN network for Passthrough and SRIOV interfaces |
| 162 | 'ptp': underlay E-LINE network for Passthrough and SRIOV interfaces. |
| 163 | 'ip_profile': is a dict containing the IP parameters of the network |
| 164 | 'ip_version': can be "IPv4" or "IPv6" (Currently only IPv4 is implemented) |
| 165 | 'subnet_address': ip_prefix_schema, that is X.X.X.X/Y |
| 166 | 'gateway_address': (Optional) ip_schema, that is X.X.X.X |
| 167 | 'dns_address': (Optional) comma separated list of ip_schema, e.g. X.X.X.X[,X,X,X,X] |
| 168 | 'dhcp_enabled': True or False |
| 169 | 'dhcp_start_address': ip_schema, first IP to grant |
| 170 | 'dhcp_count': number of IPs to grant. |
| 171 | 'shared': if this network can be seen/use by other tenants/organization |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 172 | Returns the network identifier on success or raises and exception on failure |
| 173 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 174 | self.logger.debug("new_network: {}".format(locals())) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 175 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 176 | if net_type in ["data", "ptp"]: |
| 177 | raise vimconn.VimConnNotImplemented( |
| 178 | "{} type of network not supported".format(net_type) |
| 179 | ) |
| 180 | |
| 181 | net_uuid = "{}".format(uuid.uuid4()) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 182 | desc = { |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 183 | "uuid": net_uuid, |
| 184 | "name": net_name, |
| 185 | "net_type": "ELAN", |
| 186 | "is_mgmt": False, |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 187 | } |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 188 | |
| 189 | if ip_profile is not None: |
| 190 | ip = {} |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 191 | if ip_profile.get("ip_version") == "IPv4": |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 192 | ip_info = {} |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 193 | ip_range = self.__get_ip_range( |
| 194 | ip_profile.get("dhcp_start_address"), ip_profile.get("dhcp_count") |
| 195 | ) |
| 196 | dhcp_range = "{},{}".format(ip_range[0], ip_range[1]) |
| 197 | ip["subnet"] = ip_profile.get("subnet_address") |
| 198 | ip["dns"] = ip_profile.get("dns", None) |
| 199 | ip["dhcp_enable"] = ip_profile.get("dhcp_enabled", False) |
| 200 | ip["dhcp_range"] = dhcp_range |
| 201 | ip["gateway"] = ip_profile.get("gateway_address", None) |
| 202 | desc["ip_configuration"] = ip_info |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 203 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 204 | raise vimconn.VimConnNotImplemented( |
| 205 | "IPV6 network is not implemented at VIM" |
| 206 | ) |
| 207 | |
| 208 | desc["ip_configuration"] = ip |
| 209 | |
| 210 | self.logger.debug( |
| 211 | "VIM new_network args: {} - Generated Eclipse fog05 Descriptor {}".format( |
| 212 | locals(), desc |
| 213 | ) |
| 214 | ) |
| 215 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 216 | try: |
| 217 | self.fos_api.network.add_network(desc) |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 218 | except fimapi.FIMAResouceExistingException as free: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 219 | raise vimconn.VimConnConflictException( |
| 220 | "Network already exists at VIM. Error {}".format(free) |
| 221 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 222 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 223 | raise vimconn.VimConnException( |
| 224 | "Unable to create network {}. Error {}".format(net_name, e) |
| 225 | ) |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 226 | # No way from the current rest service to get the actual error, most likely it will be an already |
| 227 | # existing error |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 228 | |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 229 | return net_uuid, {} |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 230 | |
| 231 | def get_network_list(self, filter_dict={}): |
| 232 | """Obtain tenant networks of VIM |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 233 | :param filter_dict: (optional) contains entries to return only networks that matches ALL entries: |
| 234 | name: string => returns only networks with this name |
| 235 | id: string => returns networks with this VIM id, this imply returns one network at most |
| 236 | shared: boolean >= returns only networks that are (or are not) shared |
| 237 | tenant_id: sting => returns only networks that belong to this tenant/project |
| 238 | (not used yet) admin_state_up: boolean => returns only networks that are (or are not) in admin state active |
| 239 | (not used yet) status: 'ACTIVE','ERROR',... => filter networks that are on this status |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 240 | Returns the network list of dictionaries. each dictionary contains: |
| 241 | 'id': (mandatory) VIM network id |
| 242 | 'name': (mandatory) VIM network name |
| 243 | 'status': (mandatory) can be 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER' |
| 244 | 'network_type': (optional) can be 'vxlan', 'vlan' or 'flat' |
| 245 | 'segmentation_id': (optional) in case network_type is vlan or vxlan this field contains the segmentation id |
| 246 | 'error_msg': (optional) text that explains the ERROR status |
| 247 | other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param |
| 248 | List can be empty if no network map the filter_dict. Raise an exception only upon VIM connectivity, |
| 249 | authorization, or some other unspecific error |
| 250 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 251 | self.logger.debug("get_network_list: {}".format(filter_dict)) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 252 | res = [] |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 253 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 254 | try: |
| 255 | nets = self.fos_api.network.list() |
| 256 | except Exception as e: |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 257 | raise vimconn.VimConnConnectionException( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 258 | "Cannot get network list from VIM, connection error. Error {}".format(e) |
| 259 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 260 | |
| 261 | filters = [ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 262 | partial(self.__name_filter, filter_name=filter_dict.get("name")), |
| 263 | partial(self.__id_filter, filter_id=filter_dict.get("id")), |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 264 | ] |
| 265 | |
| 266 | r1 = [] |
| 267 | |
| 268 | for n in nets: |
| 269 | match = True |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 270 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 271 | for f in filters: |
| 272 | match = match and f(n) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 273 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 274 | if match: |
| 275 | r1.append(n) |
| 276 | |
| 277 | for n in r1: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 278 | osm_net = {"id": n.get("uuid"), "name": n.get("name"), "status": "ACTIVE"} |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 279 | res.append(osm_net) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 280 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 281 | return res |
| 282 | |
| 283 | def get_network(self, net_id): |
| 284 | """Obtain network details from the 'net_id' VIM network |
| 285 | Return a dict that contains: |
| 286 | 'id': (mandatory) VIM network id, that is, net_id |
| 287 | 'name': (mandatory) VIM network name |
| 288 | 'status': (mandatory) can be 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER' |
| 289 | 'error_msg': (optional) text that explains the ERROR status |
| 290 | other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param |
| 291 | Raises an exception upon error or when network is not found |
| 292 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 293 | self.logger.debug("get_network: {}".format(net_id)) |
| 294 | res = self.get_network_list(filter_dict={"id": net_id}) |
| 295 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 296 | if len(res) == 0: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 297 | raise vimconn.VimConnNotFoundException( |
| 298 | "Network {} not found at VIM".format(net_id) |
| 299 | ) |
| 300 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 301 | return res[0] |
| 302 | |
| baldoni | fb5855c | 2019-11-07 12:50:11 +0100 | [diff] [blame] | 303 | def delete_network(self, net_id, created_items=None): |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 304 | """Deletes a tenant network from VIM |
| 305 | Returns the network identifier or raises an exception upon error or when network is not found |
| 306 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 307 | self.logger.debug("delete_network: {}".format(net_id)) |
| 308 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 309 | try: |
| 310 | self.fos_api.network.remove_network(net_id) |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 311 | except fimapi.FIMNotFoundException as fnfe: |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 312 | raise vimconn.VimConnNotFoundException( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 313 | "Network {} not found at VIM (already deleted?). Error {}".format( |
| 314 | net_id, fnfe |
| 315 | ) |
| 316 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 317 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 318 | raise vimconn.VimConnException( |
| 319 | "Cannot delete network {} from VIM. Error {}".format(net_id, e) |
| 320 | ) |
| 321 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 322 | return net_id |
| 323 | |
| 324 | def refresh_nets_status(self, net_list): |
| 325 | """Get the status of the networks |
| 326 | Params: |
| 327 | 'net_list': a list with the VIM network id to be get the status |
| 328 | Returns a dictionary with: |
| 329 | 'net_id': #VIM id of this network |
| 330 | status: #Mandatory. Text with one of: |
| 331 | # DELETED (not found at vim) |
| 332 | # VIM_ERROR (Cannot connect to VIM, authentication problems, VIM response error, ...) |
| 333 | # OTHER (Vim reported other status not understood) |
| 334 | # ERROR (VIM indicates an ERROR status) |
| 335 | # ACTIVE, INACTIVE, DOWN (admin down), |
| 336 | # BUILD (on building process) |
| 337 | error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR |
| 338 | vim_info: #Text with plain information obtained from vim (yaml.safe_dump) |
| 339 | 'net_id2': ... |
| 340 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 341 | self.logger.debug("Refeshing network status with args: {}".format(locals())) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 342 | r = {} |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 343 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 344 | for n in net_list: |
| 345 | try: |
| 346 | osm_n = self.get_network(n) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 347 | r[osm_n.get("id")] = {"status": osm_n.get("status")} |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 348 | except vimconn.VimConnNotFoundException: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 349 | r[n] = {"status": "VIM_ERROR"} |
| 350 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 351 | return r |
| 352 | |
| 353 | def get_flavor(self, flavor_id): |
| 354 | """Obtain flavor details from the VIM |
| 355 | Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } |
| 356 | Raises an exception upon error or if not found |
| 357 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 358 | self.logger.debug("VIM get_flavor with args: {}".format(locals())) |
| 359 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 360 | try: |
| 361 | r = self.fos_api.flavor.get(flavor_id) |
| 362 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 363 | raise vimconn.VimConnConnectionException( |
| 364 | "VIM not reachable. Error {}".format(e) |
| 365 | ) |
| 366 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 367 | if r is None: |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 368 | raise vimconn.VimConnNotFoundException("Flavor not found at VIM") |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 369 | |
| 370 | return {"id": r.get("uuid"), "name": r.get("name"), "fos": r} |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 371 | |
| 372 | def get_flavor_id_from_data(self, flavor_dict): |
| 373 | """Obtain flavor id that match the flavor description |
| 374 | Params: |
| 375 | 'flavor_dict': dictionary that contains: |
| 376 | 'disk': main hard disk in GB |
| 377 | 'ram': meomry in MB |
| 378 | 'vcpus': number of virtual cpus |
| 379 | #TODO: complete parameters for EPA |
| 380 | Returns the flavor_id or raises a vimconnNotFoundException |
| 381 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 382 | self.logger.debug("VIM get_flavor_id_from_data with args : {}".format(locals())) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 383 | |
| 384 | try: |
| 385 | flvs = self.fos_api.flavor.list() |
| 386 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 387 | raise vimconn.VimConnConnectionException( |
| 388 | "VIM not reachable. Error {}".format(e) |
| 389 | ) |
| 390 | |
| 391 | r = [ |
| 392 | x.get("uuid") |
| 393 | for x in flvs |
| 394 | if ( |
| 395 | x.get("cpu_min_count") == flavor_dict.get("vcpus") |
| 396 | and x.get("ram_size_mb") == flavor_dict.get("ram") |
| 397 | and x.get("storage_size_gb") == flavor_dict.get("disk") |
| 398 | ) |
| 399 | ] |
| 400 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 401 | if len(r) == 0: |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 402 | raise vimconn.VimConnNotFoundException("No flavor found") |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 403 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 404 | return r[0] |
| 405 | |
| 406 | def new_flavor(self, flavor_data): |
| 407 | """Adds a tenant flavor to VIM |
| 408 | flavor_data contains a dictionary with information, keys: |
| 409 | name: flavor name |
| 410 | ram: memory (cloud type) in MBytes |
| 411 | vpcus: cpus (cloud type) |
| 412 | extended: EPA parameters |
| 413 | - numas: #items requested in same NUMA |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 414 | memory: number of 1G huge pages memory |
| 415 | paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads |
| 416 | interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 417 | - name: interface name |
| 418 | dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC |
| 419 | bandwidth: X Gbps; requested guarantee bandwidth |
| 420 | vpci: requested virtual PCI address |
| 421 | disk: disk size |
| 422 | is_public: |
| 423 | #TODO to concrete |
| 424 | Returns the flavor identifier""" |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 425 | self.logger.debug("VIM new_flavor with args: {}".format(locals())) |
| 426 | flv_id = "{}".format(uuid.uuid4()) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 427 | desc = { |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 428 | "uuid": flv_id, |
| 429 | "name": flavor_data.get("name"), |
| 430 | "cpu_arch": self.arch, |
| 431 | "cpu_min_count": flavor_data.get("vcpus"), |
| 432 | "cpu_min_freq": 0, |
| 433 | "ram_size_mb": float(flavor_data.get("ram")), |
| 434 | "storage_size_gb": float(flavor_data.get("disk")), |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 435 | } |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 436 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 437 | try: |
| 438 | self.fos_api.flavor.add(desc) |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 439 | except fimapi.FIMAResouceExistingException as free: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 440 | raise vimconn.VimConnConflictException( |
| 441 | "Flavor {} already exist at VIM. Error {}".format(flv_id, free) |
| 442 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 443 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 444 | raise vimconn.VimConnConnectionException( |
| 445 | "VIM not reachable. Error {}".format(e) |
| 446 | ) |
| 447 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 448 | return flv_id |
| 449 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 450 | def delete_flavor(self, flavor_id): |
| 451 | """Deletes a tenant flavor from VIM identify by its id |
| 452 | Returns the used id or raise an exception""" |
| 453 | try: |
| 454 | self.fos_api.flavor.remove(flavor_id) |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 455 | except fimapi.FIMNotFoundException as fnfe: |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 456 | raise vimconn.VimConnNotFoundException( |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 457 | "Flavor {} not found at VIM (already deleted?). Error {}".format( |
| 458 | flavor_id, fnfe |
| 459 | ) |
| 460 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 461 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 462 | raise vimconn.VimConnConnectionException( |
| 463 | "VIM not reachable. Error {}".format(e) |
| 464 | ) |
| 465 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 466 | return flavor_id |
| 467 | |
| 468 | def new_image(self, image_dict): |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 469 | """Adds a tenant image to VIM. imge_dict is a dictionary with: |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 470 | name: name |
| 471 | disk_format: qcow2, vhd, vmdk, raw (by default), ... |
| 472 | location: path or URI |
| 473 | public: "yes" or "no" |
| 474 | metadata: metadata of the image |
| 475 | Returns the image id or raises an exception if failed |
| 476 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 477 | self.logger.debug("VIM new_image with args: {}".format(locals())) |
| 478 | img_id = "{}".format(uuid.uuid4()) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 479 | desc = { |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 480 | "name": image_dict.get("name"), |
| 481 | "uuid": img_id, |
| 482 | "uri": image_dict.get("location"), |
| 483 | "format": image_dict.get("disk_format"), |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 484 | } |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 485 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 486 | try: |
| 487 | self.fos_api.image.add(desc) |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 488 | except fimapi.FIMAResouceExistingException as free: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 489 | raise vimconn.VimConnConflictException( |
| 490 | "Image {} already exist at VIM. Error {}".format(img_id, free) |
| 491 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 492 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 493 | raise vimconn.VimConnConnectionException( |
| 494 | "VIM not reachable. Error {}".format(e) |
| 495 | ) |
| 496 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 497 | return img_id |
| 498 | |
| 499 | def get_image_id_from_path(self, path): |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 500 | """Get the image id from image path in the VIM database. |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 501 | Returns the image_id or raises a vimconnNotFoundException |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 502 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 503 | self.logger.debug("VIM get_image_id_from_path with args: {}".format(locals())) |
| 504 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 505 | try: |
| 506 | imgs = self.fos_api.image.list() |
| 507 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 508 | raise vimconn.VimConnConnectionException( |
| 509 | "VIM not reachable. Error {}".format(e) |
| 510 | ) |
| 511 | |
| 512 | res = [x.get("uuid") for x in imgs if x.get("uri") == path] |
| 513 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 514 | if len(res) == 0: |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 515 | raise vimconn.VimConnNotFoundException("Image with this path was not found") |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 516 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 517 | return res[0] |
| 518 | |
| 519 | def get_image_list(self, filter_dict={}): |
| 520 | """Obtain tenant images from VIM |
| 521 | Filter_dict can be: |
| 522 | name: image name |
| 523 | id: image uuid |
| 524 | checksum: image checksum |
| 525 | location: image path |
| 526 | Returns the image list of dictionaries: |
| 527 | [{<the fields at Filter_dict plus some VIM specific>}, ...] |
| 528 | List can be empty |
| 529 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 530 | self.logger.debug("VIM get_image_list args: {}".format(locals())) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 531 | r = [] |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 532 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 533 | try: |
| 534 | fimgs = self.fos_api.image.list() |
| 535 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 536 | raise vimconn.VimConnConnectionException( |
| 537 | "VIM not reachable. Error {}".format(e) |
| 538 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 539 | |
| 540 | filters = [ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 541 | partial(self.__name_filter, filter_name=filter_dict.get("name")), |
| 542 | partial(self.__id_filter, filter_id=filter_dict.get("id")), |
| 543 | partial( |
| 544 | self.__checksum_filter, filter_checksum=filter_dict.get("checksum") |
| 545 | ), |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 546 | ] |
| 547 | |
| 548 | r1 = [] |
| 549 | |
| 550 | for i in fimgs: |
| 551 | match = True |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 552 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 553 | for f in filters: |
| 554 | match = match and f(i) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 555 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 556 | if match: |
| 557 | r1.append(i) |
| 558 | |
| 559 | for i in r1: |
| 560 | img_info = { |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 561 | "name": i.get("name"), |
| 562 | "id": i.get("uuid"), |
| 563 | "checksum": i.get("checksum"), |
| 564 | "location": i.get("uri"), |
| 565 | "fos": i, |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 566 | } |
| 567 | r.append(img_info) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 568 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 569 | return r |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 570 | # raise VimConnNotImplemented( "Should have implemented this" ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 571 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 572 | def new_vminstance( |
| 573 | self, |
| 574 | name, |
| 575 | description, |
| 576 | start, |
| 577 | image_id, |
| 578 | flavor_id, |
| 579 | net_list, |
| 580 | cloud_config=None, |
| 581 | disk_list=None, |
| 582 | availability_zone_index=None, |
| 583 | availability_zone_list=None, |
| 584 | ): |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 585 | """Adds a VM instance to VIM |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 586 | :param start: (boolean) indicates if VM must start or created in pause mode. |
| 587 | :param image_id: :param flavor_id: image and flavor VIM id to use for the VM |
| 588 | :param net_list: list of interfaces, each one is a dictionary with: |
| 589 | 'name': (optional) name for the interface. |
| 590 | 'net_id': VIM network id where this interface must be connect to. Mandatory for type==virtual |
| 591 | 'vpci': (optional) virtual vPCI address to assign at the VM. Can be ignored depending on VIM capabilities |
| 592 | 'model': (optional and only have sense for type==virtual) interface model: virtio, e1000, ... |
| 593 | 'mac_address': (optional) mac address to assign to this interface |
| 594 | 'ip_address': (optional) IP address to assign to this interface |
| 595 | #TODO: CHECK if an optional 'vlan' parameter is needed for VIMs when type if VF and net_id is not provided, |
| 596 | the VLAN tag to be used. In case net_id is provided, the internal network vlan is used for tagging VF |
| 597 | 'type': (mandatory) can be one of: |
| 598 | 'virtual', in this case always connected to a network of type 'net_type=bridge' |
| 599 | 'PCI-PASSTHROUGH' or 'PF' (passthrough): depending on VIM capabilities it can be connected to a |
| 600 | data/ptp network ot it can created unconnected |
| 601 | 'SR-IOV' or 'VF' (SRIOV with VLAN tag): same as PF for network connectivity. |
| 602 | 'VFnotShared'(SRIOV without VLAN tag) same as PF for network connectivity. VF where no other VFs |
| 603 | are allocated on the same physical NIC |
| 604 | 'bw': (optional) only for PF/VF/VFnotShared. Minimal Bandwidth required for the interface in GBPS |
| 605 | 'port_security': (optional) If False it must avoid any traffic filtering at this interface. If missing |
| 606 | or True, it must apply the default VIM behaviour |
| 607 | After execution the method will add the key: |
| 608 | 'vim_id': must be filled/added by this method with the VIM identifier generated by the VIM for this |
| 609 | interface. 'net_list' is modified |
| 610 | :param cloud_config: (optional) dictionary with: |
| 611 | 'key-pairs': (optional) list of strings with the public key to be inserted to the default user |
| 612 | 'users': (optional) list of users to be inserted, each item is a dict with: |
| 613 | 'name': (mandatory) user name, |
| 614 | 'key-pairs': (optional) list of strings with the public key to be inserted to the user |
| 615 | 'user-data': (optional) can be a string with the text script to be passed directly to cloud-init, |
| 616 | or a list of strings, each one contains a script to be passed, usually with a MIMEmultipart file |
| 617 | 'config-files': (optional). List of files to be transferred. Each item is a dict with: |
| 618 | 'dest': (mandatory) string with the destination absolute path |
| 619 | 'encoding': (optional, by default text). Can be one of: |
| 620 | 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64' |
| 621 | 'content' (mandatory): string with the content of the file |
| 622 | 'permissions': (optional) string with file permissions, typically octal notation '0644' |
| 623 | 'owner': (optional) file owner, string with the format 'owner:group' |
| 624 | 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk) |
| 625 | :param disk_list: (optional) list with additional disks to the VM. Each item is a dict with: |
| 626 | 'image_id': (optional). VIM id of an existing image. If not provided an empty disk must be mounted |
| 627 | 'size': (mandatory) string with the size of the disk in GB |
| 628 | :param availability_zone_index: Index of availability_zone_list to use for this this VM. None if not AV required |
| 629 | :param availability_zone_list: list of availability zones given by user in the VNFD descriptor. Ignore if |
| 630 | availability_zone_index is None |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 631 | Returns a tuple with the instance identifier and created_items or raises an exception on error |
| 632 | created_items can be None or a dictionary where this method can include key-values that will be passed to |
| 633 | the method delete_vminstance and action_vminstance. Can be used to store created ports, volumes, etc. |
| 634 | Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same |
| 635 | as not present. |
| 636 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 637 | self.logger.debug("new_vminstance with args: {}".format(locals())) |
| 638 | fdu_uuid = "{}".format(uuid.uuid4()) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 639 | |
| 640 | flv = self.fos_api.flavor.get(flavor_id) |
| 641 | img = self.fos_api.image.get(image_id) |
| 642 | |
| 643 | if flv is None: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 644 | raise vimconn.VimConnNotFoundException( |
| 645 | "Flavor {} not found at VIM".format(flavor_id) |
| 646 | ) |
| 647 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 648 | if img is None: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 649 | raise vimconn.VimConnNotFoundException( |
| 650 | "Image {} not found at VIM".format(image_id) |
| 651 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 652 | |
| 653 | created_items = { |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 654 | "fdu_id": "", |
| 655 | "node_id": "", |
| 656 | "connection_points": [], |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 657 | } |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 658 | |
| 659 | fdu_desc = { |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 660 | "name": name, |
| 661 | "id": fdu_uuid, |
| 662 | "uuid": fdu_uuid, |
| 663 | "computation_requirements": flv, |
| 664 | "image": img, |
| 665 | "hypervisor": self.hv, |
| 666 | "migration_kind": "LIVE", |
| 667 | "interfaces": [], |
| 668 | "io_ports": [], |
| 669 | "connection_points": [], |
| 670 | "depends_on": [], |
| 671 | "storage": [], |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 672 | } |
| 673 | |
| 674 | nets = [] |
| 675 | cps = [] |
| 676 | intf_id = 0 |
| 677 | for n in net_list: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 678 | cp_id = "{}".format(uuid.uuid4()) |
| 679 | n["vim_id"] = cp_id |
| 680 | pair_id = n.get("net_id") |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 681 | |
| 682 | cp_d = { |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 683 | "id": cp_id, |
| 684 | "name": cp_id, |
| 685 | "vld_ref": pair_id, |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 686 | } |
| 687 | intf_d = { |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 688 | "name": n.get("name", "eth{}".format(intf_id)), |
| 689 | "is_mgmt": False, |
| 690 | "if_type": "INTERNAL", |
| 691 | "virtual_interface": { |
| 692 | "intf_type": n.get("model", "VIRTIO"), |
| 693 | "vpci": n.get("vpci", "0:0:0"), |
| 694 | "bandwidth": int(n.get("bw", 100)), |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 695 | }, |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 696 | "cp_id": cp_id, |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 697 | } |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 698 | if n.get("mac_address", None) is not None: |
| 699 | intf_d["mac_address"] = n["mac_address"] |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 700 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 701 | created_items["connection_points"].append(cp_id) |
| 702 | fdu_desc["connection_points"].append(cp_d) |
| 703 | fdu_desc["interfaces"].append(intf_d) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 704 | |
| 705 | intf_id = intf_id + 1 |
| 706 | |
| 707 | if cloud_config is not None: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 708 | configuration = {"conf_type": "CLOUD_INIT"} |
| 709 | if cloud_config.get("user-data") is not None: |
| 710 | configuration["script"] = cloud_config.get("user-data") |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 711 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 712 | if cloud_config.get("key-pairs") is not None: |
| 713 | configuration["ssh_keys"] = cloud_config.get("key-pairs") |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 714 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 715 | if "script" in configuration: |
| 716 | fdu_desc["configuration"] = configuration |
| 717 | |
| 718 | self.logger.debug("Eclipse fog05 FDU Descriptor: {}".format(fdu_desc)) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 719 | |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 720 | fdu = FDU(fdu_desc) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 721 | |
| 722 | try: |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 723 | self.fos_api.fdu.onboard(fdu) |
| 724 | instance = self.fos_api.fdu.define(fdu_uuid) |
| 725 | instance_list = self.fos_api.fdu.instance_list(fdu_uuid) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 726 | selected_node = "" |
| 727 | |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 728 | for n in instance_list: |
| 729 | instances = instance_list[n] |
| 730 | if instance.uuid in instances: |
| 731 | selected_node = n |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 732 | |
| 733 | if selected_node == "": |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 734 | raise ValueError("Unable to find node for network creation") |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 735 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 736 | self.logger.debug("Selected node by VIM: {}".format(selected_node)) |
| 737 | created_items["fdu_id"] = fdu_uuid |
| 738 | created_items["node_id"] = selected_node |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 739 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 740 | for cp in fdu_desc["connection_points"]: |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 741 | nets = self.fos_api.network.list() |
| 742 | for net in nets: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 743 | if net.get("uuid") == cp["vld_ref"]: |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 744 | self.fos_api.network.add_network_to_node(net, selected_node) |
| 745 | |
| 746 | self.fos_api.fdu.configure(instance.uuid) |
| 747 | self.fos_api.fdu.start(instance.uuid) |
| 748 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 749 | self.logger.debug("Eclipse fog05 FDU Started {}".format(instance.uuid)) |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 750 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 751 | created_items["instance_id"] = str(instance.uuid) |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 752 | |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 753 | self.fdu_node_map[instance.uuid] = selected_node |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 754 | self.logger.debug( |
| 755 | "new_vminstance returns: {} {}".format(instance.uuid, created_items) |
| 756 | ) |
| 757 | |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 758 | return str(instance.uuid), created_items |
| 759 | except fimapi.FIMAResouceExistingException as free: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 760 | raise vimconn.VimConnConflictException( |
| 761 | "VM already exists at VIM. Error {}".format(free) |
| 762 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 763 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 764 | raise vimconn.VimConnException( |
| 765 | "Error while instantiating VM {}. Error {}".format(name, e) |
| 766 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 767 | |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 768 | def get_vminstance(self, vm_id): |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 769 | """Returns the VM instance information from VIM""" |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 770 | self.logger.debug("VIM get_vminstance with args: {}".format(locals())) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 771 | |
| 772 | try: |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 773 | instance = self.fos_api.fdu.instance_info(vm_id) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 774 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 775 | raise vimconn.VimConnConnectionException( |
| 776 | "VIM not reachable. Error {}".format(e) |
| 777 | ) |
| 778 | |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 779 | if instance is None: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 780 | raise vimconn.VimConnNotFoundException( |
| 781 | "VM with id {} not found!".format(vm_id) |
| 782 | ) |
| 783 | |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 784 | return instance.to_json() |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 785 | |
| 786 | def delete_vminstance(self, vm_id, created_items=None): |
| 787 | """ |
| 788 | Removes a VM instance from VIM and each associate elements |
| 789 | :param vm_id: VIM identifier of the VM, provided by method new_vminstance |
| 790 | :param created_items: dictionary with extra items to be deleted. provided by method new_vminstance and/or method |
| 791 | action_vminstance |
| 792 | :return: None or the same vm_id. Raises an exception on fail |
| 793 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 794 | self.logger.debug("FOS delete_vminstance with args: {}".format(locals())) |
| 795 | fduid = created_items.get("fdu_id") |
| 796 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 797 | try: |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 798 | instance = self.fos_api.fdu.instance_info(vm_id) |
| 799 | instance_list = self.fos_api.fdu.instance_list(instance.fdu_id) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 800 | selected_node = "" |
| 801 | |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 802 | for n in instance_list: |
| 803 | instances = instance_list[n] |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 804 | |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 805 | if instance.uuid in instances: |
| 806 | selected_node = n |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 807 | |
| 808 | if selected_node == "": |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 809 | raise ValueError("Unable to find node for the given Instance") |
| 810 | |
| 811 | self.fos_api.fdu.stop(vm_id) |
| 812 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 813 | for cp in instance.to_json()["connection_points"]: |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 814 | nets = self.fos_api.network.list() |
| 815 | for net in nets: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 816 | if net.get("uuid") == cp["vld_ref"]: |
| 817 | self.fos_api.network.remove_network_from_node( |
| 818 | net.get("uuid"), selected_node |
| 819 | ) |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 820 | |
| 821 | self.fos_api.fdu.clean(vm_id) |
| 822 | self.fos_api.fdu.undefine(vm_id) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 823 | self.fos_api.fdu.offload(fduid) |
| 824 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 825 | raise vimconn.VimConnException( |
| 826 | "Error on deleting VM with id {}. Error {}".format(vm_id, e) |
| 827 | ) |
| 828 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 829 | return vm_id |
| 830 | |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 831 | # raise VimConnNotImplemented( "Should have implemented this" ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 832 | |
| 833 | def refresh_vms_status(self, vm_list): |
| 834 | """Get the status of the virtual machines and their interfaces/ports |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 835 | Params: the list of VM identifiers |
| 836 | Returns a dictionary with: |
| 837 | vm_id: #VIM id of this Virtual Machine |
| 838 | status: #Mandatory. Text with one of: |
| 839 | # DELETED (not found at vim) |
| 840 | # VIM_ERROR (Cannot connect to VIM, VIM response error, ...) |
| 841 | # OTHER (Vim reported other status not understood) |
| 842 | # ERROR (VIM indicates an ERROR status) |
| 843 | # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running), |
| 844 | # BUILD (on building process), ERROR |
| 845 | # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address |
| 846 | # |
| 847 | error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR |
| 848 | vim_info: #Text with plain information obtained from vim (yaml.safe_dump) |
| 849 | interfaces: list with interface info. Each item a dictionary with: |
| 850 | vim_info: #Text with plain information obtained from vim (yaml.safe_dump) |
| 851 | mac_address: #Text format XX:XX:XX:XX:XX:XX |
| 852 | vim_net_id: #network id where this interface is connected, if provided at creation |
| 853 | vim_interface_id: #interface/port VIM id |
| 854 | ip_address: #null, or text with IPv4, IPv6 address |
| 855 | compute_node: #identification of compute node where PF,VF interface is allocated |
| 856 | pci: #PCI address of the NIC that hosts the PF,VF |
| 857 | vlan: #physical VLAN used for VF |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 858 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 859 | self.logger.debug("FOS refresh_vms_status with args: {}".format(locals())) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 860 | fos2osm_status = { |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 861 | "DEFINE": "OTHER", |
| 862 | "CONFIGURE": "INACTIVE", |
| 863 | "RUN": "ACTIVE", |
| 864 | "PAUSE": "PAUSED", |
| 865 | "ERROR": "ERROR", |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 866 | } |
| 867 | |
| 868 | r = {} |
| 869 | |
| 870 | for vm in vm_list: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 871 | self.logger.debug("FOS refresh_vms_status for {}".format(vm)) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 872 | |
| 873 | info = {} |
| 874 | nid = self.fdu_node_map.get(vm) |
| 875 | if nid is None: |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 876 | r[vm] = { |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 877 | "status": "VIM_ERROR", |
| 878 | "error_msg": "Not compute node associated for VM", |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 879 | } |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 880 | continue |
| 881 | |
| 882 | try: |
| 883 | vm_info = self.fos_api.fdu.instance_info(vm) |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 884 | except Exception: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 885 | r[vm] = {"status": "VIM_ERROR", "error_msg": "unable to connect to VIM"} |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 886 | continue |
| 887 | |
| 888 | if vm_info is None: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 889 | r[vm:] = {"status": "DELETED"} |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 890 | continue |
| 891 | |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 892 | desc = self.fos_api.fdu.info(str(vm_info.fdu_id)) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 893 | |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 894 | vm_info = vm_info.to_json() |
| 895 | desc = desc.to_json() |
| 896 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 897 | osm_status = fos2osm_status.get(vm_info.get("status")) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 898 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 899 | self.logger.debug("FOS status info {}".format(vm_info)) |
| 900 | self.logger.debug( |
| 901 | "FOS status is {} <-> OSM Status {}".format( |
| 902 | vm_info.get("status"), osm_status |
| 903 | ) |
| 904 | ) |
| 905 | info["status"] = osm_status |
| 906 | |
| 907 | if vm_info.get("status") == "ERROR": |
| 908 | info["error_msg"] = vm_info.get("error_code") |
| 909 | |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 910 | # yaml.safe_dump(json.loads(json.dumps(vm_info))) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 911 | # info["vim_info"] = "" |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 912 | faces = [] |
| 913 | i = 0 |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 914 | for intf_name in vm_info.get("hypervisor_info").get("network", []): |
| 915 | intf_info = vm_info.get("hypervisor_info").get("network").get(intf_name) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 916 | face = {} |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 917 | face["compute_node"] = nid |
| 918 | # face["vim_info"] = "" #yaml.safe_dump(json.loads(json.dumps(intf_info))) |
| 919 | face["mac_address"] = intf_info.get("hwaddr") |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 920 | addrs = [] |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 921 | |
| 922 | for a in intf_info.get("addresses"): |
| 923 | addrs.append(a.get("address")) |
| 924 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 925 | if len(addrs) >= 0: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 926 | face["ip_address"] = ",".join(addrs) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 927 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 928 | face["ip_address"] = "" |
| 929 | |
| 930 | face["pci"] = "0:0:0.0" |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 931 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 932 | try: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 933 | cp_info = vm_info.get("connection_points")[i] |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 934 | except IndexError: |
| 935 | cp_info = None |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 936 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 937 | if cp_info is not None: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 938 | cp_id = cp_info["cp_id"] |
| 939 | cps_d = desc["connection_points"] |
| 940 | matches = [x for x in cps_d if x["id"] == cp_id] |
| 941 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 942 | if len(matches) > 0: |
| 943 | cpd = matches[0] |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 944 | face["vim_net_id"] = cpd.get("vld_ref", "") |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 945 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 946 | face["vim_net_id"] = "" |
| 947 | |
| 948 | face["vim_interface_id"] = cp_id |
| 949 | # cp_info.get("uuid") |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 950 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 951 | face["vim_net_id"] = "" |
| 952 | face["vim_interface_id"] = intf_name |
| 953 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 954 | faces.append(face) |
| 955 | i += 1 |
| 956 | |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 957 | info["interfaces"] = faces |
| tierno | 1ec592d | 2020-06-16 15:29:47 +0000 | [diff] [blame] | 958 | r[vm] = info |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 959 | self.logger.debug( |
| 960 | "FOS refresh_vms_status res for {} is {}".format(vm, info) |
| 961 | ) |
| 962 | |
| 963 | self.logger.debug("FOS refresh_vms_status res is {}".format(r)) |
| 964 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 965 | return r |
| 966 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 967 | def action_vminstance(self, vm_id, action_dict, created_items={}): |
| 968 | """ |
| 969 | Send and action over a VM instance. Returns created_items if the action was successfully sent to the VIM. |
| 970 | created_items is a dictionary with items that |
| 971 | :param vm_id: VIM identifier of the VM, provided by method new_vminstance |
| 972 | :param action_dict: dictionary with the action to perform |
| 973 | :param created_items: provided by method new_vminstance is a dictionary with key-values that will be passed to |
| 974 | the method delete_vminstance. Can be used to store created ports, volumes, etc. Format is vimconnector |
| 975 | dependent, but do not use nested dictionaries and a value of None should be the same as not present. This |
| 976 | method can modify this value |
| 977 | :return: None, or a console dict |
| 978 | """ |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 979 | self.logger.debug("VIM action_vminstance with args: {}".format(locals())) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 980 | nid = self.fdu_node_map.get(vm_id) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 981 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 982 | if nid is None: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 983 | raise vimconn.VimConnNotFoundException("No node for this VM") |
| 984 | |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 985 | try: |
| baldoni | 07df0d2 | 2020-06-12 15:24:24 +0200 | [diff] [blame] | 986 | instance = self.fos_api.fdu.instance_info(vm_id) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 987 | if "start" in action_dict: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 988 | if instance.get("status") == "CONFIGURE": |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 989 | self.fos_api.fdu.start(vm_id) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 990 | elif instance.get("status") == "PAUSE": |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 991 | self.fos_api.fdu.resume(vm_id) |
| 992 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 993 | raise vimconn.VimConnConflictException( |
| 994 | "Cannot start from current state: {}".format( |
| 995 | instance.get("status") |
| 996 | ) |
| 997 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 998 | elif "pause" in action_dict: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 999 | if instance.get("status") == "RUN": |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 1000 | self.fos_api.fdu.pause(vm_id) |
| 1001 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1002 | raise vimconn.VimConnConflictException( |
| 1003 | "Cannot pause from current state: {}".format( |
| 1004 | instance.get("status") |
| 1005 | ) |
| 1006 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 1007 | elif "resume" in action_dict: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1008 | if instance.get("status") == "PAUSE": |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 1009 | self.fos_api.fdu.resume(vm_id) |
| 1010 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1011 | raise vimconn.VimConnConflictException( |
| 1012 | "Cannot resume from current state: {}".format( |
| 1013 | instance.get("status") |
| 1014 | ) |
| 1015 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 1016 | elif "shutoff" in action_dict or "shutdown" or "forceOff" in action_dict: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1017 | if instance.get("status") == "RUN": |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 1018 | self.fos_api.fdu.stop(vm_id) |
| 1019 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1020 | raise vimconn.VimConnConflictException( |
| 1021 | "Cannot shutoff from current state: {}".format( |
| 1022 | instance.get("status") |
| 1023 | ) |
| 1024 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 1025 | elif "terminate" in action_dict: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1026 | if instance.get("status") == "RUN": |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 1027 | self.fos_api.fdu.stop(vm_id) |
| 1028 | self.fos_api.fdu.clean(vm_id) |
| 1029 | self.fos_api.fdu.undefine(vm_id) |
| 1030 | # self.fos_api.fdu.offload(vm_id) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1031 | elif instance.get("status") == "CONFIGURE": |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 1032 | self.fos_api.fdu.clean(vm_id) |
| 1033 | self.fos_api.fdu.undefine(vm_id) |
| 1034 | # self.fos_api.fdu.offload(vm_id) |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1035 | elif instance.get("status") == "PAUSE": |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 1036 | self.fos_api.fdu.resume(vm_id) |
| 1037 | self.fos_api.fdu.stop(vm_id) |
| 1038 | self.fos_api.fdu.clean(vm_id) |
| 1039 | self.fos_api.fdu.undefine(vm_id) |
| 1040 | # self.fos_api.fdu.offload(vm_id) |
| 1041 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1042 | raise vimconn.VimConnConflictException( |
| 1043 | "Cannot terminate from current state: {}".format( |
| 1044 | instance.get("status") |
| 1045 | ) |
| 1046 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 1047 | elif "rebuild" in action_dict: |
| tierno | 7277486 | 2020-05-04 11:44:15 +0000 | [diff] [blame] | 1048 | raise vimconn.VimConnNotImplemented("Rebuild not implemented") |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 1049 | elif "reboot" in action_dict: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1050 | if instance.get("status") == "RUN": |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 1051 | self.fos_api.fdu.stop(vm_id) |
| 1052 | self.fos_api.fdu.start(vm_id) |
| 1053 | else: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1054 | raise vimconn.VimConnConflictException( |
| 1055 | "Cannot reboot from current state: {}".format( |
| 1056 | instance.get("status") |
| 1057 | ) |
| 1058 | ) |
| baldoni | 1075715 | 2019-03-27 10:46:08 +0100 | [diff] [blame] | 1059 | except Exception as e: |
| sousaedu | 80135b9 | 2021-02-17 15:05:18 +0100 | [diff] [blame] | 1060 | raise vimconn.VimConnConnectionException( |
| 1061 | "VIM not reachable. Error {}".format(e) |
| 1062 | ) |