blob: 8f946338f79db61f1a679529735cf1a1b3e4585a [file] [log] [blame]
baldoni10757152019-03-27 10:46:08 +01001# -*- coding: utf-8 -*-
2
3##
baldoni07df0d22020-06-12 15:24:24 +02004# Copyright 2020 ADLINK Technology Inc.
baldoni10757152019-03-27 10:46:08 +01005# 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"""
baldoni07df0d22020-06-12 15:24:24 +020023Eclipse fog05 connector, implements methods to interact with Eclipse fog05
baldoni10757152019-03-27 10:46:08 +010024
25Manages LXD containers on x86_64 by default, currently missing EPA and VF/PF
26Support 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"""
baldoni10757152019-03-27 10:46:08 +010034
sousaedue493e9b2021-02-09 15:30:01 +010035import logging
baldoni10757152019-03-27 10:46:08 +010036import uuid
37import socket
38import struct
tierno72774862020-05-04 11:44:15 +000039from osm_ro_plugin import vimconn
sousaedu80135b92021-02-17 15:05:18 +010040
tierno1ec592d2020-06-16 15:29:47 +000041# import json
baldoni10757152019-03-27 10:46:08 +010042from functools import partial
baldoni07df0d22020-06-12 15:24:24 +020043from fog05 import FIMAPI
44from fog05 import fimapi
45from fog05_sdk.interfaces.FDU import FDU
baldoni10757152019-03-27 10:46:08 +010046
tierno1ec592d2020-06-16 15:29:47 +000047__author__ = "Gabriele Baldoni"
48__date__ = "$2-june-2020 10:35:12$"
49
baldoni10757152019-03-27 10:46:08 +010050
tierno72774862020-05-04 11:44:15 +000051class vimconnector(vimconn.VimConnector):
sousaedu80135b92021-02-17 15:05:18 +010052 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 ):
baldoni10757152019-03-27 10:46:08 +010066 """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 """
sousaedu80135b92021-02-17 15:05:18 +010083 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 )
baldoni10757152019-03-27 10:46:08 +010097
sousaedu80135b92021-02-17 15:05:18 +010098 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", [])
baldoni10757152019-03-27 10:46:08 +0100103 self.fdu_node_map = {}
104 self.fos_api = FIMAPI(locator=self.url)
105
baldoni10757152019-03-27 10:46:08 +0100106 def __get_ip_range(self, first, count):
sousaedu80135b92021-02-17 15:05:18 +0100107 int_first = struct.unpack("!L", socket.inet_aton(first))[0]
baldoni10757152019-03-27 10:46:08 +0100108 int_last = int_first + count
sousaedu80135b92021-02-17 15:05:18 +0100109 last = socket.inet_ntoa(struct.pack("!L", int_last))
110
baldoni10757152019-03-27 10:46:08 +0100111 return (first, last)
112
113 def __name_filter(self, desc, filter_name=None):
114 if filter_name is None:
115 return True
sousaedu80135b92021-02-17 15:05:18 +0100116
117 return desc.get("name") == filter_name
baldoni10757152019-03-27 10:46:08 +0100118
119 def __id_filter(self, desc, filter_id=None):
120 if filter_id is None:
121 return True
sousaedu80135b92021-02-17 15:05:18 +0100122
123 return desc.get("uuid") == filter_id
baldoni10757152019-03-27 10:46:08 +0100124
125 def __checksum_filter(self, desc, filter_checksum=None):
126 if filter_checksum is None:
127 return True
sousaedu80135b92021-02-17 15:05:18 +0100128
129 return desc.get("checksum") == filter_checksum
baldoni10757152019-03-27 10:46:08 +0100130
131 def check_vim_connectivity(self):
132 """Checks VIM can be reached and user credentials are ok.
tierno72774862020-05-04 11:44:15 +0000133 Returns None if success or raised VimConnConnectionException, VimConnAuthException, ...
baldoni10757152019-03-27 10:46:08 +0100134 """
135 try:
baldoni07df0d22020-06-12 15:24:24 +0200136 self.fos_api.node.list()
sousaedu80135b92021-02-17 15:05:18 +0100137
baldoni10757152019-03-27 10:46:08 +0100138 return None
baldoni07df0d22020-06-12 15:24:24 +0200139 except fimapi.FIMAuthExcetpion as fae:
sousaedu80135b92021-02-17 15:05:18 +0100140 raise vimconn.VimConnAuthException(
141 "Unable to authenticate to the VIM. Error {}".format(fae)
142 )
baldoni10757152019-03-27 10:46:08 +0100143 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100144 raise vimconn.VimConnConnectionException(
145 "VIM not reachable. Error {}".format(e)
146 )
baldoni10757152019-03-27 10:46:08 +0100147
sousaedu80135b92021-02-17 15:05:18 +0100148 def new_network(
149 self,
150 net_name,
151 net_type,
152 ip_profile=None,
153 shared=False,
154 provider_network_profile=None,
155 ):
baldoni10757152019-03-27 10:46:08 +0100156 """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
baldoni10757152019-03-27 10:46:08 +0100172 Returns the network identifier on success or raises and exception on failure
173 """
sousaedu80135b92021-02-17 15:05:18 +0100174 self.logger.debug("new_network: {}".format(locals()))
baldoni10757152019-03-27 10:46:08 +0100175
sousaedu80135b92021-02-17 15:05:18 +0100176 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())
baldoni10757152019-03-27 10:46:08 +0100182 desc = {
sousaedu80135b92021-02-17 15:05:18 +0100183 "uuid": net_uuid,
184 "name": net_name,
185 "net_type": "ELAN",
186 "is_mgmt": False,
tierno1ec592d2020-06-16 15:29:47 +0000187 }
baldoni10757152019-03-27 10:46:08 +0100188
189 if ip_profile is not None:
190 ip = {}
sousaedu80135b92021-02-17 15:05:18 +0100191 if ip_profile.get("ip_version") == "IPv4":
baldoni10757152019-03-27 10:46:08 +0100192 ip_info = {}
sousaedu80135b92021-02-17 15:05:18 +0100193 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
baldoni10757152019-03-27 10:46:08 +0100203 else:
sousaedu80135b92021-02-17 15:05:18 +0100204 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
baldoni10757152019-03-27 10:46:08 +0100216 try:
217 self.fos_api.network.add_network(desc)
baldoni07df0d22020-06-12 15:24:24 +0200218 except fimapi.FIMAResouceExistingException as free:
sousaedu80135b92021-02-17 15:05:18 +0100219 raise vimconn.VimConnConflictException(
220 "Network already exists at VIM. Error {}".format(free)
221 )
baldoni10757152019-03-27 10:46:08 +0100222 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100223 raise vimconn.VimConnException(
224 "Unable to create network {}. Error {}".format(net_name, e)
225 )
tierno1ec592d2020-06-16 15:29:47 +0000226 # No way from the current rest service to get the actual error, most likely it will be an already
227 # existing error
sousaedu80135b92021-02-17 15:05:18 +0100228
tierno1ec592d2020-06-16 15:29:47 +0000229 return net_uuid, {}
baldoni10757152019-03-27 10:46:08 +0100230
231 def get_network_list(self, filter_dict={}):
232 """Obtain tenant networks of VIM
tierno1ec592d2020-06-16 15:29:47 +0000233 :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
baldoni10757152019-03-27 10:46:08 +0100240 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 """
sousaedu80135b92021-02-17 15:05:18 +0100251 self.logger.debug("get_network_list: {}".format(filter_dict))
baldoni10757152019-03-27 10:46:08 +0100252 res = []
sousaedu80135b92021-02-17 15:05:18 +0100253
baldoni10757152019-03-27 10:46:08 +0100254 try:
255 nets = self.fos_api.network.list()
256 except Exception as e:
tierno1ec592d2020-06-16 15:29:47 +0000257 raise vimconn.VimConnConnectionException(
sousaedu80135b92021-02-17 15:05:18 +0100258 "Cannot get network list from VIM, connection error. Error {}".format(e)
259 )
baldoni10757152019-03-27 10:46:08 +0100260
261 filters = [
sousaedu80135b92021-02-17 15:05:18 +0100262 partial(self.__name_filter, filter_name=filter_dict.get("name")),
263 partial(self.__id_filter, filter_id=filter_dict.get("id")),
baldoni10757152019-03-27 10:46:08 +0100264 ]
265
266 r1 = []
267
268 for n in nets:
269 match = True
sousaedu80135b92021-02-17 15:05:18 +0100270
baldoni10757152019-03-27 10:46:08 +0100271 for f in filters:
272 match = match and f(n)
sousaedu80135b92021-02-17 15:05:18 +0100273
baldoni10757152019-03-27 10:46:08 +0100274 if match:
275 r1.append(n)
276
277 for n in r1:
sousaedu80135b92021-02-17 15:05:18 +0100278 osm_net = {"id": n.get("uuid"), "name": n.get("name"), "status": "ACTIVE"}
baldoni10757152019-03-27 10:46:08 +0100279 res.append(osm_net)
sousaedu80135b92021-02-17 15:05:18 +0100280
baldoni10757152019-03-27 10:46:08 +0100281 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 """
sousaedu80135b92021-02-17 15:05:18 +0100293 self.logger.debug("get_network: {}".format(net_id))
294 res = self.get_network_list(filter_dict={"id": net_id})
295
baldoni10757152019-03-27 10:46:08 +0100296 if len(res) == 0:
sousaedu80135b92021-02-17 15:05:18 +0100297 raise vimconn.VimConnNotFoundException(
298 "Network {} not found at VIM".format(net_id)
299 )
300
baldoni10757152019-03-27 10:46:08 +0100301 return res[0]
302
baldonifb5855c2019-11-07 12:50:11 +0100303 def delete_network(self, net_id, created_items=None):
baldoni10757152019-03-27 10:46:08 +0100304 """Deletes a tenant network from VIM
305 Returns the network identifier or raises an exception upon error or when network is not found
306 """
sousaedu80135b92021-02-17 15:05:18 +0100307 self.logger.debug("delete_network: {}".format(net_id))
308
baldoni10757152019-03-27 10:46:08 +0100309 try:
310 self.fos_api.network.remove_network(net_id)
baldoni07df0d22020-06-12 15:24:24 +0200311 except fimapi.FIMNotFoundException as fnfe:
tierno1ec592d2020-06-16 15:29:47 +0000312 raise vimconn.VimConnNotFoundException(
sousaedu80135b92021-02-17 15:05:18 +0100313 "Network {} not found at VIM (already deleted?). Error {}".format(
314 net_id, fnfe
315 )
316 )
baldoni10757152019-03-27 10:46:08 +0100317 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100318 raise vimconn.VimConnException(
319 "Cannot delete network {} from VIM. Error {}".format(net_id, e)
320 )
321
baldoni10757152019-03-27 10:46:08 +0100322 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 """
sousaedu80135b92021-02-17 15:05:18 +0100341 self.logger.debug("Refeshing network status with args: {}".format(locals()))
baldoni10757152019-03-27 10:46:08 +0100342 r = {}
sousaedu80135b92021-02-17 15:05:18 +0100343
baldoni10757152019-03-27 10:46:08 +0100344 for n in net_list:
345 try:
346 osm_n = self.get_network(n)
sousaedu80135b92021-02-17 15:05:18 +0100347 r[osm_n.get("id")] = {"status": osm_n.get("status")}
tierno72774862020-05-04 11:44:15 +0000348 except vimconn.VimConnNotFoundException:
sousaedu80135b92021-02-17 15:05:18 +0100349 r[n] = {"status": "VIM_ERROR"}
350
baldoni10757152019-03-27 10:46:08 +0100351 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 """
sousaedu80135b92021-02-17 15:05:18 +0100358 self.logger.debug("VIM get_flavor with args: {}".format(locals()))
359
baldoni10757152019-03-27 10:46:08 +0100360 try:
361 r = self.fos_api.flavor.get(flavor_id)
362 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100363 raise vimconn.VimConnConnectionException(
364 "VIM not reachable. Error {}".format(e)
365 )
366
baldoni10757152019-03-27 10:46:08 +0100367 if r is None:
tierno72774862020-05-04 11:44:15 +0000368 raise vimconn.VimConnNotFoundException("Flavor not found at VIM")
sousaedu80135b92021-02-17 15:05:18 +0100369
370 return {"id": r.get("uuid"), "name": r.get("name"), "fos": r}
baldoni10757152019-03-27 10:46:08 +0100371
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 """
sousaedu80135b92021-02-17 15:05:18 +0100382 self.logger.debug("VIM get_flavor_id_from_data with args : {}".format(locals()))
baldoni10757152019-03-27 10:46:08 +0100383
384 try:
385 flvs = self.fos_api.flavor.list()
386 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100387 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
baldoni10757152019-03-27 10:46:08 +0100401 if len(r) == 0:
tierno1ec592d2020-06-16 15:29:47 +0000402 raise vimconn.VimConnNotFoundException("No flavor found")
sousaedu80135b92021-02-17 15:05:18 +0100403
baldoni10757152019-03-27 10:46:08 +0100404 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
tierno1ec592d2020-06-16 15:29:47 +0000414 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
baldoni10757152019-03-27 10:46:08 +0100417 - 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"""
sousaedu80135b92021-02-17 15:05:18 +0100425 self.logger.debug("VIM new_flavor with args: {}".format(locals()))
426 flv_id = "{}".format(uuid.uuid4())
baldoni10757152019-03-27 10:46:08 +0100427 desc = {
sousaedu80135b92021-02-17 15:05:18 +0100428 "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")),
baldoni10757152019-03-27 10:46:08 +0100435 }
sousaedu80135b92021-02-17 15:05:18 +0100436
baldoni10757152019-03-27 10:46:08 +0100437 try:
438 self.fos_api.flavor.add(desc)
baldoni07df0d22020-06-12 15:24:24 +0200439 except fimapi.FIMAResouceExistingException as free:
sousaedu80135b92021-02-17 15:05:18 +0100440 raise vimconn.VimConnConflictException(
441 "Flavor {} already exist at VIM. Error {}".format(flv_id, free)
442 )
baldoni10757152019-03-27 10:46:08 +0100443 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100444 raise vimconn.VimConnConnectionException(
445 "VIM not reachable. Error {}".format(e)
446 )
447
baldoni10757152019-03-27 10:46:08 +0100448 return flv_id
449
baldoni10757152019-03-27 10:46:08 +0100450 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)
baldoni07df0d22020-06-12 15:24:24 +0200455 except fimapi.FIMNotFoundException as fnfe:
tierno1ec592d2020-06-16 15:29:47 +0000456 raise vimconn.VimConnNotFoundException(
sousaedu80135b92021-02-17 15:05:18 +0100457 "Flavor {} not found at VIM (already deleted?). Error {}".format(
458 flavor_id, fnfe
459 )
460 )
baldoni10757152019-03-27 10:46:08 +0100461 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100462 raise vimconn.VimConnConnectionException(
463 "VIM not reachable. Error {}".format(e)
464 )
465
baldoni10757152019-03-27 10:46:08 +0100466 return flavor_id
467
468 def new_image(self, image_dict):
sousaedu80135b92021-02-17 15:05:18 +0100469 """Adds a tenant image to VIM. imge_dict is a dictionary with:
baldoni10757152019-03-27 10:46:08 +0100470 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 """
sousaedu80135b92021-02-17 15:05:18 +0100477 self.logger.debug("VIM new_image with args: {}".format(locals()))
478 img_id = "{}".format(uuid.uuid4())
baldoni10757152019-03-27 10:46:08 +0100479 desc = {
sousaedu80135b92021-02-17 15:05:18 +0100480 "name": image_dict.get("name"),
481 "uuid": img_id,
482 "uri": image_dict.get("location"),
483 "format": image_dict.get("disk_format"),
baldoni10757152019-03-27 10:46:08 +0100484 }
sousaedu80135b92021-02-17 15:05:18 +0100485
baldoni10757152019-03-27 10:46:08 +0100486 try:
487 self.fos_api.image.add(desc)
baldoni07df0d22020-06-12 15:24:24 +0200488 except fimapi.FIMAResouceExistingException as free:
sousaedu80135b92021-02-17 15:05:18 +0100489 raise vimconn.VimConnConflictException(
490 "Image {} already exist at VIM. Error {}".format(img_id, free)
491 )
baldoni10757152019-03-27 10:46:08 +0100492 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100493 raise vimconn.VimConnConnectionException(
494 "VIM not reachable. Error {}".format(e)
495 )
496
baldoni10757152019-03-27 10:46:08 +0100497 return img_id
498
499 def get_image_id_from_path(self, path):
baldoni10757152019-03-27 10:46:08 +0100500 """Get the image id from image path in the VIM database.
sousaedu80135b92021-02-17 15:05:18 +0100501 Returns the image_id or raises a vimconnNotFoundException
baldoni10757152019-03-27 10:46:08 +0100502 """
sousaedu80135b92021-02-17 15:05:18 +0100503 self.logger.debug("VIM get_image_id_from_path with args: {}".format(locals()))
504
baldoni10757152019-03-27 10:46:08 +0100505 try:
506 imgs = self.fos_api.image.list()
507 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100508 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
baldoni10757152019-03-27 10:46:08 +0100514 if len(res) == 0:
tierno72774862020-05-04 11:44:15 +0000515 raise vimconn.VimConnNotFoundException("Image with this path was not found")
sousaedu80135b92021-02-17 15:05:18 +0100516
baldoni10757152019-03-27 10:46:08 +0100517 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 """
sousaedu80135b92021-02-17 15:05:18 +0100530 self.logger.debug("VIM get_image_list args: {}".format(locals()))
baldoni10757152019-03-27 10:46:08 +0100531 r = []
sousaedu80135b92021-02-17 15:05:18 +0100532
baldoni10757152019-03-27 10:46:08 +0100533 try:
534 fimgs = self.fos_api.image.list()
535 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100536 raise vimconn.VimConnConnectionException(
537 "VIM not reachable. Error {}".format(e)
538 )
baldoni10757152019-03-27 10:46:08 +0100539
540 filters = [
sousaedu80135b92021-02-17 15:05:18 +0100541 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 ),
baldoni10757152019-03-27 10:46:08 +0100546 ]
547
548 r1 = []
549
550 for i in fimgs:
551 match = True
sousaedu80135b92021-02-17 15:05:18 +0100552
baldoni10757152019-03-27 10:46:08 +0100553 for f in filters:
554 match = match and f(i)
sousaedu80135b92021-02-17 15:05:18 +0100555
baldoni10757152019-03-27 10:46:08 +0100556 if match:
557 r1.append(i)
558
559 for i in r1:
560 img_info = {
sousaedu80135b92021-02-17 15:05:18 +0100561 "name": i.get("name"),
562 "id": i.get("uuid"),
563 "checksum": i.get("checksum"),
564 "location": i.get("uri"),
565 "fos": i,
baldoni10757152019-03-27 10:46:08 +0100566 }
567 r.append(img_info)
sousaedu80135b92021-02-17 15:05:18 +0100568
baldoni10757152019-03-27 10:46:08 +0100569 return r
tierno1ec592d2020-06-16 15:29:47 +0000570 # raise VimConnNotImplemented( "Should have implemented this" )
baldoni10757152019-03-27 10:46:08 +0100571
sousaedu80135b92021-02-17 15:05:18 +0100572 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 ):
baldoni10757152019-03-27 10:46:08 +0100585 """Adds a VM instance to VIM
tierno1ec592d2020-06-16 15:29:47 +0000586 :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
baldoni10757152019-03-27 10:46:08 +0100631 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 """
sousaedu80135b92021-02-17 15:05:18 +0100637 self.logger.debug("new_vminstance with args: {}".format(locals()))
638 fdu_uuid = "{}".format(uuid.uuid4())
baldoni10757152019-03-27 10:46:08 +0100639
640 flv = self.fos_api.flavor.get(flavor_id)
641 img = self.fos_api.image.get(image_id)
642
643 if flv is None:
sousaedu80135b92021-02-17 15:05:18 +0100644 raise vimconn.VimConnNotFoundException(
645 "Flavor {} not found at VIM".format(flavor_id)
646 )
647
baldoni10757152019-03-27 10:46:08 +0100648 if img is None:
sousaedu80135b92021-02-17 15:05:18 +0100649 raise vimconn.VimConnNotFoundException(
650 "Image {} not found at VIM".format(image_id)
651 )
baldoni10757152019-03-27 10:46:08 +0100652
653 created_items = {
sousaedu80135b92021-02-17 15:05:18 +0100654 "fdu_id": "",
655 "node_id": "",
656 "connection_points": [],
tierno1ec592d2020-06-16 15:29:47 +0000657 }
baldoni10757152019-03-27 10:46:08 +0100658
659 fdu_desc = {
sousaedu80135b92021-02-17 15:05:18 +0100660 "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": [],
baldoni10757152019-03-27 10:46:08 +0100672 }
673
674 nets = []
675 cps = []
676 intf_id = 0
677 for n in net_list:
sousaedu80135b92021-02-17 15:05:18 +0100678 cp_id = "{}".format(uuid.uuid4())
679 n["vim_id"] = cp_id
680 pair_id = n.get("net_id")
baldoni10757152019-03-27 10:46:08 +0100681
682 cp_d = {
sousaedu80135b92021-02-17 15:05:18 +0100683 "id": cp_id,
684 "name": cp_id,
685 "vld_ref": pair_id,
baldoni10757152019-03-27 10:46:08 +0100686 }
687 intf_d = {
sousaedu80135b92021-02-17 15:05:18 +0100688 "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)),
baldoni07df0d22020-06-12 15:24:24 +0200695 },
sousaedu80135b92021-02-17 15:05:18 +0100696 "cp_id": cp_id,
baldoni10757152019-03-27 10:46:08 +0100697 }
sousaedu80135b92021-02-17 15:05:18 +0100698 if n.get("mac_address", None) is not None:
699 intf_d["mac_address"] = n["mac_address"]
baldoni10757152019-03-27 10:46:08 +0100700
sousaedu80135b92021-02-17 15:05:18 +0100701 created_items["connection_points"].append(cp_id)
702 fdu_desc["connection_points"].append(cp_d)
703 fdu_desc["interfaces"].append(intf_d)
baldoni10757152019-03-27 10:46:08 +0100704
705 intf_id = intf_id + 1
706
707 if cloud_config is not None:
sousaedu80135b92021-02-17 15:05:18 +0100708 configuration = {"conf_type": "CLOUD_INIT"}
709 if cloud_config.get("user-data") is not None:
710 configuration["script"] = cloud_config.get("user-data")
baldoni10757152019-03-27 10:46:08 +0100711
sousaedu80135b92021-02-17 15:05:18 +0100712 if cloud_config.get("key-pairs") is not None:
713 configuration["ssh_keys"] = cloud_config.get("key-pairs")
baldoni10757152019-03-27 10:46:08 +0100714
sousaedu80135b92021-02-17 15:05:18 +0100715 if "script" in configuration:
716 fdu_desc["configuration"] = configuration
717
718 self.logger.debug("Eclipse fog05 FDU Descriptor: {}".format(fdu_desc))
baldoni10757152019-03-27 10:46:08 +0100719
baldoni07df0d22020-06-12 15:24:24 +0200720 fdu = FDU(fdu_desc)
baldoni10757152019-03-27 10:46:08 +0100721
722 try:
baldoni07df0d22020-06-12 15:24:24 +0200723 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)
sousaedu80135b92021-02-17 15:05:18 +0100726 selected_node = ""
727
baldoni07df0d22020-06-12 15:24:24 +0200728 for n in instance_list:
729 instances = instance_list[n]
730 if instance.uuid in instances:
731 selected_node = n
sousaedu80135b92021-02-17 15:05:18 +0100732
733 if selected_node == "":
baldoni07df0d22020-06-12 15:24:24 +0200734 raise ValueError("Unable to find node for network creation")
baldoni10757152019-03-27 10:46:08 +0100735
sousaedu80135b92021-02-17 15:05:18 +0100736 self.logger.debug("Selected node by VIM: {}".format(selected_node))
737 created_items["fdu_id"] = fdu_uuid
738 created_items["node_id"] = selected_node
baldoni07df0d22020-06-12 15:24:24 +0200739
sousaedu80135b92021-02-17 15:05:18 +0100740 for cp in fdu_desc["connection_points"]:
baldoni07df0d22020-06-12 15:24:24 +0200741 nets = self.fos_api.network.list()
742 for net in nets:
sousaedu80135b92021-02-17 15:05:18 +0100743 if net.get("uuid") == cp["vld_ref"]:
baldoni07df0d22020-06-12 15:24:24 +0200744 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
sousaedu80135b92021-02-17 15:05:18 +0100749 self.logger.debug("Eclipse fog05 FDU Started {}".format(instance.uuid))
baldoni07df0d22020-06-12 15:24:24 +0200750
sousaedu80135b92021-02-17 15:05:18 +0100751 created_items["instance_id"] = str(instance.uuid)
baldoni07df0d22020-06-12 15:24:24 +0200752
tierno1ec592d2020-06-16 15:29:47 +0000753 self.fdu_node_map[instance.uuid] = selected_node
sousaedu80135b92021-02-17 15:05:18 +0100754 self.logger.debug(
755 "new_vminstance returns: {} {}".format(instance.uuid, created_items)
756 )
757
baldoni07df0d22020-06-12 15:24:24 +0200758 return str(instance.uuid), created_items
759 except fimapi.FIMAResouceExistingException as free:
sousaedu80135b92021-02-17 15:05:18 +0100760 raise vimconn.VimConnConflictException(
761 "VM already exists at VIM. Error {}".format(free)
762 )
baldoni10757152019-03-27 10:46:08 +0100763 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100764 raise vimconn.VimConnException(
765 "Error while instantiating VM {}. Error {}".format(name, e)
766 )
baldoni10757152019-03-27 10:46:08 +0100767
tierno1ec592d2020-06-16 15:29:47 +0000768 def get_vminstance(self, vm_id):
baldoni10757152019-03-27 10:46:08 +0100769 """Returns the VM instance information from VIM"""
sousaedu80135b92021-02-17 15:05:18 +0100770 self.logger.debug("VIM get_vminstance with args: {}".format(locals()))
baldoni10757152019-03-27 10:46:08 +0100771
772 try:
baldoni07df0d22020-06-12 15:24:24 +0200773 instance = self.fos_api.fdu.instance_info(vm_id)
baldoni10757152019-03-27 10:46:08 +0100774 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100775 raise vimconn.VimConnConnectionException(
776 "VIM not reachable. Error {}".format(e)
777 )
778
baldoni07df0d22020-06-12 15:24:24 +0200779 if instance is None:
sousaedu80135b92021-02-17 15:05:18 +0100780 raise vimconn.VimConnNotFoundException(
781 "VM with id {} not found!".format(vm_id)
782 )
783
baldoni07df0d22020-06-12 15:24:24 +0200784 return instance.to_json()
baldoni10757152019-03-27 10:46:08 +0100785
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 """
sousaedu80135b92021-02-17 15:05:18 +0100794 self.logger.debug("FOS delete_vminstance with args: {}".format(locals()))
795 fduid = created_items.get("fdu_id")
796
baldoni10757152019-03-27 10:46:08 +0100797 try:
baldoni07df0d22020-06-12 15:24:24 +0200798 instance = self.fos_api.fdu.instance_info(vm_id)
799 instance_list = self.fos_api.fdu.instance_list(instance.fdu_id)
sousaedu80135b92021-02-17 15:05:18 +0100800 selected_node = ""
801
baldoni07df0d22020-06-12 15:24:24 +0200802 for n in instance_list:
803 instances = instance_list[n]
sousaedu80135b92021-02-17 15:05:18 +0100804
baldoni07df0d22020-06-12 15:24:24 +0200805 if instance.uuid in instances:
806 selected_node = n
sousaedu80135b92021-02-17 15:05:18 +0100807
808 if selected_node == "":
baldoni07df0d22020-06-12 15:24:24 +0200809 raise ValueError("Unable to find node for the given Instance")
810
811 self.fos_api.fdu.stop(vm_id)
812
sousaedu80135b92021-02-17 15:05:18 +0100813 for cp in instance.to_json()["connection_points"]:
baldoni07df0d22020-06-12 15:24:24 +0200814 nets = self.fos_api.network.list()
815 for net in nets:
sousaedu80135b92021-02-17 15:05:18 +0100816 if net.get("uuid") == cp["vld_ref"]:
817 self.fos_api.network.remove_network_from_node(
818 net.get("uuid"), selected_node
819 )
baldoni07df0d22020-06-12 15:24:24 +0200820
821 self.fos_api.fdu.clean(vm_id)
822 self.fos_api.fdu.undefine(vm_id)
baldoni10757152019-03-27 10:46:08 +0100823 self.fos_api.fdu.offload(fduid)
824 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100825 raise vimconn.VimConnException(
826 "Error on deleting VM with id {}. Error {}".format(vm_id, e)
827 )
828
baldoni10757152019-03-27 10:46:08 +0100829 return vm_id
830
tierno1ec592d2020-06-16 15:29:47 +0000831 # raise VimConnNotImplemented( "Should have implemented this" )
baldoni10757152019-03-27 10:46:08 +0100832
833 def refresh_vms_status(self, vm_list):
834 """Get the status of the virtual machines and their interfaces/ports
sousaedu80135b92021-02-17 15:05:18 +0100835 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
baldoni10757152019-03-27 10:46:08 +0100858 """
sousaedu80135b92021-02-17 15:05:18 +0100859 self.logger.debug("FOS refresh_vms_status with args: {}".format(locals()))
baldoni10757152019-03-27 10:46:08 +0100860 fos2osm_status = {
sousaedu80135b92021-02-17 15:05:18 +0100861 "DEFINE": "OTHER",
862 "CONFIGURE": "INACTIVE",
863 "RUN": "ACTIVE",
864 "PAUSE": "PAUSED",
865 "ERROR": "ERROR",
baldoni10757152019-03-27 10:46:08 +0100866 }
867
868 r = {}
869
870 for vm in vm_list:
sousaedu80135b92021-02-17 15:05:18 +0100871 self.logger.debug("FOS refresh_vms_status for {}".format(vm))
baldoni10757152019-03-27 10:46:08 +0100872
873 info = {}
874 nid = self.fdu_node_map.get(vm)
875 if nid is None:
tierno1ec592d2020-06-16 15:29:47 +0000876 r[vm] = {
sousaedu80135b92021-02-17 15:05:18 +0100877 "status": "VIM_ERROR",
878 "error_msg": "Not compute node associated for VM",
tierno1ec592d2020-06-16 15:29:47 +0000879 }
baldoni10757152019-03-27 10:46:08 +0100880 continue
881
882 try:
883 vm_info = self.fos_api.fdu.instance_info(vm)
tierno1ec592d2020-06-16 15:29:47 +0000884 except Exception:
sousaedu80135b92021-02-17 15:05:18 +0100885 r[vm] = {"status": "VIM_ERROR", "error_msg": "unable to connect to VIM"}
baldoni10757152019-03-27 10:46:08 +0100886 continue
887
888 if vm_info is None:
sousaedu80135b92021-02-17 15:05:18 +0100889 r[vm:] = {"status": "DELETED"}
baldoni10757152019-03-27 10:46:08 +0100890 continue
891
baldoni07df0d22020-06-12 15:24:24 +0200892 desc = self.fos_api.fdu.info(str(vm_info.fdu_id))
baldoni10757152019-03-27 10:46:08 +0100893
baldoni07df0d22020-06-12 15:24:24 +0200894 vm_info = vm_info.to_json()
895 desc = desc.to_json()
896
sousaedu80135b92021-02-17 15:05:18 +0100897 osm_status = fos2osm_status.get(vm_info.get("status"))
baldoni10757152019-03-27 10:46:08 +0100898
sousaedu80135b92021-02-17 15:05:18 +0100899 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
baldoni07df0d22020-06-12 15:24:24 +0200910 # yaml.safe_dump(json.loads(json.dumps(vm_info)))
sousaedu80135b92021-02-17 15:05:18 +0100911 # info["vim_info"] = ""
baldoni10757152019-03-27 10:46:08 +0100912 faces = []
913 i = 0
sousaedu80135b92021-02-17 15:05:18 +0100914 for intf_name in vm_info.get("hypervisor_info").get("network", []):
915 intf_info = vm_info.get("hypervisor_info").get("network").get(intf_name)
baldoni10757152019-03-27 10:46:08 +0100916 face = {}
sousaedu80135b92021-02-17 15:05:18 +0100917 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")
baldoni10757152019-03-27 10:46:08 +0100920 addrs = []
sousaedu80135b92021-02-17 15:05:18 +0100921
922 for a in intf_info.get("addresses"):
923 addrs.append(a.get("address"))
924
baldoni10757152019-03-27 10:46:08 +0100925 if len(addrs) >= 0:
sousaedu80135b92021-02-17 15:05:18 +0100926 face["ip_address"] = ",".join(addrs)
baldoni10757152019-03-27 10:46:08 +0100927 else:
sousaedu80135b92021-02-17 15:05:18 +0100928 face["ip_address"] = ""
929
930 face["pci"] = "0:0:0.0"
baldoni07df0d22020-06-12 15:24:24 +0200931
baldoni10757152019-03-27 10:46:08 +0100932 try:
sousaedu80135b92021-02-17 15:05:18 +0100933 cp_info = vm_info.get("connection_points")[i]
baldoni10757152019-03-27 10:46:08 +0100934 except IndexError:
935 cp_info = None
sousaedu80135b92021-02-17 15:05:18 +0100936
baldoni10757152019-03-27 10:46:08 +0100937 if cp_info is not None:
sousaedu80135b92021-02-17 15:05:18 +0100938 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
baldoni10757152019-03-27 10:46:08 +0100942 if len(matches) > 0:
943 cpd = matches[0]
sousaedu80135b92021-02-17 15:05:18 +0100944 face["vim_net_id"] = cpd.get("vld_ref", "")
baldoni10757152019-03-27 10:46:08 +0100945 else:
sousaedu80135b92021-02-17 15:05:18 +0100946 face["vim_net_id"] = ""
947
948 face["vim_interface_id"] = cp_id
949 # cp_info.get("uuid")
baldoni10757152019-03-27 10:46:08 +0100950 else:
sousaedu80135b92021-02-17 15:05:18 +0100951 face["vim_net_id"] = ""
952 face["vim_interface_id"] = intf_name
953
baldoni10757152019-03-27 10:46:08 +0100954 faces.append(face)
955 i += 1
956
sousaedu80135b92021-02-17 15:05:18 +0100957 info["interfaces"] = faces
tierno1ec592d2020-06-16 15:29:47 +0000958 r[vm] = info
sousaedu80135b92021-02-17 15:05:18 +0100959 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
baldoni10757152019-03-27 10:46:08 +0100965 return r
966
baldoni10757152019-03-27 10:46:08 +0100967 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 """
sousaedu80135b92021-02-17 15:05:18 +0100979 self.logger.debug("VIM action_vminstance with args: {}".format(locals()))
baldoni10757152019-03-27 10:46:08 +0100980 nid = self.fdu_node_map.get(vm_id)
sousaedu80135b92021-02-17 15:05:18 +0100981
baldoni10757152019-03-27 10:46:08 +0100982 if nid is None:
sousaedu80135b92021-02-17 15:05:18 +0100983 raise vimconn.VimConnNotFoundException("No node for this VM")
984
baldoni10757152019-03-27 10:46:08 +0100985 try:
baldoni07df0d22020-06-12 15:24:24 +0200986 instance = self.fos_api.fdu.instance_info(vm_id)
baldoni10757152019-03-27 10:46:08 +0100987 if "start" in action_dict:
sousaedu80135b92021-02-17 15:05:18 +0100988 if instance.get("status") == "CONFIGURE":
baldoni10757152019-03-27 10:46:08 +0100989 self.fos_api.fdu.start(vm_id)
sousaedu80135b92021-02-17 15:05:18 +0100990 elif instance.get("status") == "PAUSE":
baldoni10757152019-03-27 10:46:08 +0100991 self.fos_api.fdu.resume(vm_id)
992 else:
sousaedu80135b92021-02-17 15:05:18 +0100993 raise vimconn.VimConnConflictException(
994 "Cannot start from current state: {}".format(
995 instance.get("status")
996 )
997 )
baldoni10757152019-03-27 10:46:08 +0100998 elif "pause" in action_dict:
sousaedu80135b92021-02-17 15:05:18 +0100999 if instance.get("status") == "RUN":
baldoni10757152019-03-27 10:46:08 +01001000 self.fos_api.fdu.pause(vm_id)
1001 else:
sousaedu80135b92021-02-17 15:05:18 +01001002 raise vimconn.VimConnConflictException(
1003 "Cannot pause from current state: {}".format(
1004 instance.get("status")
1005 )
1006 )
baldoni10757152019-03-27 10:46:08 +01001007 elif "resume" in action_dict:
sousaedu80135b92021-02-17 15:05:18 +01001008 if instance.get("status") == "PAUSE":
baldoni10757152019-03-27 10:46:08 +01001009 self.fos_api.fdu.resume(vm_id)
1010 else:
sousaedu80135b92021-02-17 15:05:18 +01001011 raise vimconn.VimConnConflictException(
1012 "Cannot resume from current state: {}".format(
1013 instance.get("status")
1014 )
1015 )
baldoni10757152019-03-27 10:46:08 +01001016 elif "shutoff" in action_dict or "shutdown" or "forceOff" in action_dict:
sousaedu80135b92021-02-17 15:05:18 +01001017 if instance.get("status") == "RUN":
baldoni10757152019-03-27 10:46:08 +01001018 self.fos_api.fdu.stop(vm_id)
1019 else:
sousaedu80135b92021-02-17 15:05:18 +01001020 raise vimconn.VimConnConflictException(
1021 "Cannot shutoff from current state: {}".format(
1022 instance.get("status")
1023 )
1024 )
baldoni10757152019-03-27 10:46:08 +01001025 elif "terminate" in action_dict:
sousaedu80135b92021-02-17 15:05:18 +01001026 if instance.get("status") == "RUN":
baldoni10757152019-03-27 10:46:08 +01001027 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)
sousaedu80135b92021-02-17 15:05:18 +01001031 elif instance.get("status") == "CONFIGURE":
baldoni10757152019-03-27 10:46:08 +01001032 self.fos_api.fdu.clean(vm_id)
1033 self.fos_api.fdu.undefine(vm_id)
1034 # self.fos_api.fdu.offload(vm_id)
sousaedu80135b92021-02-17 15:05:18 +01001035 elif instance.get("status") == "PAUSE":
baldoni10757152019-03-27 10:46:08 +01001036 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:
sousaedu80135b92021-02-17 15:05:18 +01001042 raise vimconn.VimConnConflictException(
1043 "Cannot terminate from current state: {}".format(
1044 instance.get("status")
1045 )
1046 )
baldoni10757152019-03-27 10:46:08 +01001047 elif "rebuild" in action_dict:
tierno72774862020-05-04 11:44:15 +00001048 raise vimconn.VimConnNotImplemented("Rebuild not implemented")
baldoni10757152019-03-27 10:46:08 +01001049 elif "reboot" in action_dict:
sousaedu80135b92021-02-17 15:05:18 +01001050 if instance.get("status") == "RUN":
baldoni10757152019-03-27 10:46:08 +01001051 self.fos_api.fdu.stop(vm_id)
1052 self.fos_api.fdu.start(vm_id)
1053 else:
sousaedu80135b92021-02-17 15:05:18 +01001054 raise vimconn.VimConnConflictException(
1055 "Cannot reboot from current state: {}".format(
1056 instance.get("status")
1057 )
1058 )
baldoni10757152019-03-27 10:46:08 +01001059 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +01001060 raise vimconn.VimConnConnectionException(
1061 "VIM not reachable. Error {}".format(e)
1062 )