import os
import subprocess
import uuid
+import tempfile
+import yaml
import rift.rwcal.openstack as openstack_drv
import rw_status
import rwlogger
import neutronclient.common.exceptions as NeutronException
import keystoneclient.exceptions as KeystoneExceptions
+import tornado
+import gi
+
+gi.require_version('RwSdn', '1.0')
from gi.repository import (
GObject,
RwTypes,
RwcalYang)
-PREPARE_VM_CMD = "prepare_vm.py --auth_url {auth_url} --username {username} --password {password} --tenant_name {tenant_name} --mgmt_network {mgmt_network} --server_id {server_id} --port_metadata"
+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 "
rwstatus_exception_map = { IndexError: RwTypes.RwStatus.NOTFOUND,
KeyError: RwTypes.RwStatus.NOTFOUND,
self._rwlog_handler = None
RwcalOpenstackPlugin.instance_num += 1
-
@contextlib.contextmanager
def _use_driver(self, account):
if self._rwlog_handler is None:
with rwlogger.rwlog_root_handler(self._rwlog_handler):
try:
- drv = self._driver_class(username = account.openstack.key,
- password = account.openstack.secret,
- auth_url = account.openstack.auth_url,
- tenant_name = account.openstack.tenant,
- mgmt_network = account.openstack.mgmt_network,
- cert_validate = account.openstack.cert_validate )
+ drv = self._driver_class(username = account.openstack.key,
+ password = account.openstack.secret,
+ auth_url = account.openstack.auth_url,
+ tenant_name = account.openstack.tenant,
+ mgmt_network = account.openstack.mgmt_network,
+ cert_validate = account.openstack.cert_validate,
+ user_domain_name = account.openstack.user_domain,
+ project_domain_name = account.openstack.project_domain,
+ region = account.openstack.region)
except (KeystoneExceptions.Unauthorized, KeystoneExceptions.AuthorizationFailure,
NeutronException.NotFound) as e:
raise
image = drv.glance_image_get(image_id)
return RwcalOpenstackPlugin._fill_image_info(image)
+ # This is being deprecated. Please do not use for new SW development
@rwstatus(ret_on_failure=[""])
def do_create_vm(self, account, vminfo):
"""Create a new virtual machine.
with self._use_driver(account) as drv:
### If floating_ip is required and we don't have one, better fail before any further allocation
+ pool_name = None
+ floating_ip = False
if vminfo.has_field('allocate_public_address') and vminfo.allocate_public_address:
if account.openstack.has_field('floating_ip_pool'):
pool_name = account.openstack.floating_ip_pool
- else:
- pool_name = None
- floating_ip = self._allocate_floating_ip(drv, pool_name)
- else:
- floating_ip = None
+ floating_ip = True
if vminfo.has_field('cloud_init') and vminfo.cloud_init.has_field('userdata'):
kwargs['userdata'] = vminfo.cloud_init.userdata
if ('fixed_ips' in port_info) and (len(port_info['fixed_ips']) >= 1):
if 'ip_address' in port_info['fixed_ips'][0]:
c_point.ip_address = port_info['fixed_ips'][0]['ip_address']
+ if 'mac_address' in port_info :
+ c_point.mac_addr = port_info['mac_address']
if port_info['status'] == 'ACTIVE':
c_point.state = 'active'
else:
return link
@staticmethod
- def _fill_vdu_info(vm_info, flavor_info, mgmt_network, port_list, server_group, volume_list = None):
+ def _fill_vdu_info(drv, vm_info, flavor_info, mgmt_network, port_list, server_group, volume_list = None):
"""Create a GI object for VDUInfoParams
Converts VM information dictionary object returned by openstack
vdu.public_ip = interface['addr']
# Look for any metadata
- for key, value in vm_info['metadata'].items():
- if key == 'node_id':
- vdu.node_id = value
+# for key, value in vm_info['metadata'].items():
+# if key == 'node_id':
+# vdu.node_id = value
+# else:
+# custommetadata = vdu.supplemental_boot_data.custom_meta_data.add()
+# custommetadata.name = key
+# custommetadata.value = str(value)
+
+ # Look for config_drive
+ if ('config_drive' in vm_info):
+ vdu.supplemental_boot_data.boot_data_drive = vm_info['config_drive']
if ('image' in vm_info) and ('id' in vm_info['image']):
vdu.image_id = vm_info['image']['id']
if ('flavor' in vm_info) and ('id' in vm_info['flavor']):
continue
volr.name = vol_name
volr.volume_id = os_volume['volumeId']
+ try:
+ vol_details = drv.cinder_volume_get(volr.volume_id)
+ except:
+ continue
+ if vol_details is None:
+ continue
+ for key, value in vol_details.metadata.items():
+ volmd = volr.custom_meta_data.add()
+ volmd.name = key
+ volmd.value = value
return vdu
else:
raise NotImplementedError("Port Type: %s not supported" %(c_point.type_yang))
+ # By default port gets created with post_security enaled as True
+ if 'port_security_enabled' in c_point:
+ kwargs['port_security_enabled'] = c_point.port_security_enabled
+
with self._use_driver(account) as drv:
if c_point.has_field('security_group'):
group = drv.neutron_security_group_by_name(c_point.security_group)
with self._use_driver(account) as drv:
### If floating_ip is required and we don't have one, better fail before any further allocation
+ floating_ip = False
+ pool_name = None
if vduinfo.has_field('allocate_public_address') and vduinfo.allocate_public_address:
if account.openstack.has_field('floating_ip_pool'):
pool_name = account.openstack.floating_ip_pool
- else:
- pool_name = None
- floating_ip = self._allocate_floating_ip(drv, pool_name)
- else:
- floating_ip = None
+ floating_ip = True
if vduinfo.has_field('vdu_init') and vduinfo.vdu_init.has_field('userdata'):
kwargs['userdata'] = vduinfo.vdu_init.userdata
kwargs['network_list'] = network_list
metadata = {}
+ files = {}
+ config_drive = False
# Add all metadata related fields
if vduinfo.has_field('node_id'):
metadata['node_id'] = vduinfo.node_id
if pci_assignement is not None:
metadata['pci_assignement'] = pci_assignement
+ if vduinfo.has_field('supplemental_boot_data'):
+ if vduinfo.supplemental_boot_data.has_field('custom_meta_data'):
+ for custom_meta_item in vduinfo.supplemental_boot_data.custom_meta_data:
+ if custom_meta_item.data_type == "STRING":
+ metadata[custom_meta_item.name] = custom_meta_item.value
+ elif custom_meta_item.data_type == "JSON":
+ metadata[custom_meta_item.name] = tornado.escape.json_decode(custom_meta_item.value)
+ else:
+ raise OpenstackCALOperationFailure("Create-vdu operation failed. Unsupported data-type {} for custom-meta-data name {} ".format(custom_meta_item.data_type, custom_meta_item.name))
+ if vduinfo.supplemental_boot_data.has_field('config_file'):
+ for custom_config_file in vduinfo.supplemental_boot_data.config_file:
+ files[custom_config_file.dest] = custom_config_file.source
+
+ if vduinfo.supplemental_boot_data.has_field('boot_data_drive'):
+ if vduinfo.supplemental_boot_data.boot_data_drive is True:
+ config_drive = True
+
kwargs['metadata'] = metadata
+ kwargs['files'] = files
+ kwargs['config_drive'] = config_drive
if vduinfo.has_field('availability_zone') and vduinfo.availability_zone.has_field('name'):
kwargs['availability_zone'] = vduinfo.availability_zone
kwargs['scheduler_hints'] = None
kwargs['block_device_mapping_v2'] = None
+ vol_metadata = False
if vduinfo.has_field('volumes') :
kwargs['block_device_mapping_v2'] = []
with self._use_driver(account) as drv:
# Only support image->volume
for volume in vduinfo.volumes:
block_map = dict()
- block_map['boot_index'] = volume.boot_params.boot_priority
+ block_map['boot_index'] = volume.boot_priority
if "image" in volume:
# Support image->volume
# Match retrived image info with volume based image name and checksum
block_map['destination_type'] = "volume"
block_map['volume_size'] = volume.size
block_map['delete_on_termination'] = True
- if volume.guest_params.has_field('device_type') and volume.guest_params.device_type == 'cdrom':
+ if volume.has_field('device_type') and volume.device_type == 'cdrom':
block_map['device_type'] = 'cdrom'
- if volume.guest_params.has_field('device_bus') and volume.guest_params.device_bus == 'ide':
+ if volume.has_field('device_bus') and volume.device_bus == 'ide':
block_map['disk_bus'] = 'ide'
kwargs['block_device_mapping_v2'].append(block_map)
with self._use_driver(account) as drv:
vm_id = drv.nova_server_create(**kwargs)
if floating_ip:
- self.prepare_vdu_on_boot(account, vm_id, floating_ip)
+ self.prepare_vdu_on_boot(account, vm_id, floating_ip, pool_name, vduinfo.volumes)
return vm_id
The vdu_id
"""
### First create required number of ports aka connection points
+ # Add the mgmt_ntwk by default.
+ mgmt_network_id = None
with self._use_driver(account) as drv:
- ### If floating_ip is required and we don't have one, better fail before any further allocation
- if vdu_init.has_field('allocate_public_address') and vdu_init.allocate_public_address:
- if account.openstack.has_field('floating_ip_pool'):
- pool_name = account.openstack.floating_ip_pool
- else:
- pool_name = None
- floating_ip = self._allocate_floating_ip(drv, pool_name)
- else:
- floating_ip = None
+ mgmt_network_id = drv._mgmt_network_id
port_list = []
network_list = []
imageinfo_list = []
+ is_explicit_mgmt_defined = False
for c_point in vdu_init.connection_points:
+ # if the user has specified explicit mgmt_network connection point
+ # then remove the mgmt_network from the VM list
+ if c_point.virtual_link_id == mgmt_network_id:
+ is_explicit_mgmt_defined = True
if c_point.virtual_link_id in network_list:
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"
else:
with self._use_driver(account) as drv:
### Now Create VM
vm_network_list = []
- vm_network_list.append(drv._mgmt_network_id)
+ if not is_explicit_mgmt_defined:
+ vm_network_list.append(drv._mgmt_network_id)
if vdu_init.has_field('volumes'):
# Only combination supported: Image->Volume
err_str = ("VDU Volume source not supported yet")
self.log.error(err_str)
raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
- if "guest_params" not in volume:
- err_str = ("VDU Volume destination parameters '%s' not defined")
- self.log.error(err_str)
- raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
- if not volume.guest_params.has_field('device_type'):
- err_str = ("VDU Volume destination type '%s' not defined")
+ if not volume.has_field('device_type'):
+ err_str = ("VDU Volume destination type not defined")
self.log.error(err_str)
raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
- if volume.guest_params.device_type not in ['disk', 'cdrom'] :
- err_str = ("VDU Volume destination type '%s' not supported" % volume.guest_params.device_type)
+ if volume.device_type not in ['disk', 'cdrom'] :
+ err_str = ("VDU Volume destination type '%s' not supported" % volume.device_type)
self.log.error(err_str)
raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
vm.user_tags.pci_assignement = pci_assignement
vm_id = self._create_vm(account, vdu_init, pci_assignement=pci_assignement, server_group=server_group, port_list=port_list, network_list=vm_network_list, imageinfo_list = imageinfo_list)
- self.prepare_vdu_on_boot(account, vm_id, floating_ip)
return vm_id
def prepare_vpci_metadata(self, drv, vdu_init):
- def prepare_vdu_on_boot(self, account, server_id, floating_ip):
- cmd = PREPARE_VM_CMD.format(auth_url = account.openstack.auth_url,
- username = account.openstack.key,
- password = account.openstack.secret,
- tenant_name = account.openstack.tenant,
- mgmt_network = account.openstack.mgmt_network,
- server_id = server_id)
-
- if floating_ip is not None:
- cmd += (" --floating_ip "+ floating_ip.ip)
+ def prepare_vdu_on_boot(self, account, server_id, floating_ip, pool_name, volumes=None):
+ cmd = PREPARE_VM_CMD.format(auth_url = account.openstack.auth_url,
+ username = account.openstack.key,
+ password = account.openstack.secret,
+ tenant_name = account.openstack.tenant,
+ region = account.openstack.region,
+ user_domain = account.openstack.user_domain,
+ project_domain = account.openstack.project_domain,
+ mgmt_network = account.openstack.mgmt_network,
+ server_id = server_id)
+ if floating_ip:
+ cmd += " --floating_ip"
+ if pool_name:
+ cmd += (" --pool_name " + pool_name)
+
+ vol_metadata = False
+ if volumes is not None:
+ for volume in volumes:
+ if volume.has_field('custom_meta_data'):
+ vol_metadata = True
+ break
+
+ if vol_metadata is True:
+ tmp_file = None
+ with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp_file:
+ vol_list = list()
+ for volume in volumes:
+ vol_dict = volume.as_dict()
+ vol_list.append(vol_dict)
+
+ yaml.dump(vol_list, tmp_file)
+ cmd += (" --vol_metadata {}").format(tmp_file.name)
exec_path = 'python3 ' + os.path.dirname(openstack_drv.__file__)
exec_cmd = exec_path+'/'+cmd
Object of type RwcalYang.VDUInfoParams
"""
with self._use_driver(account) as drv:
-
- ### Get list of ports excluding the one for management network
- port_list = [p for p in drv.neutron_port_list(**{'device_id': vdu_id}) if p['network_id'] != drv.get_mgmt_network_id()]
+ port_list = drv.neutron_port_list(**{'device_id': vdu_id})
vm = drv.nova_server_get(vdu_id)
openstack_group_list = drv.nova_server_group_list()
server_group = [ i['name'] for i in openstack_group_list if vm['id'] in i['members']]
openstack_srv_volume_list = drv.nova_volume_list(vm['id'])
- vdu_info = RwcalOpenstackPlugin._fill_vdu_info(vm,
+ vdu_info = RwcalOpenstackPlugin._fill_vdu_info(drv, vm,
flavor_info,
account.openstack.mgmt_network,
port_list,
with self._use_driver(account) as drv:
vms = drv.nova_server_list()
for vm in vms:
- ### Get list of ports excluding one for management network
- port_list = [p for p in drv.neutron_port_list(**{'device_id': vm['id']}) if p['network_id'] != drv.get_mgmt_network_id()]
+ port_list = drv.neutron_port_list(**{'device_id': vm['id']})
flavor_info = None
server_group = [ i['name'] for i in openstack_group_list if vm['id'] in i['members']]
openstack_srv_volume_list = drv.nova_volume_list(vm['id'])
- vdu = RwcalOpenstackPlugin._fill_vdu_info(vm,
+ vdu = RwcalOpenstackPlugin._fill_vdu_info(drv, vm,
flavor_info,
account.openstack.mgmt_network,
port_list,