SO Multidisk changes
Change-Id: I75a5029fbaa295c11af24cfa4fe8ca872a73c69f
Signed-off-by: chamarty <ravi.chamarty@riftio.com>
diff --git a/models/plugins/yang/mano-types.yang b/models/plugins/yang/mano-types.yang
index e7c7d3d..5f68b41 100644
--- a/models/plugins/yang/mano-types.yang
+++ b/models/plugins/yang/mano-types.yang
@@ -112,6 +112,28 @@
}
+ grouping image-properties {
+ leaf image {
+ description
+ "Image name for the software image.
+ If the image name is found within the VNF packaage it will
+ be uploaded to all cloud accounts during onboarding process.
+ Otherwise, the image must be added to the cloud account with
+ the same name as entered here.
+ ";
+ type string;
+ }
+
+ leaf image-checksum {
+ description
+ "Image md5sum for the software image.
+ The md5sum, if provided, along with the image name uniquely
+ identifies an image uploaded to the CAL.
+ ";
+ type string;
+ }
+ }
+
grouping vnf-configuration {
container vnf-configuration {
rwpb:msg-new VnfConfiguration;
@@ -2002,5 +2024,79 @@
uses ip-profile-info;
}
}
-
+
+ grouping volume-info {
+ description "Grouping for Volume-info";
+
+ leaf description {
+ description "Description for Volume";
+ type string;
+ }
+
+ leaf size {
+ description "Size of disk in GB";
+ type uint64;
+ }
+
+ choice volume-source {
+ description
+ "Defines the source of the volume. Possible options are
+ 1. Ephemeral -- Empty disk
+ 2. Image -- Refer to image to be used for volume
+ 3. Volume -- Reference of pre-existing volume to be used
+ ";
+
+ case ephemeral {
+ leaf ephemeral {
+ type empty;
+ }
+ }
+
+ case image {
+ uses image-properties;
+ }
+
+ case volume {
+ leaf volume-ref {
+ description "Reference for pre-existing volume in VIM";
+ type string;
+ }
+ }
+ }
+
+ container boot-params {
+ leaf boot-volume {
+ description "This flag indicates if this is boot volume or not";
+ type boolean;
+ }
+ leaf boot-priority {
+ description "Boot priority associated with volume";
+ type int32;
+ }
+ }
+
+ container guest-params {
+ description "Guest virtualization parameter associated with volume";
+
+ leaf device_bus {
+ description "Type of disk-bus on which this disk is exposed to guest";
+ type enumeration {
+ enum ide;
+ enum usb;
+ enum virtio;
+ enum scsi;
+ }
+ }
+
+ leaf device_type {
+ description "The type of device as exposed to guest";
+ type enumeration {
+ enum disk;
+ enum cdrom;
+ enum floppy;
+ enum lun;
+ }
+ }
+ }
+ }
}
diff --git a/models/plugins/yang/vnfd.yang b/models/plugins/yang/vnfd.yang
index 2cc43d3..81bb2aa 100644
--- a/models/plugins/yang/vnfd.yang
+++ b/models/plugins/yang/vnfd.yang
@@ -342,26 +342,7 @@
uses manotypes:alarm;
}
- leaf image {
- description
- "Image name for the software image.
- If the image name is found within the VNF packaage it will
- be uploaded to all cloud accounts during onboarding process.
- Otherwise, the image must be added to the cloud account with
- the same name as entered here.
- ";
- mandatory true;
- type string;
- }
-
- leaf image-checksum {
- description
- "Image md5sum for the software image.
- The md5sum, if provided, along with the image name uniquely
- identifies an image uploaded to the CAL.
- ";
- type string;
- }
+ uses manotypes:image-properties;
choice cloud-init-input {
description
@@ -447,6 +428,17 @@
}
uses virtual-interface;
}
+
+ list volumes {
+ key "name";
+
+ leaf name {
+ description "Name of the disk-volumes, e.g. vda, vdb etc";
+ type string;
+ }
+
+ uses manotypes:volume-info;
+ }
}
list vdu-dependency {
diff --git a/models/plugins/yang/vnfr.yang b/models/plugins/yang/vnfr.yang
index a4419ce..8f739f4 100644
--- a/models/plugins/yang/vnfr.yang
+++ b/models/plugins/yang/vnfr.yang
@@ -338,6 +338,22 @@
uses manotypes:hypervisor-epa;
uses manotypes:host-epa;
+ list volumes {
+ key "name";
+
+ leaf name {
+ description "Name of the disk-volumes, e.g. vda, vdb etc";
+ type string;
+ }
+
+ leaf volume-id {
+ description "VIM assigned volume id";
+ type string;
+ }
+
+ uses manotypes:volume-info;
+ }
+
list alarms {
description
"A list of the alarms that have been created for this VDU";
diff --git a/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/openstack_drv.py b/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/openstack_drv.py
index 2b8ab7c..943cdd5 100644
--- a/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/openstack_drv.py
+++ b/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/openstack_drv.py
@@ -529,7 +529,8 @@
{
server_name(string) : Name of the VM/Server
flavor_id (string) : UUID of the flavor to be used for VM
- image_id (string) : UUID of the image to be used VM/Server instance
+ image_id (string) : UUID of the image to be used VM/Server instance,
+ This could be None if volumes (with images) are being used
network_list(List) : A List of network_ids. A port will be created in these networks
port_list (List) : A List of port-ids. These ports will be added to VM.
metadata (dict) : A dictionary of arbitrary key-value pairs associated with VM/server
@@ -552,6 +553,7 @@
nvconn = self._get_nova_connection()
+
try:
server = nvconn.servers.create(kwargs['name'],
kwargs['image_id'],
@@ -564,7 +566,7 @@
userdata = kwargs['userdata'],
security_groups = kwargs['security_groups'],
availability_zone = kwargs['availability_zone'],
- block_device_mapping = None,
+ block_device_mapping_v2 = kwargs['block_device_mapping_v2'],
nics = nics,
scheduler_hints = kwargs['scheduler_hints'],
config_drive = None)
@@ -836,6 +838,26 @@
logger.error("OpenstackDriver: Release Floating IP operation failed. Exception: %s" %str(e))
raise
+ def volume_list(self, server_id):
+ """
+ List of volumes attached to the server
+
+ Arguments:
+ None
+ Returns:
+ List of dictionary objects where dictionary is representation of class (novaclient.v2.volumes.Volume)
+ """
+ nvconn = self._get_nova_connection()
+ try:
+ volumes = nvconn.volumes.get_server_volumes(server_id=server_id)
+ except Exception as e:
+ logger.error("OpenstackDriver: Get volume information failed. Exception: %s" %str(e))
+ raise
+
+ volume_info = [v.to_dict() for v in volumes]
+ return volume_info
+
+
def group_list(self):
"""
List of Server Affinity and Anti-Affinity Groups
@@ -1725,10 +1747,19 @@
return self.nova_drv.flavor_get(flavor_id)
def nova_server_create(self, **kwargs):
+ def _verify_image(image_id):
+ image = self.glance_drv.image_get(image_id)
+ if image['status'] != 'active':
+ raise GlanceException.NotFound("Image with image_id: %s not found in active state. Current State: %s" %(image['id'], image['status']))
+
assert kwargs['flavor_id'] == self.nova_drv.flavor_get(kwargs['flavor_id'])['id']
- image = self.glance_drv.image_get(kwargs['image_id'])
- if image['status'] != 'active':
- raise GlanceException.NotFound("Image with image_id: %s not found in active state. Current State: %s" %(image['id'], image['status']))
+
+ if kwargs['block_device_mapping_v2'] is not None:
+ for block_map in kwargs['block_device_mapping_v2']:
+ if 'uuid' in block_map:
+ _verify_image(block_map['uuid'])
+ else:
+ _verify_image(kwargs['image_id'])
# if 'network_list' in kwargs:
# kwargs['network_list'].append(self._mgmt_network_id)
@@ -1794,6 +1825,9 @@
def nova_server_group_list(self):
return self.nova_drv.group_list()
+ def nova_volume_list(self, server_id):
+ return self.nova_drv.volume_list(server_id)
+
def neutron_network_list(self):
return self.neutron_drv.network_list()
diff --git a/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/prepare_vm.py b/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/prepare_vm.py
index 7acf0fd..0d658f1 100644
--- a/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/prepare_vm.py
+++ b/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/prepare_vm.py
@@ -96,9 +96,9 @@
### Important to call create_port_metadata before assign_floating_ip_address
### since assign_floating_ip_address can wait thus delaying port_metadata creation
- ### Wait for 2 minute for server to come up -- Needs fine tuning
- wait_time = 120
- sleep_time = 1
+ ### Wait for a max of 5 minute for server to come up -- Needs fine tuning
+ wait_time = 300
+ sleep_time = 2
for i in range(int(wait_time/sleep_time)):
server = drv.nova_server_get(argument.server_id)
if server['status'] == 'ACTIVE':
diff --git a/rwcal/plugins/vala/rwcal_openstack/rwcal_openstack.py b/rwcal/plugins/vala/rwcal_openstack/rwcal_openstack.py
index 8a2d275..e5dcb67 100644
--- a/rwcal/plugins/vala/rwcal_openstack/rwcal_openstack.py
+++ b/rwcal/plugins/vala/rwcal_openstack/rwcal_openstack.py
@@ -376,7 +376,8 @@
kwargs = {}
kwargs['name'] = vminfo.vm_name
kwargs['flavor_id'] = vminfo.flavor_id
- kwargs['image_id'] = vminfo.image_id
+ if vminfo.has_field('image_id'):
+ kwargs['image_id'] = vminfo.image_id
with self._use_driver(account) as drv:
### If floating_ip is required and we don't have one, better fail before any further allocation
@@ -1227,7 +1228,7 @@
return link
@staticmethod
- def _fill_vdu_info(vm_info, flavor_info, mgmt_network, port_list, server_group):
+ def _fill_vdu_info(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
@@ -1284,6 +1285,19 @@
if flavor_info is not None:
RwcalOpenstackPlugin._fill_epa_attributes(vdu, flavor_info)
+
+ # Fill the volume information
+ if volume_list is not None:
+ for os_volume in volume_list:
+ volr = vdu.volumes.add()
+ try:
+ " Device name is of format /dev/vda"
+ vol_name = (os_volume['device']).split('/')[2]
+ except:
+ continue
+ volr.name = vol_name
+ volr.volume_id = os_volume['volumeId']
+
return vdu
@rwcalstatus(ret_on_failure=[""])
@@ -1854,6 +1868,136 @@
raise OpenstackCALOperationFailure("Create-flavor operation failed for cloud account: %s" %(account.name))
return flavor_id
+ def _create_vm(self, account, vduinfo, pci_assignement=None, server_group=None, port_list=None, network_list=None, imageinfo_list=None):
+ """Create a new virtual machine.
+
+ Arguments:
+ account - a cloud account
+ vminfo - information that defines the type of VM to create
+
+ Returns:
+ The image id
+ """
+ kwargs = {}
+ kwargs['name'] = vduinfo.name
+ kwargs['flavor_id'] = vduinfo.flavor_id
+ if vduinfo.has_field('image_id'):
+ kwargs['image_id'] = vduinfo.image_id
+ else:
+ kwargs['image_id'] = ""
+
+ 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 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
+
+ if vduinfo.has_field('vdu_init') and vduinfo.vdu_init.has_field('userdata'):
+ kwargs['userdata'] = vduinfo.vdu_init.userdata
+ else:
+ kwargs['userdata'] = ''
+
+ if account.openstack.security_groups:
+ kwargs['security_groups'] = account.openstack.security_groups
+
+ kwargs['port_list'] = port_list
+ kwargs['network_list'] = network_list
+
+ metadata = {}
+ # 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
+ kwargs['metadata'] = metadata
+
+ if vduinfo.has_field('availability_zone') and vduinfo.availability_zone.has_field('name'):
+ kwargs['availability_zone'] = vduinfo.availability_zone
+ else:
+ kwargs['availability_zone'] = None
+
+ if server_group is not None:
+ kwargs['scheduler_hints'] = {'group': server_group}
+ else:
+ kwargs['scheduler_hints'] = None
+
+ kwargs['block_device_mapping_v2'] = None
+ 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
+ if "image" in volume:
+ # Support image->volume
+ # Match retrived image info with volume based image name and checksum
+ if volume.image is not None:
+ matching_images = [img for img in imageinfo_list if img['name'] == volume.image]
+ if volume.image_checksum is not None:
+ matching_images = [img for img in matching_images if img['checksum'] == volume.image_checksum]
+ img_id = matching_images[0]['id']
+ if img_id is None:
+ raise OpenstackCALOperationFailure("Create-vdu operation failed. Volume image not found for name {} checksum {}".format(volume.name, volume.checksum))
+ block_map['uuid'] = img_id
+ block_map['source_type'] = "image"
+ else:
+ block_map['source_type'] = "blank"
+
+ block_map['device_name'] = volume.name
+ 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':
+ block_map['device_type'] = 'cdrom'
+ if volume.guest_params.has_field('device_bus') and volume.guest_params.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)
+
+ return vm_id
+
+ def get_openstack_image_info(self, account, image_name, image_checksum=None):
+ self.log.debug("Looking up image id for image name %s and checksum %s on cloud account: %s",
+ image_name, image_checksum, account.name
+ )
+
+ image_list = []
+ with self._use_driver(account) as drv:
+ image_list = drv.glance_image_list()
+ matching_images = [img for img in image_list if img['name'] == image_name]
+
+ # If the image checksum was filled in then further filter the images by the checksum
+ if image_checksum is not None:
+ matching_images = [img for img in matching_images if img['checksum'] == image_checksum]
+ else:
+ self.log.warning("Image checksum not provided. Lookup using image name (%s) only.",
+ image_name)
+
+ if len(matching_images) == 0:
+ raise ResMgrCALOperationFailure("Could not find image name {} (using checksum: {}) for cloud account: {}".format(
+ image_name, image_checksum, account.name
+ ))
+
+ elif len(matching_images) > 1:
+ unique_checksums = {i.checksum for i in matching_images}
+ if len(unique_checksums) > 1:
+ msg = ("Too many images with different checksums matched "
+ "image name of %s for cloud account: %s" % (image_name, account.name))
+ raise ResMgrCALOperationFailure(msg)
+
+ return matching_images[0]
+
@rwcalstatus(ret_on_failure=[""])
def do_create_vdu(self, account, vdu_init):
"""Create a new virtual deployment unit
@@ -1879,6 +2023,7 @@
port_list = []
network_list = []
+ imageinfo_list = []
for c_point in vdu_init.connection_points:
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"
@@ -1890,70 +2035,94 @@
if not vdu_init.has_field('flavor_id'):
vdu_init.flavor_id = self._select_resource_flavor(account,vdu_init)
+ ### Obtain all images for volumes and perform validations
+ if vdu_init.has_field('volumes'):
+ for volume in vdu_init.volumes:
+ if "image" in volume:
+ image_checksum = volume.image_checksum if volume.has_field("image_checksum") else None
+ image_info = self.get_openstack_image_info(account, volume.image, image_checksum)
+ imageinfo_list.append(image_info)
+ elif vdu_init.has_field('image_id'):
+ with self._use_driver(account) as drv:
+ image_info = drv.glance_image_get(vdu_init.image_id)
+ imageinfo_list.append(image_info)
+
+ if not imageinfo_list:
+ err_str = ("VDU has no image information")
+ self.log.error(err_str)
+ raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
+
### Check VDU Virtual Interface type and make sure VM with property exists
- if vdu_init.connection_points is not None:
+ if vdu_init.connection_points:
### All virtual interfaces need to be of the same type for Openstack Accounts
- if not all(cp.type_yang == vdu_init.connection_points[0].type_yang for cp in vdu_init.connection_points):
- ### We have a mix of E1000 & VIRTIO virtual interface types in the VDU, abort instantiation.
- assert False, "Only one type of Virtual Intefaces supported for Openstack accounts. Found a mix of VIRTIO & E1000."
-
- with self._use_driver(account) as drv:
- img_info = drv.glance_image_get(vdu_init.image_id)
-
- virt_intf_type = vdu_init.connection_points[0].type_yang
- if virt_intf_type == 'E1000':
- if 'hw_vif_model' in img_info and img_info.hw_vif_model == 'e1000':
- self.log.debug("VDU has Virtual Interface E1000, found matching image with property hw_vif_model=e1000")
+ if not (all(cp.type_yang == 'E1000' for cp in vdu_init.connection_points) or all(cp.type_yang != 'E1000' for cp in vdu_init.connection_points)):
+ ### We have a mix of E1000 & VIRTIO/SR_IPOV virtual interface types in the VDU, abort instantiation.
+ assert False, "Only one type of Virtual Intefaces supported for Openstack accounts. Found a mix of VIRTIO/SR_IOV & E1000."
+
+ ## It is not clear if all the images need to checked for HW properties. In the absence of model info describing each im age's properties,
+ ### we shall assume that all images need to have similar properties
+ for img_info in imageinfo_list:
+
+ virt_intf_type = vdu_init.connection_points[0].type_yang
+ if virt_intf_type == 'E1000':
+ if 'hw_vif_model' in img_info and img_info.hw_vif_model == 'e1000':
+ self.log.debug("VDU has Virtual Interface E1000, found matching image with property hw_vif_model=e1000")
+ else:
+ err_str = ("VDU has Virtual Interface E1000, but image '%s' does not have property hw_vif_model=e1000" % img_info.name)
+ self.log.error(err_str)
+ raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
+ elif virt_intf_type == 'VIRTIO' or virt_intf_type == 'SR_IOV':
+ if 'hw_vif_model' in img_info:
+ err_str = ("VDU has Virtual Interface %s, but image '%s' has hw_vif_model mismatch" % virt_intf_type,img_info.name)
+ self.log.error(err_str)
+ raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
+ else:
+ self.log.debug("VDU has Virtual Interface %s, found matching image" % virt_intf_type)
else:
- err_str = ("VDU has Virtual Interface E1000, but image '%s' does not have property hw_vif_model=e1000" % img_info.name)
+ err_str = ("VDU Virtual Interface '%s' not supported yet" % virt_intf_type)
self.log.error(err_str)
- raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
- elif virt_intf_type == 'VIRTIO':
- if 'hw_vif_model' in img_info:
- err_str = ("VDU has Virtual Interface VIRTIO, but image '%s' has hw_vif_model mismatch" % img_info.name)
- self.log.error(err_str)
- raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
- else:
- self.log.debug("VDU has Virtual Interface VIRTIO, found matching image")
- else:
- err_str = ("VDU Virtual Interface '%s' not supported yet" % virt_intf_type)
- self.log.error(err_str)
- raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
+ raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
with self._use_driver(account) as drv:
### Now Create VM
- vm = RwcalYang.VMInfoItem()
- vm.vm_name = vdu_init.name
- vm.flavor_id = vdu_init.flavor_id
- vm.image_id = vdu_init.image_id
- vm_network = vm.network_list.add()
- vm_network.network_id = drv._mgmt_network_id
- if vdu_init.has_field('vdu_init') and vdu_init.vdu_init.has_field('userdata'):
- vm.cloud_init.userdata = vdu_init.vdu_init.userdata
-
- if vdu_init.has_field('node_id'):
- vm.user_tags.node_id = vdu_init.node_id;
-
- if vdu_init.has_field('availability_zone') and vdu_init.availability_zone.has_field('name'):
- vm.availability_zone = vdu_init.availability_zone.name
-
+ vm_network_list = []
+ vm_network_list.append(drv._mgmt_network_id)
+
+ if vdu_init.has_field('volumes'):
+ # Only combination supported: Image->Volume
+ for volume in vdu_init.volumes:
+ if "volume" in 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")
+ 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)
+ self.log.error(err_str)
+ raise OpenstackCALOperationFailure("Create-vdu operation failed. Error- %s" % err_str)
+
+
+ server_group = None
if vdu_init.has_field('server_group'):
- ### Get list of server group in openstack for name->id mapping
- openstack_group_list = drv.nova_server_group_list()
- group_id = [ i['id'] for i in openstack_group_list if i['name'] == vdu_init.server_group.name]
- if len(group_id) != 1:
- raise OpenstackServerGroupError("VM placement failed. Server Group %s not found in openstack. Available groups" %(vdu_init.server_group.name, [i['name'] for i in openstack_group_list]))
- vm.server_group = group_id[0]
-
- for port_id in port_list:
- port = vm.port_list.add()
- port.port_id = port_id
+ ### Get list of server group in openstack for name->id mapping
+ openstack_group_list = drv.nova_server_group_list()
+ group_id = [ i['id'] for i in openstack_group_list if i['name'] == vdu_init.server_group.name]
+ if len(group_id) != 1:
+ raise OpenstackServerGroupError("VM placement failed. Server Group %s not found in openstack. Available groups" %(vdu_init.server_group.name, [i['name'] for i in openstack_group_list]))
+ server_group = group_id[0]
pci_assignement = self.prepare_vpci_metadata(drv, vdu_init)
if pci_assignement != '':
vm.user_tags.pci_assignement = pci_assignement
- vm_id = self.do_create_vm(account, vm, no_rwstatus=True)
+ 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
@@ -2107,11 +2276,13 @@
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,
flavor_info,
account.openstack.mgmt_network,
port_list,
- server_group)
+ server_group,
+ volume_list = openstack_srv_volume_list)
if vdu_info.state == 'active':
try:
console_info = drv.nova_server_console(vdu_info.vdu_id)
@@ -2155,11 +2326,13 @@
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 = RwcalOpenstackPlugin._fill_vdu_info(vm,
flavor_info,
account.openstack.mgmt_network,
port_list,
- server_group)
+ server_group,
+ volume_list = openstack_srv_volume_list)
if vdu.state == 'active':
try:
console_info = drv.nova_server_console(vdu.vdu_id)
diff --git a/rwcal/plugins/yang/rwcal.yang b/rwcal/plugins/yang/rwcal.yang
index 6f45e7c..76bd38b 100644
--- a/rwcal/plugins/yang/rwcal.yang
+++ b/rwcal/plugins/yang/rwcal.yang
@@ -998,6 +998,16 @@
type string;
}
}
+
+ list volumes {
+ key "name";
+
+ leaf name {
+ description "Name of the disk-volumes, e.g. vda, vdb etc";
+ type string;
+ }
+ uses manotypes:volume-info;
+ }
}
container vdu-init-params {
@@ -1214,8 +1224,26 @@
type string;
description "Console URL from the VIM, if available";
}
+
+ list volumes {
+ key "name";
+
+ leaf name {
+ description "Name of the disk-volumes, e.g. vda, vdb etc";
+ type string;
+ }
+
+ leaf volume-id {
+ description "CAL assigned volume-id ";
+ rwpb:field-inline "true";
+ rwpb:field-string-max 64;
+ type string;
+ }
+
+ }
}
+
container vnf-resources {
rwpb:msg-new VNFResources;
config false;
diff --git a/rwcal/test/test_rwcal_openstack.py b/rwcal/test/test_rwcal_openstack.py
index 119c22b..960beb9 100644
--- a/rwcal/test/test_rwcal_openstack.py
+++ b/rwcal/test/test_rwcal_openstack.py
@@ -39,11 +39,11 @@
openstack_info = {
'username' : 'pluto',
'password' : 'mypasswd',
- 'auth_url' : 'http://10.66.4.14:5000/v3/',
+ 'auth_url' : 'http://10.66.4.17:5000/v3/',
'project_name' : 'demo',
'mgmt_network' : 'private',
'reserved_flavor' : 'm1.medium',
- 'reserved_image' : 'rift-root-latest.qcow2',
+ 'reserved_image' : 'Fedora-x86_64-20-20131211.1-sda-ping.qcow2',
'physical_network' : None,
'network_type' : None,
'segmentation_id' : None
@@ -55,6 +55,7 @@
Creates an object for class RwcalYang.CloudAccount()
"""
account = RwcalYang.CloudAccount()
+ account.name = "Gruntxx"
account.account_type = "openstack"
account.openstack.key = openstack_info['username']
account.openstack.secret = openstack_info['password']
@@ -126,8 +127,9 @@
rc, rs = self.cal.get_network_list(self._acct)
self.assertEqual(rc, RwStatus.SUCCESS)
- networks = [ network for network in rs.networkinfo_list if (network.network_name == 'rift.cal.unittest.network' or network.network_name == 'rift.cal.virtual_link') ]
+ networks = [ network for network in rs.networkinfo_list if ((network.network_name == 'rift.cal.unittest.network') or ('rift.cal.virtual_link' in network.network_name) ) ]
for network in networks:
+ logger.debug("Openstack-CAL-Test: Deleting old VL %s", network.network_id)
self.cal.delete_virtual_link(self._acct, network.network_id)
def tearDown(self):
@@ -858,7 +860,7 @@
vlink_req = self._get_virtual_link_request_info()
rc, rsp = self.cal.create_virtual_link(self._acct, vlink_req)
- self.assertEqual(rc, RwStatus.SUCCESS)
+ self.assertEqual(rc.status, RwStatus.SUCCESS)
logger.info("Openstack-CAL-Test: Created virtual_link with Id: %s" %rsp)
vlink_id = rsp
@@ -872,7 +874,7 @@
logger.info("Openstack-CAL-Test: Test Create VDU API")
rc, rsp = self.cal.create_vdu(self._acct, vdu_req)
- self.assertEqual(rc, RwStatus.SUCCESS)
+ self.assertEqual(rc.status, RwStatus.SUCCESS)
logger.info("Openstack-CAL-Test: Created vdu with Id: %s" %rsp)
vdu_id = rsp
@@ -898,7 +900,7 @@
### Create another virtual_link
rc, rsp = self.cal.create_virtual_link(self._acct, vlink_req)
- self.assertEqual(rc, RwStatus.SUCCESS)
+ self.assertEqual(rc.status, RwStatus.SUCCESS)
logger.info("Openstack-CAL-Test: Created virtual_link with Id: %s" %rsp)
vlink_id2= rsp
@@ -932,7 +934,6 @@
logger.info("Openstack-CAL-Test: VDU/Virtual Link create-delete test successfully completed")
-
class VmData(object):
"""A convenience class that provides all the stats and EPA Attributes
from the VM provided
@@ -1059,5 +1060,5 @@
if __name__ == "__main__":
- logging.basicConfig(level=logging.INFO)
+ logging.basicConfig(level=logging.DEBUG)
unittest.main()
diff --git a/rwlaunchpad/plugins/rwmonitor/rift/tasklets/rwmonitor/core.py b/rwlaunchpad/plugins/rwmonitor/rift/tasklets/rwmonitor/core.py
index b97b2f5..b8abea7 100644
--- a/rwlaunchpad/plugins/rwmonitor/rift/tasklets/rwmonitor/core.py
+++ b/rwlaunchpad/plugins/rwmonitor/rift/tasklets/rwmonitor/core.py
@@ -317,9 +317,22 @@
vdu_metrics.memory.utilization = 100 * vdu_metrics.memory.used / vdu_metrics.memory.total
# Storage
- vdu_metrics.storage.used = metrics.storage.used
- vdu_metrics.storage.total = 1e9 * self.vdur.vm_flavor.storage_gb
- vdu_metrics.storage.utilization = 100 * vdu_metrics.storage.used / vdu_metrics.storage.total
+ try:
+ vdu_metrics.storage.used = metrics.storage.used
+ if self.vdur.has_field('volumes'):
+ for volume in self.vdur.volumes:
+ if vdu_metrics.storage.total is None:
+ vdu_metrics.storage.total = 1e9 * volume.size
+ else:
+ vdu_metrics.storage.total += (1e9 * volume.size)
+ else:
+ vdu_metrics.storage.total = 1e9 * self.vdur.vm_flavor.storage_gb
+ utilization = 100 * vdu_metrics.storage.used / vdu_metrics.storage.total
+ if utilization > 100:
+ utilization = 100
+ vdu_metrics.storage.utilization = utilization
+ except ZeroDivisionError:
+ vdu_metrics.storage.utilization = 0
# Network (incoming)
vdu_metrics.network.incoming.packets = metrics.network.incoming.packets
diff --git a/rwlaunchpad/plugins/rwresmgr/rift/tasklets/rwresmgrtasklet/rwresmgr_core.py b/rwlaunchpad/plugins/rwresmgr/rift/tasklets/rwresmgrtasklet/rwresmgr_core.py
index 161d5a4..a9fed38 100644
--- a/rwlaunchpad/plugins/rwresmgr/rift/tasklets/rwresmgrtasklet/rwresmgr_core.py
+++ b/rwlaunchpad/plugins/rwresmgr/rift/tasklets/rwresmgrtasklet/rwresmgr_core.py
@@ -196,8 +196,9 @@
params = RwcalYang.VDUInitParams()
params.from_dict(req_params.as_dict())
- image_checksum = req_params.image_checksum if req_params.has_field("image_checksum") else None
- params.image_id = yield from self.get_image_id_from_image_info(req_params.image_name, image_checksum)
+ if 'image_name' in req_params:
+ image_checksum = req_params.image_checksum if req_params.has_field("image_checksum") else None
+ params.image_id = yield from self.get_image_id_from_image_info(req_params.image_name, image_checksum)
#rc, rs = self._rwcal.create_vdu(self._account, params)
self._log.debug("Calling create_vdu API with params %s" %(str(params)))
diff --git a/rwlaunchpad/plugins/rwresmgr/rift/tasklets/rwresmgrtasklet/rwresmgr_events.py b/rwlaunchpad/plugins/rwresmgr/rift/tasklets/rwresmgrtasklet/rwresmgr_events.py
index 5f87c66..c80925c 100755
--- a/rwlaunchpad/plugins/rwresmgr/rift/tasklets/rwresmgrtasklet/rwresmgr_events.py
+++ b/rwlaunchpad/plugins/rwresmgr/rift/tasklets/rwresmgrtasklet/rwresmgr_events.py
@@ -178,10 +178,12 @@
def monitor_vdu_state(response_xpath, pathentry):
self._log.info("Initiating VDU state monitoring for xpath: %s ", response_xpath)
- loop_cnt = 180
+ time_to_wait = 300
+ sleep_time = 2
+ loop_cnt = int(time_to_wait/sleep_time)
for i in range(loop_cnt):
- self._log.debug("VDU state monitoring for xpath: %s. Sleeping for 1 second", response_xpath)
- yield from asyncio.sleep(1, loop = self._loop)
+ self._log.debug("VDU state monitoring for xpath: %s. Sleeping for 2 second", response_xpath)
+ yield from asyncio.sleep(2, loop = self._loop)
try:
response_info = yield from self._parent.read_virtual_compute_info(pathentry.key00.event_id)
except Exception as e:
@@ -203,7 +205,7 @@
return
else:
### End of loop. This is only possible if VDU did not reach active state
- err_msg = "VDU state monitoring: VDU at xpath :{} did not reached active state in {} seconds. Aborting monitoring".format(response_xpath, loop_cnt)
+ err_msg = "VDU state monitoring: VDU at xpath :{} did not reached active state in {} seconds. Aborting monitoring".format(response_xpath, time_to_wait)
self._log.info(err_msg)
response_info = RwResourceMgrYang.VDUEventData_ResourceInfo()
response_info.resource_state = 'failed'
diff --git a/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py b/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py
index f7d457e..c78c9a9 100755
--- a/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py
+++ b/rwlaunchpad/plugins/rwvnfm/rift/tasklets/rwvnfmtasklet/rwvnfmtasklet.py
@@ -340,6 +340,8 @@
@property
def image_name(self):
""" name that should be used to lookup the image on the CMP """
+ if 'image' not in self._vdud:
+ return None
return os.path.basename(self._vdud.image)
@property
@@ -380,6 +382,7 @@
"vswitch_epa",
"hypervisor_epa",
"host_epa",
+ "volumes",
"name"]
vdu_copy_dict = {k: v for k, v in
self._vdud.as_dict().items() if k in vdu_fields}
@@ -390,9 +393,10 @@
}
if self.vm_resp is not None:
vdur_dict.update({"vim_id": self.vm_resp.vdu_id,
- "flavor_id": self.vm_resp.flavor_id,
- "image_id": self.vm_resp.image_id,
+ "flavor_id": self.vm_resp.flavor_id
})
+ if self._vm_resp.has_field('image_id'):
+ vdur_dict.update({ "image_id": self.vm_resp.image_id })
if self.management_ip is not None:
vdur_dict["management_ip"] = self.management_ip
@@ -402,6 +406,13 @@
vdur_dict.update(vdu_copy_dict)
+ if self.vm_resp is not None:
+ if self._vm_resp.has_field('volumes'):
+ for opvolume in self._vm_resp.volumes:
+ vdurvol_data = [vduvol for vduvol in vdur_dict['volumes'] if vduvol['name'] == opvolume.name]
+ if len(vdurvol_data) == 1:
+ vdurvol_data[0]["volume_id"] = opvolume.volume_id
+
icp_list = []
ii_list = []
@@ -433,8 +444,8 @@
placement_groups = []
for group in self._placement_groups:
placement_groups.append(group.as_dict())
-
vdur_dict['placement_groups_info'] = placement_groups
+
return RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vdur.from_dict(vdur_dict)
@property
@@ -541,9 +552,11 @@
vm_create_msg_dict = {
"name": self.name,
- "image_name": self.image_name,
}
+ if self.image_name is not None:
+ vm_create_msg_dict["image_name"] = self.image_name
+
if self.image_checksum is not None:
vm_create_msg_dict["image_checksum"] = self.image_checksum
@@ -594,6 +607,10 @@
msg.event_id = self._request_id
msg.cloud_account = self.cloud_account_name
msg.request_info.from_dict(vm_create_msg_dict)
+
+ for volume in self._vdud.volumes:
+ v = msg.request_info.volumes.add()
+ v.from_dict(volume.as_dict())
return msg
@asyncio.coroutine
@@ -1533,7 +1550,7 @@
datastore.add(vdu)
# Substitute any variables contained in the cloud config script
- config = str(vdu.vdud_cloud_init)
+ config = str(vdu.vdud_cloud_init) if vdu.vdud_cloud_init is not None else ""
parts = re.split("\{\{ ([^\}]+) \}\}", config)
if len(parts) > 1: