3 # Copyright 2016 RIFT.IO Inc
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
25 gi
.require_version('RwCal', '1.0')
26 gi
.require_version('RwcalYang', '1.0')
28 import rift
.rwcal
.openstack
as openstack_drv
32 import rift
.cal
.rwcal_status
as rwcal_status
36 from gi
.repository
import (
42 PREPARE_VM_CMD
= "prepare_vm.py --auth_url {auth_url} --username {username} --password {password} --tenant_name {tenant_name} --region {region} --user_domain {user_domain} --project_domain {project_domain} --mgmt_network {mgmt_network} --server_id {server_id} --port_metadata "
44 rwstatus_exception_map
= {IndexError: RwTypes
.RwStatus
.NOTFOUND
,
45 KeyError: RwTypes
.RwStatus
.NOTFOUND
,
46 NotImplementedError: RwTypes
.RwStatus
.NOT_IMPLEMENTED
, }
48 rwstatus
= rw_status
.rwstatus_from_exc_map(rwstatus_exception_map
)
49 rwcalstatus
= rwcal_status
.rwcalstatus_from_exc_map(rwstatus_exception_map
)
52 class OpenstackCALOperationFailure(Exception):
55 class UninitializedPluginError(Exception):
59 class OpenstackServerGroupError(Exception):
63 class ImageUploadError(Exception):
67 class RwcalAccountDriver(object):
69 Container class per cloud account
71 def __init__(self
, logger
, **kwargs
):
74 self
._driver
= openstack_drv
.OpenstackDriver(logger
= self
.log
, **kwargs
)
75 except Exception as e
:
76 self
.log
.error("RwcalOpenstackPlugin: OpenstackDriver init failed. Exception: %s" %(str(e
)))
83 class RwcalOpenstackPlugin(GObject
.Object
, RwCal
.Cloud
):
84 """This class implements the CAL VALA methods for openstack."""
89 GObject
.Object
.__init
__(self
)
90 self
.log
= logging
.getLogger('rwcal.openstack.%s' % RwcalOpenstackPlugin
.instance_num
)
91 self
.log
.setLevel(logging
.DEBUG
)
92 self
._rwlog
_handler
= None
93 self
._account
_drivers
= dict()
94 RwcalOpenstackPlugin
.instance_num
+= 1
96 def _get_account_key(self
, account
):
98 for f
in account
.openstack
.fields
:
100 key
+= str(getattr(account
.openstack
, f
))
106 def _use_driver(self
, account
):
107 if self
._rwlog
_handler
is None:
108 raise UninitializedPluginError("Must call init() in CAL plugin before use.")
110 acct_key
= self
._get
_account
_key
(account
)
112 if acct_key
not in self
._account
_drivers
:
113 self
.log
.debug("Creating OpenstackDriver")
114 kwargs
= dict(username
= account
.openstack
.key
,
115 password
= account
.openstack
.secret
,
116 auth_url
= account
.openstack
.auth_url
,
117 project
= account
.openstack
.tenant
,
118 mgmt_network
= account
.openstack
.mgmt_network
,
119 cert_validate
= account
.openstack
.cert_validate
,
120 user_domain
= account
.openstack
.user_domain
,
121 project_domain
= account
.openstack
.project_domain
,
122 region
= account
.openstack
.region
)
123 drv
= RwcalAccountDriver(self
.log
, **kwargs
)
124 self
._account
_drivers
[account
.name
] = drv
127 return self
._account
_drivers
[acct_key
].driver
131 def do_init(self
, rwlog_ctx
):
132 self
._rwlog
_handler
= rwlogger
.RwLogger(category
="rw-cal-log",
133 subcategory
="openstack",
135 self
.log
.addHandler(self
._rwlog
_handler
)
136 self
.log
.propagate
= False
138 @rwstatus(ret_on_failure
=[None])
139 def do_validate_cloud_creds(self
, account
):
141 Validates the cloud account credentials for the specified account.
142 Performs an access to the resources using Keystone API. If creds
143 are not valid, returns an error code & reason string
145 account - a cloud account to validate
148 Validation Code and Details String
150 status
= RwcalYang
.CloudConnectionStatus()
152 drv
= self
._use
_driver
(account
)
153 drv
.validate_account_creds()
154 except Exception as e
:
155 msg
= "RwcalOpenstackPlugin: Exception: %s" %(str(e
))
157 status
.status
= "failure"
161 status
.status
= "success"
162 status
.details
= "Connection was successful"
166 @rwstatus(ret_on_failure
=[""])
167 def do_get_management_network(self
, account
):
169 Returns the management network associated with the specified account.
171 account - a cloud account
174 The management network
176 return account
.openstack
.mgmt_network
178 @rwstatus(ret_on_failure
=[""])
179 def do_create_tenant(self
, account
, name
):
180 """Create a new tenant.
183 account - a cloud account
184 name - name of the tenant
189 raise NotImplementedError
192 def do_delete_tenant(self
, account
, tenant_id
):
196 account - a cloud account
197 tenant_id - id of the tenant
199 raise NotImplementedError
201 @rwstatus(ret_on_failure
=[[]])
202 def do_get_tenant_list(self
, account
):
206 account - a cloud account
211 raise NotImplementedError
213 @rwstatus(ret_on_failure
=[""])
214 def do_create_role(self
, account
, name
):
215 """Create a new user.
218 account - a cloud account
219 name - name of the user
224 raise NotImplementedError
227 def do_delete_role(self
, account
, role_id
):
231 account - a cloud account
232 role_id - id of the user
234 raise NotImplementedError
236 @rwstatus(ret_on_failure
=[[]])
237 def do_get_role_list(self
, account
):
241 account - a cloud account
246 raise NotImplementedError
248 @rwstatus(ret_on_failure
=[""])
249 def do_create_image(self
, account
, image
):
253 account - a cloud account
254 image - a description of the image to create
259 drv
= self
._use
_driver
(account
)
260 fd
= drv
.utils
.image
.create_image_handle(image
)
261 kwargs
= drv
.utils
.image
.make_image_args(image
)
265 image_id
= drv
.glance_image_create(**kwargs
)
266 drv
.glance_image_upload(image_id
, fd
)
267 except Exception as e
:
268 self
.log
.exception("Exception %s occured during image create", str(e
))
273 # Update image properties, if they are provided
275 if image
.has_field("properties") and image
.properties
is not None:
276 for key
in image
.properties
:
277 drv
.glance_image_update(image_id
, **{key
.name
: key
.property_value
})
278 except Exception as e
:
279 self
.log
.exception("Exception %s occured during image update", str(e
))
284 stored_image
= drv
.glance_image_get(image_id
)
285 if stored_image
.checksum
!= image
.checksum
:
286 drv
.glance_image_delete(image_id
=image_id
)
287 raise ImageUploadError("image checksum did not match (actual: %s, expected: %s). Deleting." %
288 (stored_image
.checksum
, image
.checksum
))
289 except Exception as e
:
290 self
.log
.exception("Exception %s occured during image checksum verification", str(e
))
296 def do_delete_image(self
, account
, image_id
):
297 """Delete a vm image.
300 account - a cloud account
301 image_id - id of the image to delete
303 drv
= self
._use
_driver
(account
)
305 drv
.glance_image_delete(image_id
=image_id
)
306 except Exception as e
:
307 self
.log
.exception("Exception %s occured during image deletion", str(e
))
311 @rwstatus(ret_on_failure
=[[]])
312 def do_get_image_list(self
, account
):
313 """Return a list of the names of all available images.
316 account - a cloud account
319 The the list of images in VimResources object
321 response
= RwcalYang
.VimResources()
322 drv
= self
._use
_driver
(account
)
324 images
= drv
.glance_image_list()
326 response
.imageinfo_list
.append(drv
.utils
.image
.parse_cloud_image_info(img
))
327 except Exception as e
:
328 self
.log
.exception("Exception %s occured during get-image-list", str(e
))
332 @rwstatus(ret_on_failure
=[None])
333 def do_get_image(self
, account
, image_id
):
334 """Return a image information.
337 account - a cloud account
338 image_id - an id of the image
341 ImageInfoItem object containing image information.
343 drv
= self
._use
_driver
(account
)
345 image_info
= drv
.glance_image_get(image_id
)
346 image
= drv
.utils
.image
.parse_cloud_image_info(image_info
)
347 except Exception as e
:
348 self
.log
.exception("Exception %s occured during get-image", str(e
))
353 # This is being deprecated. Please do not use for new SW development
354 @rwstatus(ret_on_failure
=[""])
355 def do_create_vm(self
, account
, vminfo
):
356 """Create a new virtual machine.
359 account - a cloud account
360 vminfo - information that defines the type of VM to create
365 from warnings
import warn
366 warn("This function is deprecated")
368 kwargs
['name'] = vminfo
.vm_name
369 kwargs
['flavor_id'] = vminfo
.flavor_id
370 if vminfo
.has_field('image_id'):
371 kwargs
['image_id'] = vminfo
.image_id
373 ### If floating_ip is required and we don't have one, better fail before any further allocation
375 if vminfo
.has_field('allocate_public_address') and vminfo
.allocate_public_address
:
378 if vminfo
.has_field('cloud_init') and vminfo
.cloud_init
.has_field('userdata'):
379 kwargs
['userdata'] = vminfo
.cloud_init
.userdata
381 kwargs
['userdata'] = ''
383 if account
.openstack
.security_groups
:
384 kwargs
['security_groups'] = account
.openstack
.security_groups
387 for port
in vminfo
.port_list
:
388 port_list
.append(port
.port_id
)
391 kwargs
['port_list'] = port_list
394 for network
in vminfo
.network_list
:
395 network_list
.append(network
.network_id
)
398 kwargs
['network_list'] = network_list
401 for field
in vminfo
.user_tags
.fields
:
402 if vminfo
.user_tags
.has_field(field
):
403 metadata
[field
] = getattr(vminfo
.user_tags
, field
)
404 kwargs
['metadata'] = metadata
406 if vminfo
.has_field('availability_zone'):
407 kwargs
['availability_zone'] = vminfo
.availability_zone
409 kwargs
['availability_zone'] = None
411 if vminfo
.has_field('server_group'):
412 kwargs
['scheduler_hints'] = {'group': vminfo
.server_group
}
414 kwargs
['scheduler_hints'] = None
416 drv
= self
._use
_driver
(account
)
417 vm_id
= drv
.nova_server_create(**kwargs
)
419 self
.prepare_vdu_on_boot(account
, vm_id
, floating_ip
)
424 def do_start_vm(self
, account
, vm_id
):
425 """Start an existing virtual machine.
428 account - a cloud account
429 vm_id - an id of the VM
431 drv
= self
._use
_driver
(account
)
432 drv
.nova_server_start(vm_id
)
435 def do_stop_vm(self
, account
, vm_id
):
436 """Stop a running virtual machine.
439 account - a cloud account
440 vm_id - an id of the VM
442 drv
= self
._use
_driver
(account
)
443 drv
.nova_server_stop(vm_id
)
446 def do_delete_vm(self
, account
, vm_id
):
447 """Delete a virtual machine.
450 account - a cloud account
451 vm_id - an id of the VM
453 drv
= self
._use
_driver
(account
)
454 drv
.nova_server_delete(vm_id
)
457 def do_reboot_vm(self
, account
, vm_id
):
458 """Reboot a virtual machine.
461 account - a cloud account
462 vm_id - an id of the VM
464 drv
= self
._use
_driver
(account
)
465 drv
.nova_server_reboot(vm_id
)
468 def _fill_vm_info(vm_info
, mgmt_network
):
469 """Create a GI object from vm info dictionary
471 Converts VM information dictionary object returned by openstack
472 driver into Protobuf Gi Object
475 vm_info - VM information from openstack
476 mgmt_network - Management network
479 Protobuf Gi object for VM
481 vm
= RwcalYang
.VMInfoItem()
482 vm
.vm_id
= vm_info
['id']
483 vm
.vm_name
= vm_info
['name']
484 vm
.image_id
= vm_info
['image']['id']
485 vm
.flavor_id
= vm_info
['flavor']['id']
486 vm
.state
= vm_info
['status']
487 for network_name
, network_info
in vm_info
['addresses'].items():
489 if network_name
== mgmt_network
:
490 vm
.public_ip
= next((item
['addr']
491 for item
in network_info
492 if item
['OS-EXT-IPS:type'] == 'floating'),
493 network_info
[0]['addr'])
494 vm
.management_ip
= network_info
[0]['addr']
496 for interface
in network_info
:
497 addr
= vm
.private_ip_list
.add()
498 addr
.ip_address
= interface
['addr']
500 for network_name
, network_info
in vm_info
['addresses'].items():
501 if network_info
and network_name
== mgmt_network
and not vm
.public_ip
:
502 for interface
in network_info
:
503 if 'OS-EXT-IPS:type' in interface
and interface
['OS-EXT-IPS:type'] == 'floating':
504 vm
.public_ip
= interface
['addr']
506 # Look for any metadata
507 for key
, value
in vm_info
['metadata'].items():
508 if key
in vm
.user_tags
.fields
:
509 setattr(vm
.user_tags
, key
, value
)
510 if 'OS-EXT-SRV-ATTR:host' in vm_info
:
511 if vm_info
['OS-EXT-SRV-ATTR:host'] is not None:
512 vm
.host_name
= vm_info
['OS-EXT-SRV-ATTR:host']
513 if 'OS-EXT-AZ:availability_zone' in vm_info
:
514 if vm_info
['OS-EXT-AZ:availability_zone'] is not None:
515 vm
.availability_zone
= vm_info
['OS-EXT-AZ:availability_zone']
518 @rwstatus(ret_on_failure
=[[]])
519 def do_get_vm_list(self
, account
):
520 """Return a list of the VMs as vala boxed objects
523 account - a cloud account
526 List containing VM information
528 response
= RwcalYang
.VimResources()
529 drv
= self
._use
_driver
(account
)
530 vms
= drv
.nova_server_list()
532 response
.vminfo_list
.append(RwcalOpenstackPlugin
._fill
_vm
_info
(vm
, account
.openstack
.mgmt_network
))
535 @rwstatus(ret_on_failure
=[None])
536 def do_get_vm(self
, account
, id):
537 """Return vm information.
540 account - a cloud account
541 id - an id for the VM
546 drv
= self
._use
_driver
(account
)
547 vm
= drv
.nova_server_get(id)
548 return RwcalOpenstackPlugin
._fill
_vm
_info
(vm
, account
.openstack
.mgmt_network
)
551 @rwstatus(ret_on_failure
=[""])
552 def do_create_flavor(self
, account
, flavor
):
553 """Create new flavor.
556 account - a cloud account
557 flavor - flavor of the VM
562 drv
= self
._use
_driver
(account
)
564 flavor_id
= drv
.nova_flavor_create(name
= flavor
.name
,
565 ram
= flavor
.vm_flavor
.memory_mb
,
566 vcpus
= flavor
.vm_flavor
.vcpu_count
,
567 disk
= flavor
.vm_flavor
.storage_gb
,
568 epa_specs
= drv
.utils
.flavor
.get_extra_specs(flavor
))
569 except Exception as e
:
570 self
.log
.error("Encountered exceptions during Flavor creation. Exception: %s", str(e
))
576 def do_delete_flavor(self
, account
, flavor_id
):
580 account - a cloud account
581 flavor_id - id flavor of the VM
583 drv
= self
._use
_driver
(account
)
585 drv
.nova_flavor_delete(flavor_id
)
586 except Exception as e
:
587 self
.log
.error("Encountered exceptions during Flavor deletion. Exception: %s", str(e
))
591 @rwstatus(ret_on_failure
=[[]])
592 def do_get_flavor_list(self
, account
):
593 """Return flavor information.
596 account - a cloud account
601 response
= RwcalYang
.VimResources()
602 drv
= self
._use
_driver
(account
)
604 flavors
= drv
.nova_flavor_list()
606 response
.flavorinfo_list
.append(drv
.utils
.flavor
.parse_flavor_info(flv
))
607 except Exception as e
:
608 self
.log
.error("Encountered exceptions during get-flavor-list. Exception: %s", str(e
))
613 @rwstatus(ret_on_failure
=[None])
614 def do_get_flavor(self
, account
, id):
615 """Return flavor information.
618 account - a cloud account
619 id - an id for the flavor
624 drv
= self
._use
_driver
(account
)
626 flavor
= drv
.nova_flavor_get(id)
627 response
= drv
.utils
.flavor
.parse_flavor_info(flavor
)
628 except Exception as e
:
629 self
.log
.error("Encountered exceptions during get-flavor. Exception: %s", str(e
))
635 def _fill_network_info(self
, network_info
, account
):
636 """Create a GI object from network info dictionary
638 Converts Network information dictionary object returned by openstack
639 driver into Protobuf Gi Object
642 network_info - Network information from openstack
643 account - a cloud account
648 network
= RwcalYang
.NetworkInfoItem()
649 network
.network_name
= network_info
['name']
650 network
.network_id
= network_info
['id']
651 if ('provider:network_type' in network_info
) and (network_info
['provider:network_type'] is not None):
652 network
.provider_network
.overlay_type
= network_info
['provider:network_type'].upper()
653 if ('provider:segmentation_id' in network_info
) and (network_info
['provider:segmentation_id']):
654 network
.provider_network
.segmentation_id
= network_info
['provider:segmentation_id']
655 if ('provider:physical_network' in network_info
) and (network_info
['provider:physical_network']):
656 network
.provider_network
.physical_network
= network_info
['provider:physical_network'].upper()
658 if 'subnets' in network_info
and network_info
['subnets']:
659 subnet_id
= network_info
['subnets'][0]
660 drv
= self
._use
_driver
(account
)
661 subnet
= drv
.neutron_subnet_get(subnet_id
)
662 network
.subnet
= subnet
['cidr']
665 @rwstatus(ret_on_failure
=[[]])
666 def do_get_network_list(self
, account
):
667 """Return a list of networks
670 account - a cloud account
675 response
= RwcalYang
.VimResources()
676 drv
= self
._use
_driver
(account
)
677 networks
= drv
.neutron_network_list()
678 for network
in networks
:
679 response
.networkinfo_list
.append(self
._fill
_network
_info
(network
, account
))
682 @rwstatus(ret_on_failure
=[None])
683 def do_get_network(self
, account
, id):
687 account - a cloud account
688 id - an id for the network
693 drv
= self
._use
_driver
(account
)
694 network
= drv
.neutron_network_get(id)
695 return self
._fill
_network
_info
(network
, account
)
697 @rwstatus(ret_on_failure
=[""])
698 def do_create_network(self
, account
, network
):
699 """Create a new network
702 account - a cloud account
703 network - Network object
708 from warnings
import warn
709 warn("This function is deprecated")
712 kwargs
['name'] = network
.network_name
713 kwargs
['admin_state_up'] = True
714 kwargs
['external_router'] = False
715 kwargs
['shared'] = False
717 if network
.has_field('provider_network'):
718 if network
.provider_network
.has_field('physical_network'):
719 kwargs
['physical_network'] = network
.provider_network
.physical_network
720 if network
.provider_network
.has_field('overlay_type'):
721 kwargs
['network_type'] = network
.provider_network
.overlay_type
.lower()
722 if network
.provider_network
.has_field('segmentation_id'):
723 kwargs
['segmentation_id'] = network
.provider_network
.segmentation_id
725 drv
= self
._use
_driver
(account
)
726 network_id
= drv
.neutron_network_create(**kwargs
)
727 drv
.neutron_subnet_create(network_id
= network_id
,
728 cidr
= network
.subnet
)
732 def do_delete_network(self
, account
, network_id
):
736 account - a cloud account
737 network_id - an id for the network
739 drv
= self
._use
_driver
(account
)
740 drv
.neutron_network_delete(network_id
)
743 def _fill_port_info(port_info
):
744 """Create a GI object from port info dictionary
746 Converts Port information dictionary object returned by openstack
747 driver into Protobuf Gi Object
750 port_info - Port information from openstack
755 port
= RwcalYang
.PortInfoItem()
757 port
.port_name
= port_info
['name']
758 port
.port_id
= port_info
['id']
759 port
.network_id
= port_info
['network_id']
760 port
.port_state
= port_info
['status']
761 if 'device_id' in port_info
:
762 port
.vm_id
= port_info
['device_id']
763 if 'fixed_ips' in port_info
:
764 port
.ip_address
= port_info
['fixed_ips'][0]['ip_address']
767 @rwstatus(ret_on_failure
=[None])
768 def do_get_port(self
, account
, port_id
):
772 account - a cloud account
773 port_id - an id for the port
778 drv
= self
._use
_driver
(account
)
779 port
= drv
.neutron_port_get(port_id
)
780 return RwcalOpenstackPlugin
._fill
_port
_info
(port
)
782 @rwstatus(ret_on_failure
=[[]])
783 def do_get_port_list(self
, account
):
784 """Return a list of ports
787 account - a cloud account
792 response
= RwcalYang
.VimResources()
793 drv
= self
._use
_driver
(account
)
794 ports
= drv
.neutron_port_list(*{})
796 response
.portinfo_list
.append(RwcalOpenstackPlugin
._fill
_port
_info
(port
))
799 @rwstatus(ret_on_failure
=[""])
800 def do_create_port(self
, account
, port
):
804 account - a cloud account
810 from warnings
import warn
811 warn("This function is deprecated")
814 kwargs
['name'] = port
.port_name
815 kwargs
['network_id'] = port
.network_id
816 kwargs
['admin_state_up'] = True
817 if port
.has_field('vm_id'):
818 kwargs
['vm_id'] = port
.vm_id
819 if port
.has_field('port_type'):
820 kwargs
['port_type'] = port
.port_type
822 kwargs
['port_type'] = "normal"
824 drv
= self
._use
_driver
(account
)
825 return drv
.neutron_port_create(**kwargs
)
828 def do_delete_port(self
, account
, port_id
):
832 account - a cloud account
833 port_id - an id for port
835 drv
= self
._use
_driver
(account
)
836 drv
.neutron_port_delete(port_id
)
838 @rwstatus(ret_on_failure
=[""])
839 def do_add_host(self
, account
, host
):
843 account - a cloud account
849 raise NotImplementedError
852 def do_remove_host(self
, account
, host_id
):
856 account - a cloud account
857 host_id - an id for the host
859 raise NotImplementedError
861 @rwstatus(ret_on_failure
=[None])
862 def do_get_host(self
, account
, host_id
):
866 account - a cloud account
867 host_id - an id for host
872 raise NotImplementedError
874 @rwstatus(ret_on_failure
=[[]])
875 def do_get_host_list(self
, account
):
876 """Return a list of hosts
879 account - a cloud account
884 raise NotImplementedError
887 @rwcalstatus(ret_on_failure
=[""])
888 def do_create_virtual_link(self
, account
, link_params
):
889 """Create a new virtual link
892 account - a cloud account
893 link_params - information that defines the type of VDU to create
896 A kwargs dictionary for glance operation
899 drv
= self
._use
_driver
(account
)
901 kwargs
= drv
.utils
.network
.make_virtual_link_args(link_params
)
902 network_id
= drv
.neutron_network_create(**kwargs
)
903 kwargs
= drv
.utils
.network
.make_subnet_args(link_params
, network_id
)
904 drv
.neutron_subnet_create(**kwargs
)
905 except Exception as e
:
906 self
.log
.error("Encountered exceptions during network creation. Exception: %s", str(e
))
907 # This is to delete the network if neutron_subnet_create fails after creation of network
908 # Note:- Any subnet created will be implicitly deleted.
910 drv
.neutron_network_delete(network_id
)
911 except Exception as delete_exception
:
912 self
.log
.debug("Exception while deleting the network after failure of neutron_subnet_create or make_subnet_args: %s", str(delete_exception
))
918 def do_delete_virtual_link(self
, account
, link_id
):
919 """Delete a virtual link
922 account - a cloud account
923 link_id - id for the virtual-link to be deleted
928 drv
= self
._use
_driver
(account
)
930 port_list
= drv
.neutron_port_list(**{'network_id': link_id
})
931 for port
in port_list
:
932 if ((port
['device_owner'] == 'compute:None') or (port
['device_owner'] == '')):
933 self
.do_delete_port(account
, port
['id'], no_rwstatus
=True)
934 self
.do_delete_network(account
, link_id
, no_rwstatus
=True)
935 except Exception as e
:
936 self
.log
.exception("Exception %s occured during virtual-link deletion", str(e
))
939 @rwstatus(ret_on_failure
=[None])
940 def do_get_virtual_link(self
, account
, link_id
):
941 """Get information about virtual link.
944 account - a cloud account
945 link_id - id for the virtual-link
948 Object of type RwcalYang.VirtualLinkInfoParams
950 drv
= self
._use
_driver
(account
)
952 network
= drv
.neutron_network_get(link_id
)
954 port_list
= drv
.neutron_port_list(**{'network_id': network
['id']})
955 if 'subnets' in network
and network
['subnets']:
956 subnet
= drv
.neutron_subnet_get(network
['subnets'][0])
959 virtual_link
= drv
.utils
.network
.parse_cloud_virtual_link_info(network
, port_list
, subnet
)
960 except Exception as e
:
961 self
.log
.exception("Exception %s occured during virtual-link-get", str(e
))
965 @rwstatus(ret_on_failure
=[None])
966 def do_get_virtual_link_list(self
, account
):
967 """Get information about all the virtual links
970 account - a cloud account
973 A list of objects of type RwcalYang.VirtualLinkInfoParams
975 vnf_resources
= RwcalYang
.VNFResources()
976 drv
= self
._use
_driver
(account
)
978 networks
= drv
.neutron_network_list()
979 for network
in networks
:
980 port_list
= drv
.neutron_port_list(**{'network_id': network
['id']})
981 if 'subnets' in network
and network
['subnets']:
982 subnet
= drv
.neutron_subnet_get(network
['subnets'][0])
985 virtual_link
= drv
.utils
.network
.parse_cloud_virtual_link_info(network
, port_list
, subnet
)
986 vnf_resources
.virtual_link_info_list
.append(virtual_link
)
987 except Exception as e
:
988 self
.log
.exception("Exception %s occured during virtual-link-list-get", str(e
))
994 @rwcalstatus(ret_on_failure
=[""])
995 def do_create_vdu(self
, account
, vdu_init
):
996 """Create a new virtual deployment unit
999 account - a cloud account
1000 vdu_init - information about VDU to create (RwcalYang.VDUInitParams)
1005 drv
= self
._use
_driver
(account
)
1007 kwargs
= drv
.utils
.compute
.make_vdu_create_args(vdu_init
, account
)
1008 vm_id
= drv
.nova_server_create(**kwargs
)
1009 self
.prepare_vdu_on_boot(account
, vm_id
, vdu_init
)
1010 except Exception as e
:
1011 self
.log
.exception("Exception %s occured during create-vdu", str(e
))
1016 def prepare_vdu_on_boot(self
, account
, server_id
, vdu_params
):
1017 cmd
= PREPARE_VM_CMD
.format(auth_url
= account
.openstack
.auth_url
,
1018 username
= account
.openstack
.key
,
1019 password
= account
.openstack
.secret
,
1020 tenant_name
= account
.openstack
.tenant
,
1021 region
= account
.openstack
.region
,
1022 user_domain
= account
.openstack
.user_domain
,
1023 project_domain
= account
.openstack
.project_domain
,
1024 mgmt_network
= account
.openstack
.mgmt_network
,
1025 server_id
= server_id
)
1028 if vdu_params
.has_field('allocate_public_address') and vdu_params
.allocate_public_address
:
1029 cmd
+= " --floating_ip"
1030 if account
.openstack
.has_field('floating_ip_pool'):
1031 cmd
+= (" --pool_name " + account
.openstack
.floating_ip_pool
)
1033 if vdu_params
.has_field('volumes'):
1034 for volume
in vdu_params
.volumes
:
1035 if volume
.has_field('custom_meta_data'):
1036 vol_list
.append(volume
.as_dict())
1039 with tempfile
.NamedTemporaryFile(mode
='w', delete
=False) as tmp_file
:
1040 yaml
.dump(vol_list
, tmp_file
)
1041 cmd
+= (" --vol_metadata {}").format(tmp_file
.name
)
1043 exec_path
= 'python3 ' + os
.path
.dirname(openstack_drv
.__file
__)
1044 exec_cmd
= exec_path
+ '/' + cmd
1045 self
.log
.info("Running command: %s" %(exec_cmd))
1046 subprocess
.call(exec_cmd
, shell
=True)
1049 def do_modify_vdu(self
, account
, vdu_modify
):
1050 """Modify Properties of existing virtual deployment unit
1053 account - a cloud account
1054 vdu_modify - Information about VDU Modification (RwcalYang.VDUModifyParams)
1056 drv
= self
._use
_driver
(account
)
1057 ### First create required number of ports aka connection points
1060 for c_point
in vdu_modify
.connection_points_add
:
1061 if c_point
.virtual_link_id
in network_list
:
1062 assert False, "Only one port per network supported. Refer: http://specs.openstack.org/openstack/nova-specs/specs/juno/implemented/nfv-multiple-if-1-net.html"
1064 network_list
.append(c_point
.virtual_link_id
)
1065 port_id
= self
._create
_connection
_point
(account
, c_point
)
1066 port_list
.append(port_id
)
1068 drv
= self
._use
_driver
(account
)
1069 ### Now add the ports to VM
1070 for port_id
in port_list
:
1071 drv
.nova_server_add_port(vdu_modify
.vdu_id
, port_id
)
1073 ### Delete the requested connection_points
1074 for c_point
in vdu_modify
.connection_points_remove
:
1075 self
.do_delete_port(account
, c_point
.connection_point_id
, no_rwstatus
=True)
1077 if vdu_modify
.has_field('image_id'):
1078 drv
.nova_server_rebuild(vdu_modify
.vdu_id
, vdu_modify
.image_id
)
1082 def do_delete_vdu(self
, account
, vdu_id
):
1083 """Delete a virtual deployment unit
1086 account - a cloud account
1087 vdu_id - id for the vdu to be deleted
1092 drv
= self
._use
_driver
(account
)
1094 drv
.utils
.compute
.perform_vdu_network_cleanup(vdu_id
)
1095 drv
.nova_server_delete(vdu_id
)
1096 except Exception as e
:
1097 self
.log
.exception("Exception %s occured during delete-vdu", str(e
))
1101 @rwstatus(ret_on_failure
=[None])
1102 def do_get_vdu(self
, account
, vdu_id
):
1103 """Get information about a virtual deployment unit.
1106 account - a cloud account
1107 vdu_id - id for the vdu
1110 Object of type RwcalYang.VDUInfoParams
1112 drv
= self
._use
_driver
(account
)
1114 vm_info
= drv
.nova_server_get(vdu_id
)
1115 vdu_info
= drv
.utils
.compute
.parse_cloud_vdu_info(vm_info
)
1116 except Exception as e
:
1117 self
.log
.exception("Exception %s occured during get-vdu", str(e
))
1123 @rwstatus(ret_on_failure
=[None])
1124 def do_get_vdu_list(self
, account
):
1125 """Get information about all the virtual deployment units
1128 account - a cloud account
1131 A list of objects of type RwcalYang.VDUInfoParams
1133 vnf_resources
= RwcalYang
.VNFResources()
1134 drv
= self
._use
_driver
(account
)
1136 vms
= drv
.nova_server_list()
1138 vdu
= drv
.utils
.compute
.parse_cloud_vdu_info(vm
)
1139 vnf_resources
.vdu_info_list
.append(vdu
)
1140 except Exception as e
:
1141 self
.log
.exception("Exception %s occured during get-vdu-list", str(e
))
1143 return vnf_resources