# Copyright 2013 IBM Corp. import sys import itertools import time import traceback from oslo.config import cfg from glance.openstack.common import gettextutils gettextutils.install('glance') import glance.openstack.common.log as logging from glance.common import config as logging_config from glanceclient.v1 import images as v1images from powervc.common import config from powervc.glance.common import constants # PowerVC Driver ImageManager specific configuration image_opts = [ # The image period sync interval in seconds cfg.IntOpt('image_periodic_sync_interval_in_seconds', default=constants.IMAGE_PERIODIC_SYNC_INTERVAL_IN_SECONDS) ] CONF = config.CONF CONF.register_opts(image_opts, 'powervc') LOG = logging.getLogger(__name__) config.parse_power_config(sys.argv, 'glance') from powervc.common import messaging from powervc.common import constants as consts import powervc.common.client.factory as clients def test_image_events(wait_forever=True): def local_reconnect(): LOG.debug(_('Re-established connection to local hosting OS ' 'Qpid broker')) local_conn = messaging.LocalConnection(log=logging, reconnect_handler=local_reconnect) # local_conn = messaging.QpidConnection('localhost:5672', \ # 'admin', 'ICA1NTQxNzI5ODgK') # conn = messaging.QpidConnection('localhost:5672', 'admin', 'openstack1') local_listener = local_conn.create_listener('glance', 'notifications.info') local_listener.register_handler('image.*', handle_local_image_notifications) local_conn.start() # pvc_conn = messaging.QpidConnection('9.5.125.55:5672', \ # 'anonymous', '') def pvc_reconnect(): LOG.debug(_('Re-established connection to PowerVC Qpid broker')) pvc_conn = messaging.PowerVCConnection(log=logging, reconnect_handler=pvc_reconnect) # pvc_conn = messaging.QpidConnection('9.5.125.55:5672', \ # 'root', 'passw0rd') pvc_listener = pvc_conn.create_listener('glance', 'notifications.info') pvc_listener.register_handler('image.*', handle_pvc_image_notifications) pvc_conn.start() print 'Monitoring hosting OS and PowerVC for Image notifications...' while wait_forever: time.sleep(5) def test_pvc_image_events(wait_forever=True): # pvc_conn = messaging.QpidConnection('9.5.125.55:5672', \ # 'anonymous', '') def pvc_reconnect(): LOG.debug(_('Re-established connection to PowerVC Qpid broker')) pvc_conn = messaging.PowerVCConnection(log=logging, reconnect_handler=pvc_reconnect) # pvc_conn = messaging.QpidConnection('9.5.125.55:5672', \ # 'root', 'passw0rd') pvc_listener = pvc_conn.create_listener('glance', 'notifications.info') pvc_listener.register_handler('image.*', handle_pvc_image_notifications) pvc_conn.start() print 'Monitoring PowerVC for Image notifications...' while wait_forever: time.sleep(5) def handle_local_image_notifications(context, message): print '=' * 80 print 'LOCAL:', str(context) print 'LOCAL:', str(message) image = message.get('payload') # should be the v1 image as a dict dump_image(image) print '=' * 80 def handle_pvc_image_notifications(context, message): print '=' * 80 print 'PVC:', str(context) print 'PVC:', str(message) image = message.get('payload') # should be the v1 image as a dict dump_image(image) print '=' * 80 def dump_image(image_dict): for v1imagekey in image_dict.keys(): print v1imagekey, '=', image_dict.get(v1imagekey) props = image_dict.get('properties') if props: for v1imageprop in props.keys(): print 'property: ', v1imageprop, '=',\ props.get(v1imageprop) def test_update_local_image(image_id): params = {} filters = {} filters['is_public'] = False params['filters'] = filters local_v1client = \ clients.LOCAL.get_client(str(consts.SERVICE_TYPES.image), 'v1') v1local_images = local_v1client.images image = \ get_v1image_from_id(image_id, itertools.chain( v1local_images.list(), v1local_images.list(**params))) if image: field_dict, patch_dict = get_v1image_update_fields(image) if 'is_public' in field_dict.keys(): public = field_dict['is_public'] field_dict['is_public'] = not public v1local_images.update(image, **field_dict) if len(patch_dict) > 0: local_v2client = \ clients.LOCAL.get_client(str(consts.SERVICE_TYPES.image), 'v2') v2local_images = local_v2client.images v2local_images.update(image.id, **patch_dict) print 'Image', image.name, 'updated.' else: print 'Image', image_id, 'not found!' def get_v1image_update_fields(image): """ Get the properties for an image update :param: image The image to pull properties from to be used for an image update operation. :returns: A tuple containing with the dict containing the properties to use for an image update operation, and the dict of the properties that are too large to be processed by v1 Image APIs. Those properties should be updated using the v2 Image PATCH API. """ field_dict = {} patch_dict = {} props = image.properties if props and props is not None: patch_dict = remove_large_properties(props) image.properties = props image_dict = image.to_dict() for imagekey in image_dict.keys(): if imagekey in v1images.UPDATE_PARAMS and \ imagekey not in constants.IMAGE_UPDATE_PARAMS_FILTER: field_value = image_dict.get(imagekey) if field_value is not None: if len(str(field_value)) < constants.MAX_HEADER_LEN_V1: field_dict[imagekey] = field_value else: patch_dict[imagekey] = field_value return field_dict, patch_dict def remove_large_properties(properties): """ Remove any properties that are too large to be processed by the v1 APIs and return them in a dict to the caller. The properties passed in are also modified. :param: properties. The properties dict to remove large properties from. Large properties are removed from the original properties dict :returns: A dict containing properties that are too large to be processed by v1 Image APIs """ too_large_properties = {} if properties and properties is not None: for propkey in properties.keys(): propvalue = properties.get(propkey) if propvalue and propvalue is not None: if properties.get(propkey) and (len(str(propvalue)) >= constants.MAX_HEADER_LEN_V1): too_large_properties[propkey] = properties.pop(propkey) return too_large_properties def test_delete_local_image(image_id): pass def get_v1image_from_id(image_id, v1images): """ Get a v1 Image from an image id. :param: image_id The image id :param: v1images The image manager used to obtain images from the v1 glance client :returns: The image for the specified id or None if not found. """ for image in v1images: if image and image.id == image_id: return image return None """ Main test entry point """ if __name__ == '__main__': try: # turn off debug logging # CONF.debug = False logging_config.setup_logging() logging.setup('powervc') # test getting the staging project id # test_image_events(wait_forever=True) test_pvc_image_events(wait_forever=True) # image_id = '3060d198-c951-4693-9b1d-6314ac0539bf' # test_update_local_image(image_id) # test_delete_local_image(image_id) print 'Tests done!' except Exception: traceback.print_exc() raise