blob: 21f1b9f1230ae291bd0f59caf9edfa6a1b3dfddb [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
35import uuid
36import socket
37import struct
tierno72774862020-05-04 11:44:15 +000038from osm_ro_plugin import vimconn
tierno1ec592d2020-06-16 15:29:47 +000039# import json
baldoni10757152019-03-27 10:46:08 +010040from functools import partial
baldoni07df0d22020-06-12 15:24:24 +020041from fog05 import FIMAPI
42from fog05 import fimapi
43from fog05_sdk.interfaces.FDU import FDU
baldoni10757152019-03-27 10:46:08 +010044
tierno1ec592d2020-06-16 15:29:47 +000045__author__ = "Gabriele Baldoni"
46__date__ = "$2-june-2020 10:35:12$"
47
baldoni10757152019-03-27 10:46:08 +010048
tierno72774862020-05-04 11:44:15 +000049class vimconnector(vimconn.VimConnector):
baldoni10757152019-03-27 10:46:08 +010050 def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level=None,
51 config={}, persistent_info={}):
52 """Constructor of VIM
53 Params:
54 'uuid': id asigned to this VIM
55 'name': name assigned to this VIM, can be used for logging
56 'tenant_id', 'tenant_name': (only one of them is mandatory) VIM tenant to be used
57 'url_admin': (optional), url used for administrative tasks
58 'user', 'passwd': credentials of the VIM user
59 'log_level': provider if it should use a different log_level than the general one
60 'config': dictionary with extra VIM information. This contains a consolidate version of general VIM config
61 at creation and particular VIM config at teh attachment
62 'persistent_info': dict where the class can store information that will be available among class
63 destroy/creation cycles. This info is unique per VIM/credential. At first call it will contain an
64 empty dict. Useful to store login/tokens information for speed up communication
65
66 Returns: Raise an exception is some needed parameter is missing, but it must not do any connectivity
67 check against the VIM
68 """
69
tierno72774862020-05-04 11:44:15 +000070 vimconn.VimConnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, log_level,
baldoni10757152019-03-27 10:46:08 +010071 config, persistent_info)
72
73 self.logger.debug('vimconn_fos init with config: {}'.format(config))
74 self.arch = config.get('arch', 'x86_64')
75 self.hv = config.get('hypervisor', 'LXD')
76 self.nodes = config.get('nodes', [])
77 self.fdu_node_map = {}
78 self.fos_api = FIMAPI(locator=self.url)
79
baldoni10757152019-03-27 10:46:08 +010080 def __get_ip_range(self, first, count):
81 int_first = struct.unpack('!L', socket.inet_aton(first))[0]
82 int_last = int_first + count
83 last = socket.inet_ntoa(struct.pack('!L', int_last))
84 return (first, last)
85
86 def __name_filter(self, desc, filter_name=None):
87 if filter_name is None:
88 return True
89 return desc.get('name') == filter_name
90
91 def __id_filter(self, desc, filter_id=None):
92 if filter_id is None:
93 return True
94 return desc.get('uuid') == filter_id
95
96 def __checksum_filter(self, desc, filter_checksum=None):
97 if filter_checksum is None:
98 return True
99 return desc.get('checksum') == filter_checksum
100
101 def check_vim_connectivity(self):
102 """Checks VIM can be reached and user credentials are ok.
tierno72774862020-05-04 11:44:15 +0000103 Returns None if success or raised VimConnConnectionException, VimConnAuthException, ...
baldoni10757152019-03-27 10:46:08 +0100104 """
105 try:
baldoni07df0d22020-06-12 15:24:24 +0200106 self.fos_api.node.list()
baldoni10757152019-03-27 10:46:08 +0100107 return None
baldoni07df0d22020-06-12 15:24:24 +0200108 except fimapi.FIMAuthExcetpion as fae:
tierno72774862020-05-04 11:44:15 +0000109 raise vimconn.VimConnAuthException("Unable to authenticate to the VIM. Error {}".format(fae))
baldoni10757152019-03-27 10:46:08 +0100110 except Exception as e:
tierno72774862020-05-04 11:44:15 +0000111 raise vimconn.VimConnConnectionException("VIM not reachable. Error {}".format(e))
baldoni10757152019-03-27 10:46:08 +0100112
kbsuba85c54d2019-10-17 16:30:32 +0000113 def new_network(self, net_name, net_type, ip_profile=None, shared=False, provider_network_profile=None):
baldoni10757152019-03-27 10:46:08 +0100114 """Adds a tenant network to VIM
115 Params:
116 'net_name': name of the network
117 'net_type': one of:
118 'bridge': overlay isolated network
119 'data': underlay E-LAN network for Passthrough and SRIOV interfaces
120 'ptp': underlay E-LINE network for Passthrough and SRIOV interfaces.
121 'ip_profile': is a dict containing the IP parameters of the network
122 'ip_version': can be "IPv4" or "IPv6" (Currently only IPv4 is implemented)
123 'subnet_address': ip_prefix_schema, that is X.X.X.X/Y
124 'gateway_address': (Optional) ip_schema, that is X.X.X.X
125 'dns_address': (Optional) comma separated list of ip_schema, e.g. X.X.X.X[,X,X,X,X]
126 'dhcp_enabled': True or False
127 'dhcp_start_address': ip_schema, first IP to grant
128 'dhcp_count': number of IPs to grant.
129 'shared': if this network can be seen/use by other tenants/organization
baldoni10757152019-03-27 10:46:08 +0100130 Returns the network identifier on success or raises and exception on failure
131 """
132 self.logger.debug('new_network: {}'.format(locals()))
tierno1ec592d2020-06-16 15:29:47 +0000133 if net_type in ['data', 'ptp']:
tierno72774862020-05-04 11:44:15 +0000134 raise vimconn.VimConnNotImplemented('{} type of network not supported'.format(net_type))
baldoni10757152019-03-27 10:46:08 +0100135
136 net_uuid = '{}'.format(uuid.uuid4())
137 desc = {
tierno1ec592d2020-06-16 15:29:47 +0000138 'uuid': net_uuid,
139 'name': net_name,
140 'net_type': 'ELAN',
141 'is_mgmt': False
142 }
baldoni10757152019-03-27 10:46:08 +0100143
144 if ip_profile is not None:
145 ip = {}
146 if ip_profile.get('ip_version') == 'IPv4':
147 ip_info = {}
148 ip_range = self.__get_ip_range(ip_profile.get('dhcp_start_address'), ip_profile.get('dhcp_count'))
tierno1ec592d2020-06-16 15:29:47 +0000149 dhcp_range = '{},{}'.format(ip_range[0], ip_range[1])
150 ip['subnet'] = ip_profile.get('subnet_address')
151 ip['dns'] = ip_profile.get('dns', None)
152 ip['dhcp_enable'] = ip_profile.get('dhcp_enabled', False)
153 ip['dhcp_range'] = dhcp_range
154 ip['gateway'] = ip_profile.get('gateway_address', None)
155 desc['ip_configuration'] = ip_info
baldoni10757152019-03-27 10:46:08 +0100156 else:
tierno72774862020-05-04 11:44:15 +0000157 raise vimconn.VimConnNotImplemented('IPV6 network is not implemented at VIM')
tierno1ec592d2020-06-16 15:29:47 +0000158 desc['ip_configuration'] = ip
baldoni10757152019-03-27 10:46:08 +0100159 self.logger.debug('VIM new_network args: {} - Generated Eclipse fog05 Descriptor {}'.format(locals(), desc))
160 try:
161 self.fos_api.network.add_network(desc)
baldoni07df0d22020-06-12 15:24:24 +0200162 except fimapi.FIMAResouceExistingException as free:
tierno72774862020-05-04 11:44:15 +0000163 raise vimconn.VimConnConflictException("Network already exists at VIM. Error {}".format(free))
baldoni10757152019-03-27 10:46:08 +0100164 except Exception as e:
tierno72774862020-05-04 11:44:15 +0000165 raise vimconn.VimConnException("Unable to create network {}. Error {}".format(net_name, e))
tierno1ec592d2020-06-16 15:29:47 +0000166 # No way from the current rest service to get the actual error, most likely it will be an already
167 # existing error
168 return net_uuid, {}
baldoni10757152019-03-27 10:46:08 +0100169
170 def get_network_list(self, filter_dict={}):
171 """Obtain tenant networks of VIM
tierno1ec592d2020-06-16 15:29:47 +0000172 :param filter_dict: (optional) contains entries to return only networks that matches ALL entries:
173 name: string => returns only networks with this name
174 id: string => returns networks with this VIM id, this imply returns one network at most
175 shared: boolean >= returns only networks that are (or are not) shared
176 tenant_id: sting => returns only networks that belong to this tenant/project
177 (not used yet) admin_state_up: boolean => returns only networks that are (or are not) in admin state active
178 (not used yet) status: 'ACTIVE','ERROR',... => filter networks that are on this status
baldoni10757152019-03-27 10:46:08 +0100179 Returns the network list of dictionaries. each dictionary contains:
180 'id': (mandatory) VIM network id
181 'name': (mandatory) VIM network name
182 'status': (mandatory) can be 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER'
183 'network_type': (optional) can be 'vxlan', 'vlan' or 'flat'
184 'segmentation_id': (optional) in case network_type is vlan or vxlan this field contains the segmentation id
185 'error_msg': (optional) text that explains the ERROR status
186 other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param
187 List can be empty if no network map the filter_dict. Raise an exception only upon VIM connectivity,
188 authorization, or some other unspecific error
189 """
190 self.logger.debug('get_network_list: {}'.format(filter_dict))
191 res = []
192 try:
193 nets = self.fos_api.network.list()
194 except Exception as e:
tierno1ec592d2020-06-16 15:29:47 +0000195 raise vimconn.VimConnConnectionException(
196 "Cannot get network list from VIM, connection error. Error {}".format(e))
baldoni10757152019-03-27 10:46:08 +0100197
198 filters = [
199 partial(self.__name_filter, filter_name=filter_dict.get('name')),
tierno1ec592d2020-06-16 15:29:47 +0000200 partial(self.__id_filter, filter_id=filter_dict.get('id'))
baldoni10757152019-03-27 10:46:08 +0100201 ]
202
203 r1 = []
204
205 for n in nets:
206 match = True
207 for f in filters:
208 match = match and f(n)
209 if match:
210 r1.append(n)
211
212 for n in r1:
213 osm_net = {
tierno1ec592d2020-06-16 15:29:47 +0000214 'id': n.get('uuid'),
215 'name': n.get('name'),
216 'status': 'ACTIVE'
baldoni10757152019-03-27 10:46:08 +0100217 }
218 res.append(osm_net)
219 return res
220
221 def get_network(self, net_id):
222 """Obtain network details from the 'net_id' VIM network
223 Return a dict that contains:
224 'id': (mandatory) VIM network id, that is, net_id
225 'name': (mandatory) VIM network name
226 'status': (mandatory) can be 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER'
227 'error_msg': (optional) text that explains the ERROR status
228 other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param
229 Raises an exception upon error or when network is not found
230 """
231 self.logger.debug('get_network: {}'.format(net_id))
tierno1ec592d2020-06-16 15:29:47 +0000232 res = self.get_network_list(filter_dict={'id': net_id})
baldoni10757152019-03-27 10:46:08 +0100233 if len(res) == 0:
tierno72774862020-05-04 11:44:15 +0000234 raise vimconn.VimConnNotFoundException("Network {} not found at VIM".format(net_id))
baldoni10757152019-03-27 10:46:08 +0100235 return res[0]
236
baldonifb5855c2019-11-07 12:50:11 +0100237 def delete_network(self, net_id, created_items=None):
baldoni10757152019-03-27 10:46:08 +0100238 """Deletes a tenant network from VIM
239 Returns the network identifier or raises an exception upon error or when network is not found
240 """
241 self.logger.debug('delete_network: {}'.format(net_id))
242 try:
243 self.fos_api.network.remove_network(net_id)
baldoni07df0d22020-06-12 15:24:24 +0200244 except fimapi.FIMNotFoundException as fnfe:
tierno1ec592d2020-06-16 15:29:47 +0000245 raise vimconn.VimConnNotFoundException(
246 "Network {} not found at VIM (already deleted?). Error {}".format(net_id, fnfe))
baldoni10757152019-03-27 10:46:08 +0100247 except Exception as e:
tierno72774862020-05-04 11:44:15 +0000248 raise vimconn.VimConnException("Cannot delete network {} from VIM. Error {}".format(net_id, e))
baldoni10757152019-03-27 10:46:08 +0100249 return net_id
250
251 def refresh_nets_status(self, net_list):
252 """Get the status of the networks
253 Params:
254 'net_list': a list with the VIM network id to be get the status
255 Returns a dictionary with:
256 'net_id': #VIM id of this network
257 status: #Mandatory. Text with one of:
258 # DELETED (not found at vim)
259 # VIM_ERROR (Cannot connect to VIM, authentication problems, VIM response error, ...)
260 # OTHER (Vim reported other status not understood)
261 # ERROR (VIM indicates an ERROR status)
262 # ACTIVE, INACTIVE, DOWN (admin down),
263 # BUILD (on building process)
264 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
265 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
266 'net_id2': ...
267 """
268 self.logger.debug('Refeshing network status with args: {}'.format(locals()))
269 r = {}
270 for n in net_list:
271 try:
272 osm_n = self.get_network(n)
tierno1ec592d2020-06-16 15:29:47 +0000273 r[osm_n.get('id')] = {'status': osm_n.get('status')}
tierno72774862020-05-04 11:44:15 +0000274 except vimconn.VimConnNotFoundException:
tierno1ec592d2020-06-16 15:29:47 +0000275 r[n] = {'status': 'VIM_ERROR'}
baldoni10757152019-03-27 10:46:08 +0100276 return r
277
278 def get_flavor(self, flavor_id):
279 """Obtain flavor details from the VIM
280 Returns the flavor dict details {'id':<>, 'name':<>, other vim specific }
281 Raises an exception upon error or if not found
282 """
283 self.logger.debug('VIM get_flavor with args: {}'.format(locals()))
284 try:
285 r = self.fos_api.flavor.get(flavor_id)
286 except Exception as e:
tierno72774862020-05-04 11:44:15 +0000287 raise vimconn.VimConnConnectionException("VIM not reachable. Error {}".format(e))
baldoni10757152019-03-27 10:46:08 +0100288 if r is None:
tierno72774862020-05-04 11:44:15 +0000289 raise vimconn.VimConnNotFoundException("Flavor not found at VIM")
tierno1ec592d2020-06-16 15:29:47 +0000290 return {'id': r.get('uuid'), 'name': r.get('name'), 'fos': r}
baldoni10757152019-03-27 10:46:08 +0100291
292 def get_flavor_id_from_data(self, flavor_dict):
293 """Obtain flavor id that match the flavor description
294 Params:
295 'flavor_dict': dictionary that contains:
296 'disk': main hard disk in GB
297 'ram': meomry in MB
298 'vcpus': number of virtual cpus
299 #TODO: complete parameters for EPA
300 Returns the flavor_id or raises a vimconnNotFoundException
301 """
302 self.logger.debug('VIM get_flavor_id_from_data with args : {}'.format(locals()))
303
304 try:
305 flvs = self.fos_api.flavor.list()
306 except Exception as e:
tierno72774862020-05-04 11:44:15 +0000307 raise vimconn.VimConnConnectionException("VIM not reachable. Error {}".format(e))
tierno1ec592d2020-06-16 15:29:47 +0000308 r = [x.get('uuid') for x in flvs if (x.get('cpu_min_count') == flavor_dict.get('vcpus') and
309 x.get('ram_size_mb') == flavor_dict.get('ram') and
310 x.get('storage_size_gb') == flavor_dict.get('disk'))]
baldoni10757152019-03-27 10:46:08 +0100311 if len(r) == 0:
tierno1ec592d2020-06-16 15:29:47 +0000312 raise vimconn.VimConnNotFoundException("No flavor found")
baldoni10757152019-03-27 10:46:08 +0100313 return r[0]
314
315 def new_flavor(self, flavor_data):
316 """Adds a tenant flavor to VIM
317 flavor_data contains a dictionary with information, keys:
318 name: flavor name
319 ram: memory (cloud type) in MBytes
320 vpcus: cpus (cloud type)
321 extended: EPA parameters
322 - numas: #items requested in same NUMA
tierno1ec592d2020-06-16 15:29:47 +0000323 memory: number of 1G huge pages memory
324 paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads
325 interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
baldoni10757152019-03-27 10:46:08 +0100326 - name: interface name
327 dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC
328 bandwidth: X Gbps; requested guarantee bandwidth
329 vpci: requested virtual PCI address
330 disk: disk size
331 is_public:
332 #TODO to concrete
333 Returns the flavor identifier"""
334 self.logger.debug('VIM new_flavor with args: {}'.format(locals()))
335 flv_id = '{}'.format(uuid.uuid4())
336 desc = {
tierno1ec592d2020-06-16 15:29:47 +0000337 'uuid': flv_id,
338 'name': flavor_data.get('name'),
baldoni10757152019-03-27 10:46:08 +0100339 'cpu_arch': self.arch,
340 'cpu_min_count': flavor_data.get('vcpus'),
baldoni07df0d22020-06-12 15:24:24 +0200341 'cpu_min_freq': 0,
tierno1ec592d2020-06-16 15:29:47 +0000342 'ram_size_mb': float(flavor_data.get('ram')),
343 'storage_size_gb': float(flavor_data.get('disk'))
baldoni10757152019-03-27 10:46:08 +0100344 }
345 try:
346 self.fos_api.flavor.add(desc)
baldoni07df0d22020-06-12 15:24:24 +0200347 except fimapi.FIMAResouceExistingException as free:
tierno72774862020-05-04 11:44:15 +0000348 raise vimconn.VimConnConflictException("Flavor {} already exist at VIM. Error {}".format(flv_id, free))
baldoni10757152019-03-27 10:46:08 +0100349 except Exception as e:
tierno72774862020-05-04 11:44:15 +0000350 raise vimconn.VimConnConnectionException("VIM not reachable. Error {}".format(e))
baldoni10757152019-03-27 10:46:08 +0100351 return flv_id
352
baldoni10757152019-03-27 10:46:08 +0100353 def delete_flavor(self, flavor_id):
354 """Deletes a tenant flavor from VIM identify by its id
355 Returns the used id or raise an exception"""
356 try:
357 self.fos_api.flavor.remove(flavor_id)
baldoni07df0d22020-06-12 15:24:24 +0200358 except fimapi.FIMNotFoundException as fnfe:
tierno1ec592d2020-06-16 15:29:47 +0000359 raise vimconn.VimConnNotFoundException(
360 "Flavor {} not found at VIM (already deleted?). Error {}".format(flavor_id, fnfe))
baldoni10757152019-03-27 10:46:08 +0100361 except Exception as e:
tierno72774862020-05-04 11:44:15 +0000362 raise vimconn.VimConnConnectionException("VIM not reachable. Error {}".format(e))
baldoni10757152019-03-27 10:46:08 +0100363 return flavor_id
364
365 def new_image(self, image_dict):
366 """ Adds a tenant image to VIM. imge_dict is a dictionary with:
367 name: name
368 disk_format: qcow2, vhd, vmdk, raw (by default), ...
369 location: path or URI
370 public: "yes" or "no"
371 metadata: metadata of the image
372 Returns the image id or raises an exception if failed
373 """
374 self.logger.debug('VIM new_image with args: {}'.format(locals()))
375 img_id = '{}'.format(uuid.uuid4())
376 desc = {
tierno1ec592d2020-06-16 15:29:47 +0000377 'name': image_dict.get('name'),
378 'uuid': img_id,
379 'uri': image_dict.get('location'),
380 'format': image_dict.get('disk_format')
baldoni10757152019-03-27 10:46:08 +0100381 }
382 try:
383 self.fos_api.image.add(desc)
baldoni07df0d22020-06-12 15:24:24 +0200384 except fimapi.FIMAResouceExistingException as free:
tierno72774862020-05-04 11:44:15 +0000385 raise vimconn.VimConnConflictException("Image {} already exist at VIM. Error {}".format(img_id, free))
baldoni10757152019-03-27 10:46:08 +0100386 except Exception as e:
tierno72774862020-05-04 11:44:15 +0000387 raise vimconn.VimConnConnectionException("VIM not reachable. Error {}".format(e))
baldoni10757152019-03-27 10:46:08 +0100388 return img_id
389
390 def get_image_id_from_path(self, path):
391
392 """Get the image id from image path in the VIM database.
393 Returns the image_id or raises a vimconnNotFoundException
394 """
395 self.logger.debug('VIM get_image_id_from_path with args: {}'.format(locals()))
396 try:
397 imgs = self.fos_api.image.list()
398 except Exception as e:
tierno72774862020-05-04 11:44:15 +0000399 raise vimconn.VimConnConnectionException("VIM not reachable. Error {}".format(e))
tierno1ec592d2020-06-16 15:29:47 +0000400 res = [x.get('uuid') for x in imgs if x.get('uri') == path]
baldoni10757152019-03-27 10:46:08 +0100401 if len(res) == 0:
tierno72774862020-05-04 11:44:15 +0000402 raise vimconn.VimConnNotFoundException("Image with this path was not found")
baldoni10757152019-03-27 10:46:08 +0100403 return res[0]
404
405 def get_image_list(self, filter_dict={}):
406 """Obtain tenant images from VIM
407 Filter_dict can be:
408 name: image name
409 id: image uuid
410 checksum: image checksum
411 location: image path
412 Returns the image list of dictionaries:
413 [{<the fields at Filter_dict plus some VIM specific>}, ...]
414 List can be empty
415 """
416 self.logger.debug('VIM get_image_list args: {}'.format(locals()))
417 r = []
418 try:
419 fimgs = self.fos_api.image.list()
420 except Exception as e:
tierno72774862020-05-04 11:44:15 +0000421 raise vimconn.VimConnConnectionException("VIM not reachable. Error {}".format(e))
baldoni10757152019-03-27 10:46:08 +0100422
423 filters = [
424 partial(self.__name_filter, filter_name=filter_dict.get('name')),
tierno1ec592d2020-06-16 15:29:47 +0000425 partial(self.__id_filter, filter_id=filter_dict.get('id')),
426 partial(self.__checksum_filter, filter_checksum=filter_dict.get('checksum'))
baldoni10757152019-03-27 10:46:08 +0100427 ]
428
429 r1 = []
430
431 for i in fimgs:
432 match = True
433 for f in filters:
434 match = match and f(i)
435 if match:
436 r1.append(i)
437
438 for i in r1:
439 img_info = {
tierno1ec592d2020-06-16 15:29:47 +0000440 'name': i.get('name'),
441 'id': i.get('uuid'),
442 'checksum': i.get('checksum'),
443 'location': i.get('uri'),
444 'fos': i
baldoni10757152019-03-27 10:46:08 +0100445 }
446 r.append(img_info)
447 return r
tierno1ec592d2020-06-16 15:29:47 +0000448 # raise VimConnNotImplemented( "Should have implemented this" )
baldoni10757152019-03-27 10:46:08 +0100449
450 def new_vminstance(self, name, description, start, image_id, flavor_id, net_list, cloud_config=None, disk_list=None,
tierno1ec592d2020-06-16 15:29:47 +0000451 availability_zone_index=None, availability_zone_list=None):
baldoni10757152019-03-27 10:46:08 +0100452 """Adds a VM instance to VIM
tierno1ec592d2020-06-16 15:29:47 +0000453 :param start: (boolean) indicates if VM must start or created in pause mode.
454 :param image_id: :param flavor_id: image and flavor VIM id to use for the VM
455 :param net_list: list of interfaces, each one is a dictionary with:
456 'name': (optional) name for the interface.
457 'net_id': VIM network id where this interface must be connect to. Mandatory for type==virtual
458 'vpci': (optional) virtual vPCI address to assign at the VM. Can be ignored depending on VIM capabilities
459 'model': (optional and only have sense for type==virtual) interface model: virtio, e1000, ...
460 'mac_address': (optional) mac address to assign to this interface
461 'ip_address': (optional) IP address to assign to this interface
462 #TODO: CHECK if an optional 'vlan' parameter is needed for VIMs when type if VF and net_id is not provided,
463 the VLAN tag to be used. In case net_id is provided, the internal network vlan is used for tagging VF
464 'type': (mandatory) can be one of:
465 'virtual', in this case always connected to a network of type 'net_type=bridge'
466 'PCI-PASSTHROUGH' or 'PF' (passthrough): depending on VIM capabilities it can be connected to a
467 data/ptp network ot it can created unconnected
468 'SR-IOV' or 'VF' (SRIOV with VLAN tag): same as PF for network connectivity.
469 'VFnotShared'(SRIOV without VLAN tag) same as PF for network connectivity. VF where no other VFs
470 are allocated on the same physical NIC
471 'bw': (optional) only for PF/VF/VFnotShared. Minimal Bandwidth required for the interface in GBPS
472 'port_security': (optional) If False it must avoid any traffic filtering at this interface. If missing
473 or True, it must apply the default VIM behaviour
474 After execution the method will add the key:
475 'vim_id': must be filled/added by this method with the VIM identifier generated by the VIM for this
476 interface. 'net_list' is modified
477 :param cloud_config: (optional) dictionary with:
478 'key-pairs': (optional) list of strings with the public key to be inserted to the default user
479 'users': (optional) list of users to be inserted, each item is a dict with:
480 'name': (mandatory) user name,
481 'key-pairs': (optional) list of strings with the public key to be inserted to the user
482 'user-data': (optional) can be a string with the text script to be passed directly to cloud-init,
483 or a list of strings, each one contains a script to be passed, usually with a MIMEmultipart file
484 'config-files': (optional). List of files to be transferred. Each item is a dict with:
485 'dest': (mandatory) string with the destination absolute path
486 'encoding': (optional, by default text). Can be one of:
487 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64'
488 'content' (mandatory): string with the content of the file
489 'permissions': (optional) string with file permissions, typically octal notation '0644'
490 'owner': (optional) file owner, string with the format 'owner:group'
491 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk)
492 :param disk_list: (optional) list with additional disks to the VM. Each item is a dict with:
493 'image_id': (optional). VIM id of an existing image. If not provided an empty disk must be mounted
494 'size': (mandatory) string with the size of the disk in GB
495 :param availability_zone_index: Index of availability_zone_list to use for this this VM. None if not AV required
496 :param availability_zone_list: list of availability zones given by user in the VNFD descriptor. Ignore if
497 availability_zone_index is None
baldoni10757152019-03-27 10:46:08 +0100498 Returns a tuple with the instance identifier and created_items or raises an exception on error
499 created_items can be None or a dictionary where this method can include key-values that will be passed to
500 the method delete_vminstance and action_vminstance. Can be used to store created ports, volumes, etc.
501 Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
502 as not present.
503 """
baldoni07df0d22020-06-12 15:24:24 +0200504 self.logger.debug('new_vminstance with args: {}'.format(locals()))
baldoni10757152019-03-27 10:46:08 +0100505 fdu_uuid = '{}'.format(uuid.uuid4())
506
507 flv = self.fos_api.flavor.get(flavor_id)
508 img = self.fos_api.image.get(image_id)
509
510 if flv is None:
tierno72774862020-05-04 11:44:15 +0000511 raise vimconn.VimConnNotFoundException("Flavor {} not found at VIM".format(flavor_id))
baldoni10757152019-03-27 10:46:08 +0100512 if img is None:
tierno72774862020-05-04 11:44:15 +0000513 raise vimconn.VimConnNotFoundException("Image {} not found at VIM".format(image_id))
baldoni10757152019-03-27 10:46:08 +0100514
515 created_items = {
tierno1ec592d2020-06-16 15:29:47 +0000516 'fdu_id': '',
517 'node_id': '',
518 'connection_points': []
519 }
baldoni10757152019-03-27 10:46:08 +0100520
521 fdu_desc = {
tierno1ec592d2020-06-16 15:29:47 +0000522 'name': name,
523 'id': fdu_uuid,
524 'uuid': fdu_uuid,
525 'computation_requirements': flv,
526 'image': img,
527 'hypervisor': self.hv,
528 'migration_kind': 'LIVE',
529 'interfaces': [],
530 'io_ports': [],
531 'connection_points': [],
532 'depends_on': [],
533 'storage': []
baldoni10757152019-03-27 10:46:08 +0100534 }
535
536 nets = []
537 cps = []
538 intf_id = 0
539 for n in net_list:
540 cp_id = '{}'.format(uuid.uuid4())
tierno1ec592d2020-06-16 15:29:47 +0000541 n['vim_id'] = cp_id
baldoni10757152019-03-27 10:46:08 +0100542 pair_id = n.get('net_id')
543
544 cp_d = {
tierno1ec592d2020-06-16 15:29:47 +0000545 'id': cp_id,
baldoni07df0d22020-06-12 15:24:24 +0200546 'name': cp_id,
547 'vld_ref': pair_id
baldoni10757152019-03-27 10:46:08 +0100548 }
549 intf_d = {
tierno1ec592d2020-06-16 15:29:47 +0000550 'name': n.get('name', 'eth{}'.format(intf_id)),
551 'is_mgmt': False,
552 'if_type': 'INTERNAL',
553 'virtual_interface': {
554 'intf_type': n.get('model', 'VIRTIO'),
555 'vpci': n.get('vpci', '0:0:0'),
556 'bandwidth': int(n.get('bw', 100))
baldoni07df0d22020-06-12 15:24:24 +0200557 },
558 'cp_id': cp_id
baldoni10757152019-03-27 10:46:08 +0100559 }
560 if n.get('mac_address', None) is not None:
561 intf_d['mac_address'] = n['mac_address']
562
563 created_items['connection_points'].append(cp_id)
564 fdu_desc['connection_points'].append(cp_d)
565 fdu_desc['interfaces'].append(intf_d)
566
567 intf_id = intf_id + 1
568
569 if cloud_config is not None:
tierno1ec592d2020-06-16 15:29:47 +0000570 configuration = {'conf_type': 'CLOUD_INIT'}
baldoni10757152019-03-27 10:46:08 +0100571 if cloud_config.get('user-data') is not None:
tierno1ec592d2020-06-16 15:29:47 +0000572 configuration['script'] = cloud_config.get('user-data')
baldoni10757152019-03-27 10:46:08 +0100573 if cloud_config.get('key-pairs') is not None:
tierno1ec592d2020-06-16 15:29:47 +0000574 configuration['ssh_keys'] = cloud_config.get('key-pairs')
baldoni10757152019-03-27 10:46:08 +0100575
576 if 'script' in configuration:
tierno1ec592d2020-06-16 15:29:47 +0000577 fdu_desc['configuration'] = configuration
baldoni10757152019-03-27 10:46:08 +0100578
baldoni07df0d22020-06-12 15:24:24 +0200579 self.logger.debug('Eclipse fog05 FDU Descriptor: {}'.format(fdu_desc))
baldoni10757152019-03-27 10:46:08 +0100580
baldoni07df0d22020-06-12 15:24:24 +0200581 fdu = FDU(fdu_desc)
baldoni10757152019-03-27 10:46:08 +0100582
583 try:
baldoni07df0d22020-06-12 15:24:24 +0200584 self.fos_api.fdu.onboard(fdu)
585 instance = self.fos_api.fdu.define(fdu_uuid)
586 instance_list = self.fos_api.fdu.instance_list(fdu_uuid)
587 selected_node = ''
588 for n in instance_list:
589 instances = instance_list[n]
590 if instance.uuid in instances:
591 selected_node = n
592 if selected_node == '':
593 raise ValueError("Unable to find node for network creation")
baldoni10757152019-03-27 10:46:08 +0100594
baldoni07df0d22020-06-12 15:24:24 +0200595 self.logger.debug('Selected node by VIM: {}'.format(selected_node))
tierno1ec592d2020-06-16 15:29:47 +0000596 created_items['fdu_id'] = fdu_uuid
597 created_items['node_id'] = selected_node
baldoni07df0d22020-06-12 15:24:24 +0200598
599 for cp in fdu_desc['connection_points']:
600 nets = self.fos_api.network.list()
601 for net in nets:
602 if net.get('uuid') == cp['vld_ref']:
603 self.fos_api.network.add_network_to_node(net, selected_node)
604
605 self.fos_api.fdu.configure(instance.uuid)
606 self.fos_api.fdu.start(instance.uuid)
607
608 self.logger.debug('Eclipse fog05 FDU Started {}'.format(instance.uuid))
609
tierno1ec592d2020-06-16 15:29:47 +0000610 created_items['instance_id'] = str(instance.uuid)
baldoni07df0d22020-06-12 15:24:24 +0200611
tierno1ec592d2020-06-16 15:29:47 +0000612 self.fdu_node_map[instance.uuid] = selected_node
613 self.logger.debug('new_vminstance returns: {} {}'.format(instance.uuid, created_items))
baldoni07df0d22020-06-12 15:24:24 +0200614 return str(instance.uuid), created_items
615 except fimapi.FIMAResouceExistingException as free:
tierno72774862020-05-04 11:44:15 +0000616 raise vimconn.VimConnConflictException("VM already exists at VIM. Error {}".format(free))
baldoni10757152019-03-27 10:46:08 +0100617 except Exception as e:
tierno72774862020-05-04 11:44:15 +0000618 raise vimconn.VimConnException("Error while instantiating VM {}. Error {}".format(name, e))
baldoni10757152019-03-27 10:46:08 +0100619
tierno1ec592d2020-06-16 15:29:47 +0000620 def get_vminstance(self, vm_id):
baldoni10757152019-03-27 10:46:08 +0100621 """Returns the VM instance information from VIM"""
622 self.logger.debug('VIM get_vminstance with args: {}'.format(locals()))
623
624 try:
baldoni07df0d22020-06-12 15:24:24 +0200625 instance = self.fos_api.fdu.instance_info(vm_id)
baldoni10757152019-03-27 10:46:08 +0100626 except Exception as e:
tierno72774862020-05-04 11:44:15 +0000627 raise vimconn.VimConnConnectionException("VIM not reachable. Error {}".format(e))
baldoni07df0d22020-06-12 15:24:24 +0200628 if instance is None:
tierno72774862020-05-04 11:44:15 +0000629 raise vimconn.VimConnNotFoundException('VM with id {} not found!'.format(vm_id))
baldoni07df0d22020-06-12 15:24:24 +0200630 return instance.to_json()
baldoni10757152019-03-27 10:46:08 +0100631
632 def delete_vminstance(self, vm_id, created_items=None):
633 """
634 Removes a VM instance from VIM and each associate elements
635 :param vm_id: VIM identifier of the VM, provided by method new_vminstance
636 :param created_items: dictionary with extra items to be deleted. provided by method new_vminstance and/or method
637 action_vminstance
638 :return: None or the same vm_id. Raises an exception on fail
639 """
640 self.logger.debug('FOS delete_vminstance with args: {}'.format(locals()))
tierno1ec592d2020-06-16 15:29:47 +0000641 fduid = created_items.get('fdu_id')
baldoni10757152019-03-27 10:46:08 +0100642 try:
baldoni07df0d22020-06-12 15:24:24 +0200643 instance = self.fos_api.fdu.instance_info(vm_id)
644 instance_list = self.fos_api.fdu.instance_list(instance.fdu_id)
645 selected_node = ''
646 for n in instance_list:
647 instances = instance_list[n]
648 if instance.uuid in instances:
649 selected_node = n
650 if selected_node == '':
651 raise ValueError("Unable to find node for the given Instance")
652
653 self.fos_api.fdu.stop(vm_id)
654
655 for cp in instance.to_json()['connection_points']:
656 nets = self.fos_api.network.list()
657 for net in nets:
658 if net.get('uuid') == cp['vld_ref']:
659 self.fos_api.network.remove_network_from_node(net.get('uuid'), selected_node)
660
661 self.fos_api.fdu.clean(vm_id)
662 self.fos_api.fdu.undefine(vm_id)
663
baldoni10757152019-03-27 10:46:08 +0100664 self.fos_api.fdu.offload(fduid)
665 except Exception as e:
tierno1ec592d2020-06-16 15:29:47 +0000666 raise vimconn.VimConnException("Error on deleting VM with id {}. Error {}".format(vm_id, e))
baldoni10757152019-03-27 10:46:08 +0100667 return vm_id
668
tierno1ec592d2020-06-16 15:29:47 +0000669 # raise VimConnNotImplemented( "Should have implemented this" )
baldoni10757152019-03-27 10:46:08 +0100670
671 def refresh_vms_status(self, vm_list):
672 """Get the status of the virtual machines and their interfaces/ports
673 Params: the list of VM identifiers
674 Returns a dictionary with:
675 vm_id: #VIM id of this Virtual Machine
676 status: #Mandatory. Text with one of:
677 # DELETED (not found at vim)
678 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
679 # OTHER (Vim reported other status not understood)
680 # ERROR (VIM indicates an ERROR status)
681 # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
682 # BUILD (on building process), ERROR
683 # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
684 #
685 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
686 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
687 interfaces: list with interface info. Each item a dictionary with:
688 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
689 mac_address: #Text format XX:XX:XX:XX:XX:XX
690 vim_net_id: #network id where this interface is connected, if provided at creation
691 vim_interface_id: #interface/port VIM id
692 ip_address: #null, or text with IPv4, IPv6 address
693 compute_node: #identification of compute node where PF,VF interface is allocated
694 pci: #PCI address of the NIC that hosts the PF,VF
695 vlan: #physical VLAN used for VF
696 """
697 self.logger.debug('FOS refresh_vms_status with args: {}'.format(locals()))
698 fos2osm_status = {
tierno1ec592d2020-06-16 15:29:47 +0000699 'DEFINE': 'OTHER',
700 'CONFIGURE': 'INACTIVE',
701 'RUN': 'ACTIVE',
702 'PAUSE': 'PAUSED',
703 'ERROR': 'ERROR'
baldoni10757152019-03-27 10:46:08 +0100704 }
705
706 r = {}
707
708 for vm in vm_list:
709 self.logger.debug('FOS refresh_vms_status for {}'.format(vm))
710
711 info = {}
712 nid = self.fdu_node_map.get(vm)
713 if nid is None:
tierno1ec592d2020-06-16 15:29:47 +0000714 r[vm] = {
715 'status': 'VIM_ERROR',
716 'error_msg': 'Not compute node associated for VM'
717 }
baldoni10757152019-03-27 10:46:08 +0100718 continue
719
720 try:
721 vm_info = self.fos_api.fdu.instance_info(vm)
tierno1ec592d2020-06-16 15:29:47 +0000722 except Exception:
723 r[vm] = {
724 'status': 'VIM_ERROR',
725 'error_msg': 'unable to connect to VIM'
726 }
baldoni10757152019-03-27 10:46:08 +0100727 continue
728
729 if vm_info is None:
tierno1ec592d2020-06-16 15:29:47 +0000730 r[vm:] = {'status': 'DELETED'}
baldoni10757152019-03-27 10:46:08 +0100731 continue
732
baldoni07df0d22020-06-12 15:24:24 +0200733 desc = self.fos_api.fdu.info(str(vm_info.fdu_id))
baldoni10757152019-03-27 10:46:08 +0100734
baldoni07df0d22020-06-12 15:24:24 +0200735 vm_info = vm_info.to_json()
736 desc = desc.to_json()
737
baldoni10757152019-03-27 10:46:08 +0100738 osm_status = fos2osm_status.get(vm_info.get('status'))
739
740 self.logger.debug('FOS status info {}'.format(vm_info))
741 self.logger.debug('FOS status is {} <-> OSM Status {}'.format(vm_info.get('status'), osm_status))
tierno1ec592d2020-06-16 15:29:47 +0000742 info['status'] = osm_status
baldoni10757152019-03-27 10:46:08 +0100743 if vm_info.get('status') == 'ERROR':
tierno1ec592d2020-06-16 15:29:47 +0000744 info['error_msg'] = vm_info.get('error_code')
baldoni07df0d22020-06-12 15:24:24 +0200745 # yaml.safe_dump(json.loads(json.dumps(vm_info)))
tierno1ec592d2020-06-16 15:29:47 +0000746 # info['vim_info'] = ''
baldoni10757152019-03-27 10:46:08 +0100747 faces = []
748 i = 0
tierno1ec592d2020-06-16 15:29:47 +0000749 for intf_name in vm_info.get('hypervisor_info').get('network', []):
baldoni10757152019-03-27 10:46:08 +0100750 intf_info = vm_info.get('hypervisor_info').get('network').get(intf_name)
751 face = {}
752 face['compute_node'] = nid
baldoni07df0d22020-06-12 15:24:24 +0200753 # face['vim_info'] = '' #yaml.safe_dump(json.loads(json.dumps(intf_info)))
baldoni10757152019-03-27 10:46:08 +0100754 face['mac_address'] = intf_info.get('hwaddr')
755 addrs = []
756 for a in intf_info.get('addresses'):
757 addrs.append(a.get('address'))
758 if len(addrs) >= 0:
759 face['ip_address'] = ','.join(addrs)
760 else:
761 face['ip_address'] = ''
762 face['pci'] = '0:0:0.0'
baldoni07df0d22020-06-12 15:24:24 +0200763
baldoni10757152019-03-27 10:46:08 +0100764 try:
765 cp_info = vm_info.get('connection_points')[i]
766 except IndexError:
767 cp_info = None
768 if cp_info is not None:
baldoni07df0d22020-06-12 15:24:24 +0200769 cp_id = cp_info['cp_id']
baldoni10757152019-03-27 10:46:08 +0100770 cps_d = desc['connection_points']
baldoni07df0d22020-06-12 15:24:24 +0200771 matches = [x for x in cps_d if x['id'] == cp_id]
baldoni10757152019-03-27 10:46:08 +0100772 if len(matches) > 0:
773 cpd = matches[0]
tierno1ec592d2020-06-16 15:29:47 +0000774 face['vim_net_id'] = cpd.get('vld_ref', '')
baldoni10757152019-03-27 10:46:08 +0100775 else:
776 face['vim_net_id'] = ''
777 face['vim_interface_id'] = cp_id
778 # cp_info.get('uuid')
779 else:
780 face['vim_net_id'] = ''
781 face['vim_interface_id'] = intf_name
782 faces.append(face)
783 i += 1
784
tierno1ec592d2020-06-16 15:29:47 +0000785 info['interfaces'] = faces
786 r[vm] = info
baldoni10757152019-03-27 10:46:08 +0100787 self.logger.debug('FOS refresh_vms_status res for {} is {}'.format(vm, info))
788 self.logger.debug('FOS refresh_vms_status res is {}'.format(r))
789 return r
790
baldoni10757152019-03-27 10:46:08 +0100791 def action_vminstance(self, vm_id, action_dict, created_items={}):
792 """
793 Send and action over a VM instance. Returns created_items if the action was successfully sent to the VIM.
794 created_items is a dictionary with items that
795 :param vm_id: VIM identifier of the VM, provided by method new_vminstance
796 :param action_dict: dictionary with the action to perform
797 :param created_items: provided by method new_vminstance is a dictionary with key-values that will be passed to
798 the method delete_vminstance. Can be used to store created ports, volumes, etc. Format is vimconnector
799 dependent, but do not use nested dictionaries and a value of None should be the same as not present. This
800 method can modify this value
801 :return: None, or a console dict
802 """
803 self.logger.debug('VIM action_vminstance with args: {}'.format(locals()))
804 nid = self.fdu_node_map.get(vm_id)
805 if nid is None:
tierno72774862020-05-04 11:44:15 +0000806 raise vimconn.VimConnNotFoundException('No node for this VM')
baldoni10757152019-03-27 10:46:08 +0100807 try:
baldoni07df0d22020-06-12 15:24:24 +0200808 instance = self.fos_api.fdu.instance_info(vm_id)
baldoni10757152019-03-27 10:46:08 +0100809 if "start" in action_dict:
baldoni07df0d22020-06-12 15:24:24 +0200810 if instance.get('status') == 'CONFIGURE':
baldoni10757152019-03-27 10:46:08 +0100811 self.fos_api.fdu.start(vm_id)
baldoni07df0d22020-06-12 15:24:24 +0200812 elif instance.get('status') == 'PAUSE':
baldoni10757152019-03-27 10:46:08 +0100813 self.fos_api.fdu.resume(vm_id)
814 else:
tierno1ec592d2020-06-16 15:29:47 +0000815 raise vimconn.VimConnConflictException('Cannot start from current state: {}'.format(
816 instance.get('status')))
baldoni10757152019-03-27 10:46:08 +0100817 elif "pause" in action_dict:
baldoni07df0d22020-06-12 15:24:24 +0200818 if instance.get('status') == 'RUN':
baldoni10757152019-03-27 10:46:08 +0100819 self.fos_api.fdu.pause(vm_id)
820 else:
tierno1ec592d2020-06-16 15:29:47 +0000821 raise vimconn.VimConnConflictException('Cannot pause from current state: {}'.format(
822 instance.get('status')))
baldoni10757152019-03-27 10:46:08 +0100823 elif "resume" in action_dict:
baldoni07df0d22020-06-12 15:24:24 +0200824 if instance.get('status') == 'PAUSE':
baldoni10757152019-03-27 10:46:08 +0100825 self.fos_api.fdu.resume(vm_id)
826 else:
tierno1ec592d2020-06-16 15:29:47 +0000827 raise vimconn.VimConnConflictException('Cannot resume from current state: {}'.format(
828 instance.get('status')))
baldoni10757152019-03-27 10:46:08 +0100829 elif "shutoff" in action_dict or "shutdown" or "forceOff" in action_dict:
baldoni07df0d22020-06-12 15:24:24 +0200830 if instance.get('status') == 'RUN':
baldoni10757152019-03-27 10:46:08 +0100831 self.fos_api.fdu.stop(vm_id)
832 else:
tierno1ec592d2020-06-16 15:29:47 +0000833 raise vimconn.VimConnConflictException('Cannot shutoff from current state: {}'.format(
834 instance.get('status')))
baldoni10757152019-03-27 10:46:08 +0100835 elif "terminate" in action_dict:
baldoni07df0d22020-06-12 15:24:24 +0200836 if instance.get('status') == 'RUN':
baldoni10757152019-03-27 10:46:08 +0100837 self.fos_api.fdu.stop(vm_id)
838 self.fos_api.fdu.clean(vm_id)
839 self.fos_api.fdu.undefine(vm_id)
840 # self.fos_api.fdu.offload(vm_id)
baldoni07df0d22020-06-12 15:24:24 +0200841 elif instance.get('status') == 'CONFIGURE':
baldoni10757152019-03-27 10:46:08 +0100842 self.fos_api.fdu.clean(vm_id)
843 self.fos_api.fdu.undefine(vm_id)
844 # self.fos_api.fdu.offload(vm_id)
baldoni07df0d22020-06-12 15:24:24 +0200845 elif instance.get('status') == 'PAUSE':
baldoni10757152019-03-27 10:46:08 +0100846 self.fos_api.fdu.resume(vm_id)
847 self.fos_api.fdu.stop(vm_id)
848 self.fos_api.fdu.clean(vm_id)
849 self.fos_api.fdu.undefine(vm_id)
850 # self.fos_api.fdu.offload(vm_id)
851 else:
tierno1ec592d2020-06-16 15:29:47 +0000852 raise vimconn.VimConnConflictException('Cannot terminate from current state: {}'.format(
853 instance.get('status')))
baldoni10757152019-03-27 10:46:08 +0100854 elif "rebuild" in action_dict:
tierno72774862020-05-04 11:44:15 +0000855 raise vimconn.VimConnNotImplemented("Rebuild not implemented")
baldoni10757152019-03-27 10:46:08 +0100856 elif "reboot" in action_dict:
baldoni07df0d22020-06-12 15:24:24 +0200857 if instance.get('status') == 'RUN':
baldoni10757152019-03-27 10:46:08 +0100858 self.fos_api.fdu.stop(vm_id)
859 self.fos_api.fdu.start(vm_id)
860 else:
tierno1ec592d2020-06-16 15:29:47 +0000861 raise vimconn.VimConnConflictException('Cannot reboot from current state: {}'.format(
862 instance.get('status')))
baldoni10757152019-03-27 10:46:08 +0100863 except Exception as e:
tierno72774862020-05-04 11:44:15 +0000864 raise vimconn.VimConnConnectionException("VIM not reachable. Error {}".format(e))