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
35 import neutronclient
.common
.exceptions
as NeutronException
36 import keystoneclient
.exceptions
as KeystoneExceptions
39 from gi
.repository
import (
45 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 "
47 rwstatus_exception_map
= { IndexError: RwTypes
.RwStatus
.NOTFOUND
,
48 KeyError: RwTypes
.RwStatus
.NOTFOUND
,
49 NotImplementedError: RwTypes
.RwStatus
.NOT_IMPLEMENTED
,}
51 rwstatus
= rw_status
.rwstatus_from_exc_map(rwstatus_exception_map
)
52 rwcalstatus
= rwcal_status
.rwcalstatus_from_exc_map(rwstatus_exception_map
)
55 class OpenstackCALOperationFailure(Exception):
58 class UninitializedPluginError(Exception):
62 class OpenstackServerGroupError(Exception):
66 class ImageUploadError(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 (KeystoneExceptions
.Unauthorized
, KeystoneExceptions
.AuthorizationFailure
,
79 NeutronException
.NotFound
) as e
:
81 except Exception as e
:
82 self
.log
.error("RwcalOpenstackPlugin: OpenstackDriver init failed. Exception: %s" %(str(e
)))
89 class RwcalOpenstackPlugin(GObject
.Object
, RwCal
.Cloud
):
90 """This class implements the CAL VALA methods for openstack."""
95 GObject
.Object
.__init
__(self
)
96 self
.log
= logging
.getLogger('rwcal.openstack.%s' % RwcalOpenstackPlugin
.instance_num
)
97 self
.log
.setLevel(logging
.DEBUG
)
98 self
._rwlog
_handler
= None
99 self
._account
_drivers
= dict()
100 RwcalOpenstackPlugin
.instance_num
+= 1
102 def _get_account_key(self
, account
):
104 for f
in account
.openstack
.fields
:
106 key
+= str(getattr(account
.openstack
, f
))
112 def _use_driver(self
, account
):
113 if self
._rwlog
_handler
is None:
114 raise UninitializedPluginError("Must call init() in CAL plugin before use.")
116 acct_key
= self
._get
_account
_key
(account
)
118 if acct_key
not in self
._account
_drivers
:
119 self
.log
.debug("Creating OpenstackDriver")
120 kwargs
= dict(username
= account
.openstack
.key
,
121 password
= account
.openstack
.secret
,
122 auth_url
= account
.openstack
.auth_url
,
123 project
= account
.openstack
.tenant
,
124 mgmt_network
= account
.openstack
.mgmt_network
,
125 cert_validate
= account
.openstack
.cert_validate
,
126 user_domain
= account
.openstack
.user_domain
,
127 project_domain
= account
.openstack
.project_domain
,
128 region
= account
.openstack
.region
)
129 drv
= RwcalAccountDriver(self
.log
, **kwargs
)
130 self
._account
_drivers
[account
.name
] = drv
133 return self
._account
_drivers
[acct_key
].driver
137 def do_init(self
, rwlog_ctx
):
138 self
._rwlog
_handler
= rwlogger
.RwLogger(category
="rw-cal-log",
139 subcategory
="openstack",
141 self
.log
.addHandler(self
._rwlog
_handler
)
142 self
.log
.propagate
= False
144 @rwstatus(ret_on_failure
=[None])
145 def do_validate_cloud_creds(self
, account
):
147 Validates the cloud account credentials for the specified account.
148 Performs an access to the resources using Keystone API. If creds
149 are not valid, returns an error code & reason string
151 account - a cloud account to validate
154 Validation Code and Details String
156 status
= RwcalYang
.CloudConnectionStatus()
157 drv
= self
._use
_driver
(account
)
159 drv
.validate_account_creds()
160 except KeystoneExceptions
.Unauthorized
as e
:
161 self
.log
.error("Invalid credentials given for VIM account %s", account
.name
)
162 status
.status
= "failure"
163 status
.details
= "Invalid Credentials: %s" % str(e
)
165 except KeystoneExceptions
.AuthorizationFailure
as e
:
166 self
.log
.error("Bad authentication URL given for VIM account %s. Given auth url: %s",
167 account
.name
, account
.openstack
.auth_url
)
168 status
.status
= "failure"
169 status
.details
= "Invalid auth url: %s" % str(e
)
171 except NeutronException
.NotFound
as e
:
172 self
.log
.error("Given management network %s could not be found for VIM account %s",
173 account
.openstack
.mgmt_network
,
175 status
.status
= "failure"
176 status
.details
= "mgmt network does not exist: %s" % str(e
)
178 except openstack_drv
.ValidationError
as e
:
179 self
.log
.error("RwcalOpenstackPlugin: OpenstackDriver credential validation failed. Exception: %s", str(e
))
180 status
.status
= "failure"
181 status
.details
= "Invalid Credentials: %s" % str(e
)
183 except Exception as e
:
184 msg
= "RwcalOpenstackPlugin: OpenstackDriver connection failed. Exception: %s" %(str(e
))
186 status
.status
= "failure"
190 status
.status
= "success"
191 status
.details
= "Connection was successful"
195 @rwstatus(ret_on_failure
=[""])
196 def do_get_management_network(self
, account
):
198 Returns the management network associated with the specified account.
200 account - a cloud account
203 The management network
205 return account
.openstack
.mgmt_network
207 @rwstatus(ret_on_failure
=[""])
208 def do_create_tenant(self
, account
, name
):
209 """Create a new tenant.
212 account - a cloud account
213 name - name of the tenant
218 raise NotImplementedError
221 def do_delete_tenant(self
, account
, tenant_id
):
225 account - a cloud account
226 tenant_id - id of the tenant
228 raise NotImplementedError
230 @rwstatus(ret_on_failure
=[[]])
231 def do_get_tenant_list(self
, account
):
235 account - a cloud account
240 raise NotImplementedError
242 @rwstatus(ret_on_failure
=[""])
243 def do_create_role(self
, account
, name
):
244 """Create a new user.
247 account - a cloud account
248 name - name of the user
253 raise NotImplementedError
256 def do_delete_role(self
, account
, role_id
):
260 account - a cloud account
261 role_id - id of the user
263 raise NotImplementedError
265 @rwstatus(ret_on_failure
=[[]])
266 def do_get_role_list(self
, account
):
270 account - a cloud account
275 raise NotImplementedError
277 @rwstatus(ret_on_failure
=[""])
278 def do_create_image(self
, account
, image
):
282 account - a cloud account
283 image - a description of the image to create
288 drv
= self
._use
_driver
(account
)
289 fd
= drv
.utils
.image
.create_image_handle(image
)
290 kwargs
= drv
.utils
.image
.make_image_args(image
)
294 image_id
= drv
.glance_image_create(**kwargs
)
295 drv
.glance_image_upload(image_id
, fd
)
296 except Exception as e
:
297 self
.log
.exception("Exception %s occured during image create", str(e
))
302 # Update image properties, if they are provided
304 if image
.has_field("properties") and image
.properties
is not None:
305 for key
in image
.properties
:
306 drv
.glance_image_update(image_id
, **{key
.name
: key
.property_value
})
307 except Exception as e
:
308 self
.log
.exception("Exception %s occured during image update", str(e
))
313 stored_image
= drv
.glance_image_get(image_id
)
314 if stored_image
.checksum
!= image
.checksum
:
315 drv
.glance_image_delete(image_id
=image_id
)
316 raise ImageUploadError("image checksum did not match (actual: %s, expected: %s). Deleting." %
317 (stored_image
.checksum
, image
.checksum
))
318 except Exception as e
:
319 self
.log
.exception("Exception %s occured during image checksum verification", str(e
))
325 def do_delete_image(self
, account
, image_id
):
326 """Delete a vm image.
329 account - a cloud account
330 image_id - id of the image to delete
332 drv
= self
._use
_driver
(account
)
334 drv
.glance_image_delete(image_id
=image_id
)
335 except Exception as e
:
336 self
.log
.exception("Exception %s occured during image deletion", str(e
))
340 @rwstatus(ret_on_failure
=[[]])
341 def do_get_image_list(self
, account
):
342 """Return a list of the names of all available images.
345 account - a cloud account
348 The the list of images in VimResources object
350 response
= RwcalYang
.VimResources()
351 drv
= self
._use
_driver
(account
)
353 images
= drv
.glance_image_list()
355 response
.imageinfo_list
.append(drv
.utils
.image
.parse_cloud_image_info(img
))
356 except Exception as e
:
357 self
.log
.exception("Exception %s occured during get-image-list", str(e
))
361 @rwstatus(ret_on_failure
=[None])
362 def do_get_image(self
, account
, image_id
):
363 """Return a image information.
366 account - a cloud account
367 image_id - an id of the image
370 ImageInfoItem object containing image information.
372 drv
= self
._use
_driver
(account
)
374 image_info
= drv
.glance_image_get(image_id
)
375 image
= drv
.utils
.image
.parse_cloud_image_info(image_info
)
376 except Exception as e
:
377 self
.log
.exception("Exception %s occured during get-image", str(e
))
382 # This is being deprecated. Please do not use for new SW development
383 @rwstatus(ret_on_failure
=[""])
384 def do_create_vm(self
, account
, vminfo
):
385 """Create a new virtual machine.
388 account - a cloud account
389 vminfo - information that defines the type of VM to create
394 from warnings
import warn
395 warn("This function is deprecated")
397 kwargs
['name'] = vminfo
.vm_name
398 kwargs
['flavor_id'] = vminfo
.flavor_id
399 if vminfo
.has_field('image_id'):
400 kwargs
['image_id'] = vminfo
.image_id
402 ### If floating_ip is required and we don't have one, better fail before any further allocation
405 if vminfo
.has_field('allocate_public_address') and vminfo
.allocate_public_address
:
406 if account
.openstack
.has_field('floating_ip_pool'):
407 pool_name
= account
.openstack
.floating_ip_pool
410 if vminfo
.has_field('cloud_init') and vminfo
.cloud_init
.has_field('userdata'):
411 kwargs
['userdata'] = vminfo
.cloud_init
.userdata
413 kwargs
['userdata'] = ''
415 if account
.openstack
.security_groups
:
416 kwargs
['security_groups'] = account
.openstack
.security_groups
419 for port
in vminfo
.port_list
:
420 port_list
.append(port
.port_id
)
423 kwargs
['port_list'] = port_list
426 for network
in vminfo
.network_list
:
427 network_list
.append(network
.network_id
)
430 kwargs
['network_list'] = network_list
433 for field
in vminfo
.user_tags
.fields
:
434 if vminfo
.user_tags
.has_field(field
):
435 metadata
[field
] = getattr(vminfo
.user_tags
, field
)
436 kwargs
['metadata'] = metadata
438 if vminfo
.has_field('availability_zone'):
439 kwargs
['availability_zone'] = vminfo
.availability_zone
441 kwargs
['availability_zone'] = None
443 if vminfo
.has_field('server_group'):
444 kwargs
['scheduler_hints'] = {'group': vminfo
.server_group
}
446 kwargs
['scheduler_hints'] = None
448 drv
= self
._use
_driver
(account
)
449 vm_id
= drv
.nova_server_create(**kwargs
)
451 self
.prepare_vdu_on_boot(account
, vm_id
, floating_ip
)
456 def do_start_vm(self
, account
, vm_id
):
457 """Start an existing virtual machine.
460 account - a cloud account
461 vm_id - an id of the VM
463 drv
= self
._use
_driver
(account
)
464 drv
.nova_server_start(vm_id
)
467 def do_stop_vm(self
, account
, vm_id
):
468 """Stop a running virtual machine.
471 account - a cloud account
472 vm_id - an id of the VM
474 drv
= self
._use
_driver
(account
)
475 drv
.nova_server_stop(vm_id
)
478 def do_delete_vm(self
, account
, vm_id
):
479 """Delete a virtual machine.
482 account - a cloud account
483 vm_id - an id of the VM
485 drv
= self
._use
_driver
(account
)
486 drv
.nova_server_delete(vm_id
)
489 def do_reboot_vm(self
, account
, vm_id
):
490 """Reboot a virtual machine.
493 account - a cloud account
494 vm_id - an id of the VM
496 drv
= self
._use
_driver
(account
)
497 drv
.nova_server_reboot(vm_id
)
500 def _fill_vm_info(vm_info
, mgmt_network
):
501 """Create a GI object from vm info dictionary
503 Converts VM information dictionary object returned by openstack
504 driver into Protobuf Gi Object
507 vm_info - VM information from openstack
508 mgmt_network - Management network
511 Protobuf Gi object for VM
513 vm
= RwcalYang
.VMInfoItem()
514 vm
.vm_id
= vm_info
['id']
515 vm
.vm_name
= vm_info
['name']
516 vm
.image_id
= vm_info
['image']['id']
517 vm
.flavor_id
= vm_info
['flavor']['id']
518 vm
.state
= vm_info
['status']
519 for network_name
, network_info
in vm_info
['addresses'].items():
521 if network_name
== mgmt_network
:
522 vm
.public_ip
= next((item
['addr']
523 for item
in network_info
524 if item
['OS-EXT-IPS:type'] == 'floating'),
525 network_info
[0]['addr'])
526 vm
.management_ip
= network_info
[0]['addr']
528 for interface
in network_info
:
529 addr
= vm
.private_ip_list
.add()
530 addr
.ip_address
= interface
['addr']
532 for network_name
, network_info
in vm_info
['addresses'].items():
533 if network_info
and network_name
== mgmt_network
and not vm
.public_ip
:
534 for interface
in network_info
:
535 if 'OS-EXT-IPS:type' in interface
and interface
['OS-EXT-IPS:type'] == 'floating':
536 vm
.public_ip
= interface
['addr']
538 # Look for any metadata
539 for key
, value
in vm_info
['metadata'].items():
540 if key
in vm
.user_tags
.fields
:
541 setattr(vm
.user_tags
, key
, value
)
542 if 'OS-EXT-SRV-ATTR:host' in vm_info
:
543 if vm_info
['OS-EXT-SRV-ATTR:host'] != None:
544 vm
.host_name
= vm_info
['OS-EXT-SRV-ATTR:host']
545 if 'OS-EXT-AZ:availability_zone' in vm_info
:
546 if vm_info
['OS-EXT-AZ:availability_zone'] != None:
547 vm
.availability_zone
= vm_info
['OS-EXT-AZ:availability_zone']
550 @rwstatus(ret_on_failure
=[[]])
551 def do_get_vm_list(self
, account
):
552 """Return a list of the VMs as vala boxed objects
555 account - a cloud account
558 List containing VM information
560 response
= RwcalYang
.VimResources()
561 drv
= self
._use
_driver
(account
)
562 vms
= drv
.nova_server_list()
564 response
.vminfo_list
.append(RwcalOpenstackPlugin
._fill
_vm
_info
(vm
, account
.openstack
.mgmt_network
))
567 @rwstatus(ret_on_failure
=[None])
568 def do_get_vm(self
, account
, id):
569 """Return vm information.
572 account - a cloud account
573 id - an id for the VM
578 drv
= self
._use
_driver
(account
)
579 vm
= drv
.nova_server_get(id)
580 return RwcalOpenstackPlugin
._fill
_vm
_info
(vm
, account
.openstack
.mgmt_network
)
583 @rwstatus(ret_on_failure
=[""])
584 def do_create_flavor(self
, account
, flavor
):
585 """Create new flavor.
588 account - a cloud account
589 flavor - flavor of the VM
594 drv
= self
._use
_driver
(account
)
596 flavor_id
= drv
.nova_flavor_create(name
= flavor
.name
,
597 ram
= flavor
.vm_flavor
.memory_mb
,
598 vcpus
= flavor
.vm_flavor
.vcpu_count
,
599 disk
= flavor
.vm_flavor
.storage_gb
,
600 epa_specs
= drv
.utils
.flavor
.get_extra_specs(flavor
))
601 except Exception as e
:
602 self
.log
.error("Encountered exceptions during Flavor creation. Exception: %s", str(e
))
608 def do_delete_flavor(self
, account
, flavor_id
):
612 account - a cloud account
613 flavor_id - id flavor of the VM
615 drv
= self
._use
_driver
(account
)
617 drv
.nova_flavor_delete(flavor_id
)
618 except Exception as e
:
619 self
.log
.error("Encountered exceptions during Flavor deletion. Exception: %s", str(e
))
623 @rwstatus(ret_on_failure
=[[]])
624 def do_get_flavor_list(self
, account
):
625 """Return flavor information.
628 account - a cloud account
633 response
= RwcalYang
.VimResources()
634 drv
= self
._use
_driver
(account
)
636 flavors
= drv
.nova_flavor_list()
638 response
.flavorinfo_list
.append(drv
.utils
.flavor
.parse_flavor_info(flv
))
639 except Exception as e
:
640 self
.log
.error("Encountered exceptions during get-flavor-list. Exception: %s", str(e
))
645 @rwstatus(ret_on_failure
=[None])
646 def do_get_flavor(self
, account
, id):
647 """Return flavor information.
650 account - a cloud account
651 id - an id for the flavor
656 drv
= self
._use
_driver
(account
)
658 flavor
= drv
.nova_flavor_get(id)
659 response
= drv
.utils
.flavor
.parse_flavor_info(flavor
)
660 except Exception as e
:
661 self
.log
.error("Encountered exceptions during get-flavor. Exception: %s", str(e
))
667 def _fill_network_info(self
, network_info
, account
):
668 """Create a GI object from network info dictionary
670 Converts Network information dictionary object returned by openstack
671 driver into Protobuf Gi Object
674 network_info - Network information from openstack
675 account - a cloud account
680 network
= RwcalYang
.NetworkInfoItem()
681 network
.network_name
= network_info
['name']
682 network
.network_id
= network_info
['id']
683 if ('provider:network_type' in network_info
) and (network_info
['provider:network_type'] != None):
684 network
.provider_network
.overlay_type
= network_info
['provider:network_type'].upper()
685 if ('provider:segmentation_id' in network_info
) and (network_info
['provider:segmentation_id']):
686 network
.provider_network
.segmentation_id
= network_info
['provider:segmentation_id']
687 if ('provider:physical_network' in network_info
) and (network_info
['provider:physical_network']):
688 network
.provider_network
.physical_network
= network_info
['provider:physical_network'].upper()
690 if 'subnets' in network_info
and network_info
['subnets']:
691 subnet_id
= network_info
['subnets'][0]
692 drv
= self
._use
_driver
(account
)
693 subnet
= drv
.neutron_subnet_get(subnet_id
)
694 network
.subnet
= subnet
['cidr']
697 @rwstatus(ret_on_failure
=[[]])
698 def do_get_network_list(self
, account
):
699 """Return a list of networks
702 account - a cloud account
707 response
= RwcalYang
.VimResources()
708 drv
= self
._use
_driver
(account
)
709 networks
= drv
.neutron_network_list()
710 for network
in networks
:
711 response
.networkinfo_list
.append(self
._fill
_network
_info
(network
, account
))
714 @rwstatus(ret_on_failure
=[None])
715 def do_get_network(self
, account
, id):
719 account - a cloud account
720 id - an id for the network
725 drv
= self
._use
_driver
(account
)
726 network
= drv
.neutron_network_get(id)
727 return self
._fill
_network
_info
(network
, account
)
729 @rwstatus(ret_on_failure
=[""])
730 def do_create_network(self
, account
, network
):
731 """Create a new network
734 account - a cloud account
735 network - Network object
740 from warnings
import warn
741 warn("This function is deprecated")
744 kwargs
['name'] = network
.network_name
745 kwargs
['admin_state_up'] = True
746 kwargs
['external_router'] = False
747 kwargs
['shared'] = False
749 if network
.has_field('provider_network'):
750 if network
.provider_network
.has_field('physical_network'):
751 kwargs
['physical_network'] = network
.provider_network
.physical_network
752 if network
.provider_network
.has_field('overlay_type'):
753 kwargs
['network_type'] = network
.provider_network
.overlay_type
.lower()
754 if network
.provider_network
.has_field('segmentation_id'):
755 kwargs
['segmentation_id'] = network
.provider_network
.segmentation_id
757 drv
= self
._use
_driver
(account
)
758 network_id
= drv
.neutron_network_create(**kwargs
)
759 drv
.neutron_subnet_create(network_id
= network_id
,
760 cidr
= network
.subnet
)
764 def do_delete_network(self
, account
, network_id
):
768 account - a cloud account
769 network_id - an id for the network
771 drv
= self
._use
_driver
(account
)
772 drv
.neutron_network_delete(network_id
)
775 def _fill_port_info(port_info
):
776 """Create a GI object from port info dictionary
778 Converts Port information dictionary object returned by openstack
779 driver into Protobuf Gi Object
782 port_info - Port information from openstack
787 port
= RwcalYang
.PortInfoItem()
789 port
.port_name
= port_info
['name']
790 port
.port_id
= port_info
['id']
791 port
.network_id
= port_info
['network_id']
792 port
.port_state
= port_info
['status']
793 if 'device_id' in port_info
:
794 port
.vm_id
= port_info
['device_id']
795 if 'fixed_ips' in port_info
:
796 port
.ip_address
= port_info
['fixed_ips'][0]['ip_address']
799 @rwstatus(ret_on_failure
=[None])
800 def do_get_port(self
, account
, port_id
):
804 account - a cloud account
805 port_id - an id for the port
810 drv
= self
._use
_driver
(account
)
811 port
= drv
.neutron_port_get(port_id
)
812 return RwcalOpenstackPlugin
._fill
_port
_info
(port
)
814 @rwstatus(ret_on_failure
=[[]])
815 def do_get_port_list(self
, account
):
816 """Return a list of ports
819 account - a cloud account
824 response
= RwcalYang
.VimResources()
825 drv
= self
._use
_driver
(account
)
826 ports
= drv
.neutron_port_list(*{})
828 response
.portinfo_list
.append(RwcalOpenstackPlugin
._fill
_port
_info
(port
))
831 @rwstatus(ret_on_failure
=[""])
832 def do_create_port(self
, account
, port
):
836 account - a cloud account
842 from warnings
import warn
843 warn("This function is deprecated")
846 kwargs
['name'] = port
.port_name
847 kwargs
['network_id'] = port
.network_id
848 kwargs
['admin_state_up'] = True
849 if port
.has_field('vm_id'):
850 kwargs
['vm_id'] = port
.vm_id
851 if port
.has_field('port_type'):
852 kwargs
['port_type'] = port
.port_type
854 kwargs
['port_type'] = "normal"
856 drv
= self
._use
_driver
(account
)
857 return drv
.neutron_port_create(**kwargs
)
860 def do_delete_port(self
, account
, port_id
):
864 account - a cloud account
865 port_id - an id for port
867 drv
= self
._use
_driver
(account
)
868 drv
.neutron_port_delete(port_id
)
870 @rwstatus(ret_on_failure
=[""])
871 def do_add_host(self
, account
, host
):
875 account - a cloud account
881 raise NotImplementedError
884 def do_remove_host(self
, account
, host_id
):
888 account - a cloud account
889 host_id - an id for the host
891 raise NotImplementedError
893 @rwstatus(ret_on_failure
=[None])
894 def do_get_host(self
, account
, host_id
):
898 account - a cloud account
899 host_id - an id for host
904 raise NotImplementedError
906 @rwstatus(ret_on_failure
=[[]])
907 def do_get_host_list(self
, account
):
908 """Return a list of hosts
911 account - a cloud account
916 raise NotImplementedError
919 @rwcalstatus(ret_on_failure
=[""])
920 def do_create_virtual_link(self
, account
, link_params
):
921 """Create a new virtual link
924 account - a cloud account
925 link_params - information that defines the type of VDU to create
928 A kwargs dictionary for glance operation
931 drv
= self
._use
_driver
(account
)
933 kwargs
= drv
.utils
.network
.make_virtual_link_args(link_params
)
934 network_id
= drv
.neutron_network_create(**kwargs
)
935 kwargs
= drv
.utils
.network
.make_subnet_args(link_params
, network_id
)
936 drv
.neutron_subnet_create(**kwargs
)
937 except Exception as e
:
938 self
.log
.error("Encountered exceptions during network creation. Exception: %s", str(e
))
945 def do_delete_virtual_link(self
, account
, link_id
):
946 """Delete a virtual link
949 account - a cloud account
950 link_id - id for the virtual-link to be deleted
955 drv
= self
._use
_driver
(account
)
957 port_list
= drv
.neutron_port_list(**{'network_id': link_id
})
958 for port
in port_list
:
959 if ((port
['device_owner'] == 'compute:None') or (port
['device_owner'] == '')):
960 self
.do_delete_port(account
, port
['id'], no_rwstatus
=True)
961 self
.do_delete_network(account
, link_id
, no_rwstatus
=True)
962 except Exception as e
:
963 self
.log
.exception("Exception %s occured during virtual-link deletion", str(e
))
966 @rwstatus(ret_on_failure
=[None])
967 def do_get_virtual_link(self
, account
, link_id
):
968 """Get information about virtual link.
971 account - a cloud account
972 link_id - id for the virtual-link
975 Object of type RwcalYang.VirtualLinkInfoParams
977 drv
= self
._use
_driver
(account
)
979 network
= drv
.neutron_network_get(link_id
)
981 port_list
= drv
.neutron_port_list(**{'network_id': network
['id']})
982 if 'subnets' in network
and network
['subnets']:
983 subnet
= drv
.neutron_subnet_get(network
['subnets'][0])
986 virtual_link
= drv
.utils
.network
.parse_cloud_virtual_link_info(network
, port_list
, subnet
)
987 except Exception as e
:
988 self
.log
.exception("Exception %s occured during virtual-link-get", str(e
))
992 @rwstatus(ret_on_failure
=[None])
993 def do_get_virtual_link_list(self
, account
):
994 """Get information about all the virtual links
997 account - a cloud account
1000 A list of objects of type RwcalYang.VirtualLinkInfoParams
1002 vnf_resources
= RwcalYang
.VNFResources()
1003 drv
= self
._use
_driver
(account
)
1005 networks
= drv
.neutron_network_list()
1006 for network
in networks
:
1007 port_list
= drv
.neutron_port_list(**{'network_id': network
['id']})
1008 if 'subnets' in network
and network
['subnets']:
1009 subnet
= drv
.neutron_subnet_get(network
['subnets'][0])
1012 virtual_link
= drv
.utils
.network
.parse_cloud_virtual_link_info(network
, port_list
, subnet
)
1013 vnf_resources
.virtual_link_info_list
.append(virtual_link
)
1014 except Exception as e
:
1015 self
.log
.exception("Exception %s occured during virtual-link-list-get", str(e
))
1017 return vnf_resources
1021 @rwcalstatus(ret_on_failure
=[""])
1022 def do_create_vdu(self
, account
, vdu_init
):
1023 """Create a new virtual deployment unit
1026 account - a cloud account
1027 vdu_init - information about VDU to create (RwcalYang.VDUInitParams)
1032 drv
= self
._use
_driver
(account
)
1034 kwargs
= drv
.utils
.compute
.make_vdu_create_args(vdu_init
, account
)
1035 vm_id
= drv
.nova_server_create(**kwargs
)
1036 self
.prepare_vdu_on_boot(account
, vm_id
, vdu_init
)
1037 except Exception as e
:
1038 self
.log
.exception("Exception %s occured during create-vdu", str(e
))
1043 def prepare_vdu_on_boot(self
, account
, server_id
, vdu_params
):
1044 cmd
= PREPARE_VM_CMD
.format(auth_url
= account
.openstack
.auth_url
,
1045 username
= account
.openstack
.key
,
1046 password
= account
.openstack
.secret
,
1047 tenant_name
= account
.openstack
.tenant
,
1048 region
= account
.openstack
.region
,
1049 user_domain
= account
.openstack
.user_domain
,
1050 project_domain
= account
.openstack
.project_domain
,
1051 mgmt_network
= account
.openstack
.mgmt_network
,
1052 server_id
= server_id
)
1055 if vdu_params
.has_field('allocate_public_address') and vdu_params
.allocate_public_address
:
1056 cmd
+= " --floating_ip"
1057 if account
.openstack
.has_field('floating_ip_pool'):
1058 cmd
+= (" --pool_name " + account
.openstack
.floating_ip_pool
)
1060 if vdu_params
.has_field('volumes'):
1061 for volume
in vdu_params
.volumes
:
1062 if volume
.has_field('custom_meta_data'):
1063 vol_list
.append(volume
.as_dict())
1066 with tempfile
.NamedTemporaryFile(mode
='w', delete
=False) as tmp_file
:
1067 yaml
.dump(vol_list
, tmp_file
)
1068 cmd
+= (" --vol_metadata {}").format(tmp_file
.name
)
1070 exec_path
= 'python3 ' + os
.path
.dirname(openstack_drv
.__file
__)
1071 exec_cmd
= exec_path
+'/'+cmd
1072 self
.log
.info("Running command: %s" %(exec_cmd))
1073 subprocess
.call(exec_cmd
, shell
=True)
1076 def do_modify_vdu(self
, account
, vdu_modify
):
1077 """Modify Properties of existing virtual deployment unit
1080 account - a cloud account
1081 vdu_modify - Information about VDU Modification (RwcalYang.VDUModifyParams)
1083 drv
= self
._use
_driver
(account
)
1084 ### First create required number of ports aka connection points
1087 for c_point
in vdu_modify
.connection_points_add
:
1088 if c_point
.virtual_link_id
in network_list
:
1089 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"
1091 network_list
.append(c_point
.virtual_link_id
)
1092 port_id
= self
._create
_connection
_point
(account
, c_point
)
1093 port_list
.append(port_id
)
1095 drv
= self
._use
_driver
(account
)
1096 ### Now add the ports to VM
1097 for port_id
in port_list
:
1098 drv
.nova_server_add_port(vdu_modify
.vdu_id
, port_id
)
1100 ### Delete the requested connection_points
1101 for c_point
in vdu_modify
.connection_points_remove
:
1102 self
.do_delete_port(account
, c_point
.connection_point_id
, no_rwstatus
=True)
1104 if vdu_modify
.has_field('image_id'):
1105 drv
.nova_server_rebuild(vdu_modify
.vdu_id
, vdu_modify
.image_id
)
1109 def do_delete_vdu(self
, account
, vdu_id
):
1110 """Delete a virtual deployment unit
1113 account - a cloud account
1114 vdu_id - id for the vdu to be deleted
1119 drv
= self
._use
_driver
(account
)
1121 drv
.utils
.compute
.perform_vdu_network_cleanup(vdu_id
)
1122 drv
.nova_server_delete(vdu_id
)
1123 except Exception as e
:
1124 self
.log
.exception("Exception %s occured during delete-vdu", str(e
))
1128 @rwstatus(ret_on_failure
=[None])
1129 def do_get_vdu(self
, account
, vdu_id
):
1130 """Get information about a virtual deployment unit.
1133 account - a cloud account
1134 vdu_id - id for the vdu
1137 Object of type RwcalYang.VDUInfoParams
1139 drv
= self
._use
_driver
(account
)
1141 vm_info
= drv
.nova_server_get(vdu_id
)
1142 vdu_info
= drv
.utils
.compute
.parse_cloud_vdu_info(vm_info
)
1143 except Exception as e
:
1144 self
.log
.exception("Exception %s occured during get-vdu", str(e
))
1150 @rwstatus(ret_on_failure
=[None])
1151 def do_get_vdu_list(self
, account
):
1152 """Get information about all the virtual deployment units
1155 account - a cloud account
1158 A list of objects of type RwcalYang.VDUInfoParams
1160 vnf_resources
= RwcalYang
.VNFResources()
1161 drv
= self
._use
_driver
(account
)
1163 vms
= drv
.nova_server_list()
1165 vdu
= drv
.utils
.compute
.parse_cloud_vdu_info(vm
)
1166 vnf_resources
.vdu_info_list
.append(vdu
)
1167 except Exception as e
:
1168 self
.log
.exception("Exception %s occured during get-vdu-list", str(e
))
1170 return vnf_resources