1 # -*- coding: utf-8 -*-
4 # Copyright 2017 Telefonica Digital Spain S.L.U.
5 # This file is part of ETSI OSM
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
12 # http://www.apache.org/licenses/LICENSE-2.0
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
18 # License for the specific language governing permissions and limitations
21 # For those usages not covered by the Apache License, Version 2.0 please
22 # contact with: patent-office@telefonica.com
26 vimconnector implements all the methods to interact with OpenNebula using the XML-RPC API.
28 __author__
= "Jose Maria Carmona Perez,Juan Antonio Hernando Labajo, Emilio Abraham Garrido Garcia,Alberto Florez " \
29 "Pages, Andres Pozo Munoz, Santiago Perez Marin, Onlife Networks Telefonica I+D Product Innovation "
30 __date__
= "$13-dec-2017 11:09:29$"
31 from osm_ro_plugin
import vimconn
41 class vimconnector(vimconn
.VimConnector
):
42 def __init__(self
, uuid
, name
, tenant_id
, tenant_name
, url
, url_admin
=None, user
=None, passwd
=None,
43 log_level
="DEBUG", config
={}, persistent_info
={}):
47 'uuid': id asigned to this VIM
48 'name': name assigned to this VIM, can be used for logging
49 'tenant_id', 'tenant_name': (only one of them is mandatory) VIM tenant to be used
50 'url_admin': (optional), url used for administrative tasks
51 'user', 'passwd': credentials of the VIM user
52 'log_level': provider if it should use a different log_level than the general one
53 'config': dictionary with extra VIM information. This contains a consolidate version of general VIM config
54 at creation and particular VIM config at teh attachment
55 'persistent_info': dict where the class can store information that will be available among class
56 destroy/creation cycles. This info is unique per VIM/credential. At first call it will contain an
57 empty dict. Useful to store login/tokens information for speed up communication
59 Returns: Raise an exception is some needed parameter is missing, but it must not do any connectivity
63 vimconn
.VimConnector
.__init
__(self
, uuid
, name
, tenant_id
, tenant_name
, url
, url_admin
, user
, passwd
, log_level
,
66 def _new_one_connection(self
):
67 return pyone
.OneServer(self
.url
, session
=self
.user
+ ':' + self
.passwd
)
69 def new_tenant(self
, tenant_name
, tenant_description
):
70 # '''Adds a new tenant to VIM with this name and description, returns the tenant identifier'''
72 client
= oca
.Client(self
.user
+ ':' + self
.passwd
, self
.url
)
73 group_list
= oca
.GroupPool(client
)
74 user_list
= oca
.UserPool(client
)
77 create_primarygroup
= 1
79 for group
in group_list
:
80 if str(group
.name
) == str(tenant_name
):
81 create_primarygroup
= 0
83 if create_primarygroup
== 1:
84 oca
.Group
.allocate(client
, tenant_name
)
86 # set to primary_group the tenant_group and oneadmin to secondary_group
87 for group
in group_list
:
88 if str(group
.name
) == str(tenant_name
):
89 for user
in user_list
:
90 if str(user
.name
) == str(self
.user
):
91 if user
.name
== "oneadmin":
94 self
._add
_secondarygroup
(user
.id, group
.id)
97 except Exception as e
:
98 self
.logger
.error("Create new tenant error: " + str(e
))
99 raise vimconn
.VimConnException(e
)
101 def delete_tenant(self
, tenant_id
):
102 """Delete a tenant from VIM. Returns the old tenant identifier"""
104 client
= oca
.Client(self
.user
+ ':' + self
.passwd
, self
.url
)
105 group_list
= oca
.GroupPool(client
)
106 user_list
= oca
.UserPool(client
)
109 for group
in group_list
:
110 if str(group
.id) == str(tenant_id
):
111 for user
in user_list
:
112 if str(user
.name
) == str(self
.user
):
113 self
._delete
_secondarygroup
(user
.id, group
.id)
116 raise vimconn
.VimConnNotFoundException("Group {} not found".format(tenant_id
))
117 except Exception as e
:
118 self
.logger
.error("Delete tenant " + str(tenant_id
) + " error: " + str(e
))
119 raise vimconn
.VimConnException(e
)
121 def _add_secondarygroup(self
, id_user
, id_group
):
122 # change secondary_group to primary_group
123 params
= '<?xml version="1.0"?> \
125 <methodName>one.user.addgroup</methodName>\
128 <value><string>{}:{}</string></value>\
131 <value><int>{}</int></value>\
134 <value><int>{}</int></value>\
137 </methodCall>'.format(self
.user
, self
.passwd
, (str(id_user
)), (str(id_group
)))
138 requests
.post(self
.url
, params
)
140 def _delete_secondarygroup(self
, id_user
, id_group
):
141 params
= '<?xml version="1.0"?> \
143 <methodName>one.user.delgroup</methodName>\
146 <value><string>{}:{}</string></value>\
149 <value><int>{}</int></value>\
152 <value><int>{}</int></value>\
155 </methodCall>'.format(self
.user
, self
.passwd
, (str(id_user
)), (str(id_group
)))
156 requests
.post(self
.url
, params
)
158 def new_network(self
, net_name
, net_type
, ip_profile
=None, shared
=False, provider_network_profile
=None):
159 """Adds a tenant network to VIM
161 'net_name': name of the network
163 'bridge': overlay isolated network
164 'data': underlay E-LAN network for Passthrough and SRIOV interfaces
165 'ptp': underlay E-LINE network for Passthrough and SRIOV interfaces.
166 'ip_profile': is a dict containing the IP parameters of the network
167 'ip_version': can be "IPv4" or "IPv6" (Currently only IPv4 is implemented)
168 'subnet_address': ip_prefix_schema, that is X.X.X.X/Y
169 'gateway_address': (Optional) ip_schema, that is X.X.X.X
170 'dns_address': (Optional) comma separated list of ip_schema, e.g. X.X.X.X[,X,X,X,X]
171 'dhcp_enabled': True or False
172 'dhcp_start_address': ip_schema, first IP to grant
173 'dhcp_count': number of IPs to grant.
174 'shared': if this network can be seen/use by other tenants/organization
175 'provider_network_profile': (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk}
176 Returns a tuple with the network identifier and created_items, or raises an exception on error
177 created_items can be None or a dictionary where this method can include key-values that will be passed to
178 the method delete_network. Can be used to store created segments, created l2gw connections, etc.
179 Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
183 # oca library method cannot be used in this case (problem with cluster parameters)
186 if provider_network_profile
:
187 vlan
= provider_network_profile
.get("segmentation-id")
189 one
= self
._new
_one
_connection
()
191 if ip_profile
is None:
192 subnet_rand
= random
.randint(0, 255)
193 ip_start
= "192.168.{}.1".format(subnet_rand
)
195 index
= ip_profile
["subnet_address"].find("/")
196 ip_start
= ip_profile
["subnet_address"][:index
]
197 if "dhcp_count" in ip_profile
and ip_profile
["dhcp_count"] is not None:
198 size
= str(ip_profile
["dhcp_count"])
199 elif "dhcp_count" not in ip_profile
and ip_profile
["ip_version"] == "IPv4":
200 prefix
= ip_profile
["subnet_address"][index
+ 1:]
201 size
= int(math
.pow(2, 32 - prefix
))
202 if "dhcp_start_address" in ip_profile
and ip_profile
["dhcp_start_address"] is not None:
203 ip_start
= str(ip_profile
["dhcp_start_address"])
204 # if ip_profile["ip_version"] == "IPv6":
205 # ip_prefix_type = "GLOBAL_PREFIX"
210 vlan_id
= str(random
.randint(100, 4095))
211 # if "internal" in net_name:
212 # OpenNebula not support two networks with same name
213 random_net_name
= str(random
.randint(1, 1000000))
214 net_name
= net_name
+ random_net_name
215 net_id
= one
.vn
.allocate({
218 'PHYDEV': self
.config
["network"]["phydev"],
220 }, self
.config
["cluster"]["id"])
230 one
.vn
.add_ar(net_id
, arpool
)
231 return net_id
, created_items
232 except Exception as e
:
233 self
.logger
.error("Create new network error: " + str(e
))
234 raise vimconn
.VimConnException(e
)
236 def get_network_list(self
, filter_dict
={}):
237 """Obtain tenant networks of VIM
238 :params filter_dict: (optional) contains entries to return only networks that matches ALL entries:
239 name: string => returns only networks with this name
240 id: string => returns networks with this VIM id, this imply returns one network at most
241 shared: boolean >= returns only networks that are (or are not) shared
242 tenant_id: sting => returns only networks that belong to this tenant/project
243 (not used yet) admin_state_up: boolean => returns only networks that are (or are not) in admin state active
244 (not used yet) status: 'ACTIVE','ERROR',... => filter networks that are on this status
245 Returns the network list of dictionaries. each dictionary contains:
246 'id': (mandatory) VIM network id
247 'name': (mandatory) VIM network name
248 'status': (mandatory) can be 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER'
249 'network_type': (optional) can be 'vxlan', 'vlan' or 'flat'
250 'segmentation_id': (optional) in case network_type is vlan or vxlan this field contains the segmentation id
251 'error_msg': (optional) text that explains the ERROR status
252 other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param
253 List can be empty if no network map the filter_dict. Raise an exception only upon VIM connectivity,
254 authorization, or some other unspecific error
258 one
= self
._new
_one
_connection
()
259 net_pool
= one
.vnpool
.info(-2, -1, -1).VNET
261 if "name" in filter_dict
:
262 network_name_filter
= filter_dict
["name"]
264 network_name_filter
= None
265 if "id" in filter_dict
:
266 network_id_filter
= filter_dict
["id"]
268 network_id_filter
= None
269 for network
in net_pool
:
270 if network
.NAME
== network_name_filter
or str(network
.ID
) == str(network_id_filter
):
271 net_dict
= {"name": network
.NAME
, "id": str(network
.ID
), "status": "ACTIVE"}
272 response
.append(net_dict
)
274 except Exception as e
:
275 self
.logger
.error("Get network list error: " + str(e
))
276 raise vimconn
.VimConnException(e
)
278 def get_network(self
, net_id
):
279 """Obtain network details from the 'net_id' VIM network
280 Return a dict that contains:
281 'id': (mandatory) VIM network id, that is, net_id
282 'name': (mandatory) VIM network name
283 'status': (mandatory) can be 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER'
284 'error_msg': (optional) text that explains the ERROR status
285 other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param
286 Raises an exception upon error or when network is not found
289 one
= self
._new
_one
_connection
()
290 net_pool
= one
.vnpool
.info(-2, -1, -1).VNET
292 for network
in net_pool
:
293 if str(network
.ID
) == str(net_id
):
294 net
['id'] = network
.ID
295 net
['name'] = network
.NAME
296 net
['status'] = "ACTIVE"
301 raise vimconn
.VimConnNotFoundException("Network {} not found".format(net_id
))
302 except Exception as e
:
303 self
.logger
.error("Get network " + str(net_id
) + " error): " + str(e
))
304 raise vimconn
.VimConnException(e
)
306 def delete_network(self
, net_id
, created_items
=None):
308 Removes a tenant network from VIM and its associated elements
309 :param net_id: VIM identifier of the network, provided by method new_network
310 :param created_items: dictionary with extra items to be deleted. provided by method new_network
311 Returns the network identifier or raises an exception upon error or when network is not found
315 one
= self
._new
_one
_connection
()
316 one
.vn
.delete(int(net_id
))
318 except Exception as e
:
319 self
.logger
.error("Delete network " + str(net_id
) + "error: network not found" + str(e
))
320 raise vimconn
.VimConnException(e
)
322 def refresh_nets_status(self
, net_list
):
323 """Get the status of the networks
325 'net_list': a list with the VIM network id to be get the status
326 Returns a dictionary with:
327 'net_id': #VIM id of this network
328 status: #Mandatory. Text with one of:
329 # DELETED (not found at vim)
330 # VIM_ERROR (Cannot connect to VIM, authentication problems, VIM response error, ...)
331 # OTHER (Vim reported other status not understood)
332 # ERROR (VIM indicates an ERROR status)
333 # ACTIVE, INACTIVE, DOWN (admin down),
334 # BUILD (on building process)
335 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
336 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
341 for net_id
in net_list
:
344 net_vim
= self
.get_network(net_id
)
345 net
["status"] = net_vim
["status"]
346 net
["vim_info"] = None
347 except vimconn
.VimConnNotFoundException
as e
:
348 self
.logger
.error("Exception getting net status: {}".format(str(e
)))
349 net
['status'] = "DELETED"
350 net
['error_msg'] = str(e
)
351 except vimconn
.VimConnException
as e
:
353 net
["status"] = "VIM_ERROR"
354 net
["error_msg"] = str(e
)
355 net_dict
[net_id
] = net
357 except vimconn
.VimConnException
as e
:
360 net_dict
[k
]["status"] = "VIM_ERROR"
361 net_dict
[k
]["error_msg"] = str(e
)
364 def get_flavor(self
, flavor_id
): # Esta correcto
365 """Obtain flavor details from the VIM
366 Returns the flavor dict details {'id':<>, 'name':<>, other vim specific }
367 Raises an exception upon error or if not found
371 one
= self
._new
_one
_connection
()
372 template
= one
.template
.info(int(flavor_id
))
373 if template
is not None:
374 return {'id': template
.ID
, 'name': template
.NAME
}
375 raise vimconn
.VimConnNotFoundException("Flavor {} not found".format(flavor_id
))
376 except Exception as e
:
377 self
.logger
.error("get flavor " + str(flavor_id
) + " error: " + str(e
))
378 raise vimconn
.VimConnException(e
)
380 def new_flavor(self
, flavor_data
):
381 """Adds a tenant flavor to VIM
382 flavor_data contains a dictionary with information, keys:
384 ram: memory (cloud type) in MBytes
385 vpcus: cpus (cloud type)
386 extended: EPA parameters
387 - numas: #items requested in same NUMA
388 memory: number of 1G huge pages memory
389 paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads
390 interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
391 - name: interface name
392 dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC
393 bandwidth: X Gbps; requested guarantee bandwidth
394 vpci: requested virtual PCI address
398 Returns the flavor identifier"""
400 disk_size
= str(int(flavor_data
["disk"])*1024)
403 one
= self
._new
_one
_connection
()
404 template_id
= one
.template
.allocate({
406 'NAME': flavor_data
["name"],
407 'CPU': flavor_data
["vcpus"],
408 'VCPU': flavor_data
["vcpus"],
409 'MEMORY': flavor_data
["ram"],
415 'SSH_PUBLIC_KEY': '$USER[SSH_PUBLIC_KEY]'
421 'CLUSTER_ID': self
.config
["cluster"]["id"]
426 except Exception as e
:
427 self
.logger
.error("Create new flavor error: " + str(e
))
428 raise vimconn
.VimConnException(e
)
430 def delete_flavor(self
, flavor_id
):
431 """ Deletes a tenant flavor from VIM
432 Returns the old flavor_id
435 one
= self
._new
_one
_connection
()
436 one
.template
.delete(int(flavor_id
), False)
438 except Exception as e
:
439 self
.logger
.error("Error deleting flavor " + str(flavor_id
) + ". Flavor not found")
440 raise vimconn
.VimConnException(e
)
442 def get_image_list(self
, filter_dict
={}):
443 """Obtain tenant images from VIM
447 checksum: image checksum
449 Returns the image list of dictionaries:
450 [{<the fields at Filter_dict plus some VIM specific>}, ...]
454 one
= self
._new
_one
_connection
()
455 image_pool
= one
.imagepool
.info(-2, -1, -1).IMAGE
457 if "name" in filter_dict
:
458 image_name_filter
= filter_dict
["name"]
460 image_name_filter
= None
461 if "id" in filter_dict
:
462 image_id_filter
= filter_dict
["id"]
464 image_id_filter
= None
465 for image
in image_pool
:
466 if str(image_name_filter
) == str(image
.NAME
) or str(image
.ID
) == str(image_id_filter
):
467 images_dict
= {"name": image
.NAME
, "id": str(image
.ID
)}
468 images
.append(images_dict
)
470 except Exception as e
:
471 self
.logger
.error("Get image list error: " + str(e
))
472 raise vimconn
.VimConnException(e
)
474 def new_vminstance(self
, name
, description
, start
, image_id
, flavor_id
, net_list
, cloud_config
=None, disk_list
=None,
475 availability_zone_index
=None, availability_zone_list
=None):
477 Adds a VM instance to VIM
480 :param start: (boolean) indicates if VM must start or created in pause mode.
481 :param image_id: image VIM id to use for the VM
482 :param flavor_id: flavor VIM id to use for the VM
483 :param net_list: list of interfaces, each one is a dictionary with:
484 'name': (optional) name for the interface.
485 'net_id': VIM network id where this interface must be connect to. Mandatory for type==virtual
486 'vpci': (optional) virtual vPCI address to assign at the VM. Can be ignored depending on VIM
488 'model': (optional and only have sense for type==virtual) interface model: virtio, e1000, ...
489 'mac_address': (optional) mac address to assign to this interface
490 'ip_address': (optional) IP address to assign to this interface
491 #TODO: CHECK if an optional 'vlan' parameter is needed for VIMs when type if VF and net_id is not
492 provided, the VLAN tag to be used. In case net_id is provided, the internal network vlan is
494 'type': (mandatory) can be one of:
495 'virtual', in this case always connected to a network of type 'net_type=bridge'
496 'PCI-PASSTHROUGH' or 'PF' (passthrough): depending on VIM capabilities it can be connected to
497 a data/ptp network ot itcan created unconnected
498 'SR-IOV' or 'VF' (SRIOV with VLAN tag): same as PF for network connectivity.
499 'VFnotShared'(SRIOV without VLAN tag) same as PF for network connectivity. VF where no other VFs
500 are allocated on the same physical NIC
501 'bw': (optional) only for PF/VF/VFnotShared. Minimal Bandwidth required for the interface in GBPS
502 'port_security': (optional) If False it must avoid any traffic filtering at this interface. If missing
503 or True, it must apply the default VIM behaviour
504 After execution the method will add the key:
505 'vim_id': must be filled/added by this method with the VIM identifier generated by the VIM for this
506 interface. 'net_list' is modified
507 :param cloud_config: (optional) dictionary with:
508 'key-pairs': (optional) list of strings with the public key to be inserted to the default user
509 'users': (optional) list of users to be inserted, each item is a dict with:
510 'name': (mandatory) user name,
511 'key-pairs': (optional) list of strings with the public key to be inserted to the user
512 'user-data': (optional) can be a string with the text script to be passed directly to cloud-init,
513 or a list of strings, each one contains a script to be passed, usually with a MIMEmultipart file
514 'config-files': (optional). List of files to be transferred. Each item is a dict with:
515 'dest': (mandatory) string with the destination absolute path
516 'encoding': (optional, by default text). Can be one of:
517 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64'
518 'content' (mandatory): string with the content of the file
519 'permissions': (optional) string with file permissions, typically octal notation '0644'
520 'owner': (optional) file owner, string with the format 'owner:group'
521 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk)
522 :param disk_list: (optional) list with additional disks to the VM. Each item is a dict with:
523 'image_id': (optional). VIM id of an existing image. If not provided an empty disk must be mounted
524 'size': (mandatory) string with the size of the disk in GB
525 :param availability_zone_index: Index of availability_zone_list to use for this this VM. None if not AV
527 :param availability_zone_list: list of availability zones given by user in the VNFD descriptor. Ignore if
528 availability_zone_index is None
529 :return: a tuple with the instance identifier and created_items or raises an exception on error
530 created_items can be None or a dictionary where this method can include key-values that will be passed to
531 the method delete_vminstance and action_vminstance. Can be used to store created ports, volumes, etc.
532 Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
536 "new_vminstance input: image='{}' flavor='{}' nics='{}'".format(image_id
, flavor_id
, str(net_list
)))
538 one
= self
._new
_one
_connection
()
539 template_vim
= one
.template
.info(int(flavor_id
), True)
540 disk_size
= str(template_vim
.TEMPLATE
["DISK"]["SIZE"])
542 one
= self
._new
_one
_connection
()
543 template_updated
= ""
545 net_in_vim
= one
.vn
.info(int(net
["net_id"]))
546 net
["vim_id"] = str(net_in_vim
.ID
)
547 network
= 'NIC = [NETWORK = "{}",NETWORK_UNAME = "{}" ]'.format(
548 net_in_vim
.NAME
, net_in_vim
.UNAME
)
549 template_updated
+= network
551 template_updated
+= "DISK = [ IMAGE_ID = {},\n SIZE = {}]".format(image_id
, disk_size
)
553 if isinstance(cloud_config
, dict):
554 if cloud_config
.get("key-pairs"):
555 context
= 'CONTEXT = [\n NETWORK = "YES",\n SSH_PUBLIC_KEY = "'
556 for key
in cloud_config
["key-pairs"]:
557 context
+= key
+ '\n'
559 # context += '"\n USERNAME = '
561 template_updated
+= context
563 vm_instance_id
= one
.template
.instantiate(int(flavor_id
), name
, False, template_updated
)
565 "Instanciating in OpenNebula a new VM name:{} id:{}".format(name
, flavor_id
))
566 return str(vm_instance_id
), None
567 except pyone
.OneNoExistsException
as e
:
568 self
.logger
.error("Network with id " + str(e
) + " not found: " + str(e
))
569 raise vimconn
.VimConnNotFoundException(e
)
570 except Exception as e
:
571 self
.logger
.error("Create new vm instance error: " + str(e
))
572 raise vimconn
.VimConnException(e
)
574 def get_vminstance(self
, vm_id
):
575 """Returns the VM instance information from VIM"""
577 one
= self
._new
_one
_connection
()
578 vm
= one
.vm
.info(int(vm_id
))
580 except Exception as e
:
581 self
.logger
.error("Getting vm instance error: " + str(e
) + ": VM Instance not found")
582 raise vimconn
.VimConnException(e
)
584 def delete_vminstance(self
, vm_id
, created_items
=None):
586 Removes a VM instance from VIM and its associated elements
587 :param vm_id: VIM identifier of the VM, provided by method new_vminstance
588 :param created_items: dictionary with extra items to be deleted. provided by method new_vminstance and/or method
590 :return: None or the same vm_id. Raises an exception on fail
593 one
= self
._new
_one
_connection
()
594 one
.vm
.recover(int(vm_id
), 3)
597 if vm
is not None and vm
.LCM_STATE
== 0:
600 vm
= one
.vm
.info(int(vm_id
))
602 except pyone
.OneNoExistsException
:
603 self
.logger
.info("The vm " + str(vm_id
) + " does not exist or is already deleted")
604 raise vimconn
.VimConnNotFoundException("The vm {} does not exist or is already deleted".format(vm_id
))
605 except Exception as e
:
606 self
.logger
.error("Delete vm instance " + str(vm_id
) + " error: " + str(e
))
607 raise vimconn
.VimConnException(e
)
609 def refresh_vms_status(self
, vm_list
):
610 """Get the status of the virtual machines and their interfaces/ports
611 Params: the list of VM identifiers
612 Returns a dictionary with:
613 vm_id: #VIM id of this Virtual Machine
614 status: #Mandatory. Text with one of:
615 # DELETED (not found at vim)
616 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
617 # OTHER (Vim reported other status not understood)
618 # ERROR (VIM indicates an ERROR status)
619 # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
620 # BUILD (on building process), ERROR
621 # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
623 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
624 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
625 interfaces: list with interface info. Each item a dictionary with:
626 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
627 mac_address: #Text format XX:XX:XX:XX:XX:XX
628 vim_net_id: #network id where this interface is connected, if provided at creation
629 vim_interface_id: #interface/port VIM id
630 ip_address: #null, or text with IPv4, IPv6 address
631 compute_node: #identification of compute node where PF,VF interface is allocated
632 pci: #PCI address of the NIC that hosts the PF,VF
633 vlan: #physical VLAN used for VF
637 for vm_id
in vm_list
:
639 if self
.get_vminstance(vm_id
) is not None:
640 vm_element
= self
.get_vminstance(vm_id
)
642 self
.logger
.info("The vm " + str(vm_id
) + " does not exist.")
643 vm
['status'] = "DELETED"
644 vm
['error_msg'] = ("The vm " + str(vm_id
) + " does not exist.")
646 vm
["vim_info"] = None
647 vm_status
= vm_element
.LCM_STATE
649 vm
['status'] = "ACTIVE"
650 elif vm_status
== 36:
651 vm
['status'] = "ERROR"
652 vm
['error_msg'] = "VM failure"
654 vm
['status'] = "BUILD"
656 if vm_element
is not None:
657 interfaces
= self
._get
_networks
_vm
(vm_element
)
658 vm
["interfaces"] = interfaces
661 except Exception as e
:
664 vm_dict
[k
]["status"] = "VIM_ERROR"
665 vm_dict
[k
]["error_msg"] = str(e
)
668 def _get_networks_vm(self
, vm_element
):
671 if isinstance(vm_element
.TEMPLATE
["NIC"], list):
672 for net
in vm_element
.TEMPLATE
["NIC"]:
673 interface
= {'vim_info': None, "mac_address": str(net
["MAC"]), "vim_net_id": str(net
["NETWORK_ID"]),
674 "vim_interface_id": str(net
["NETWORK_ID"])}
675 # maybe it should be 2 different keys for ip_address if an interface has ipv4 and ipv6
677 interface
["ip_address"] = str(net
["IP"])
678 if 'IP6_GLOBAL' in net
:
679 interface
["ip_address"] = str(net
["IP6_GLOBAL"])
680 interfaces
.append(interface
)
682 net
= vm_element
.TEMPLATE
["NIC"]
683 interface
= {'vim_info': None, "mac_address": str(net
["MAC"]), "vim_net_id": str(net
["NETWORK_ID"]),
684 "vim_interface_id": str(net
["NETWORK_ID"])}
685 # maybe it should be 2 different keys for ip_address if an interface has ipv4 and ipv6
687 interface
["ip_address"] = str(net
["IP"])
688 if 'IP6_GLOBAL' in net
:
689 interface
["ip_address"] = str(net
["IP6_GLOBAL"])
690 interfaces
.append(interface
)
693 self
.logger
.error("Error getting vm interface_information of vm_id: " + str(vm_element
.ID
))