8f7fad84eb2562f67ac803f9a6ab1f68719bd375
[osm/RO.git] / osm_ro / vimconn_opennebula.py
1 # -*- coding: utf-8 -*-
2
3 ##
4 # Copyright 2017 Telefonica Digital Spain S.L.U.
5 # This file is part of ETSI OSM
6 # All Rights Reserved.
7 #
8 # Licensed under the Apache License, Version 2.0 (the "License"); you may
9 # not use this file except in compliance with the License. You may obtain
10 # a copy of the License at
11 #
12 # http://www.apache.org/licenses/LICENSE-2.0
13 #
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17
18 # License for the specific language governing permissions and limitations
19 # under the License.
20 #
21 # For those usages not covered by the Apache License, Version 2.0 please
22 # contact with: patent-office@telefonica.com
23 ##
24
25 """
26 vimconnector implements all the methods to interact with OpenNebula using the XML-RPC API.
27 """
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 import vimconn
32 import requests
33 import logging
34 import oca
35 import untangle
36 import math
37 import random
38
39
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={}):
43 vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, log_level,
44 config)
45 self.tenant = None
46 self.headers_req = {'content-type': 'application/json'}
47 self.logger = logging.getLogger('openmano.vim.opennebula')
48 self.persistent_info = persistent_info
49 if tenant_id:
50 self.tenant = tenant_id
51
52 def __setitem__(self, index, value):
53 """Set individuals parameters
54 Throw TypeError, KeyError
55 """
56 if index == 'tenant_id':
57 self.tenant = value
58 elif index == 'tenant_name':
59 self.tenant = None
60 vimconn.vimconnector.__setitem__(self, index, value)
61
62 def new_tenant(self, tenant_name, tenant_description):
63 # '''Adds a new tenant to VIM with this name and description, returns the tenant identifier'''
64 try:
65 client = oca.Client(self.user + ':' + self.passwd, self.url)
66 group_list = oca.GroupPool(client)
67 user_list = oca.UserPool(client)
68 group_list.info()
69 user_list.info()
70 create_primarygroup = 1
71 # create group-tenant
72 for group in group_list:
73 if str(group.name) == str(tenant_name):
74 create_primarygroup = 0
75 break
76 if create_primarygroup == 1:
77 oca.Group.allocate(client, tenant_name)
78 group_list.info()
79 # set to primary_group the tenant_group and oneadmin to secondary_group
80 for group in group_list:
81 if str(group.name) == str(tenant_name):
82 for user in user_list:
83 if str(user.name) == str(self.user):
84 if user.name == "oneadmin":
85 return str(0)
86 else:
87 self._add_secondarygroup(user.id, group.id)
88 user.chgrp(group.id)
89 return str(group.id)
90 except Exception as e:
91 self.logger.error("Create new tenant error: " + str(e))
92 raise vimconn.vimconnException(e)
93
94 def _add_secondarygroup(self, id_user, id_group):
95 # change secondary_group to primary_group
96 params = '<?xml version="1.0"?> \
97 <methodCall>\
98 <methodName>one.user.addgroup</methodName>\
99 <params>\
100 <param>\
101 <value><string>{}:{}</string></value>\
102 </param>\
103 <param>\
104 <value><int>{}</int></value>\
105 </param>\
106 <param>\
107 <value><int>{}</int></value>\
108 </param>\
109 </params>\
110 </methodCall>'.format(self.user, self.passwd, (str(id_user)), (str(id_group)))
111 requests.post(self.url, params)
112
113 def delete_tenant(self, tenant_id):
114 """Delete a tenant from VIM. Returns the old tenant identifier"""
115 try:
116 client = oca.Client(self.user + ':' + self.passwd, self.url)
117 group_list = oca.GroupPool(client)
118 user_list = oca.UserPool(client)
119 group_list.info()
120 user_list.info()
121 for group in group_list:
122 if str(group.id) == str(tenant_id):
123 for user in user_list:
124 if str(user.name) == str(self.user):
125 self._delete_secondarygroup(user.id, group.id)
126 group.delete(client)
127 return None
128 raise vimconn.vimconnNotFoundException("Group {} not found".format(tenant_id))
129 except Exception as e:
130 self.logger.error("Delete tenant " + str(tenant_id) + " error: " + str(e))
131 raise vimconn.vimconnException(e)
132
133 # to be used in future commits
134 def _delete_secondarygroup(self, id_user, id_group):
135 params = '<?xml version="1.0"?> \
136 <methodCall>\
137 <methodName>one.user.delgroup</methodName>\
138 <params>\
139 <param>\
140 <value><string>{}:{}</string></value>\
141 </param>\
142 <param>\
143 <value><int>{}</int></value>\
144 </param>\
145 <param>\
146 <value><int>{}</int></value>\
147 </param>\
148 </params>\
149 </methodCall>'.format(self.user, self.passwd, (str(id_user)), (str(id_group)))
150 requests.post(self.url, params)
151
152 # to be used in future commits
153 # def get_tenant_list(self, filter_dict={}):
154 # return ["tenant"]
155
156 # to be used in future commits
157 # def _check_tenant(self):
158 # try:
159 # client = oca.Client(self.user + ':' + self.passwd, self.url)
160 # group_list = oca.GroupPool(client)
161 # user_list = oca.UserPool(client)
162 # group_list.info()
163 # user_list.info()
164 # for group in group_list:
165 # if str(group.name) == str(self.tenant_name):
166 # for user in user_list:
167 # if str(user.name) == str(self.user):
168 # self._add_secondarygroup(user.id, group.id)
169 # user.chgrp(group.id)
170 # except vimconn.vimconnException as e:
171 # self.logger.error(e)
172
173 # to be used in future commits, needs refactor to manage networks
174 # def _create_bridge_host(self, vlan):
175 # file = open('manage_bridge_OSM', 'w')
176 # # password_path = self.config["password"]["path"]
177 # a = "#! /bin/bash\nsudo brctl addbr br_osm_{vlanused}\n" \
178 # "sudo ip link add link veth1 name veth1.{vlanused} type vlan id {vlanused}\n" \
179 # "sudo brctl addif br_osm_{vlanused} veth1.{vlanused}\n" \
180 # "sudo ip link set dev br_osm_{vlanused} up\n" \
181 # "sudo ip link set dev veth1.{vlanused} up\n".format(vlanused=vlan)
182 # # a = "#! /bin/bash\nsudo brctl addbr br_osm\nsudo ip link set dev br_osm up\n"
183 # file.write(a)
184 # file.close()
185 # for host in self.config["cluster"]["ip"]:
186 # file_scp = "/usr/bin/scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i {} manage_bridge_OSM {}@{}:/home/{}".format(
187 # self.config["cluster"]["password_path"][host], self.config["cluster"]["login"][host],
188 # self.config["cluster"]["ip"][host], self.config["cluster"]["login"][host])
189 # os.system(file_scp)
190 # file_permissions = "/usr/bin/ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i {} {}@{} sudo chmod 700 manage_bridge_OSM".format(
191 # self.config["cluster"]["password_path"][host], self.config["cluster"]["login"][host],
192 # self.config["cluster"]["ip"][host])
193 # os.system(file_permissions)
194 # exec_script = "/usr/bin/ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i {} {}@{} sudo ./manage_bridge_OSM".format(
195 # self.config["cluster"]["password_path"][host], self.config["cluster"]["login"][host],
196 # self.config["cluster"]["ip"][host])
197 # os.system(exec_script)
198 # os.remove("manage_bridge_OSM")
199
200 # to be used to manage networks with vlan
201 # def delete_bridge_host(self, vlan):
202 # file = open('manage_bridge_OSM', 'w')
203 # a = "#! /bin/bash\nsudo ip link set dev veth1.3142 down\nsudo ip link set dev br_3142 down\nsudo brctl delbr br_3142\n"
204 # file.write(a)
205 # file.close()
206 # os.system("/usr/bin/scp -i onlife manage_bridge_OSM sysadmin@10.95.84.12:/home/sysadmin")
207 # os.system("/usr/bin/ssh -i onlife sysadmin@10.95.84.12 sudo chmod 700 manage_bridge_OSM")
208 # os.system("/usr/bin/ssh -i onlife sysadmin@10.95.84.12 sudo ./manage_bridge_OSM")
209 # os.remove("manage_bridge_OSM")
210
211 def new_network(self, net_name, net_type, ip_profile=None, shared=False, vlan=None): # , **vim_specific):
212 """Adds a tenant network to VIM
213 Params:
214 'net_name': name of the network
215 'net_type': one of:
216 'bridge': overlay isolated network
217 'data': underlay E-LAN network for Passthrough and SRIOV interfaces
218 'ptp': underlay E-LINE network for Passthrough and SRIOV interfaces.
219 'ip_profile': is a dict containing the IP parameters of the network
220 'ip_version': can be "IPv4" or "IPv6" (Currently only IPv4 is implemented)
221 'subnet_address': ip_prefix_schema, that is X.X.X.X/Y
222 'gateway_address': (Optional) ip_schema, that is X.X.X.X
223 'dns_address': (Optional) comma separated list of ip_schema, e.g. X.X.X.X[,X,X,X,X]
224 'dhcp_enabled': True or False
225 'dhcp_start_address': ip_schema, first IP to grant
226 'dhcp_count': number of IPs to grant.
227 'shared': if this network can be seen/use by other tenants/organization
228 'vlan': in case of a data or ptp net_type, the intended vlan tag to be used for the network
229 Returns a tuple with the network identifier and created_items, or raises an exception on error
230 created_items can be None or a dictionary where this method can include key-values that will be passed to
231 the method delete_network. Can be used to store created segments, created l2gw connections, etc.
232 Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
233 as not present.
234 """
235
236 # oca library method cannot be used in this case (problem with cluster parameters)
237 try:
238 created_items = {}
239 # vlan = str(random.randint(self.config["vlan"]["start-range"], self.config["vlan"]["finish-range"]))
240 # self.create_bridge_host(vlan)
241 bridge_config = self.config["bridge_service"]
242 ip_version = "IP4"
243 size = "256"
244 if ip_profile is None:
245 random_number_ipv4 = random.randint(1, 255)
246 ip_start = "192.168." + str(random_number_ipv4) + ".1" # random value
247 else:
248 index = ip_profile["subnet_address"].find("/")
249 ip_start = ip_profile["subnet_address"][:index]
250 if "dhcp_count" in ip_profile.keys() and ip_profile["dhcp_count"] is not None:
251 size = str(ip_profile["dhcp_count"])
252 elif not ("dhcp_count" in ip_profile.keys()) and ip_profile["ip_version"] == "IPv4":
253 prefix = ip_profile["subnet_address"][index + 1:]
254 size = int(math.pow(2, 32 - prefix))
255 if "dhcp_start_address" in ip_profile.keys() and ip_profile["dhcp_start_address"] is not None:
256 ip_start = str(ip_profile["dhcp_start_address"])
257 if ip_profile["ip_version"] == "IPv6":
258 ip_version = "IP6"
259 if ip_version == "IP6":
260 config = "NAME = {}\
261 BRIDGE = {}\
262 VN_MAD = dummy\
263 AR = [TYPE = {}, GLOBAL_PREFIX = {}, SIZE = {}]".format(net_name, bridge_config, ip_version,
264 ip_start, size)
265 else:
266 config = 'NAME = "{}"\
267 BRIDGE = {}\
268 VN_MAD = dummy\
269 AR = [TYPE = {}, IP = {}, SIZE = {}]'.format(net_name, bridge_config, ip_version, ip_start,
270 size)
271
272 params = '<?xml version="1.0"?> \
273 <methodCall>\
274 <methodName>one.vn.allocate</methodName>\
275 <params>\
276 <param>\
277 <value><string>{}:{}</string></value>\
278 </param>\
279 <param>\
280 <value><string>{}</string></value>\
281 </param>\
282 <param>\
283 <value><int>{}</int></value>\
284 </param>\
285 </params>\
286 </methodCall>'.format(self.user, self.passwd, config, self.config["cluster"]["id"])
287 r = requests.post(self.url, params)
288 obj = untangle.parse(str(r.content))
289 return obj.methodResponse.params.param.value.array.data.value[1].i4.cdata.encode('utf-8'), created_items
290 except Exception as e:
291 self.logger.error("Create new network error: " + str(e))
292 raise vimconn.vimconnException(e)
293
294 def get_network_list(self, filter_dict={}):
295 """Obtain tenant networks of VIM
296 Filter_dict can be:
297 name: network name
298 id: network uuid
299 public: boolean
300 tenant_id: tenant
301 admin_state_up: boolean
302 status: 'ACTIVE'
303 Returns the network list of dictionaries
304 """
305 try:
306 client = oca.Client(self.user + ':' + self.passwd, self.url)
307 networkList = oca.VirtualNetworkPool(client)
308 networkList.info()
309 response = []
310 if "name" in filter_dict.keys():
311 network_name_filter = filter_dict["name"]
312 else:
313 network_name_filter = None
314 if "id" in filter_dict.keys():
315 network_id_filter = filter_dict["id"]
316 else:
317 network_id_filter = None
318 for network in networkList:
319 match = False
320 if network.name == network_name_filter and str(network.id) == str(network_id_filter):
321 match = True
322 if network_name_filter is None and str(network.id) == str(network_id_filter):
323 match = True
324 if network_id_filter is None and network.name == network_name_filter:
325 match = True
326 if match:
327 net_dict = {"name": network.name, "id": str(network.id)}
328 response.append(net_dict)
329 return response
330 except Exception as e:
331 self.logger.error("Get network list error: " + str(e))
332 raise vimconn.vimconnException(e)
333
334 def get_network(self, net_id):
335 """Obtain network details of network id"""
336 try:
337 client = oca.Client(self.user + ':' + self.passwd, self.url)
338 networkList = oca.VirtualNetworkPool(client)
339 networkList.info()
340 net = {}
341 for network in networkList:
342 if str(network.id) == str(net_id):
343 net['id'] = net_id
344 net['name'] = network.name
345 net['status'] = "ACTIVE"
346 break
347 if net:
348 return net
349 else:
350 raise vimconn.vimconnNotFoundException("Network {} not found".format(net_id))
351 except Exception as e:
352 self.logger.error("Get network " + str(net_id) + " error): " + str(e))
353 raise vimconn.vimconnException(e)
354
355 def delete_network(self, net_id, created_items=None):
356 """
357 Removes a tenant network from VIM and its associated elements
358 :param net_id: VIM identifier of the network, provided by method new_network
359 :param created_items: dictionary with extra items to be deleted. provided by method new_network
360 Returns the network identifier or raises an exception upon error or when network is not found
361 """
362 try:
363 # self.delete_bridge_host()
364 client = oca.Client(self.user + ':' + self.passwd, self.url)
365 networkList = oca.VirtualNetworkPool(client)
366 networkList.info()
367 network_deleted = False
368 for network in networkList:
369 if str(network.id) == str(net_id):
370 oca.VirtualNetwork.delete(network)
371 network_deleted = True
372 if network_deleted:
373 return net_id
374 else:
375 raise vimconn.vimconnNotFoundException("Network {} not found".format(net_id))
376 except Exception as e:
377 self.logger.error("Delete network " + str(net_id) + "error: " + str(e))
378 raise vimconn.vimconnException(e)
379
380 def get_flavor(self, flavor_id): # Esta correcto
381 """Obtain flavor details from the VIM"""
382 try:
383 client = oca.Client(self.user + ':' + self.passwd, self.url)
384 listaTemplate = oca.VmTemplatePool(client)
385 listaTemplate.info()
386 for template in listaTemplate:
387 if str(template.id) == str(flavor_id):
388 return {'id': template.id, 'name': template.name}
389 raise vimconn.vimconnNotFoundException("Flavor {} not found".format(flavor_id))
390 except Exception as e:
391 self.logger.error("get flavor " + str(flavor_id) + " error: " + str(e))
392 raise vimconn.vimconnException(e)
393
394 def new_flavor(self, flavor_data):
395 """Adds a tenant flavor to VIM
396 Returns the flavor identifier"""
397 try:
398 client = oca.Client(self.user + ':' + self.passwd, self.url)
399 template_name = flavor_data["name"][:-4]
400 name = 'NAME = "{}" '.format(template_name)
401 cpu = 'CPU = "{}" '.format(flavor_data["vcpus"])
402 vcpu = 'VCPU = "{}" '.format(flavor_data["vcpus"])
403 memory = 'MEMORY = "{}" '.format(flavor_data["ram"])
404 context = 'CONTEXT = [NETWORK = "YES",SSH_PUBLIC_KEY = "$USER[SSH_PUBLIC_KEY]" ] '
405 graphics = 'GRAPHICS = [ LISTEN = "0.0.0.0", TYPE = "VNC" ] '
406 sched_requeriments = 'CLUSTER_ID={}'.format(self.config["cluster"]["id"])
407 template = name + cpu + vcpu + memory + context + graphics + sched_requeriments
408 template_id = oca.VmTemplate.allocate(client, template)
409 return template_id
410 except Exception as e:
411 self.logger.error("Create new flavor error: " + str(e))
412 raise vimconn.vimconnException(e)
413
414 def delete_flavor(self, flavor_id):
415 """ Deletes a tenant flavor from VIM
416 Returns the old flavor_id
417 """
418 try:
419 client = oca.Client(self.user + ':' + self.passwd, self.url)
420 listaTemplate = oca.VmTemplatePool(client)
421 listaTemplate.info()
422 self.logger.info("Deleting VIM flavor DELETE {}".format(self.url))
423 for template in listaTemplate:
424 if str(template.id) == str(flavor_id):
425 template.delete()
426 return template.id
427 raise vimconn.vimconnNotFoundException("Flavor {} not found".format(flavor_id))
428 except Exception as e:
429 self.logger.error("Delete flavor " + str(flavor_id) + " error: " + str(e))
430 raise vimconn.vimconnException(e)
431
432 def get_image_list(self, filter_dict={}):
433 """Obtain tenant images from VIM
434 Filter_dict can be:
435 name: image name
436 id: image uuid
437 checksum: image checksum
438 location: image path
439 Returns the image list of dictionaries:
440 [{<the fields at Filter_dict plus some VIM specific>}, ...]
441 List can be empty
442 """
443 # IMPORTANT!!!!! Modify python oca library path pool.py line 102
444
445 try:
446 client = oca.Client(self.user + ':' + self.passwd, self.url)
447 image_pool = oca.ImagePool(client)
448 image_pool.info()
449 images = []
450 if "name" in filter_dict.keys():
451 image_name_filter = filter_dict["name"]
452 else:
453 image_name_filter = None
454 if "id" in filter_dict.keys():
455 image_id_filter = filter_dict["id"]
456 else:
457 image_id_filter = None
458 for image in image_pool:
459 match = False
460 if str(image_name_filter) == str(image.name) and str(image.id) == str(image_id_filter):
461 match = True
462 if image_name_filter is None and str(image.id) == str(image_id_filter):
463 match = True
464 if image_id_filter is None and str(image_name_filter) == str(image.name):
465 match = True
466 if match:
467 images_dict = {"name": image.name, "id": str(image.id)}
468 images.append(images_dict)
469 return images
470 except Exception as e:
471 self.logger.error("Get image list error: " + str(e))
472 raise vimconn.vimconnException(e)
473
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):
476 """Adds a VM instance to VIM
477 Params:
478 start: indicates if VM must start or boot in pause mode. Ignored
479 image_id,flavor_id: image and flavor uuid
480 net_list: list of interfaces, each one is a dictionary with:
481 name:
482 net_id: network uuid to connect
483 vpci: virtual vcpi to assign
484 model: interface model, virtio, e1000, ...
485 mac_address:
486 use: 'data', 'bridge', 'mgmt'
487 type: 'virtual', 'PF', 'VF', 'VFnotShared'
488 vim_id: filled/added by this function
489 #TODO ip, security groups
490 Returns the instance identifier
491 """
492 self.logger.debug(
493 "new_vminstance input: image='{}' flavor='{}' nics='{}'".format(image_id, flavor_id, str(net_list)))
494 try:
495 client = oca.Client(self.user + ':' + self.passwd, self.url)
496 listaTemplate = oca.VmTemplatePool(client)
497 listaTemplate.info()
498 for template in listaTemplate:
499 if str(template.id) == str(flavor_id):
500 cpu = ' CPU = "{}"'.format(template.template.cpu)
501 vcpu = ' VCPU = "{}"'.format(template.template.cpu)
502 memory = ' MEMORY = "{}"'.format(template.template.memory)
503 context = ' CONTEXT = [NETWORK = "YES",SSH_PUBLIC_KEY = "$USER[SSH_PUBLIC_KEY]" ]'
504 graphics = ' GRAPHICS = [ LISTEN = "0.0.0.0", TYPE = "VNC" ]'
505 disk = ' DISK = [ IMAGE_ID = {}]'.format(image_id)
506 template_updated = cpu + vcpu + memory + context + graphics + disk
507 networkListVim = oca.VirtualNetworkPool(client)
508 networkListVim.info()
509 network = ""
510 for net in net_list:
511 network_found = False
512 for network_existingInVim in networkListVim:
513 if str(net["net_id"]) == str(network_existingInVim.id):
514 net["vim_id"] = network_existingInVim["id"]
515 network = 'NIC = [NETWORK = "{}",NETWORK_UNAME = "{}" ]'.format(
516 network_existingInVim.name, network_existingInVim.uname)
517 network_found = True
518 break
519 if not network_found:
520 raise vimconn.vimconnNotFoundException("Network {} not found".format(net["net_id"]))
521 template_updated += network
522 if isinstance(cloud_config, dict):
523 if cloud_config.get("user-data"):
524 if isinstance(cloud_config["user-data"], str):
525 template_updated += cloud_config["user-data"]
526 else:
527 for u in cloud_config["user-data"]:
528 template_updated += u
529 oca.VmTemplate.update(template, template_updated)
530 self.logger.info(
531 "Instanciating in OpenNebula a new VM name:{} id:{}".format(template.name, template.id))
532 vminstance_id = template.instantiate(name=name)
533 return str(vminstance_id), None
534 raise vimconn.vimconnNotFoundException("Flavor {} not found".format(flavor_id))
535 except Exception as e:
536 self.logger.error("Create new vm instance error: " + str(e))
537 raise vimconn.vimconnException(e)
538
539 def delete_vminstance(self, vm_id, created_items=None):
540 """Removes a VM instance from VIM, returns the deleted vm_id"""
541 try:
542 client = oca.Client(self.user + ':' + self.passwd, self.url)
543 vm_pool = oca.VirtualMachinePool(client)
544 vm_pool.info()
545 vm_exist = False
546 for i in vm_pool:
547 if str(i.id) == str(vm_id):
548 vm_exist = True
549 break
550 if not vm_exist:
551 self.logger.info("The vm " + str(vm_id) + " does not exist or is already deleted")
552 raise vimconn.vimconnNotFoundException("The vm {} does not exist or is already deleted".format(vm_id))
553 params = '<?xml version="1.0"?> \
554 <methodCall>\
555 <methodName>one.vm.recover</methodName>\
556 <params>\
557 <param>\
558 <value><string>{}:{}</string></value>\
559 </param>\
560 <param>\
561 <value><int>{}</int></value>\
562 </param>\
563 <param>\
564 <value><int>{}</int></value>\
565 </param>\
566 </params>\
567 </methodCall>'.format(self.user, self.passwd, str(vm_id), str(3))
568 r = requests.post(self.url, params)
569 obj = untangle.parse(str(r.content))
570 response_success = obj.methodResponse.params.param.value.array.data.value[0].boolean.cdata.encode('utf-8')
571 response = obj.methodResponse.params.param.value.array.data.value[1].i4.cdata.encode('utf-8')
572 # response can be the resource ID on success or the error string on failure.
573 response_error_code = obj.methodResponse.params.param.value.array.data.value[2].i4.cdata.encode('utf-8')
574 if response_success.lower() == "true":
575 return response
576 else:
577 raise vimconn.vimconnException("vm {} cannot be deleted with error_code {}: {}".format(vm_id, response_error_code, response))
578 except Exception as e:
579 self.logger.error("Delete vm instance " + str(vm_id) + " error: " + str(e))
580 raise vimconn.vimconnException(e)
581
582 def refresh_vms_status(self, vm_list):
583 """Refreshes the status of the virtual machines"""
584 vm_dict = {}
585 try:
586 client = oca.Client(self.user + ':' + self.passwd, self.url)
587 vm_pool = oca.VirtualMachinePool(client)
588 vm_pool.info()
589 for vm_id in vm_list:
590 vm = {"interfaces": []}
591 vm_exist = False
592 vm_element = None
593 for i in vm_pool:
594 if str(i.id) == str(vm_id):
595 vm_exist = True
596 vm_element = i
597 break
598 if not vm_exist:
599 self.logger.info("The vm " + str(vm_id) + " does not exist.")
600 vm['status'] = "DELETED"
601 vm['error_msg'] = ("The vm " + str(vm_id) + " does not exist.")
602 continue
603 vm_element.info()
604 vm["vim_info"] = None
605 VMstatus = vm_element.str_lcm_state
606 if VMstatus == "RUNNING":
607 vm['status'] = "ACTIVE"
608 elif "FAILURE" in VMstatus:
609 vm['status'] = "ERROR"
610 vm['error_msg'] = "VM failure"
611 else:
612 vm['status'] = "BUILD"
613 try:
614 for red in vm_element.template.nics:
615 interface = {'vim_info': None, "mac_address": str(red.mac), "vim_net_id": str(red.network_id),
616 "vim_interface_id": str(red.network_id)}
617 # maybe it should be 2 different keys for ip_address if an interface has ipv4 and ipv6
618 if hasattr(red, 'ip'):
619 interface["ip_address"] = str(red.ip)
620 if hasattr(red, 'ip6_global'):
621 interface["ip_address"] = str(red.ip6_global)
622 vm["interfaces"].append(interface)
623 except Exception as e:
624 self.logger.error("Error getting vm interface_information " + type(e).__name__ + ":" + str(e))
625 vm["status"] = "VIM_ERROR"
626 vm["error_msg"] = "Error getting vm interface_information " + type(e).__name__ + ":" + str(e)
627 vm_dict[vm_id] = vm
628 return vm_dict
629 except Exception as e:
630 self.logger.error(e)
631 for k in vm_dict:
632 vm_dict[k]["status"] = "VIM_ERROR"
633 vm_dict[k]["error_msg"] = str(e)
634 return vm_dict
635
636 def refresh_nets_status(self, net_list):
637 """Get the status of the networks
638 Params: the list of network identifiers
639 Returns a dictionary with:
640 net_id: #VIM id of this network
641 status: #Mandatory. Text with one of:
642 # DELETED (not found at vim)
643 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
644 # OTHER (Vim reported other status not understood)
645 # ERROR (VIM indicates an ERROR status)
646 # ACTIVE, INACTIVE, DOWN (admin down),
647 # BUILD (on building process)
648 #
649 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
650 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
651 """
652 net_dict = {}
653 try:
654 for net_id in net_list:
655 net = {}
656 try:
657 net_vim = self.get_network(net_id)
658 net["status"] = net_vim["status"]
659 net["vim_info"] = None
660 except vimconn.vimconnNotFoundException as e:
661 self.logger.error("Exception getting net status: {}".format(str(e)))
662 net['status'] = "DELETED"
663 net['error_msg'] = str(e)
664 except vimconn.vimconnException as e:
665 self.logger.error(e)
666 net["status"] = "VIM_ERROR"
667 net["error_msg"] = str(e)
668 net_dict[net_id] = net
669 return net_dict
670 except vimconn.vimconnException as e:
671 self.logger.error(e)
672 for k in net_dict:
673 net_dict[k]["status"] = "VIM_ERROR"
674 net_dict[k]["error_msg"] = str(e)
675 return net_dict
676
677 # to be used and fixed in future commits... not working properly
678 # def action_vminstance(self, vm_id, action_dict):
679 # """Send and action over a VM instance from VIM
680 # Returns the status"""
681 # try:
682 # if "console" in action_dict:
683 # console_dict = {"protocol": "http",
684 # "server": "10.95.84.42",
685 # "port": "29876",
686 # "suffix": "?token=4hsb9cu9utruakon4p3z"
687 # }
688 # return console_dict
689 # except vimconn.vimconnException as e:
690 # self.logger.error(e)
691