diff --git a/image/cascading.py b/image/cascading.py deleted file mode 100644 index 492f782..0000000 --- a/image/cascading.py +++ /dev/null @@ -1,185 +0,0 @@ -"""Implementation of an cascading image service that uses to sync the image - from cascading glance to the special cascaded glance. - """ -import logging -import os -import urlparse - -from oslo.config import cfg - -from nova.image import glance -from nova.image.sync import drivers as drivermgr - - -CONF = cfg.CONF -LOG = logging.getLogger(__name__) - -glance_cascading_opt = [ - cfg.StrOpt('image_copy_dest_location_url', - default='file:///var/lib/glance/images', - help=("The path cascaded image_data copy to."), - deprecated_opts=[cfg.DeprecatedOpt('dest_location_url', - group='DEFAULT')]), - cfg.StrOpt('image_copy_dest_host', - default='127.0.0.1', - help=("The host name where image_data copy to."), - deprecated_opts=[cfg.DeprecatedOpt('dest_host', - group='DEFAULT')]), - cfg.StrOpt('image_copy_dest_user', - default='glance', - help=("The user name of cascaded glance for copy."), - deprecated_opts=[cfg.DeprecatedOpt('dest_user', - group='DEFAULT')]), - cfg.StrOpt('image_copy_dest_password', - default='openstack', - help=("The passowrd of cascaded glance for copy."), - deprecated_opts=[cfg.DeprecatedOpt('dest_password', - group='DEFAULT')]), - cfg.StrOpt('image_copy_source_location_url', - default='file:///var/lib/glance/images', - help=("where the cascaded image data from"), - deprecated_opts=[cfg.DeprecatedOpt('source_location_url', - group='DEFAULT')]), - cfg.StrOpt('image_copy_source_host', - default='0.0.0.1', - help=("The host name where image_data copy from."), - deprecated_opts=[cfg.DeprecatedOpt('source_host', - group='DEFAULT')]), - cfg.StrOpt('image_copy_source_user', - default='glance', - help=("The user name of glance for copy."), - deprecated_opts=[cfg.DeprecatedOpt('source_user', - group='DEFAULT')]), - cfg.StrOpt('image_copy_source_password', - default='openstack', - help=("The passowrd of glance for copy."), - deprecated_opts=[cfg.DeprecatedOpt('source_password', - group='DEFAULT')]), - ] - -CONF.register_opts(glance_cascading_opt) - -_V2_IMAGE_CREATE_PROPERTIES = ['container_format', 'disk_format', 'min_disk', - 'min_ram', 'name', 'protected'] - - -def get_adding_image_properties(image): - _tags = list(image.tags) or [] - kwargs = {} - for key in _V2_IMAGE_CREATE_PROPERTIES: - try: - value = getattr(image, key, None) - if value and value != 'None': - kwargs[key] = value - except KeyError: - pass - if _tags: - kwargs['tags'] = _tags - return kwargs - - -def get_candidate_path(image, scheme='file'): - locations = image.locations or [] - for loc in locations: - if loc['url'].startswith(scheme): - return loc['url'] if scheme != 'file' \ - else loc['url'][len('file://'):] - return None - - -def get_copy_driver(scheme_key): - return drivermgr.get_store_driver(scheme_key) - - -def get_host_port(url): - if not url: - return None, None - pieces = urlparse.urlparse(url) - return pieces.netloc.split(":")[0], pieces.netloc.split(":")[1] - - -class GlanceCascadingService(object): - - def __init__(self, cascading_client=None): - self._client = cascading_client or glance.GlanceClientWrapper() - - def sync_image(self, context, cascaded_url, cascading_image): - cascaded_glance_url = cascaded_url - _host, _port = get_host_port(cascaded_glance_url) - _cascaded_client = glance.GlanceClientWrapper(context=context, - host=_host, - port=_port, - version=2) - - image_meta = get_adding_image_properties(cascading_image) - cascaded_image = _cascaded_client.call(context, 2, 'create', - **image_meta) - image_id = cascading_image.id - cascaded_id = cascaded_image.id - candidate_path = get_candidate_path(cascading_image) - LOG.debug("the candidate path is %s." % (candidate_path)) - # copy image - try: - image_loc = self._copy_data(image_id, cascaded_id, candidate_path) - except Exception as e: - LOG.exception(("copy image failed, reason=%s") % e) - raise - else: - if not image_loc: - LOG.exception(("copy image Exception, no cascaded_loc")) - try: - # patch loc to the cascaded image - csd_locs = [{'url': image_loc, - 'metadata': {} - }] - _cascaded_client.call(context, 2, 'update', cascaded_id, - remove_props=None, - locations=csd_locs) - except Exception as e: - LOG.exception(("patch loc to cascaded image Exception, reason: %s" - % e)) - raise - - try: - # patch glance-loc to cascading image - csg_locs = cascading_image.locations - glance_loc = '%s/v2/images/%s' % (cascaded_glance_url, - cascaded_id) - csg_locs.append({'url': glance_loc, - 'metadata': {'image_id': str(cascaded_id), - 'action': 'upload' - } - }) - self._client.call(context, 2, 'update', image_id, - remove_props=None, locations=csg_locs) - except Exception as e: - LOG.exception(("patch loc to cascading image Exception, reason: %s" - % e)) - raise - - return cascaded_id - - @staticmethod - def _copy_data(cascading_id, cascaded_id, candidate_path): - source_pieces = urlparse.urlparse(CONF.image_copy_source_location_url) - dest_pieces = urlparse.urlparse(CONF.image_copy_dest_location_url) - source_scheme = source_pieces.scheme - dest_scheme = dest_pieces.scheme - _key = ('%s:%s' % (source_scheme, dest_scheme)) - copy_driver = get_copy_driver(_key) - source_path = os.path.join(source_pieces.path, cascading_id) - dest_path = os.path.join(dest_pieces.path, cascaded_id) - - source_location = {'host': CONF.image_copy_source_host, - 'login_user': CONF.image_copy_source_user, - 'login_password': CONF.image_copy_source_password, - 'path': source_path - } - dest_location = {'host': CONF.image_copy_dest_host, - 'login_user': CONF.image_copy_dest_user, - 'login_password': CONF.image_copy_dest_password, - 'path': dest_path - } - return copy_driver.copy_to(source_location, - dest_location, - candidate_path=candidate_path) diff --git a/image/exception.py b/image/exception.py deleted file mode 100644 index f93e672..0000000 --- a/image/exception.py +++ /dev/null @@ -1,6 +0,0 @@ -from nova.exception import NovaException -from nova.i18n import _ - - -class GlanceSyncException(NovaException): - msg_fmt = _("Sync image failed: %(reason)s") diff --git a/image/sync/__init__.py b/image/sync/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/image/sync/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/image/sync/drivers/__init__.py b/image/sync/drivers/__init__.py deleted file mode 100644 index 43d41e4..0000000 --- a/image/sync/drivers/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -import nova.image.sync.drivers.filesystem - - -_store_drivers_map = { - 'file:file':filesystem.Store - -} - - -def get_store_driver(scheme_key): - cls = _store_drivers_map.get(scheme_key) - return cls() \ No newline at end of file diff --git a/image/sync/drivers/filesystem.py b/image/sync/drivers/filesystem.py deleted file mode 100644 index 5e04735..0000000 --- a/image/sync/drivers/filesystem.py +++ /dev/null @@ -1,106 +0,0 @@ -import logging -import sys - -from oslo.config import cfg -import pxssh -import pexpect - -from nova.i18n import _ -from nova.image import exception - -LOG = logging.getLogger(__name__) - -CONF = cfg.CONF - -sync_opt = [ - cfg.IntOpt('scp_copy_timeout', default=3600, - help=_('when snapshot, max wait (second)time for snapshot ' - 'status become active.'), - deprecated_opts=[cfg.DeprecatedOpt('scp_copy_timeout', - group='DEFAULT')]), - ] -CONF.register_opts(sync_opt, group='sync') - - -def _get_ssh(hostname, username, password): - s = pxssh.pxssh() - s.login(hostname, username, password, original_prompt='[#$>]') - s.logfile = sys.stdout - return s - - -class Store(object): - - def copy_to(self, from_location, to_location, candidate_path=None): - - from_store_loc = from_location - to_store_loc = to_location - LOG.debug(_('from_store_loc is: %s'), from_store_loc) - - if from_store_loc['host'] == to_store_loc['host'] and \ - from_store_loc['path'] == to_store_loc['path']: - - LOG.info(_('The from_loc is same to to_loc, no need to copy. the ' - 'host:path is %s:%s') % (from_store_loc['host'], - from_store_loc['path'])) - return 'file://%s' % to_store_loc['path'] - - to_host = r"""{username}@{host}""".format( - username=to_store_loc['login_user'], - host=to_store_loc['host']) - - to_path = r"""{to_host}:{path}""".format(to_host=to_host, - path=to_store_loc['path']) - - copy_path = from_store_loc['path'] - - try: - from_ssh = _get_ssh(from_store_loc['host'], - from_store_loc['login_user'], - from_store_loc['login_password']) - except Exception: - msg = _('ssh login failed to %(user)s:%(passwd)s %(host)s' % - {'user': from_store_loc['login_user'], - 'passwd': from_store_loc['login_password'], - 'host': from_store_loc['host'] - }) - LOG.exception(msg) - raise exception.GlanceSyncException(reason=msg) - - from_ssh.sendline('ls %s' % copy_path) - from_ssh.prompt() - if 'cannot access' in from_ssh.before or \ - 'No such file' in from_ssh.before: - if candidate_path: - from_ssh.sendline('ls %s' % candidate_path) - from_ssh.prompt() - if 'cannot access' not in from_ssh.before and \ - 'No such file' not in from_ssh.before: - copy_path = candidate_path - else: - msg = _("the image path for copy to is not exists, file copy" - "failed: path is %s" % copy_path) - LOG.exception(msg) - raise exception.GlanceSyncException(reason=msg) - - from_ssh.sendline('scp -P 22 %s %s' % (copy_path, to_path)) - while True: - scp_index = from_ssh.expect(['.yes/no.', '.assword:.', - pexpect.TIMEOUT]) - if scp_index == 0: - from_ssh.sendline('yes') - from_ssh.prompt() - elif scp_index == 1: - from_ssh.sendline(to_store_loc['login_password']) - from_ssh.prompt(timeout=CONF.sync.scp_copy_timeout) - break - else: - msg = _("scp commond execute failed, with copy_path %s and " - "to_path %s" % (copy_path, to_path)) - LOG.exception(msg) - raise exception.GlanceSyncException(reason=msg) - - if from_ssh: - from_ssh.logout() - - return 'file://%s' % to_store_loc['path']