Add an extra property for selecting SCG / Storage Template

In order to select an SCG / Storage Template , we add an extra
 propertity to image properties , UI could use this data to format
the data for user to select the specific SCG / Storage Template ,
and also, other components which consumes PowerVC images in
Openstack can also leverage this.

Change-Id: I4b9dba719dada3823dc159748d15a3266ca9efa3
Closes-Bug: #1362904
This commit is contained in:
Eric_Zhao 2014-09-19 13:56:36 +08:00 committed by Zhao_Jian
parent 2b714e12e5
commit 187efa1bbb
4 changed files with 250 additions and 2 deletions

View File

@ -503,6 +503,12 @@ class Utils(object):
return accessible_storage_providers
def get_all_storage_templates(self):
"""
Get all storage templates from PowerVC
"""
return self._cinderclient.volume_types.list_all_storage_templates()
def get_multi_scg_accessible_storage_templates(self,
scg_uuid_list,
scg_name_list):
@ -587,6 +593,37 @@ class Utils(object):
(accessible_storage_templates)))
return accessible_storage_templates
def get_scg_accessible_storage_templates_extended(self,
scg_list,
all_storage_templates):
"""
Get a dict that stores the scgs and the corresponding
accessible storage templates . The key is scg id ,
and the value is the storage templates.
:param: scg_list : All available Storage Connectivity Groups
:param: all_storage_templates : All available storage
templates from PowerVC
:return: The dict to store the scgs and
the corresponding storage templates
"""
if scg_list is not None:
scg_storage_templates = {}
for scg in scg_list:
accessible_storage_templates = []
volume_types = scg.list_all_volume_types()
volume_type_ids = []
for vol_type in volume_types:
volume_type_ids.append(vol_type.__dict__.get("id"))
for storage_template in all_storage_templates:
if(storage_template.__dict__.get("id") in volume_type_ids):
accessible_storage_templates.append(storage_template)
scg_storage_templates[scg.id] = accessible_storage_templates
return scg_storage_templates
else:
return {}
def get_multi_scg_accessible_volumes(self,
scg_uuid_list,
scg_name_list,
@ -770,6 +807,30 @@ class Utils(object):
LOG.debug(_('Unable to find staging user: %s'), staginguser)
raise exception.StagingUserNotFound(name=staginguser)
def get_image_scgs_dict(self, scg_list):
"""
Get a dict that store the image and the corresponding scg list .
The key is the image UUID , and the value is the corresponding scg list
:param scg_list : All available Storage Connectivity Groups
:returns The dict to store the image and the corresponding scg list
"""
if scg_list is not None:
image_scgs_dict = {}
for scg in scg_list:
image_id_list = self.get_scg_image_ids(scg.id)
for image_id in image_id_list:
if image_id in image_scgs_dict.keys():
scg_list = image_scgs_dict[image_id]
scg_list.append(scg)
image_scgs_dict[image_id] = scg_list
else:
scg_list = [scg]
image_scgs_dict[image_id] = scg_list
return image_scgs_dict
else:
return {}
def import_relative_module(relative_import_str, import_str):
"""

View File

@ -17,6 +17,7 @@ from powervc.common import config
from nova.openstack.common import service
from nova.openstack.common import log as logging
from nova.openstack.common import timeutils
from nova.openstack.common import jsonutils
from glanceclient.v1 import images as v1images
from glanceclient.exc import CommunicationError
from glanceclient.exc import HTTPNotFound
@ -231,6 +232,11 @@ class PowerVCImageManager(service.Service):
local_v2client = self._get_local_v2_client()
v2local_images = local_v2client.images
# Get image_scg_dict and scg_storage_templates_dict for
# the special property image_topology format
image_scgs_dict, scg_storage_templates_dict = \
self._get_dicts_for_extra_image_property()
# When catching exceptions during sync operations we will look for
# CommunicationError, and raise those so we don't waste time
# trying to process all images when there is a connection failure.
@ -277,6 +283,15 @@ class PowerVCImageManager(service.Service):
if uuid in self.ids_dict.keys():
self.ids_dict.pop(uuid)
else:
# Add an extra property named image_topology , which allows
# user to select a SCG/Storage Template when booting an VM
pvc_image = pvc_image_dict[uuid]
if pvc_image:
pvc_image = \
self._insert_extra_property_image_topology(
pvc_image,
image_scgs_dict,
scg_storage_templates_dict)
# Update the image if it has changed. (Right now, always
# update it, and update all fields). Update using the
@ -326,6 +341,14 @@ class PowerVCImageManager(service.Service):
# that are accessible from our Storage Connectivity
# Group
if status and status == 'active':
# Add an extra property named image_topology ,
# which allows user to select a SCG/Storage
# Template when booting an VM
pvc_image = \
self._insert_extra_property_image_topology(
pvc_image,
image_scgs_dict,
scg_storage_templates_dict)
# Add or activate the local image
self._add_or_activate_local_image(
@ -463,6 +486,11 @@ class PowerVCImageManager(service.Service):
cur_local_image_set = set(local_image_dict)
cur_pvc_image_set = set(pvc_image_dict)
# Get image_scg_dict and scg_storage_templates_dict for
# the special property image_topology format
image_scgs_dict, scg_storage_templates_dict = \
self._get_dicts_for_extra_image_property()
# We only need to update sync images that are in both PowerVC and
# the local hosting OS. If an image is missing from either side
# it will be added or deleted, so no need to try to update it.
@ -484,6 +512,21 @@ class PowerVCImageManager(service.Service):
pvc_image = pvc_image_dict[uuid]
local_updated = self._local_image_updated(uuid, local_image)
pvc_updated = self._pvc_image_updated(uuid, pvc_image)
# Add an extra property named image_topology , which allows
# user to select a SCG/Storage Template when booting an VM
pvc_image = \
self._insert_extra_property_image_topology(
pvc_image,
image_scgs_dict,
scg_storage_templates_dict)
if 'image_topology' not in local_image.properties or \
local_image.properties['image_topology'] != \
pvc_image.properties['image_topology']:
if not pvc_updated:
pvc_updated = True
local_checksum = \
self._get_image_checksum(local_image.to_dict())
pvc_checksum = self._get_image_checksum(pvc_image.to_dict())
@ -543,11 +586,18 @@ class PowerVCImageManager(service.Service):
'the local hosting OS to PowerVC'),
local_image.name)
# To avoid the image property image_topology is
# synced to PowerVC side
local_image = \
self._filter_out_image_properties(local_image,
['image_topology'])
# Update sync local image to PowerVC
updated_image = self._update_pvc_image(uuid, local_image,
pvc_image,
v1pvc_images,
v2pvc_images)
if updated_image is None:
LOG.error(_('PowerVC image \'%s\' with UUID %s was not'
' updated during periodic image '
@ -767,6 +817,15 @@ class PowerVCImageManager(service.Service):
# that are accessible on our Storage Connectivity Group
if status and status == 'active':
# Add an extra property named image_topology ,
# which allows user to select a SCG/Storage
# Template when booting an VM
pvc_image = \
self._insert_extra_property_image_topology(
pvc_image,
image_scgs_dict,
scg_storage_templates_dict)
# Add or activate the local image
self._add_or_activate_local_image(
pvc_image, local_image_owner,
@ -1058,6 +1117,12 @@ class PowerVCImageManager(service.Service):
'merged master image to PowerVC for PowerVC UUID '
'%s'), master_image.name, uuid)
# To avoid the image property image_topology is
# synced to PowerVC side
master_image = \
self._filter_out_image_properties(master_image,
['image_topology'])
# Update sync master image to PowerVC
LOG.debug(_('Master image for pvc: %s'), str(master_image))
updated_pvc_image = self._update_pvc_image(uuid, master_image,
@ -1238,6 +1303,7 @@ class PowerVCImageManager(service.Service):
# Reset the image properties
master_image.properties = master_props
master_image._info['properties'] = master_props
LOG.debug(_('Master image for merge: %s'), str(master_image))
def _get_image(self, uuid, image_id, image_name, v1images, v2images):
@ -2583,6 +2649,12 @@ class PowerVCImageManager(service.Service):
pvc_image.name, pvc_id)
return
# To avoid the image property image_topology is
# synced to PowerVC side
local_image = \
self._filter_out_image_properties(local_image,
['image_topology'])
# Perform the image update to PowerVC
image = self._update_pvc_image(pvc_id, local_image, pvc_image,
v1pvc_images, v2pvc_images)
@ -3718,6 +3790,109 @@ class PowerVCImageManager(service.Service):
self._unescape(filtered_props)
return filtered_props
def _get_extra_property_image_topology(self,
imageUUID,
image_scg_dict,
scg_storage_template_dict):
"""
Get an extra image property , named "image_topology" ,
which is used UI to select an available Storage
Connectivity Groups or Storage templates.
"""
if imageUUID is not None:
image_topology = []
scg_list = image_scg_dict[imageUUID]
for scg in scg_list:
scg_topology = {}
scg_topology['scg_id'] = scg.id
scg_topology['display_name'] = scg.display_name
scg_storage_templates = scg_storage_template_dict[scg.id]
available_storage_templates = []
for storage_template in scg_storage_templates:
storage_template_dict = {}
storage_template_dict['id'] = storage_template.id
storage_template_dict['name'] = storage_template.name
available_storage_templates.append(storage_template_dict)
if available_storage_templates:
scg_topology['storage_template_list'] = \
available_storage_templates
image_topology.append(scg_topology)
json_image_topology = jsonutils.dumps(image_topology)
return json_image_topology
else:
return []
def _insert_extra_property_image_topology(self,
image,
image_scg_dict,
scg_storage_template_dict):
"""
Insert or Update the extra property "image_topology" for
the image object and return the image object.
:param: image The image object that need to be updated
:param: image_scg_dict: A dict to store image UUID and
the corresponding scg list
:param: scg_storage_template_dict: A dict to store scg UUID and
the corresponding storage template list
:return The image object with the property "image_topology" updated
"""
if image is not None and \
image_scg_dict is not None and \
scg_storage_template_dict:
image_topology_prop = \
self._get_extra_property_image_topology(
image.id,
image_scg_dict,
scg_storage_template_dict)
image_properties = self._get_image_properties(image.to_dict())
image_properties[u'image_topology'] = unicode(image_topology_prop)
image.properties = image_properties
image._info['properties'] = image_properties
return image
else:
return image
def _filter_out_image_properties(self, image, props):
"""
Delete the properties in the props list for the image object and return
the image object without these properties.
:param: image The image object that need to be filtered out
:param: props The properties need to delete
:return The image object without these specific properties in the props
"""
if image is not None and props is not None:
image_properties = self._get_image_properties(image.to_dict())
for prop in props:
if prop in image_properties.keys():
del(image_properties[prop])
image.properties = image_properties
image._info['properties'] = image_properties
return image
else:
return image
def _get_dicts_for_extra_image_property(self):
"""
Get two dict to format the extra property "image_topology" , one dict
stores the image UUID and the corresponding scg list , the other stores
the scg UUID and the corresponding storage templates list.
"""
available_scg_list = utils.get_utils().get_our_scg_list()
available_storage_template = \
utils.get_utils().get_all_storage_templates()
image_scgs_dict = \
utils.get_utils().get_image_scgs_dict(available_scg_list)
scg_storage_templates_dict = \
utils.get_utils().\
get_scg_accessible_storage_templates_extended(
available_scg_list, available_storage_template)
return image_scgs_dict, scg_storage_templates_dict
class ImageSyncController():
"""

View File

@ -14,6 +14,7 @@ PVM_HYPERVISOR_TYPE = "powervm"
# Flavor constants
SCG_KEY = "powervm:storage_connectivity_group"
STORAGE_TEMPLATE_KEY = "powervm:boot_volume_type"
EXTRA_SPECS = "extra_specs"
IS_PUBLIC = "os-flavor-access:is_public"

View File

@ -651,11 +651,22 @@ class PowerVCService(object):
"""
createdServer = None
self.validate_update_scg(flavorDict)
# extract activation data from instance
meta = instance._metadata
key_name = instance.key_name
extra_specs_key = constants.EXTRA_SPECS
scg_key = constants.SCG_KEY
storage_template_key = constants.STORAGE_TEMPLATE_KEY
if 'selected-scg' in meta.keys() and \
'selected-storage-template' in meta.keys():
flavorDict[extra_specs_key][scg_key] = meta['selected-scg']
flavorDict[extra_specs_key][storage_template_key] = \
meta['selected-storage-template']
self.validate_update_scg(flavorDict)
# key_data = instance.key_data
config_drive = instance._config_drive
userdata = instance.user_data # already base64 encoded by local OS