update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b second try
[osm/SO.git] / rwcal / plugins / vala / rwcal_openstack / rift / rwcal / openstack / utils / compute.py
1 #!/usr/bin/python
2
3 #
4 # Copyright 2017 RIFT.IO Inc
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 #
18 import uuid
19 import gi
20 gi.require_version('RwcalYang', '1.0')
21 from gi.repository import RwcalYang
22
23
24 class ImageValidateError(Exception):
25 pass
26
27 class VolumeValidateError(Exception):
28 pass
29
30 class AffinityGroupError(Exception):
31 pass
32
33
34 class ComputeUtils(object):
35 """
36 Utility class for compute operations
37 """
38 epa_types = ['vm_flavor',
39 'guest_epa',
40 'host_epa',
41 'host_aggregate',
42 'hypervisor_epa',
43 'vswitch_epa']
44 def __init__(self, driver):
45 """
46 Constructor for class
47 Arguments:
48 driver: object of OpenstackDriver()
49 """
50 self._driver = driver
51 self.log = driver.log
52
53 @property
54 def driver(self):
55 return self._driver
56
57 def search_vdu_flavor(self, vdu_params):
58 """
59 Function to search a matching flavor for VDU instantiation
60 from already existing flavors
61
62 Arguments:
63 vdu_params: Protobuf GI object RwcalYang.YangData_RwProject_Project_VduInitParams()
64
65 Returns:
66 flavor_id(string): Flavor id for VDU instantiation
67 None if no flavor could be found
68 """
69
70 if vdu_params.vm_flavor.has_field('vm_flavor_name') and \
71 vdu_params.vm_flavor.vm_flavor_name is not None:
72 nova_flavor_list = self.driver.nova_flavor_list()
73 for flavor in nova_flavor_list:
74 self.log.debug("Flavor {} ".format(flavor.get('name', '')))
75 if flavor.get('name', '') == vdu_params.vm_flavor.vm_flavor_name:
76 return flavor['id']
77
78 kwargs = { 'vcpus': vdu_params.vm_flavor.vcpu_count,
79 'ram' : vdu_params.vm_flavor.memory_mb,
80 'disk' : vdu_params.vm_flavor.storage_gb,}
81
82 flavors = self.driver.nova_flavor_find(**kwargs)
83 flavor_list = list()
84 for flv in flavors:
85 flavor_list.append(self.driver.utils.flavor.parse_flavor_info(flv))
86
87 flavor_id = self.driver.utils.flavor.match_resource_flavor(vdu_params, flavor_list)
88 return flavor_id
89
90 def select_vdu_flavor(self, vdu_params):
91 """
92 This function attempts to find a pre-existing flavor matching required
93 parameters for VDU instantiation. If no such flavor is found, a new one
94 is created.
95
96 Arguments:
97 vdu_params: Protobuf GI object RwcalYang.YangData_RwProject_Project_VduInitParams()
98
99 Returns:
100 flavor_id(string): Flavor id for VDU instantiation
101 """
102 flavor_id = self.search_vdu_flavor(vdu_params)
103 if flavor_id is not None:
104 self.log.info("Found flavor with id: %s matching requirements for VDU: %s",
105 flavor_id, vdu_params.name)
106 return flavor_id
107
108 flavor = RwcalYang.YangData_RwProject_Project_VimResources_FlavorinfoList()
109 flavor.name = str(uuid.uuid4())
110
111 epa_dict = { k: v for k, v in vdu_params.as_dict().items()
112 if k in ComputeUtils.epa_types }
113
114 flavor.from_dict(epa_dict)
115
116 flavor_id = self.driver.nova_flavor_create(name = flavor.name,
117 ram = flavor.vm_flavor.memory_mb,
118 vcpus = flavor.vm_flavor.vcpu_count,
119 disk = flavor.vm_flavor.storage_gb,
120 epa_specs = self.driver.utils.flavor.get_extra_specs(flavor))
121 return flavor_id
122
123 def make_vdu_flavor_args(self, vdu_params):
124 """
125 Creates flavor related arguments for VDU operation
126 Arguments:
127 vdu_params: Protobuf GI object RwcalYang.YangData_RwProject_Project_VduInitParams()
128
129 Returns:
130 A dictionary {'flavor_id': <flavor-id>}
131 """
132 return {'flavor_id': self.select_vdu_flavor(vdu_params)}
133
134
135 def make_vdu_image_args(self, vdu_params):
136 """
137 Creates image related arguments for VDU operation
138 Arguments:
139 vdu_params: Protobuf GI object RwcalYang.YangData_RwProject_Project_VduInitParams()
140
141 Returns:
142 A dictionary {'image_id': <image-id>}
143
144 """
145 kwargs = dict()
146 if vdu_params.has_field('image_name'):
147 kwargs['image_id'] = self.resolve_image_n_validate(vdu_params.image_name,
148 vdu_params.image_checksum)
149 elif vdu_params.has_field('image_id'):
150 kwargs['image_id'] = vdu_params.image_id
151
152 return kwargs
153
154 def resolve_image_n_validate(self, image_name, checksum = None):
155 """
156 Resolve the image_name to image-object by matching image_name and checksum
157
158 Arguments:
159 image_name (string): Name of image
160 checksums (string): Checksum associated with image
161
162 Raises ImageValidateError in case of Errors
163 """
164 image_info = [ i for i in self.driver._glance_image_list if i['name'] == image_name]
165
166 if not image_info:
167 self.log.error("No image with name: %s found", image_name)
168 raise ImageValidateError("No image with name %s found" %(image_name))
169
170 for image in image_info:
171 if 'status' not in image or image['status'] != 'active':
172 self.log.error("Image %s not in active state. Current state: %s",
173 image_name, image['status'])
174 raise ImageValidateError("Image with name %s found in incorrect (%s) state"
175 %(image_name, image['status']))
176 if not checksum or checksum == image['checksum']:
177 break
178 else:
179 self.log.info("No image found with matching name: %s and checksum: %s",
180 image_name, checksum)
181 raise ImageValidateError("No image found with matching name: %s and checksum: %s"
182 %(image_name, checksum))
183 return image['id']
184
185 def resolve_volume_n_validate(self, volume_ref):
186 """
187 Resolve the volume reference
188
189 Arguments:
190 volume_ref (string): Name of volume reference
191
192 Raises VolumeValidateError in case of Errors
193 """
194
195 for vol in self.driver._cinder_volume_list:
196 voldict = vol.to_dict()
197 if 'display_name' in voldict and voldict['display_name'] == volume_ref:
198 if 'status' in voldict:
199 if voldict['status'] == 'available':
200 return voldict['id']
201 else:
202 self.log.error("Volume %s not in available state. Current state: %s",
203 volume_ref, voldict['status'])
204 raise VolumeValidateError("Volume with name %s found in incorrect (%s) state"
205 %(volume_ref, voldict['status']))
206
207 self.log.info("No volume found with matching name: %s ", volume_ref)
208 raise VolumeValidateError("No volume found with matching name: %s " %(volume_ref))
209
210 def make_vdu_volume_args(self, volume, vdu_params):
211 """
212 Arguments:
213 volume: Protobuf GI object RwcalYang.YangData_RwProject_Project_VduInitParams_Volumes()
214 vdu_params: Protobuf GI object RwcalYang.YangData_RwProject_Project_VduInitParams()
215
216 Returns:
217 A dictionary required to create volume for VDU
218
219 Raises VolumeValidateError in case of Errors
220 """
221 kwargs = dict()
222
223 if 'boot_priority' in volume:
224 # Rift-only field
225 kwargs['boot_index'] = volume.boot_priority
226 if volume.has_field("image"):
227 # Support image->volume
228 kwargs['source_type'] = "image"
229 kwargs['uuid'] = self.resolve_image_n_validate(volume.image, volume.image_checksum)
230 kwargs['delete_on_termination'] = True
231 elif "volume_ref" in volume:
232 # Support volume-ref->volume (only ref)
233 # Rift-only field
234 kwargs['source_type'] = "volume"
235 kwargs['uuid'] = self.resolve_volume_n_validate(volume.volume_ref)
236 kwargs['delete_on_termination'] = False
237 else:
238 # Support blank->volume
239 kwargs['source_type'] = "blank"
240 kwargs['delete_on_termination'] = True
241 kwargs['device_name'] = volume.name
242 kwargs['destination_type'] = "volume"
243 kwargs['volume_size'] = volume.size
244
245 if volume.has_field('device_type'):
246 if volume.device_type in ['cdrom', 'disk']:
247 kwargs['device_type'] = volume.device_type
248 else:
249 self.log.error("Unsupported device_type <%s> found for volume: %s",
250 volume.device_type, volume.name)
251 raise VolumeValidateError("Unsupported device_type <%s> found for volume: %s"
252 %(volume.device_type, volume.name))
253
254 if volume.has_field('device_bus'):
255 if volume.device_bus in ['ide', 'virtio', 'scsi']:
256 kwargs['disk_bus'] = volume.device_bus
257 else:
258 self.log.error("Unsupported device_type <%s> found for volume: %s",
259 volume.device_type, volume.name)
260 raise VolumeValidateError("Unsupported device_type <%s> found for volume: %s"
261 %(volume.device_type, volume.name))
262
263 return kwargs
264
265 def make_vdu_storage_args(self, vdu_params):
266 """
267 Creates volume related arguments for VDU operation
268
269 Arguments:
270 vdu_params: Protobuf GI object RwcalYang.YangData_RwProject_Project_VduInitParams()
271
272 Returns:
273 A dictionary required for volumes creation for VDU instantiation
274 """
275 kwargs = dict()
276 if vdu_params.has_field('volumes'):
277 kwargs['block_device_mapping_v2'] = list()
278 bootvol_list = list()
279 othervol_list = list()
280 # Ignore top-level image
281 kwargs['image_id'] = ""
282 for volume in vdu_params.volumes:
283 if 'boot_priority' in volume:
284 bootvol_list.append(self.make_vdu_volume_args(volume, vdu_params))
285 else:
286 othervol_list.append(self.make_vdu_volume_args(volume, vdu_params))
287 # Sort block_device_mapping_v2 list by boot index, Openstack does not seem to respecting order by boot index
288 kwargs['block_device_mapping_v2'] = sorted(bootvol_list, key=lambda k: k['boot_index']) + othervol_list
289 return kwargs
290
291 def make_vdu_network_args(self, vdu_params):
292 """
293 Creates VDU network related arguments for VDU operation
294 Arguments:
295 vdu_params: Protobuf GI object RwcalYang.YangData_RwProject_Project_VduInitParams()
296
297 Returns:
298 A dictionary {'port_list' : [ports], 'network_list': [networks]}
299
300 """
301 kwargs = dict()
302 kwargs['port_list'], kwargs['network_list'] = self.driver.utils.network.setup_vdu_networking(vdu_params)
303
304 return kwargs
305
306
307 def make_vdu_boot_config_args(self, vdu_params):
308 """
309 Creates VDU boot config related arguments for VDU operation
310 Arguments:
311 vdu_params: Protobuf GI object RwcalYang.YangData_RwProject_Project_VduInitParams()
312
313 Returns:
314 A dictionary {
315 'userdata' : <cloud-init> ,
316 'config_drive': True/False,
317 'files' : [ file name ],
318 'metadata' : <metadata string>
319 }
320 """
321 kwargs = dict()
322 metadata = dict()
323
324 if vdu_params.has_field('node_id'):
325 metadata['rift_node_id'] = vdu_params.node_id
326 kwargs['metadata'] = metadata
327
328 if vdu_params.has_field('vdu_init') and vdu_params.vdu_init.has_field('userdata'):
329 kwargs['userdata'] = vdu_params.vdu_init.userdata
330 else:
331 kwargs['userdata'] = ''
332
333 if not vdu_params.has_field('supplemental_boot_data'):
334 return kwargs
335
336 if vdu_params.supplemental_boot_data.has_field('config_file'):
337 files = dict()
338 for cf in vdu_params.supplemental_boot_data.config_file:
339 files[cf.dest] = cf.source
340 kwargs['files'] = files
341
342 if vdu_params.supplemental_boot_data.has_field('boot_data_drive'):
343 kwargs['config_drive'] = vdu_params.supplemental_boot_data.boot_data_drive
344 else:
345 kwargs['config_drive'] = False
346
347 try:
348 # Rift model only
349 if vdu_params.supplemental_boot_data.has_field('custom_meta_data'):
350 for cm in vdu_params.supplemental_boot_data.custom_meta_data:
351 # Adding this condition as the list contains CLOUD_INIT Variables as
352 # well. CloudInit Variables such as password are visible on the OpenStack UI
353 # if not removed from the custom_meta_data list.
354 if cm.destination == 'CLOUD_METADATA':
355 metadata[cm.name] = cm.value
356 kwargs['metadata'] = metadata
357 except Exception as e:
358 pass
359
360 return kwargs
361
362 def _select_affinity_group(self, group_name):
363 """
364 Selects the affinity group based on name and return its id
365 Arguments:
366 group_name (string): Name of the Affinity/Anti-Affinity group
367 Returns:
368 Id of the matching group
369
370 Raises exception AffinityGroupError if no matching group is found
371 """
372 groups = [g['id'] for g in self.driver._nova_affinity_group if g['name'] == group_name]
373 if not groups:
374 self.log.error("No affinity/anti-affinity group with name: %s found", group_name)
375 raise AffinityGroupError("No affinity/anti-affinity group with name: %s found" %(group_name))
376 return groups[0]
377
378
379 def make_vdu_server_placement_args(self, vdu_params):
380 """
381 Function to create kwargs required for nova server placement
382
383 Arguments:
384 vdu_params: Protobuf GI object RwcalYang.YangData_RwProject_Project_VduInitParams()
385
386 Returns:
387 A dictionary { 'availability_zone' : < Zone >, 'scheduler_hints': <group-id> }
388
389 """
390 kwargs = dict()
391
392 if vdu_params.has_field('availability_zone') \
393 and vdu_params.availability_zone.has_field('name'):
394 kwargs['availability_zone'] = vdu_params.availability_zone
395
396 if vdu_params.has_field('server_group'):
397 kwargs['scheduler_hints'] = {
398 'group': self._select_affinity_group(vdu_params.server_group)
399 }
400 return kwargs
401
402 def make_vdu_server_security_args(self, vdu_params, account):
403 """
404 Function to create kwargs required for nova security group
405
406 Arguments:
407 vdu_params: Protobuf GI object RwcalYang.YangData_RwProject_Project_VduInitParams()
408 account: Protobuf GI object RwcalYang.YangData_RwProject_Project_CloudAccounts_CloudAccountList()
409
410 Returns:
411 A dictionary {'security_groups' : < group > }
412 """
413 kwargs = dict()
414 if account.openstack.security_groups:
415 kwargs['security_groups'] = account.openstack.security_groups
416 return kwargs
417
418
419 def make_vdu_create_args(self, vdu_params, account):
420 """
421 Function to create kwargs required for nova_server_create API
422
423 Arguments:
424 vdu_params: Protobuf GI object RwcalYang.YangData_RwProject_Project_VduInitParams()
425 account: Protobuf GI object RwcalYang.YangData_RwProject_Project_CloudAccounts_CloudAccountList()
426
427 Returns:
428 A kwargs dictionary for VDU create operation
429 """
430 kwargs = dict()
431
432 kwargs['name'] = vdu_params.name
433
434 kwargs.update(self.make_vdu_flavor_args(vdu_params))
435 kwargs.update(self.make_vdu_storage_args(vdu_params))
436 kwargs.update(self.make_vdu_image_args(vdu_params))
437 kwargs.update(self.make_vdu_network_args(vdu_params))
438 kwargs.update(self.make_vdu_boot_config_args(vdu_params))
439 kwargs.update(self.make_vdu_server_placement_args(vdu_params))
440 kwargs.update(self.make_vdu_server_security_args(vdu_params, account))
441 return kwargs
442
443
444 def _parse_vdu_mgmt_address_info(self, vm_info):
445 """
446 Get management_ip and public_ip for VDU
447
448 Arguments:
449 vm_info : A dictionary object return by novaclient library listing VM attributes
450
451 Returns:
452 A tuple of mgmt_ip (string) and public_ip (string)
453 """
454 mgmt_ip = None
455 public_ip = None
456 if 'addresses' in vm_info:
457 for network_name, network_info in vm_info['addresses'].items():
458 if network_info and network_name == self.driver.mgmt_network:
459 for interface in network_info:
460 if 'OS-EXT-IPS:type' in interface:
461 if interface['OS-EXT-IPS:type'] == 'fixed':
462 mgmt_ip = interface['addr']
463 elif interface['OS-EXT-IPS:type'] == 'floating':
464 public_ip = interface['addr']
465
466 return (mgmt_ip, public_ip)
467
468 def get_vdu_epa_info(self, vm_info):
469 """
470 Get flavor information (including EPA) for VDU
471
472 Arguments:
473 vm_info : A dictionary returned by novaclient library listing VM attributes
474 Returns:
475 flavor_info: A dictionary object returned by novaclient library listing flavor attributes
476 """
477 if 'flavor' in vm_info and 'id' in vm_info['flavor']:
478 try:
479 flavor_info = self.driver.nova_flavor_get(vm_info['flavor']['id'])
480 return flavor_info
481 except Exception as e:
482 self.log.exception("Exception %s occured during get-flavor", str(e))
483 return dict()
484
485 def _parse_vdu_cp_info(self, vdu_id):
486 """
487 Get connection point information for VDU identified by vdu_id
488 Arguments:
489 vdu_id (string) : VDU Id (vm_info['id'])
490 Returns:
491 A List of object RwcalYang.YangData_RwProject_Project_VnfResources_VduInfoList_ConnectionPoints()
492
493 """
494 cp_list = []
495 # Fill the port information
496 port_list = self.driver.neutron_port_list(**{'device_id': vdu_id})
497 for port in port_list:
498 cp_info = self.driver.utils.network._parse_cp(port)
499 cp = RwcalYang.YangData_RwProject_Project_VnfResources_VduInfoList_ConnectionPoints()
500 cp.from_dict(cp_info.as_dict())
501 cp_list.append(cp)
502 return cp_list
503
504 def _parse_vdu_state_info(self, vm_info):
505 """
506 Get VDU state information
507
508 Arguments:
509 vm_info : A dictionary returned by novaclient library listing VM attributes
510
511 Returns:
512 state (string): State of the VDU
513 """
514 if 'status' in vm_info:
515 if vm_info['status'] == 'ACTIVE':
516 vdu_state = 'active'
517 elif vm_info['status'] == 'ERROR':
518 vdu_state = 'failed'
519 else:
520 vdu_state = 'inactive'
521 else:
522 vdu_state = 'unknown'
523 return vdu_state
524
525 def _parse_vdu_server_group_info(self, vm_info):
526 """
527 Get VDU server group information
528 Arguments:
529 vm_info : A dictionary returned by novaclient library listing VM attributes
530
531 Returns:
532 server_group_name (string): Name of the server group to which VM belongs, else empty string
533
534 """
535 server_group = [ v['name']
536 for v in self.driver.nova_server_group_list()
537 if vm_info['id'] in v['members'] ]
538 if server_group:
539 return server_group[0]
540 else:
541 return str()
542
543 def _parse_vdu_boot_config_data(self, vm_info):
544 """
545 Parses VDU supplemental boot data
546 Arguments:
547 vm_info : A dictionary returned by novaclient library listing VM attributes
548
549 Returns:
550 List of RwcalYang.YangData_RwProject_Project_VnfResources_VduInfoList_SupplementalBootData()
551 """
552 supplemental_boot_data = None
553 node_id = None
554 if 'config_drive' in vm_info:
555 supplemental_boot_data = RwcalYang.YangData_RwProject_Project_VnfResources_VduInfoList_SupplementalBootData()
556 supplemental_boot_data.boot_data_drive = vm_info['config_drive']
557 # Look for any metadata
558 if 'metadata' not in vm_info:
559 return node_id, supplemental_boot_data
560 if supplemental_boot_data is None:
561 supplemental_boot_data = RwcalYang.YangData_RwProject_Project_VnfResources_VduInfoList_SupplementalBootData()
562 for key, value in vm_info['metadata'].items():
563 if key == 'rift_node_id':
564 node_id = value
565 else:
566 try:
567 # rift only
568 cm = supplemental_boot_data.custom_meta_data.add()
569 cm.name = key
570 cm.value = str(value)
571 except Exception as e:
572 pass
573 return node_id, supplemental_boot_data
574
575 def _parse_vdu_volume_info(self, vm_info):
576 """
577 Get VDU server group information
578 Arguments:
579 vm_info : A dictionary returned by novaclient library listing VM attributes
580
581 Returns:
582 List of RwcalYang.YangData_RwProject_Project_VnfResources_VduInfoList_Volumes()
583 """
584 volumes = list()
585
586 try:
587 volume_list = self.driver.nova_volume_list(vm_info['id'])
588 except Exception as e:
589 self.log.exception("Exception %s occured during nova-volume-list", str(e))
590 return volumes
591
592 for v in volume_list:
593 volume = RwcalYang.YangData_RwProject_Project_VnfResources_VduInfoList_Volumes()
594 try:
595 volume.name = (v['device']).split('/')[2]
596 volume.volume_id = v['volumeId']
597 details = self.driver.cinder_volume_get(volume.volume_id)
598 if details is None:
599 continue
600 try:
601 # Rift only
602 for k, v in details.metadata.items():
603 vd = volume.custom_meta_data.add()
604 vd.name = k
605 vd.value = v
606 except Exception as e:
607 pass
608 except Exception as e:
609 self.log.exception("Exception %s occured during volume list parsing", str(e))
610 continue
611 else:
612 volumes.append(volume)
613 return volumes
614
615 def _parse_vdu_console_url(self, vm_info):
616 """
617 Get VDU console URL
618 Arguments:
619 vm_info : A dictionary returned by novaclient library listing VM attributes
620
621 Returns:
622 console_url(string): Console URL for VM
623 """
624 console_url = None
625 if self._parse_vdu_state_info(vm_info) == 'active':
626 try:
627 serv_console_url = self.driver.nova_server_console(vm_info['id'])
628 if 'console' in serv_console_url:
629 console_url = serv_console_url['console']['url']
630 else:
631 self.log.error("Error fetching console url. This could be an Openstack issue. Console : " + str(serv_console_url))
632
633
634 except Exception as e:
635 self.log.warning("Exception %s occured during volume list parsing", str(e))
636 return console_url
637
638 def parse_cloud_vdu_info(self, vm_info):
639 """
640 Parse vm_info dictionary (return by python-client) and put values in GI object for VDU
641
642 Arguments:
643 vm_info : A dictionary object return by novaclient library listing VM attributes
644
645 Returns:
646 Protobuf GI Object of type RwcalYang.YangData_RwProject_Project_VnfResources_VduInfoList()
647 """
648 vdu = RwcalYang.YangData_RwProject_Project_VnfResources_VduInfoList()
649 vdu.name = vm_info['name']
650 vdu.vdu_id = vm_info['id']
651 vdu.cloud_type = 'openstack'
652
653 if 'image' in vm_info and 'id' in vm_info['image']:
654 vdu.image_id = vm_info['image']['id']
655
656 if 'availability_zone' in vm_info:
657 vdu.availability_zone = vm_info['availability_zone']
658
659 vdu.state = self._parse_vdu_state_info(vm_info)
660 management_ip,public_ip = self._parse_vdu_mgmt_address_info(vm_info)
661
662 if management_ip:
663 vdu.management_ip = management_ip
664
665 if public_ip:
666 vdu.public_ip = public_ip
667
668 if 'flavor' in vm_info and 'id' in vm_info['flavor']:
669 vdu.flavor_id = vm_info['flavor']['id']
670 flavor_info = self.get_vdu_epa_info(vm_info)
671 if flavor_info is not None:
672 vm_flavor = self.driver.utils.flavor.parse_vm_flavor_epa_info(flavor_info)
673 guest_epa = self.driver.utils.flavor.parse_guest_epa_info(flavor_info)
674 host_epa = self.driver.utils.flavor.parse_host_epa_info(flavor_info)
675 host_aggregates = self.driver.utils.flavor.parse_host_aggregate_epa_info(flavor_info)
676
677 vdu.vm_flavor.from_dict(vm_flavor.as_dict())
678 vdu.guest_epa.from_dict(guest_epa.as_dict())
679 vdu.host_epa.from_dict(host_epa.as_dict())
680 for aggr in host_aggregates:
681 ha = vdu.host_aggregate.add()
682 ha.from_dict(aggr.as_dict())
683
684 node_id, boot_data = self._parse_vdu_boot_config_data(vm_info)
685 if node_id:
686 vdu.node_id = node_id
687 if boot_data:
688 vdu.supplemental_boot_data = boot_data
689
690 cp_list = self._parse_vdu_cp_info(vdu.vdu_id)
691 for cp in cp_list:
692 vdu.connection_points.append(cp)
693
694 vdu.server_group.name = self._parse_vdu_server_group_info(vm_info)
695
696 for v in self._parse_vdu_volume_info(vm_info):
697 vdu.volumes.append(v)
698
699 vdu.console_url = self._parse_vdu_console_url(vm_info)
700 return vdu
701
702
703 def perform_vdu_network_cleanup(self, vdu_id):
704 """
705 This function cleans up networking resources related to VDU
706 Arguments:
707 vdu_id(string): VDU id
708 Returns:
709 None
710 """
711 ### Get list of floating_ips associated with this instance and delete them
712 floating_ips = [ f for f in self.driver.nova_floating_ip_list() if f.instance_id == vdu_id ]
713 for f in floating_ips:
714 self.driver.nova_floating_ip_delete(f)
715
716 ### Get list of port on VM and delete them.
717 port_list = self.driver.neutron_port_list(**{'device_id': vdu_id})
718
719 for port in port_list:
720 self.driver.neutron_port_delete(port['id'])
721