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.
26 gi
.require_version('RwCal', '1.0')
27 gi
.require_version('RwcalYang', '1.0')
29 import rift
.rwcal
.openstack
as openstack_drv
33 import rift
.cal
.rwcal_status
as rwcal_status
37 from gi
.repository
import (
43 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 "
45 rwstatus_exception_map
= {IndexError: RwTypes
.RwStatus
.NOTFOUND
,
46 KeyError: RwTypes
.RwStatus
.NOTFOUND
,
47 NotImplementedError: RwTypes
.RwStatus
.NOT_IMPLEMENTED
, }
49 rwstatus
= rw_status
.rwstatus_from_exc_map(rwstatus_exception_map
)
50 rwcalstatus
= rwcal_status
.rwcalstatus_from_exc_map(rwstatus_exception_map
)
53 class OpenstackCALOperationFailure(Exception):
56 class UninitializedPluginError(Exception):
60 class OpenstackServerGroupError(Exception):
64 class ImageUploadError(Exception):
67 class PrepareVduOnBoot(Exception):
70 class RwcalAccountDriver(object):
72 Container class per cloud account
74 def __init__(self
, logger
, **kwargs
):
77 self
._driver
= openstack_drv
.OpenstackDriver(logger
= self
.log
, **kwargs
)
78 except Exception as e
:
79 self
.log
.error("RwcalOpenstackPlugin: OpenstackDriver init failed. Exception: %s" %(str(e
)))
86 class RwcalOpenstackPlugin(GObject
.Object
, RwCal
.Cloud
):
87 """This class implements the CAL VALA methods for openstack."""
92 GObject
.Object
.__init
__(self
)
93 self
.log
= logging
.getLogger('rwcal.openstack.%s' % RwcalOpenstackPlugin
.instance_num
)
94 self
.log
.setLevel(logging
.DEBUG
)
95 self
._rwlog
_handler
= None
96 self
._account
_drivers
= dict()
97 RwcalOpenstackPlugin
.instance_num
+= 1
99 def _get_account_key(self
, account
):
101 for f
in account
.openstack
.fields
:
103 key
+= str(getattr(account
.openstack
, f
))
109 def _use_driver(self
, account
):
110 if self
._rwlog
_handler
is None:
111 raise UninitializedPluginError("Must call init() in CAL plugin before use.")
113 acct_key
= self
._get
_account
_key
(account
)
115 if acct_key
not in self
._account
_drivers
:
116 self
.log
.debug("Creating OpenstackDriver")
117 kwargs
= dict(username
= account
.openstack
.key
,
118 password
= account
.openstack
.secret
,
119 auth_url
= account
.openstack
.auth_url
,
120 project
= account
.openstack
.tenant
,
121 mgmt_network
= account
.openstack
.mgmt_network
,
122 cert_validate
= account
.openstack
.cert_validate
,
123 user_domain
= account
.openstack
.user_domain
,
124 project_domain
= account
.openstack
.project_domain
,
125 region
= account
.openstack
.region
)
126 drv
= RwcalAccountDriver(self
.log
, **kwargs
)
127 self
._account
_drivers
[account
.name
] = drv
130 return self
._account
_drivers
[acct_key
].driver
134 def do_init(self
, rwlog_ctx
):
135 self
._rwlog
_handler
= rwlogger
.RwLogger(category
="rw-cal-log",
136 subcategory
="openstack",
138 self
.log
.addHandler(self
._rwlog
_handler
)
139 self
.log
.propagate
= False
141 @rwstatus(ret_on_failure
=[None])
142 def do_validate_cloud_creds(self
, account
):
144 Validates the cloud account credentials for the specified account.
145 Performs an access to the resources using Keystone API. If creds
146 are not valid, returns an error code & reason string
148 account - a cloud account to validate
151 Validation Code and Details String
153 status
= RwcalYang
.YangData_Rwcal_ConnectionStatus()
155 drv
= self
._use
_driver
(account
)
156 drv
.validate_account_creds()
157 except Exception as e
:
158 msg
= "RwcalOpenstackPlugin: Exception: %s" %(str(e
))
160 status
.status
= "failure"
164 status
.status
= "success"
165 status
.details
= "Connection was successful"
169 @rwstatus(ret_on_failure
=[""])
170 def do_get_management_network(self
, account
):
172 Returns the management network associated with the specified account.
174 account - a cloud account
177 The management network
179 return account
.openstack
.mgmt_network
181 @rwstatus(ret_on_failure
=[""])
182 def do_create_tenant(self
, account
, name
):
183 """Create a new tenant.
186 account - a cloud account
187 name - name of the tenant
192 raise NotImplementedError
195 def do_delete_tenant(self
, account
, tenant_id
):
199 account - a cloud account
200 tenant_id - id of the tenant
202 raise NotImplementedError
204 @rwstatus(ret_on_failure
=[[]])
205 def do_get_tenant_list(self
, account
):
209 account - a cloud account
214 raise NotImplementedError
216 @rwstatus(ret_on_failure
=[""])
217 def do_create_role(self
, account
, name
):
218 """Create a new user.
221 account - a cloud account
222 name - name of the user
227 raise NotImplementedError
230 def do_delete_role(self
, account
, role_id
):
234 account - a cloud account
235 role_id - id of the user
237 raise NotImplementedError
239 @rwstatus(ret_on_failure
=[[]])
240 def do_get_role_list(self
, account
):
244 account - a cloud account
249 raise NotImplementedError
251 @rwstatus(ret_on_failure
=[""])
252 def do_create_image(self
, account
, image
):
256 account - a cloud account
257 image - a description of the image to create
262 drv
= self
._use
_driver
(account
)
263 fd
= drv
.utils
.image
.create_image_handle(image
)
264 kwargs
= drv
.utils
.image
.make_image_args(image
)
268 image_id
= drv
.glance_image_create(**kwargs
)
269 drv
.glance_image_upload(image_id
, fd
)
270 except Exception as e
:
271 self
.log
.exception("Exception %s occured during image create", str(e
))
276 # Update image properties, if they are provided
278 if image
.has_field("properties") and image
.properties
is not None:
279 for key
in image
.properties
:
280 drv
.glance_image_update(image_id
, **{key
.name
: key
.property_value
})
281 except Exception as e
:
282 self
.log
.exception("Exception %s occured during image update", str(e
))
287 stored_image
= drv
.glance_image_get(image_id
)
288 if stored_image
.checksum
!= image
.checksum
:
289 drv
.glance_image_delete(image_id
=image_id
)
290 raise ImageUploadError("image checksum did not match (actual: %s, expected: %s). Deleting." %
291 (stored_image
.checksum
, image
.checksum
))
292 except Exception as e
:
293 self
.log
.exception("Exception %s occured during image checksum verification", str(e
))
299 def do_delete_image(self
, account
, image_id
):
300 """Delete a vm image.
303 account - a cloud account
304 image_id - id of the image to delete
306 drv
= self
._use
_driver
(account
)
308 drv
.glance_image_delete(image_id
=image_id
)
309 except Exception as e
:
310 self
.log
.exception("Exception %s occured during image deletion", str(e
))
314 @rwstatus(ret_on_failure
=[[]])
315 def do_get_image_list(self
, account
):
316 """Return a list of the names of all available images.
319 account - a cloud account
322 The the list of images in VimResources object
324 response
= RwcalYang
.YangData_RwProject_Project_VimResources()
325 drv
= self
._use
_driver
(account
)
327 images
= drv
.glance_image_list()
329 response
.imageinfo_list
.append(drv
.utils
.image
.parse_cloud_image_info(img
))
330 except Exception as e
:
331 self
.log
.exception("Exception %s occured during get-image-list", str(e
))
335 @rwstatus(ret_on_failure
=[None])
336 def do_get_image(self
, account
, image_id
):
337 """Return a image information.
340 account - a cloud account
341 image_id - an id of the image
344 ImageInfoItem object containing image information.
346 drv
= self
._use
_driver
(account
)
348 image_info
= drv
.glance_image_get(image_id
)
349 image
= drv
.utils
.image
.parse_cloud_image_info(image_info
)
350 except Exception as e
:
351 self
.log
.exception("Exception %s occured during get-image", str(e
))
356 # This is being deprecated. Please do not use for new SW development
357 @rwstatus(ret_on_failure
=[""])
358 def do_create_vm(self
, account
, vminfo
):
359 """Create a new virtual machine.
362 account - a cloud account
363 vminfo - information that defines the type of VM to create
368 from warnings
import warn
369 warn("This function is deprecated")
371 kwargs
['name'] = vminfo
.vm_name
372 kwargs
['flavor_id'] = vminfo
.flavor_id
373 if vminfo
.has_field('image_id'):
374 kwargs
['image_id'] = vminfo
.image_id
376 ### If floating_ip is required and we don't have one, better fail before any further allocation
378 if vminfo
.has_field('allocate_public_address') and vminfo
.allocate_public_address
:
381 if vminfo
.has_field('cloud_init') and vminfo
.cloud_init
.has_field('userdata'):
382 kwargs
['userdata'] = vminfo
.cloud_init
.userdata
384 kwargs
['userdata'] = ''
386 if account
.openstack
.security_groups
:
387 kwargs
['security_groups'] = account
.openstack
.security_groups
390 for port
in vminfo
.port_list
:
391 port_list
.append(port
.port_id
)
394 kwargs
['port_list'] = port_list
397 for network
in vminfo
.network_list
:
398 network_list
.append(network
.network_id
)
401 kwargs
['network_list'] = network_list
404 for field
in vminfo
.user_tags
.fields
:
405 if vminfo
.user_tags
.has_field(field
):
406 metadata
[field
] = getattr(vminfo
.user_tags
, field
)
407 kwargs
['metadata'] = metadata
409 if vminfo
.has_field('availability_zone'):
410 kwargs
['availability_zone'] = vminfo
.availability_zone
412 kwargs
['availability_zone'] = None
414 if vminfo
.has_field('server_group'):
415 kwargs
['scheduler_hints'] = {'group': vminfo
.server_group
}
417 kwargs
['scheduler_hints'] = None
419 drv
= self
._use
_driver
(account
)
420 vm_id
= drv
.nova_server_create(**kwargs
)
422 self
.prepare_vdu_on_boot(account
, vm_id
, floating_ip
)
427 def do_start_vm(self
, account
, vm_id
):
428 """Start an existing virtual machine.
431 account - a cloud account
432 vm_id - an id of the VM
434 drv
= self
._use
_driver
(account
)
435 drv
.nova_server_start(vm_id
)
438 def do_stop_vm(self
, account
, vm_id
):
439 """Stop a running virtual machine.
442 account - a cloud account
443 vm_id - an id of the VM
445 drv
= self
._use
_driver
(account
)
446 drv
.nova_server_stop(vm_id
)
449 def do_delete_vm(self
, account
, vm_id
):
450 """Delete a virtual machine.
453 account - a cloud account
454 vm_id - an id of the VM
456 drv
= self
._use
_driver
(account
)
457 drv
.nova_server_delete(vm_id
)
460 def do_reboot_vm(self
, account
, vm_id
):
461 """Reboot a virtual machine.
464 account - a cloud account
465 vm_id - an id of the VM
467 drv
= self
._use
_driver
(account
)
468 drv
.nova_server_reboot(vm_id
)
471 def _fill_vm_info(vm_info
, mgmt_network
):
472 """Create a GI object from vm info dictionary
474 Converts VM information dictionary object returned by openstack
475 driver into Protobuf Gi Object
478 vm_info - VM information from openstack
479 mgmt_network - Management network
482 Protobuf Gi object for VM
484 vm
= RwcalYang
.YangData_RwProject_Project_VimResources_VminfoList()
485 vm
.vm_id
= vm_info
['id']
486 vm
.vm_name
= vm_info
['name']
487 vm
.image_id
= vm_info
['image']['id']
488 vm
.flavor_id
= vm_info
['flavor']['id']
489 vm
.state
= vm_info
['status']
490 for network_name
, network_info
in vm_info
['addresses'].items():
492 if network_name
== mgmt_network
:
493 vm
.public_ip
= next((item
['addr']
494 for item
in network_info
495 if item
['OS-EXT-IPS:type'] == 'floating'),
496 network_info
[0]['addr'])
497 vm
.management_ip
= network_info
[0]['addr']
499 for interface
in network_info
:
500 addr
= vm
.private_ip_list
.add()
501 addr
.ip_address
= interface
['addr']
503 for network_name
, network_info
in vm_info
['addresses'].items():
504 if network_info
and network_name
== mgmt_network
and not vm
.public_ip
:
505 for interface
in network_info
:
506 if 'OS-EXT-IPS:type' in interface
and interface
['OS-EXT-IPS:type'] == 'floating':
507 vm
.public_ip
= interface
['addr']
509 # Look for any metadata
510 for key
, value
in vm_info
['metadata'].items():
511 if key
in vm
.user_tags
.fields
:
512 setattr(vm
.user_tags
, key
, value
)
513 if 'OS-EXT-SRV-ATTR:host' in vm_info
:
514 if vm_info
['OS-EXT-SRV-ATTR:host'] is not None:
515 vm
.host_name
= vm_info
['OS-EXT-SRV-ATTR:host']
516 if 'OS-EXT-AZ:availability_zone' in vm_info
:
517 if vm_info
['OS-EXT-AZ:availability_zone'] is not None:
518 vm
.availability_zone
= vm_info
['OS-EXT-AZ:availability_zone']
521 @rwstatus(ret_on_failure
=[[]])
522 def do_get_vm_list(self
, account
):
523 """Return a list of the VMs as vala boxed objects
526 account - a cloud account
529 List containing VM information
531 response
= RwcalYang
.YangData_RwProject_Project_VimResources()
532 drv
= self
._use
_driver
(account
)
533 vms
= drv
.nova_server_list()
535 response
.vminfo_list
.append(RwcalOpenstackPlugin
._fill
_vm
_info
(vm
, account
.openstack
.mgmt_network
))
538 @rwstatus(ret_on_failure
=[None])
539 def do_get_vm(self
, account
, id):
540 """Return vm information.
543 account - a cloud account
544 id - an id for the VM
549 drv
= self
._use
_driver
(account
)
550 vm
= drv
.nova_server_get(id)
551 return RwcalOpenstackPlugin
._fill
_vm
_info
(vm
, account
.openstack
.mgmt_network
)
554 @rwstatus(ret_on_failure
=[""])
555 def do_create_flavor(self
, account
, flavor
):
556 """Create new flavor.
559 account - a cloud account
560 flavor - flavor of the VM
565 drv
= self
._use
_driver
(account
)
567 flavor_id
= drv
.nova_flavor_create(name
= flavor
.name
,
568 ram
= flavor
.vm_flavor
.memory_mb
,
569 vcpus
= flavor
.vm_flavor
.vcpu_count
,
570 disk
= flavor
.vm_flavor
.storage_gb
,
571 epa_specs
= drv
.utils
.flavor
.get_extra_specs(flavor
))
572 except Exception as e
:
573 self
.log
.error("Encountered exceptions during Flavor creation. Exception: %s", str(e
))
579 def do_delete_flavor(self
, account
, flavor_id
):
583 account - a cloud account
584 flavor_id - id flavor of the VM
586 drv
= self
._use
_driver
(account
)
588 drv
.nova_flavor_delete(flavor_id
)
589 except Exception as e
:
590 self
.log
.error("Encountered exceptions during Flavor deletion. Exception: %s", str(e
))
594 @rwstatus(ret_on_failure
=[[]])
595 def do_get_flavor_list(self
, account
):
596 """Return flavor information.
599 account - a cloud account
604 response
= RwcalYang
.YangData_RwProject_Project_VimResources()
605 drv
= self
._use
_driver
(account
)
607 flavors
= drv
.nova_flavor_list()
609 response
.flavorinfo_list
.append(drv
.utils
.flavor
.parse_flavor_info(flv
))
610 except Exception as e
:
611 self
.log
.error("Encountered exceptions during get-flavor-list. Exception: %s", str(e
))
616 @rwstatus(ret_on_failure
=[None])
617 def do_get_flavor(self
, account
, id):
618 """Return flavor information.
621 account - a cloud account
622 id - an id for the flavor
627 drv
= self
._use
_driver
(account
)
629 flavor
= drv
.nova_flavor_get(id)
630 response
= drv
.utils
.flavor
.parse_flavor_info(flavor
)
631 except Exception as e
:
632 self
.log
.error("Encountered exceptions during get-flavor. Exception: %s", str(e
))
638 def _fill_network_info(self
, network_info
, account
):
639 """Create a GI object from network info dictionary
641 Converts Network information dictionary object returned by openstack
642 driver into Protobuf Gi Object
645 network_info - Network information from openstack
646 account - a cloud account
651 network
= RwcalYang
.YangData_RwProject_Project_VimResources_NetworkinfoList()
652 network
.network_name
= network_info
['name']
653 network
.network_id
= network_info
['id']
654 if ('provider:network_type' in network_info
) and (network_info
['provider:network_type'] is not None):
655 network
.provider_network
.overlay_type
= network_info
['provider:network_type'].upper()
656 if ('provider:segmentation_id' in network_info
) and (network_info
['provider:segmentation_id']):
657 network
.provider_network
.segmentation_id
= network_info
['provider:segmentation_id']
658 if ('provider:physical_network' in network_info
) and (network_info
['provider:physical_network']):
659 network
.provider_network
.physical_network
= network_info
['provider:physical_network'].upper()
661 if 'subnets' in network_info
and network_info
['subnets']:
662 subnet_id
= network_info
['subnets'][0]
663 drv
= self
._use
_driver
(account
)
664 subnet
= drv
.neutron_subnet_get(subnet_id
)
665 network
.subnet
= subnet
['cidr']
668 @rwstatus(ret_on_failure
=[[]])
669 def do_get_network_list(self
, account
):
670 """Return a list of networks
673 account - a cloud account
678 response
= RwcalYang
.YangData_RwProject_Project_VimResources()
679 drv
= self
._use
_driver
(account
)
680 networks
= drv
.neutron_network_list()
681 for network
in networks
:
682 response
.networkinfo_list
.append(self
._fill
_network
_info
(network
, account
))
685 @rwstatus(ret_on_failure
=[None])
686 def do_get_network(self
, account
, id):
690 account - a cloud account
691 id - an id for the network
696 drv
= self
._use
_driver
(account
)
697 network
= drv
.neutron_network_get(id)
698 return self
._fill
_network
_info
(network
, account
)
700 @rwstatus(ret_on_failure
=[""])
701 def do_create_network(self
, account
, network
):
702 """Create a new network
705 account - a cloud account
706 network - Network object
711 from warnings
import warn
712 warn("This function is deprecated")
715 kwargs
['name'] = network
.network_name
716 kwargs
['admin_state_up'] = True
717 kwargs
['external_router'] = False
718 kwargs
['shared'] = False
720 if network
.has_field('provider_network'):
721 if network
.provider_network
.has_field('physical_network'):
722 kwargs
['physical_network'] = network
.provider_network
.physical_network
723 if network
.provider_network
.has_field('overlay_type'):
724 kwargs
['network_type'] = network
.provider_network
.overlay_type
.lower()
725 if network
.provider_network
.has_field('segmentation_id'):
726 kwargs
['segmentation_id'] = network
.provider_network
.segmentation_id
729 drv
= self
._use
_driver
(account
)
730 network_id
= drv
.neutron_network_create(**kwargs
)
731 drv
.neutron_subnet_create(network_id
= network_id
,
732 cidr
= network
.subnet
)
733 except Exception as e
:
734 self
.log
.exception("Exception %s occured during create-network", str(e
))
740 def do_delete_network(self
, account
, network_id
):
744 account - a cloud account
745 network_id - an id for the network
747 drv
= self
._use
_driver
(account
)
748 drv
.neutron_network_delete(network_id
)
751 def _fill_port_info(port_info
):
752 """Create a GI object from port info dictionary
754 Converts Port information dictionary object returned by openstack
755 driver into Protobuf Gi Object
758 port_info - Port information from openstack
763 port
= RwcalYang
.YangData_RwProject_Project_VimResources_PortinfoList()
765 port
.port_name
= port_info
['name']
766 port
.port_id
= port_info
['id']
767 port
.network_id
= port_info
['network_id']
768 port
.port_state
= port_info
['status']
769 if 'device_id' in port_info
:
770 port
.vm_id
= port_info
['device_id']
771 if 'fixed_ips' in port_info
:
772 port
.ip_address
= port_info
['fixed_ips'][0]['ip_address']
775 @rwstatus(ret_on_failure
=[None])
776 def do_get_port(self
, account
, port_id
):
780 account - a cloud account
781 port_id - an id for the port
786 drv
= self
._use
_driver
(account
)
787 port
= drv
.neutron_port_get(port_id
)
788 return RwcalOpenstackPlugin
._fill
_port
_info
(port
)
790 @rwstatus(ret_on_failure
=[[]])
791 def do_get_port_list(self
, account
):
792 """Return a list of ports
795 account - a cloud account
800 response
= RwcalYang
.YangData_RwProject_Project_VimResources()
801 drv
= self
._use
_driver
(account
)
802 ports
= drv
.neutron_port_list(*{})
804 response
.portinfo_list
.append(RwcalOpenstackPlugin
._fill
_port
_info
(port
))
807 @rwstatus(ret_on_failure
=[""])
808 def do_create_port(self
, account
, port
):
812 account - a cloud account
818 from warnings
import warn
819 warn("This function is deprecated")
822 kwargs
['name'] = port
.port_name
823 kwargs
['network_id'] = port
.network_id
824 kwargs
['admin_state_up'] = True
825 if port
.has_field('vm_id'):
826 kwargs
['vm_id'] = port
.vm_id
827 if port
.has_field('port_type'):
828 kwargs
['port_type'] = port
.port_type
830 kwargs
['port_type'] = "normal"
832 drv
= self
._use
_driver
(account
)
833 return drv
.neutron_port_create(**kwargs
)
836 def do_delete_port(self
, account
, port_id
):
840 account - a cloud account
841 port_id - an id for port
843 drv
= self
._use
_driver
(account
)
844 drv
.neutron_port_delete(port_id
)
846 @rwstatus(ret_on_failure
=[""])
847 def do_add_host(self
, account
, host
):
851 account - a cloud account
857 raise NotImplementedError
860 def do_remove_host(self
, account
, host_id
):
864 account - a cloud account
865 host_id - an id for the host
867 raise NotImplementedError
869 @rwstatus(ret_on_failure
=[None])
870 def do_get_host(self
, account
, host_id
):
874 account - a cloud account
875 host_id - an id for host
880 raise NotImplementedError
882 @rwstatus(ret_on_failure
=[[]])
883 def do_get_host_list(self
, account
):
884 """Return a list of hosts
887 account - a cloud account
892 raise NotImplementedError
895 @rwcalstatus(ret_on_failure
=[""])
896 def do_create_virtual_link(self
, account
, link_params
):
897 """Create a new virtual link
900 account - a cloud account
901 link_params - information that defines the type of VDU to create
904 A kwargs dictionary for glance operation
906 drv
= self
._use
_driver
(account
)
909 kwargs
= drv
.utils
.network
.make_virtual_link_args(link_params
)
910 network_id
= drv
.neutron_network_create(**kwargs
)
911 drv
.utils
.network
.prepare_virtual_link(link_params
, network_id
)
912 except Exception as e
:
913 self
.log
.exception("Encountered exceptions during network creation. Exception: %s", str(e
))
914 # This is to delete the network if neutron_subnet_create fails after creation of network
915 # Note:- Any subnet created will be implicitly deleted.
916 if network_id
is not None:
918 drv
.neutron_network_delete(network_id
)
919 except Exception as delete_exception
:
920 self
.log
.debug("Exception while deleting the network after failure of neutron_subnet_create or make_subnet_args: %s", str(delete_exception
))
921 # Raising exception so that the Exception is propagated to Resmgr.
922 # This fixes the UI Stuck at Vl-Init-Phase.
923 raise Exception(str(e
) + " --> " + str(delete_exception
))
929 def do_delete_virtual_link(self
, account
, link_id
):
930 """Delete a virtual link
933 account - a cloud account
934 link_id - id for the virtual-link to be deleted
939 drv
= self
._use
_driver
(account
)
941 port_list
= drv
.neutron_port_list(**{'network_id': link_id
})
942 for port
in port_list
:
943 if ((port
['device_owner'] == 'compute:None') or (port
['device_owner'] == '')):
944 self
.do_delete_port(account
, port
['id'], no_rwstatus
=True)
945 self
.do_delete_network(account
, link_id
, no_rwstatus
=True)
946 except Exception as e
:
947 self
.log
.exception("Exception %s occured during virtual-link deletion", str(e
))
950 @rwstatus(ret_on_failure
=[None])
951 def do_get_virtual_link(self
, account
, link_id
):
952 """Get information about virtual link.
955 account - a cloud account
956 link_id - id for the virtual-link
959 Object of type RwcalYang.YangData_RwProject_Project_VnfResources_VirtualLinkInfoList
961 drv
= self
._use
_driver
(account
)
963 network
= drv
.neutron_network_get(link_id
)
965 port_list
= drv
.neutron_port_list(**{'network_id': network
['id']})
966 if 'subnets' in network
and network
['subnets']:
967 subnet
= drv
.neutron_subnet_get(network
['subnets'][0])
970 virtual_link
= drv
.utils
.network
.parse_cloud_virtual_link_info(network
, port_list
, subnet
)
971 except Exception as e
:
972 self
.log
.exception("Exception %s occured during virtual-link-get", str(e
))
976 @rwstatus(ret_on_failure
=[None])
977 def do_get_virtual_link_by_name(self
, account
, link_name
):
978 """Get information about virtual link.
981 account - a cloud account
982 link_name - name for the virtual-link
985 Object of type RwcalYang.YangData_RwProject_Project_VnfResources_VirtualLinkInfoList
987 drv
= self
._use
_driver
(account
)
989 network
= drv
.neutron_network_get_by_name(link_name
)
991 port_list
= drv
.neutron_port_list(**{'network_id': network
['id']})
992 if 'subnets' in network
and network
['subnets']:
993 subnet
= drv
.neutron_subnet_get(network
['subnets'][0])
996 virtual_link
= drv
.utils
.network
.parse_cloud_virtual_link_info(network
, port_list
, subnet
)
999 except Exception as e
:
1000 self
.log
.exception("Exception %s occured during virtual-link-get-by-name", str(e
))
1004 @rwstatus(ret_on_failure
=[None])
1005 def do_get_virtual_link_list(self
, account
):
1006 """Get information about all the virtual links
1009 account - a cloud account
1012 A list of objects of type RwcalYang.YangData_RwProject_Project_VnfResources_VirtualLinkInfoList
1014 vnf_resources
= RwcalYang
.YangData_RwProject_Project_VnfResources()
1015 drv
= self
._use
_driver
(account
)
1017 networks
= drv
.neutron_network_list()
1018 for network
in networks
:
1019 port_list
= drv
.neutron_port_list(**{'network_id': network
['id']})
1020 if 'subnets' in network
and network
['subnets']:
1021 subnet
= drv
.neutron_subnet_get(network
['subnets'][0])
1024 virtual_link
= drv
.utils
.network
.parse_cloud_virtual_link_info(network
, port_list
, subnet
)
1025 vnf_resources
.virtual_link_info_list
.append(virtual_link
)
1026 except Exception as e
:
1027 self
.log
.exception("Exception %s occured during virtual-link-list-get", str(e
))
1029 return vnf_resources
1033 @rwcalstatus(ret_on_failure
=[""])
1034 def do_create_vdu(self
, account
, vdu_init
):
1035 """Create a new virtual deployment unit
1038 account - a cloud account
1039 vdu_init - information about VDU to create (RwcalYang.YangData_RwProject_Project_VduInitParams)
1044 drv
= self
._use
_driver
(account
)
1047 kwargs
= drv
.utils
.compute
.make_vdu_create_args(vdu_init
, account
)
1048 vm_id
= drv
.nova_server_create(**kwargs
)
1049 vdu_prepared_on_boot
= self
.prepare_vdu_on_boot(account
, vm_id
, vdu_init
)
1050 vdu_prepared
= vdu_prepared_on_boot
["status"]
1051 except Exception as e
:
1052 self
.log
.exception("Exception %s occured during create-vdu", str(e
))
1055 if vdu_prepared
is False:
1056 drv
.utils
.compute
.perform_vdu_network_cleanup(vm_id
)
1057 drv
.nova_server_delete(vm_id
)
1058 self
.log
.exception("Cleaning Up VDU as Prepare Vdu Failed : %s", vdu_prepared_on_boot
["exception"])
1059 raise PrepareVduOnBoot(vdu_prepared_on_boot
["exception"])
1063 def prepare_vdu_on_boot(self
, account
, server_id
, vdu_params
):
1064 if vdu_params
.mgmt_network
is not None:
1065 mgmt_network_param
= vdu_params
.mgmt_network
1067 mgmt_network_param
= account
.openstack
.mgmt_network
1069 # Adding shell quote to all parameters in case they contain special characters.
1070 cmd
= PREPARE_VM_CMD
.format(auth_url
= shlex
.quote(account
.openstack
.auth_url
),
1071 username
= shlex
.quote(account
.openstack
.key
),
1072 password
= shlex
.quote(account
.openstack
.secret
),
1073 tenant_name
= shlex
.quote(account
.openstack
.tenant
),
1074 region
= shlex
.quote(account
.openstack
.region
),
1075 user_domain
= shlex
.quote(account
.openstack
.user_domain
),
1076 project_domain
= shlex
.quote(account
.openstack
.project_domain
),
1077 mgmt_network
= shlex
.quote(mgmt_network_param
),
1078 server_id
= shlex
.quote(server_id
))
1081 vdu_prepared
= {"status": True, "exception": None}
1083 if vdu_params
.has_field('allocate_public_address') and vdu_params
.allocate_public_address
:
1084 if account
.openstack
.has_field('floating_ip_pool'):
1085 cmd
+= " --floating_ip"
1086 cmd
+= (" --pool_name " + account
.openstack
.floating_ip_pool
)
1088 if vdu_params
.has_field('volumes'):
1089 for volume
in vdu_params
.volumes
:
1090 if volume
.has_field('custom_meta_data'):
1091 vol_list
.append(volume
.as_dict())
1094 with tempfile
.NamedTemporaryFile(mode
='w', delete
=False) as tmp_file
:
1095 yaml
.dump(vol_list
, tmp_file
)
1096 cmd
+= (" --vol_metadata {}").format(tmp_file
.name
)
1099 exec_path
= 'python3 ' + os
.path
.dirname(openstack_drv
.__file
__)
1100 exec_cmd
= exec_path
+ '/' + cmd
1101 self
.log
.info("Running command: %s" %(exec_cmd))
1103 # The return code for the subprocess is always 0. Hence using check_output
1104 # for validating the success/failure of the script
1105 # The check_output returns False or True on the basis of exception
1106 # handling in prepare_vm.py
1107 prepare_vm_status
= subprocess
.check_output(exec_cmd
, shell
=True)
1109 # prepare_vm_status is a string in the format of True/False+ error message
1110 # if any. This is to propagate the detailed exception to the callers.
1111 vdu_status_elems
= prepare_vm_status
.decode("utf-8").split("+")
1112 if(vdu_status_elems
[0] == 'False'):
1113 self
.log
.exception("Exception occured while preparing vdu after boot")
1114 vdu_prepared
= {"status": False, "exception": vdu_status_elems
[1]}
1119 def do_modify_vdu(self
, account
, vdu_modify
):
1120 """Modify Properties of existing virtual deployment unit
1123 account - a cloud account
1124 vdu_modify - Information about VDU Modification (RwcalYang.YangData_RwProject_Project_VduModifyParams)
1126 drv
= self
._use
_driver
(account
)
1127 ### First create required number of ports aka connection points
1130 for c_point
in vdu_modify
.connection_points_add
:
1131 if c_point
.virtual_link_id
in network_list
:
1132 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"
1134 network_list
.append(c_point
.virtual_link_id
)
1135 port_id
= self
._create
_connection
_point
(account
, c_point
)
1136 port_list
.append(port_id
)
1138 drv
= self
._use
_driver
(account
)
1139 ### Now add the ports to VM
1140 for port_id
in port_list
:
1141 drv
.nova_server_add_port(vdu_modify
.vdu_id
, port_id
)
1143 ### Delete the requested connection_points
1144 for c_point
in vdu_modify
.connection_points_remove
:
1145 self
.do_delete_port(account
, c_point
.connection_point_id
, no_rwstatus
=True)
1147 if vdu_modify
.has_field('image_id'):
1148 drv
.nova_server_rebuild(vdu_modify
.vdu_id
, vdu_modify
.image_id
)
1152 def do_delete_vdu(self
, account
, vdu_id
):
1153 """Delete a virtual deployment unit
1156 account - a cloud account
1157 vdu_id - id for the vdu to be deleted
1162 drv
= self
._use
_driver
(account
)
1164 drv
.utils
.compute
.perform_vdu_network_cleanup(vdu_id
)
1165 drv
.nova_server_delete(vdu_id
)
1166 except Exception as e
:
1167 self
.log
.exception("Exception %s occured during delete-vdu", str(e
))
1171 @rwcalstatus(ret_on_failure
=[None])
1172 def do_get_vdu(self
, account
, vdu_id
, mgmt_network
):
1173 """Get information about a virtual deployment unit.
1176 account - a cloud account
1177 vdu_id - id for the vdu
1178 mgmt_network - mgmt_network if provided in NSD VL
1181 Object of type RwcalYang.YangData_RwProject_Project_VnfResources_VduInfoList
1183 if mgmt_network
not in [None, ""]:
1184 account
.openstack
.mgmt_network
= mgmt_network
1186 drv
= self
._use
_driver
(account
)
1188 vm_info
= drv
.nova_server_get(vdu_id
)
1189 vdu_info
= drv
.utils
.compute
.parse_cloud_vdu_info(vm_info
)
1190 except Exception as e
:
1191 self
.log
.debug("Exception occured during get-vdu: %s", str(e
))
1197 @rwcalstatus(ret_on_failure
=[None])
1198 def do_get_vdu_list(self
, account
):
1199 """Get information about all the virtual deployment units
1202 account - a cloud account
1205 A list of objects of type RwcalYang.YangData_RwProject_Project_VnfResources_VduInfoList
1207 vnf_resources
= RwcalYang
.YangData_RwProject_Project_VnfResources()
1208 drv
= self
._use
_driver
(account
)
1210 vms
= drv
.nova_server_list()
1212 vdu
= drv
.utils
.compute
.parse_cloud_vdu_info(vm
)
1213 vnf_resources
.vdu_info_list
.append(vdu
)
1214 except Exception as e
:
1215 self
.log
.debug("Exception occured during get-vdu-list: %s", str(e
))
1217 return vnf_resources