aa3d971baf6a4b1c19126cc8154309b86c04e26d
[osm/SO.git] / rwcal / plugins / vala / rwcal_openmano_vimconnector / rwcal_openmano_vimconnector.py
1
2 #
3 # Copyright 2016 RIFT.IO Inc
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17
18 import logging
19 from gi import require_version
20 require_version('RwCal', '1.0')
21 import rift.rwcal.openmano_vimconnector as vimconn_openvim
22 import contextlib
23 import requests
24 import paramiko
25 import os
26 import uuid
27
28 from gi.repository import (
29 GObject,
30 RwCal,
31 RwTypes,
32 RwcalYang)
33
34 import rw_status
35 import rift.cal.rwcal_status as rwcal_status
36 import rwlogger
37
38 logger = logging.getLogger('rwcal.openmano_vimconnector')
39
40 class UnknownAccountError(Exception):
41 pass
42
43 class OpenvimCALOperationFailure(Exception):
44 pass
45
46 class MissingFileError(Exception):
47 pass
48
49
50 class ImageLocationError(Exception):
51 pass
52
53 class UninitializedPluginError(Exception):
54 pass
55
56 rwstatus_exception_map = {IndexError: RwTypes.RwStatus.NOTFOUND,
57 KeyError: RwTypes.RwStatus.NOTFOUND,
58 UnknownAccountError: RwTypes.RwStatus.NOTFOUND,
59 MissingFileError: RwTypes.RwStatus.NOTFOUND,
60 }
61
62 rwstatus = rw_status.rwstatus_from_exc_map(rwstatus_exception_map)
63 rwcalstatus = rwcal_status.rwcalstatus_from_exc_map(rwstatus_exception_map)
64
65
66 class RwcalOpenmanoVimConnector(GObject.Object, RwCal.Cloud):
67 """Stub implementation the CAL VALA methods for Openmano. """
68
69 instance_num = 1
70 def __init__(self):
71 GObject.Object.__init__(self)
72 self._driver_class = vimconn_openvim.vimconnector
73 self.log = logging.getLogger('rwcal.openmano_vimconnector.%s' % RwcalOpenmanoVimConnector.instance_num)
74 self.log.setLevel(logging.DEBUG)
75 self._rwlog_handler = None
76 self._tenant_name = None
77 RwcalOpenmanoVimConnector.instance_num += 1
78
79 @contextlib.contextmanager
80 def _use_driver(self, account):
81 #if self._rwlog_handler is None:
82 # raise UninitializedPluginError("Must call init() in CAL plugin before use.")
83
84 #with rwlogger.rwlog_root_handler(self._rwlog_handler):
85 try:
86 if self._tenant_name != account.openvim.tenant_name:
87 tmp_drv = self._driver_class(uuid = '',
88 name = '',
89 #tenant_id = account.openvim.tenant_id,
90 tenant_id = '',
91 tenant_name = '',
92 url ='http://{}:{}/openvim'.format(account.openvim.host,account.openvim.port),
93 url_admin = '')
94 tenant_dict = {'name':account.openvim.tenant_name}
95 tenant_list = tmp_drv.get_tenant_list(tenant_dict)
96 if len(tenant_list) == 0:
97 tmp_drv.new_tenant(account.openvim.tenant_name,"default tenant")
98 self._tenant_name = account.openvim.tenant_name
99 else:
100 self._tenant_name = account.openvim.tenant_name
101
102
103 drv = self._driver_class(uuid = '',
104 name = '',
105 #tenant_id = account.openvim.tenant_id,
106 tenant_id = '',
107 tenant_name = account.openvim.tenant_name,
108 url ='http://{}:{}/openvim'.format(account.openvim.host,account.openvim.port),
109 url_admin = '')
110
111 except Exception as e:
112 self.log.error("RwcalOpenmanoVimConnectorPlugin: VimConnector init failed. Exception: %s" %(str(e)))
113 raise
114
115 yield drv
116
117 @rwstatus
118 def do_init(self, rwlog_ctx):
119 if not any(isinstance(h, rwlogger.RwLogger) for h in logger.handlers):
120 logger.addHandler(
121 rwlogger.RwLogger(
122 category="rw-cal-log",
123 subcategory="openmano_vimconnector",
124 log_hdl=rwlog_ctx,
125 )
126 )
127
128 @rwstatus(ret_on_failure=[None])
129 def do_validate_cloud_creds(self, account):
130 """
131 Validates the cloud account credentials for the specified account.
132 If creds are not valid, returns an error code & reason string
133 Arguments:
134 account - a cloud account to validate
135
136 Returns:
137 Validation Code and Details String
138 """
139 status = RwcalYang.CloudConnectionStatus()
140 url = 'http://{}:{}/openvim/'.format(account.openvim.host,account.openvim.port)
141 try:
142 r=requests.get(url,timeout=3)
143 r.raise_for_status()
144 except requests.exceptions.HTTPError as e:
145 self.log.error("OpenvimConnectorPlugin: Openvim account credential validation failed. Exception: %s", str(e))
146 status.status = "failure"
147 status.details = "Invalid Credentials: %s" % str(e)
148 except Exception as e:
149 self.log.error("OpenvimConnectorPlugin: Openvim connection failed. Exception: %s", str(e))
150 status.status = "failure"
151 status.details = "Connection Failed (Invlaid URL): %s" % str(e)
152 else:
153 self.log.debug("Openvim Successfully connected")
154 status.status = "success"
155 status.details = "Connection was successful"
156
157 return status
158
159 @rwstatus(ret_on_failure=[None])
160 def do_get_management_network(self, account):
161 raise NotImplementedError()
162
163 @rwstatus
164 def do_create_tenant(self, account, name):
165 with self._use_driver(account) as drv:
166 return drv.new_tenant(name, "New CAL teannt");
167
168 @rwstatus
169 def do_delete_tenant(self, account, tenant_id):
170 with self._use_driver(account) as drv:
171 drv.delete_tenant(tenant_id);
172
173 @staticmethod
174 def _fill_tenant_info(tenant_info):
175 """Create a GI object from tenant info dictionary
176
177 Converts tenant information dictionary object returned by openmano vimconnector
178 driver into Protobuf Gi Object
179
180 Arguments:
181 tenant_info - tenant information dictionary object
182
183 Returns:
184 The TenantInfoItem
185 """
186 tenant = RwcalYang.TenantInfoItem()
187 tenant.tenant_name = tenant_info['name']
188 tenant.tenant_id = tenant_info['id']
189 return tenant
190
191 @rwstatus(ret_on_failure=[[]])
192 def do_get_tenant_list(self, account):
193 response = RwcalYang.VimResources()
194 with self._use_driver(account) as drv:
195 tenants = drv.get_tenant_list()
196 for tenant in tenants:
197 response.tenantinfo_list.append(RwcalOpenmanoVimConnector._fill_tenant_info(tenant))
198 return response
199
200 @rwstatus
201 def do_create_role(self, account, name):
202 raise NotImplementedError()
203
204 @rwstatus
205 def do_delete_role(self, account, role_id):
206 raise NotImplementedError()
207
208 @rwstatus(ret_on_failure=[[]])
209 def do_get_role_list(self, account):
210 raise NotImplementedError()
211
212 @rwstatus(ret_on_failure=[None])
213 def do_create_image(self, account, image):
214 with self._use_driver(account) as drv:
215 try:
216 # If the use passed in a file descriptor, use that to
217 # upload the image.
218 if image.has_field("fileno"):
219 new_fileno = os.dup(image.fileno)
220 hdl = os.fdopen(new_fileno, 'rb')
221 else:
222 hdl = open(image.location, "rb")
223 except Exception as e:
224 self.log.error("Could not open file for upload. Exception received: %s", str(e))
225 raise
226
227 tpt = paramiko.Transport((account.openvim.host, 22))
228 try:
229 tpt.connect(username=account.openvim.image_management.username,
230 password=account.openvim.image_management.password)
231 except Exception as e:
232 self.log.error('Could not connect to openvim host: %s. Exception: %s', account.openvim.host, e)
233 return
234
235 sftp = paramiko.SFTPClient.from_transport(tpt)
236 destination = account.openvim.image_management.image_directory_path.rstrip('/')+'/'+image.name
237 with hdl as fd:
238 try:
239 sftp.putfo(fd, destination)
240 except Exception as e:
241 self.log.warn('*** Caught exception: %s: %s', e.__class__, e)
242 finally:
243 sftp.close()
244 tpt.close()
245
246 image_dict = {}
247 image_dict['name'] = image.name
248 image_dict['location'] = destination
249 image_id = drv.new_image(image_dict)
250 return image_id
251
252 @rwstatus
253 def do_delete_image(self, account, image_id):
254 with self._use_driver(account) as drv:
255 drv.delete_image(image_id)
256
257 @staticmethod
258 def _fill_image_info(img_info):
259 img = RwcalYang.ImageInfoItem()
260 img.name = img_info['name']
261 img.id = img_info['id']
262 img.location = img_info['path']
263 if img_info['status'] == 'ACTIVE':
264 img.state = 'active'
265 else:
266 img.state = 'inactive'
267 return img
268
269 @rwstatus(ret_on_failure=[None])
270 def do_get_image(self, account, image_id):
271 with self._use_driver(account) as drv:
272 image = drv.get_image(image_id)
273 return RwcalOpenmanoVimConnector._fill_image_info(image)
274
275 @rwstatus(ret_on_failure=[[]])
276 def do_get_image_list(self, account):
277 response = RwcalYang.VimResources()
278 with self._use_driver(account) as drv:
279 images = drv.get_image_list()
280 for img in images:
281 image_info = drv.get_image(img['id'])
282 response.imageinfo_list.append(RwcalOpenmanoVimConnector._fill_image_info(image_info))
283 return response
284
285 @rwstatus
286 def do_create_vm(self, account, vm):
287 raise NotImplementedError()
288
289 @rwstatus
290 def do_start_vm(self, account, vm_id):
291 raise NotImplementedError()
292
293 @rwstatus
294 def do_stop_vm(self, account, vm_id):
295 raise NotImplementedError()
296
297 @rwstatus
298 def do_delete_vm(self, account, vm_id):
299 raise NotImplementedError()
300
301 @rwstatus
302 def do_reboot_vm(self, account, vm_id):
303 raise NotImplementedError()
304
305 @rwstatus(ret_on_failure=[[]])
306 def do_get_vm_list(self, account):
307 return RwcalYang.VimResources()
308
309 def _fill_flavor_create_attributes(flavor):
310 flavor_dict = dict()
311 flavor_dict['name'] = flavor.name
312 flavor_dict['ram'] = flavor.vm_flavor.memory_mb
313 flavor_dict['disk'] = flavor.vm_flavor.storage_gb
314 flavor_dict['vcpus'] = flavor.vm_flavor.vcpu_count
315 return flavor_dict
316
317 @rwstatus
318 def do_create_flavor(self, account, flavor):
319 with self._use_driver(account) as drv:
320 flavor_dict = RwcalOpenmanoVimConnector._fill_flavor_create_attributes(flavor)
321 flavor_id = drv.new_flavor(flavor_dict)
322 return flavor_id
323
324 @rwstatus
325 def do_delete_flavor(self, account, flavor_id):
326 with self._use_driver(account) as drv:
327 drv.delete_flavor(flavor_id)
328
329 @staticmethod
330 def _fill_epa_attributes(flavor, flavor_info):
331 if 'ram' in flavor_info and flavor_info['ram']:
332 getattr(flavor, 'vm_flavor').memory_mb = flavor_info.get('ram',0)
333 if 'disk' in flavor_info and flavor_info['disk']:
334 getattr(flavor, 'vm_flavor').storage_gb = flavor_info.get('disk',0)
335 if 'vcpus' in flavor_info and flavor_info['vcpus']:
336 getattr(flavor, 'vm_flavor').vcpu_count = flavor_info.get('vcpus',0)
337
338 if not 'extended' in flavor_info or flavor_info['extended'] is None:
339 return
340 getattr(flavor,'guest_epa').numa_node_policy.node_cnt = len(flavor_info['extended']['numas'])
341 for attr in flavor_info['extended']['numas']:
342 numa_node = getattr(flavor,'guest_epa').numa_node_policy.node.add()
343 numa_node.memory_mb = attr.get('memory',0)*1024
344 #getattr(flavor, 'host_epa').cpu_core_thread_count =
345
346 @staticmethod
347 def _fill_flavor_info(flavor_info):
348 flavor = RwcalYang.FlavorInfoItem()
349 flavor.name = flavor_info['name']
350 flavor.id = flavor_info['id']
351 RwcalOpenmanoVimConnector._fill_epa_attributes(flavor, flavor_info)
352 return flavor
353
354 @rwstatus(ret_on_failure=[None])
355 def do_get_flavor(self, account, flavor_id):
356 with self._use_driver(account) as drv:
357 flavor = drv.get_flavor(flavor_id)
358 return RwcalOpenmanoVimConnector._fill_flavor_info(flavor)
359
360
361 @rwstatus(ret_on_failure=[[]])
362 def do_get_flavor_list(self, account):
363 response = RwcalYang.VimResources()
364 with self._use_driver(account) as drv:
365 flavors = drv.get_flavor_list()
366 for flav in flavors:
367 flav_info = drv.get_flavor(flav['id'])
368 response.flavorinfo_list.append(RwcalOpenmanoVimConnector._fill_flavor_info(flav_info))
369 return response
370
371 @rwstatus
372 def do_add_host(self, account, host):
373 raise NotImplementedError()
374
375 @rwstatus
376 def do_remove_host(self, account, host_id):
377 raise NotImplementedError()
378
379 @rwstatus(ret_on_failure=[None])
380 def do_get_host(self, account, host_id):
381 raise NotImplementedError()
382
383 @rwstatus(ret_on_failure=[[]])
384 def do_get_host_list(self, account):
385 raise NotImplementedError()
386
387 @rwstatus
388 def do_create_port(self, account, port):
389 raise NotImplementedError()
390
391 @rwstatus
392 def do_delete_port(self, account, port_id):
393 raise NotImplementedError()
394
395 @rwstatus(ret_on_failure=[None])
396 def do_get_port(self, account, port_id):
397 raise NotImplementedError()
398
399 @rwstatus(ret_on_failure=[[]])
400 def do_get_port_list(self, account):
401 return RwcalYang.VimResources()
402
403 @rwstatus
404 def do_create_network(self, account, network):
405 with self._use_driver(account) as drv:
406 network_id = drv.new_network(network.name,'bridge_man')
407 return network_id
408
409 @rwstatus
410 def do_delete_network(self, account, network_id):
411 with self._use_driver(account) as drv:
412 drv.delete_network(network_id)
413
414 def _fill_network_info(self, network_info):
415 network = RwcalYang.NetworkInfoItem()
416 network.network_name = network_info['name']
417 network.network_id = network_info['id']
418 if ('provider:physical' in network_info) and (network_info['provider:physical']):
419 network.provider_network.physical_network = network_info['provider:physical'].upper()
420 if ('provider:vlan' in network_info) and (network_info['provider:vlan']):
421 network.provider_network.segmentation_id = network_info['provider:vlan']
422 network.provider_network.overlay_type = 'vlan'
423 return network
424
425 @rwstatus(ret_on_failure=[None])
426 def do_get_network(self, account, network_id):
427 with self._use_driver(account) as drv:
428 network = drv.get_network(id)
429 return self._fill_network_info(network)
430
431 @rwstatus(ret_on_failure=[[]])
432 def do_get_network_list(self, account):
433 response = RwcalYang.VimResources()
434 with self._use_driver(account) as drv:
435 networks = drv.get_network_list()
436 for network in networks:
437 response.networkinfo_list.append(self._fill_network_info(network))
438 return response
439
440 @rwcalstatus(ret_on_failure=[""])
441 def do_create_virtual_link(self, account, link_params):
442 with self._use_driver(account) as drv:
443 net = dict()
444 if link_params.provider_network.physical_network is not None:
445 net['provider:physical'] = link_params.provider_network.physical_network
446 #else:
447 # net['provider:physical'] = 'default'
448 if link_params.provider_network.overlay_type == 'VLAN' and link_params.provider_network.segmentation_id:
449 net['provider:vlan'] = link_params.provider_network.segmentation_id
450 network_id = drv.new_network(link_params.name,'bridge_man',shared=False,**net)
451 return network_id
452
453 @rwstatus
454 def do_delete_virtual_link(self, account, link_id):
455 with self._use_driver(account) as drv:
456 drv.delete_network(link_id)
457
458
459 @staticmethod
460 def _fill_connection_point_info(c_point, port_info):
461 c_point.name = port_info['name']
462 c_point.connection_point_id = port_info['id']
463 if 'ip_address' in port_info:
464 c_point.ip_address = port_info['ip_address']
465 if port_info['status'] == 'ACTIVE':
466 c_point.state = 'active'
467 else:
468 c_point.state = 'inactive'
469 if 'network_id' in port_info:
470 c_point.virtual_link_id = port_info['network_id']
471 if ('device_id' in port_info) and (port_info['device_id']):
472 c_point.vdu_id = port_info['device_id']
473
474 def _fill_virtual_link_info(self, drv, network_info):
475 link = RwcalYang.VirtualLinkInfoParams()
476 link.name = network_info['name']
477 link.virtual_link_id = network_info['id']
478 if network_info['admin_state_up']:
479 link.state = 'active'
480 else:
481 link.state = 'inactive'
482 link.virtual_link_id = network_info['id']
483 if ('provider:physical' in network_info) and (network_info['provider:physical']):
484 link.provider_network.physical_network = network_info['provider:physical']
485 if ('provider:vlan' in network_info) and (network_info['provider:vlan']):
486 link.provider_network.segmentation_id = network_info['provider:vlan']
487 link.provider_network.overlay_type = 'VLAN'
488
489 if 'ports' in network_info:
490 for port in network_info['ports']:
491 if 'port_id' in port:
492 port_id = port['port_id']
493 port = drv.get_port(port_id)
494 c_point = link.connection_points.add()
495 RwcalOpenmanoVimConnector._fill_connection_point_info(c_point, port)
496 return link
497
498 @rwstatus(ret_on_failure=[None])
499 def do_get_virtual_link(self, account, link_id):
500 with self._use_driver(account) as drv:
501 network = drv.get_network(link_id)
502 return self._fill_virtual_link_info(drv,network)
503
504 @rwstatus(ret_on_failure=[""])
505 def do_get_virtual_link_list(self, account):
506 response = RwcalYang.VNFResources()
507 with self._use_driver(account) as drv:
508 networks = drv.get_network_list()
509 for network in networks:
510 network_info = drv.get_network(network['id'])
511 response.virtual_link_info_list.append(self._fill_virtual_link_info(drv,network_info))
512 return response
513
514 def _match_vm_flavor(self, required, available):
515 self.log.info("Matching VM Flavor attributes required {}, available {}".format(required, available))
516 if available.vcpu_count != required.vcpu_count:
517 return False
518 if available.memory_mb != required.memory_mb:
519 return False
520 if available.storage_gb != required.storage_gb:
521 return False
522 self.log.debug("VM Flavor match found")
523 return True
524
525
526 def _select_resource_flavor(self, account, vdu_init):
527 """
528 Select a existing flavor if it matches the request or create new flavor
529 """
530 flavor = RwcalYang.FlavorInfoItem()
531 flavor.name = str(uuid.uuid4())
532 epa_types = ['vm_flavor', 'guest_epa', 'host_epa', 'host_aggregate', 'hypervisor_epa', 'vswitch_epa']
533 epa_dict = {k: v for k, v in vdu_init.as_dict().items() if k in epa_types}
534 flavor.from_dict(epa_dict)
535
536 rc, response = self.do_get_flavor_list(account)
537 if rc != RwTypes.RwStatus.SUCCESS:
538 self.log.error("Get-flavor-info-list operation failed for cloud account: %s",
539 account.name)
540 raise OpenvimCALOperationFailure("Get-flavor-info-list operation failed for cloud account: %s" %(account.name))
541
542 flavor_id = None
543 flavor_list = response.flavorinfo_list
544 self.log.debug("Received %d flavor information from RW.CAL", len(flavor_list))
545 for flv in flavor_list:
546 self.log.info("Attempting to match compute requirement for VDU: %s with flavor %s",
547 vdu_init.name, flv)
548 if self._match_vm_flavor(flavor.vm_flavor,flv.vm_flavor):
549 self.log.info("Flavor match found for compute requirements for VDU: %s with flavor name: %s, flavor-id: %s",
550 vdu_init.name, flv.name, flv.id)
551 return flv.id
552
553 if account.openvim.dynamic_flavor_support is False:
554 self.log.error("Unable to create flavor for compute requirement for VDU: %s. VDU instantiation failed", vdu_init.name)
555 raise OpenvimCALOperationFailure("No resource available with matching EPA attributes")
556 else:
557 rc,flavor_id = self.do_create_flavor(account,flavor)
558 if rc != RwTypes.RwStatus.SUCCESS:
559 self.log.error("Create-flavor operation failed for cloud account: %s",
560 account.name)
561 raise OpenvimCALOperationFailure("Create-flavor operation failed for cloud account: %s" %(account.name))
562 return flavor_id
563
564
565 @rwcalstatus(ret_on_failure=[""])
566 def do_create_vdu(self, account, vdu_init):
567 with self._use_driver(account) as drv:
568 net_list = list()
569
570 if not vdu_init.has_field('flavor_id'):
571 vdu_init.flavor_id = self._select_resource_flavor(account,vdu_init)
572
573 if account.openvim.mgmt_network:
574 mgmt_net_list = drv.get_network_list()
575 mgmt_net_id = [net['id'] for net in mgmt_net_list if net['name'] == account.openvim.mgmt_network]
576 if len(mgmt_net_id) > 0:
577 mgmt_net_dict = {}
578 mgmt_net_dict['name'] = account.openvim.mgmt_network
579 mgmt_net_dict['net_id'] = mgmt_net_id[0]
580 mgmt_net_dict['type'] = 'virtual'
581 net_list.append(mgmt_net_dict)
582
583 for c_point in vdu_init.connection_points:
584 net_dict = {}
585 net_dict['name'] = c_point.name
586 net_dict['net_id'] = c_point.virtual_link_id
587 net_dict['type'] = 'virtual'
588 net_list.append(net_dict)
589
590 vm_id = drv.new_vminstance(vdu_init.name,vdu_init.name,None,vdu_init.image_id,vdu_init.flavor_id,net_list);
591 return vm_id
592
593 @rwstatus
594 def do_modify_vdu(self, account, vdu_modify):
595 pass
596
597 @rwstatus
598 def do_delete_vdu(self, account, vdu_id):
599 if not vdu_id:
600 self.log.error("empty vdu_id during the vdu deletion")
601 return
602
603 with self._use_driver(account) as drv:
604 drv.delete_vminstance(vdu_id)
605
606 @staticmethod
607 def _fill_vdu_info(drv,account,vm_info):
608 vdu = RwcalYang.VDUInfoParams()
609 vdu.name = vm_info['name']
610 vdu.vdu_id = vm_info['id']
611 mgmt_net_id = None
612 if ('image' in vm_info) and ('id' in vm_info['image']):
613 vdu.image_id = vm_info['image']['id']
614 if ('flavor' in vm_info) and ('id' in vm_info['flavor']):
615 vdu.flavor_id = vm_info['flavor']['id']
616 vdu.cloud_type = 'openvim'
617
618 if account.openvim.mgmt_network:
619 net_list = drv.get_network_list()
620 mgmt_net_list = [net['id'] for net in net_list if net['name'] == account.openvim.mgmt_network]
621 if len(mgmt_net_list) > 0:
622 mgmt_net_id = mgmt_net_list[0]
623
624 if 'networks' in vm_info:
625 for network in vm_info['networks']:
626 port_id = network['iface_id']
627 port = drv.get_port(port_id)
628 if 'network_id' in port and mgmt_net_id == port['network_id'] and 'ip_address' in port:
629 vdu.management_ip = port['ip_address']
630 vdu.public_ip = vdu.management_ip
631 else:
632 c_point = vdu.connection_points.add()
633 RwcalOpenmanoVimConnector._fill_connection_point_info(c_point, port)
634
635
636 if vm_info['status'] == 'ACTIVE' and vdu.management_ip != '':
637 vdu.state = 'active'
638 elif vm_info['status'] == 'ERROR':
639 vdu.state = 'failed'
640 else:
641 vdu.state = 'inactive'
642
643 if vdu.flavor_id:
644 flavor = drv.get_flavor(vdu.flavor_id)
645 RwcalOpenmanoVimConnector._fill_epa_attributes(vdu, flavor)
646 return vdu
647
648 @rwstatus(ret_on_failure=[None])
649 def do_get_vdu(self, account, vdu_id):
650 with self._use_driver(account) as drv:
651 vm_info = drv.get_vminstance(vdu_id)
652 return RwcalOpenmanoVimConnector._fill_vdu_info(drv,account,vm_info)
653
654 @rwstatus(ret_on_failure=[""])
655 def do_get_vdu_list(self, account):
656 vnf_resource = RwcalYang.VNFResources()
657 with self._use_driver(account) as drv:
658 vms = drv.get_vminstance_list()
659 for vm in vms:
660 vm_info = drv.get_vminstance(vm['id'])
661 vdu = RwcalOpenmanoVimConnector._fill_vdu_info(drv,account,vm_info)
662 vnf_resource.vdu_info_list.append(vdu)
663 return vnf_resource
664