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
import vimconn
40 class vimconnector(vimconn
.vimconnector
):
41 def __init__(self
, uuid
, name
, tenant_id
, tenant_name
, url
, url_admin
=None, user
=None, passwd
=None,
42 log_level
="DEBUG", config
={}, persistent_info
={}):
46 'uuid': id asigned to this VIM
47 'name': name assigned to this VIM, can be used for logging
48 'tenant_id', 'tenant_name': (only one of them is mandatory) VIM tenant to be used
49 'url_admin': (optional), url used for administrative tasks
50 'user', 'passwd': credentials of the VIM user
51 'log_level': provider if it should use a different log_level than the general one
52 'config': dictionary with extra VIM information. This contains a consolidate version of general VIM config
53 at creation and particular VIM config at teh attachment
54 'persistent_info': dict where the class can store information that will be available among class
55 destroy/creation cycles. This info is unique per VIM/credential. At first call it will contain an
56 empty dict. Useful to store login/tokens information for speed up communication
58 Returns: Raise an exception is some needed parameter is missing, but it must not do any connectivity
62 vimconn
.vimconnector
.__init
__(self
, uuid
, name
, tenant_id
, tenant_name
, url
, url_admin
, user
, passwd
, log_level
,
65 def _new_one_connection(self
):
66 return pyone
.OneServer(self
.url
, session
=self
.user
+ ':' + self
.passwd
)
68 def new_tenant(self
, tenant_name
, tenant_description
):
69 # '''Adds a new tenant to VIM with this name and description, returns the tenant identifier'''
71 client
= oca
.Client(self
.user
+ ':' + self
.passwd
, self
.url
)
72 group_list
= oca
.GroupPool(client
)
73 user_list
= oca
.UserPool(client
)
76 create_primarygroup
= 1
78 for group
in group_list
:
79 if str(group
.name
) == str(tenant_name
):
80 create_primarygroup
= 0
82 if create_primarygroup
== 1:
83 oca
.Group
.allocate(client
, tenant_name
)
85 # set to primary_group the tenant_group and oneadmin to secondary_group
86 for group
in group_list
:
87 if str(group
.name
) == str(tenant_name
):
88 for user
in user_list
:
89 if str(user
.name
) == str(self
.user
):
90 if user
.name
== "oneadmin":
93 self
._add
_secondarygroup
(user
.id, group
.id)
96 except Exception as e
:
97 self
.logger
.error("Create new tenant error: " + str(e
))
98 raise vimconn
.vimconnException(e
)
100 def delete_tenant(self
, tenant_id
):
101 """Delete a tenant from VIM. Returns the old tenant identifier"""
103 client
= oca
.Client(self
.user
+ ':' + self
.passwd
, self
.url
)
104 group_list
= oca
.GroupPool(client
)
105 user_list
= oca
.UserPool(client
)
108 for group
in group_list
:
109 if str(group
.id) == str(tenant_id
):
110 for user
in user_list
:
111 if str(user
.name
) == str(self
.user
):
112 self
._delete
_secondarygroup
(user
.id, group
.id)
115 raise vimconn
.vimconnNotFoundException("Group {} not found".format(tenant_id
))
116 except Exception as e
:
117 self
.logger
.error("Delete tenant " + str(tenant_id
) + " error: " + str(e
))
118 raise vimconn
.vimconnException(e
)
120 def _add_secondarygroup(self
, id_user
, id_group
):
121 # change secondary_group to primary_group
122 params
= '<?xml version="1.0"?> \
124 <methodName>one.user.addgroup</methodName>\
127 <value><string>{}:{}</string></value>\
130 <value><int>{}</int></value>\
133 <value><int>{}</int></value>\
136 </methodCall>'.format(self
.user
, self
.passwd
, (str(id_user
)), (str(id_group
)))
137 requests
.post(self
.url
, params
)
139 def _delete_secondarygroup(self
, id_user
, id_group
):
140 params
= '<?xml version="1.0"?> \
142 <methodName>one.user.delgroup</methodName>\
145 <value><string>{}:{}</string></value>\
148 <value><int>{}</int></value>\
151 <value><int>{}</int></value>\
154 </methodCall>'.format(self
.user
, self
.passwd
, (str(id_user
)), (str(id_group
)))
155 requests
.post(self
.url
, params
)
157 def new_network(self
, net_name
, net_type
, ip_profile
=None, shared
=False, provider_network_profile
=None): # , **vim_specific):
158 """Adds a tenant network to VIM
160 'net_name': name of the network
162 'bridge': overlay isolated network
163 'data': underlay E-LAN network for Passthrough and SRIOV interfaces
164 'ptp': underlay E-LINE network for Passthrough and SRIOV interfaces.
165 'ip_profile': is a dict containing the IP parameters of the network
166 'ip_version': can be "IPv4" or "IPv6" (Currently only IPv4 is implemented)
167 'subnet_address': ip_prefix_schema, that is X.X.X.X/Y
168 'gateway_address': (Optional) ip_schema, that is X.X.X.X
169 'dns_address': (Optional) comma separated list of ip_schema, e.g. X.X.X.X[,X,X,X,X]
170 'dhcp_enabled': True or False
171 'dhcp_start_address': ip_schema, first IP to grant
172 'dhcp_count': number of IPs to grant.
173 'shared': if this network can be seen/use by other tenants/organization
174 'provider_network_profile': (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk}
175 Returns a tuple with the network identifier and created_items, or raises an exception on error
176 created_items can be None or a dictionary where this method can include key-values that will be passed to
177 the method delete_network. Can be used to store created segments, created l2gw connections, etc.
178 Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
182 # oca library method cannot be used in this case (problem with cluster parameters)
185 if provider_network_profile
:
186 vlan
= provider_network_profile
.get("segmentation-id")
188 one
= self
._new
_one
_connection
()
190 if ip_profile
is None:
191 subnet_rand
= random
.randint(0, 255)
192 ip_start
= "192.168.{}.1".format(subnet_rand
)
194 index
= ip_profile
["subnet_address"].find("/")
195 ip_start
= ip_profile
["subnet_address"][:index
]
196 if "dhcp_count" in ip_profile
and ip_profile
["dhcp_count"] is not None:
197 size
= str(ip_profile
["dhcp_count"])
198 elif "dhcp_count" not in ip_profile
and ip_profile
["ip_version"] == "IPv4":
199 prefix
= ip_profile
["subnet_address"][index
+ 1:]
200 size
= int(math
.pow(2, 32 - prefix
))
201 if "dhcp_start_address" in ip_profile
and ip_profile
["dhcp_start_address"] is not None:
202 ip_start
= str(ip_profile
["dhcp_start_address"])
203 if ip_profile
["ip_version"] == "IPv6":
204 ip_prefix_type
= "GLOBAL_PREFIX"
209 vlan_id
= str(random
.randint(100, 4095))
210 #if "internal" in net_name:
211 # OpenNebula not support two networks with same name
212 random_net_name
= str(random
.randint(1, 1000000))
213 net_name
= net_name
+ random_net_name
214 net_id
= one
.vn
.allocate({
217 'PHYDEV': self
.config
["network"]["phydev"],
219 }, self
.config
["cluster"]["id"])
220 arpool
= {'AR_POOL': {
228 one
.vn
.add_ar(net_id
, arpool
)
229 return net_id
, created_items
230 except Exception as e
:
231 self
.logger
.error("Create new network error: " + str(e
))
232 raise vimconn
.vimconnException(e
)
234 def get_network_list(self
, filter_dict
={}):
235 """Obtain tenant networks of VIM
237 'filter_dict' (optional) contains entries to return only networks that matches ALL entries:
238 name: string => returns only networks with this name
239 id: string => returns networks with this VIM id, this imply returns one network at most
240 shared: boolean >= returns only networks that are (or are not) shared
241 tenant_id: sting => returns only networks that belong to this tenant/project
242 ,#(not used yet) admin_state_up: boolean => returns only networks that are (or are not) in admin state active
243 #(not used yet) status: 'ACTIVE','ERROR',... => filter networks that are on this status
244 Returns the network list of dictionaries. each dictionary contains:
245 'id': (mandatory) VIM network id
246 'name': (mandatory) VIM network name
247 'status': (mandatory) can be 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER'
248 'network_type': (optional) can be 'vxlan', 'vlan' or 'flat'
249 'segmentation_id': (optional) in case network_type is vlan or vxlan this field contains the segmentation id
250 'error_msg': (optional) text that explains the ERROR status
251 other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param
252 List can be empty if no network map the filter_dict. Raise an exception only upon VIM connectivity,
253 authorization, or some other unspecific error
257 one
= self
._new
_one
_connection
()
258 net_pool
= one
.vnpool
.info(-2, -1, -1).VNET
260 if "name" in filter_dict
:
261 network_name_filter
= filter_dict
["name"]
263 network_name_filter
= None
264 if "id" in filter_dict
:
265 network_id_filter
= filter_dict
["id"]
267 network_id_filter
= None
268 for network
in net_pool
:
269 if network
.NAME
== network_name_filter
or str(network
.ID
) == str(network_id_filter
):
270 net_dict
= {"name": network
.NAME
, "id": str(network
.ID
), "status": "ACTIVE"}
271 response
.append(net_dict
)
273 except Exception as e
:
274 self
.logger
.error("Get network list error: " + str(e
))
275 raise vimconn
.vimconnException(e
)
277 def get_network(self
, net_id
):
278 """Obtain network details from the 'net_id' VIM network
279 Return a dict that contains:
280 'id': (mandatory) VIM network id, that is, net_id
281 'name': (mandatory) VIM network name
282 'status': (mandatory) can be 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER'
283 'error_msg': (optional) text that explains the ERROR status
284 other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param
285 Raises an exception upon error or when network is not found
288 one
= self
._new
_one
_connection
()
289 net_pool
= one
.vnpool
.info(-2, -1, -1).VNET
291 for network
in net_pool
:
292 if str(network
.ID
) == str(net_id
):
293 net
['id'] = network
.ID
294 net
['name'] = network
.NAME
295 net
['status'] = "ACTIVE"
300 raise vimconn
.vimconnNotFoundException("Network {} not found".format(net_id
))
301 except Exception as e
:
302 self
.logger
.error("Get network " + str(net_id
) + " error): " + str(e
))
303 raise vimconn
.vimconnException(e
)
305 def delete_network(self
, net_id
, created_items
=None):
307 Removes a tenant network from VIM and its associated elements
308 :param net_id: VIM identifier of the network, provided by method new_network
309 :param created_items: dictionary with extra items to be deleted. provided by method new_network
310 Returns the network identifier or raises an exception upon error or when network is not found
314 one
= self
._new
_one
_connection
()
315 one
.vn
.delete(int(net_id
))
317 except Exception as e
:
318 self
.logger
.error("Delete network " + str(net_id
) + "error: network not found" + str(e
))
319 raise vimconn
.vimconnException(e
)
321 def refresh_nets_status(self
, net_list
):
322 """Get the status of the networks
324 'net_list': a list with the VIM network id to be get the status
325 Returns a dictionary with:
326 'net_id': #VIM id of this network
327 status: #Mandatory. Text with one of:
328 # DELETED (not found at vim)
329 # VIM_ERROR (Cannot connect to VIM, authentication problems, VIM response error, ...)
330 # OTHER (Vim reported other status not understood)
331 # ERROR (VIM indicates an ERROR status)
332 # ACTIVE, INACTIVE, DOWN (admin down),
333 # BUILD (on building process)
334 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
335 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
340 for net_id
in net_list
:
343 net_vim
= self
.get_network(net_id
)
344 net
["status"] = net_vim
["status"]
345 net
["vim_info"] = None
346 except vimconn
.vimconnNotFoundException
as e
:
347 self
.logger
.error("Exception getting net status: {}".format(str(e
)))
348 net
['status'] = "DELETED"
349 net
['error_msg'] = str(e
)
350 except vimconn
.vimconnException
as e
:
352 net
["status"] = "VIM_ERROR"
353 net
["error_msg"] = str(e
)
354 net_dict
[net_id
] = net
356 except vimconn
.vimconnException
as e
:
359 net_dict
[k
]["status"] = "VIM_ERROR"
360 net_dict
[k
]["error_msg"] = str(e
)
363 def get_flavor(self
, flavor_id
): # Esta correcto
364 """Obtain flavor details from the VIM
365 Returns the flavor dict details {'id':<>, 'name':<>, other vim specific }
366 Raises an exception upon error or if not found
370 one
= self
._new
_one
_connection
()
371 template
= one
.template
.info(int(flavor_id
))
372 if template
is not None:
373 return {'id': template
.ID
, 'name': template
.NAME
}
374 raise vimconn
.vimconnNotFoundException("Flavor {} not found".format(flavor_id
))
375 except Exception as e
:
376 self
.logger
.error("get flavor " + str(flavor_id
) + " error: " + str(e
))
377 raise vimconn
.vimconnException(e
)
379 def new_flavor(self
, flavor_data
):
380 """Adds a tenant flavor to VIM
381 flavor_data contains a dictionary with information, keys:
383 ram: memory (cloud type) in MBytes
384 vpcus: cpus (cloud type)
385 extended: EPA parameters
386 - numas: #items requested in same NUMA
387 memory: number of 1G huge pages memory
388 paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads
389 interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
390 - name: interface name
391 dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC
392 bandwidth: X Gbps; requested guarantee bandwidth
393 vpci: requested virtual PCI address
397 Returns the flavor identifier"""
399 disk_size
= str(int(flavor_data
["disk"])*1024)
402 one
= self
._new
_one
_connection
()
403 template_id
= one
.template
.allocate({
405 'NAME': flavor_data
["name"],
406 'CPU': flavor_data
["vcpus"],
407 'VCPU': flavor_data
["vcpus"],
408 'MEMORY': flavor_data
["ram"],
414 'SSH_PUBLIC_KEY': '$USER[SSH_PUBLIC_KEY]'
420 'CLUSTER_ID': self
.config
["cluster"]["id"]
425 except Exception as e
:
426 self
.logger
.error("Create new flavor error: " + str(e
))
427 raise vimconn
.vimconnException(e
)
429 def delete_flavor(self
, flavor_id
):
430 """ Deletes a tenant flavor from VIM
431 Returns the old flavor_id
434 one
= self
._new
_one
_connection
()
435 one
.template
.delete(int(flavor_id
), False)
437 except Exception as e
:
438 self
.logger
.error("Error deleting flavor " + str(flavor_id
) + ". Flavor not found")
439 raise vimconn
.vimconnException(e
)
441 def get_image_list(self
, filter_dict
={}):
442 """Obtain tenant images from VIM
446 checksum: image checksum
448 Returns the image list of dictionaries:
449 [{<the fields at Filter_dict plus some VIM specific>}, ...]
453 one
= self
._new
_one
_connection
()
454 image_pool
= one
.imagepool
.info(-2, -1, -1).IMAGE
456 if "name" in filter_dict
:
457 image_name_filter
= filter_dict
["name"]
459 image_name_filter
= None
460 if "id" in filter_dict
:
461 image_id_filter
= filter_dict
["id"]
463 image_id_filter
= None
464 for image
in image_pool
:
465 if str(image_name_filter
) == str(image
.NAME
) or str(image
.ID
) == str(image_id_filter
):
466 images_dict
= {"name": image
.NAME
, "id": str(image
.ID
)}
467 images
.append(images_dict
)
469 except Exception as e
:
470 self
.logger
.error("Get image list error: " + str(e
))
471 raise vimconn
.vimconnException(e
)
473 def new_vminstance(self
, name
, description
, start
, image_id
, flavor_id
, net_list
, cloud_config
=None, disk_list
=None,
474 availability_zone_index
=None, availability_zone_list
=None):
476 """Adds a VM instance to VIM
478 'start': (boolean) indicates if VM must start or created in pause mode.
479 'image_id','flavor_id': image and flavor VIM id to use for the VM
480 'net_list': list of interfaces, each one is a dictionary with:
481 'name': (optional) name for the interface.
482 'net_id': VIM network id where this interface must be connect to. Mandatory for type==virtual
483 'vpci': (optional) virtual vPCI address to assign at the VM. Can be ignored depending on VIM capabilities
484 'model': (optional and only have sense for type==virtual) interface model: virtio, e1000, ...
485 'mac_address': (optional) mac address to assign to this interface
486 'ip_address': (optional) IP address to assign to this interface
487 #TODO: CHECK if an optional 'vlan' parameter is needed for VIMs when type if VF and net_id is not provided,
488 the VLAN tag to be used. In case net_id is provided, the internal network vlan is used for tagging VF
489 'type': (mandatory) can be one of:
490 'virtual', in this case always connected to a network of type 'net_type=bridge'
491 'PCI-PASSTHROUGH' or 'PF' (passthrough): depending on VIM capabilities it can be connected to a data/ptp network ot it
492 can created unconnected
493 'SR-IOV' or 'VF' (SRIOV with VLAN tag): same as PF for network connectivity.
494 'VFnotShared'(SRIOV without VLAN tag) same as PF for network connectivity. VF where no other VFs
495 are allocated on the same physical NIC
496 'bw': (optional) only for PF/VF/VFnotShared. Minimal Bandwidth required for the interface in GBPS
497 'port_security': (optional) If False it must avoid any traffic filtering at this interface. If missing
498 or True, it must apply the default VIM behaviour
499 After execution the method will add the key:
500 'vim_id': must be filled/added by this method with the VIM identifier generated by the VIM for this
501 interface. 'net_list' is modified
502 'cloud_config': (optional) dictionary with:
503 'key-pairs': (optional) list of strings with the public key to be inserted to the default user
504 'users': (optional) list of users to be inserted, each item is a dict with:
505 'name': (mandatory) user name,
506 'key-pairs': (optional) list of strings with the public key to be inserted to the user
507 'user-data': (optional) can be a string with the text script to be passed directly to cloud-init,
508 or a list of strings, each one contains a script to be passed, usually with a MIMEmultipart file
509 'config-files': (optional). List of files to be transferred. Each item is a dict with:
510 'dest': (mandatory) string with the destination absolute path
511 'encoding': (optional, by default text). Can be one of:
512 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64'
513 'content' (mandatory): string with the content of the file
514 'permissions': (optional) string with file permissions, typically octal notation '0644'
515 'owner': (optional) file owner, string with the format 'owner:group'
516 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk)
517 'disk_list': (optional) list with additional disks to the VM. Each item is a dict with:
518 'image_id': (optional). VIM id of an existing image. If not provided an empty disk must be mounted
519 'size': (mandatory) string with the size of the disk in GB
520 availability_zone_index: Index of availability_zone_list to use for this this VM. None if not AV required
521 availability_zone_list: list of availability zones given by user in the VNFD descriptor. Ignore if
522 availability_zone_index is None
523 Returns a tuple with the instance identifier and created_items or raises an exception on error
524 created_items can be None or a dictionary where this method can include key-values that will be passed to
525 the method delete_vminstance and action_vminstance. Can be used to store created ports, volumes, etc.
526 Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
530 "new_vminstance input: image='{}' flavor='{}' nics='{}'".format(image_id
, flavor_id
, str(net_list
)))
532 one
= self
._new
_one
_connection
()
533 template_vim
= one
.template
.info(int(flavor_id
), True)
534 disk_size
= str(template_vim
.TEMPLATE
["DISK"]["SIZE"])
536 one
= self
._new
_one
_connection
()
537 template_updated
= ""
539 net_in_vim
= one
.vn
.info(int(net
["net_id"]))
540 net
["vim_id"] = str(net_in_vim
.ID
)
541 network
= 'NIC = [NETWORK = "{}",NETWORK_UNAME = "{}" ]'.format(
542 net_in_vim
.NAME
, net_in_vim
.UNAME
)
543 template_updated
+= network
545 template_updated
+= "DISK = [ IMAGE_ID = {},\n SIZE = {}]".format(image_id
, disk_size
)
547 if isinstance(cloud_config
, dict):
548 if cloud_config
.get("key-pairs"):
549 context
= 'CONTEXT = [\n NETWORK = "YES",\n SSH_PUBLIC_KEY = "'
550 for key
in cloud_config
["key-pairs"]:
551 context
+= key
+ '\n'
553 # context += '"\n USERNAME = '
555 template_updated
+= context
557 vm_instance_id
= one
.template
.instantiate(int(flavor_id
), name
, False, template_updated
)
559 "Instanciating in OpenNebula a new VM name:{} id:{}".format(name
, flavor_id
))
560 return str(vm_instance_id
), None
561 except pyone
.OneNoExistsException
as e
:
562 self
.logger
.error("Network with id " + str(e
) + " not found: " + str(e
))
563 raise vimconn
.vimconnNotFoundException(e
)
564 except Exception as e
:
565 self
.logger
.error("Create new vm instance error: " + str(e
))
566 raise vimconn
.vimconnException(e
)
568 def get_vminstance(self
, vm_id
):
569 """Returns the VM instance information from VIM"""
571 one
= self
._new
_one
_connection
()
572 vm
= one
.vm
.info(int(vm_id
))
574 except Exception as e
:
575 self
.logger
.error("Getting vm instance error: " + str(e
) + ": VM Instance not found")
576 raise vimconn
.vimconnException(e
)
578 def delete_vminstance(self
, vm_id
, created_items
=None):
580 Removes a VM instance from VIM and its associated elements
581 :param vm_id: VIM identifier of the VM, provided by method new_vminstance
582 :param created_items: dictionary with extra items to be deleted. provided by method new_vminstance and/or method
584 :return: None or the same vm_id. Raises an exception on fail
587 one
= self
._new
_one
_connection
()
588 one
.vm
.recover(int(vm_id
), 3)
591 if vm
is not None and vm
.LCM_STATE
== 0:
594 vm
= one
.vm
.info(int(vm_id
))
596 except pyone
.OneNoExistsException
as e
:
597 self
.logger
.info("The vm " + str(vm_id
) + " does not exist or is already deleted")
598 raise vimconn
.vimconnNotFoundException("The vm {} does not exist or is already deleted".format(vm_id
))
599 except Exception as e
:
600 self
.logger
.error("Delete vm instance " + str(vm_id
) + " error: " + str(e
))
601 raise vimconn
.vimconnException(e
)
603 def refresh_vms_status(self
, vm_list
):
604 """Get the status of the virtual machines and their interfaces/ports
605 Params: the list of VM identifiers
606 Returns a dictionary with:
607 vm_id: #VIM id of this Virtual Machine
608 status: #Mandatory. Text with one of:
609 # DELETED (not found at vim)
610 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
611 # OTHER (Vim reported other status not understood)
612 # ERROR (VIM indicates an ERROR status)
613 # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
614 # BUILD (on building process), ERROR
615 # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
617 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
618 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
619 interfaces: list with interface info. Each item a dictionary with:
620 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
621 mac_address: #Text format XX:XX:XX:XX:XX:XX
622 vim_net_id: #network id where this interface is connected, if provided at creation
623 vim_interface_id: #interface/port VIM id
624 ip_address: #null, or text with IPv4, IPv6 address
625 compute_node: #identification of compute node where PF,VF interface is allocated
626 pci: #PCI address of the NIC that hosts the PF,VF
627 vlan: #physical VLAN used for VF
631 for vm_id
in vm_list
:
633 if self
.get_vminstance(vm_id
) is not None:
634 vm_element
= self
.get_vminstance(vm_id
)
636 self
.logger
.info("The vm " + str(vm_id
) + " does not exist.")
637 vm
['status'] = "DELETED"
638 vm
['error_msg'] = ("The vm " + str(vm_id
) + " does not exist.")
640 vm
["vim_info"] = None
641 vm_status
= vm_element
.LCM_STATE
643 vm
['status'] = "ACTIVE"
644 elif vm_status
== 36:
645 vm
['status'] = "ERROR"
646 vm
['error_msg'] = "VM failure"
648 vm
['status'] = "BUILD"
650 if vm_element
is not None:
651 interfaces
= self
._get
_networks
_vm
(vm_element
)
652 vm
["interfaces"] = interfaces
655 except Exception as e
:
658 vm_dict
[k
]["status"] = "VIM_ERROR"
659 vm_dict
[k
]["error_msg"] = str(e
)
662 def _get_networks_vm(self
, vm_element
):
665 if isinstance(vm_element
.TEMPLATE
["NIC"], list):
666 for net
in vm_element
.TEMPLATE
["NIC"]:
667 interface
= {'vim_info': None, "mac_address": str(net
["MAC"]), "vim_net_id": str(net
["NETWORK_ID"]),
668 "vim_interface_id": str(net
["NETWORK_ID"])}
669 # maybe it should be 2 different keys for ip_address if an interface has ipv4 and ipv6
671 interface
["ip_address"] = str(net
["IP"])
672 if u
'IP6_GLOBAL' in net
:
673 interface
["ip_address"] = str(net
["IP6_GLOBAL"])
674 interfaces
.append(interface
)
676 net
= vm_element
.TEMPLATE
["NIC"]
677 interface
= {'vim_info': None, "mac_address": str(net
["MAC"]), "vim_net_id": str(net
["NETWORK_ID"]),
678 "vim_interface_id": str(net
["NETWORK_ID"])}
679 # maybe it should be 2 different keys for ip_address if an interface has ipv4 and ipv6
681 interface
["ip_address"] = str(net
["IP"])
682 if u
'IP6_GLOBAL' in net
:
683 interface
["ip_address"] = str(net
["IP6_GLOBAL"])
684 interfaces
.append(interface
)
686 except Exception as e
:
687 self
.logger
.error("Error getting vm interface_information of vm_id: " + str(vm_element
.ID
))