Merge "Improve engine code"

This commit is contained in:
Jenkins 2017-09-05 14:12:30 +00:00 committed by Gerrit Code Review
commit ef89cae691

@ -47,12 +47,14 @@ class Engine(object):
- requests artifact definition from artifact type registry; - requests artifact definition from artifact type registry;
- check access permission(ro, rw); - check access permission(ro, rw);
- lock artifact for update if needed; - lock artifact for update if needed;
- pass data to base artifact to execute all business logic operations - pass data to base artifact type to execute all business logic operations
with database; with database;
- check quotas during upload;
- call operations pre- and post- hooks;
- notify other users about finished operation. - notify other users about finished operation.
Engine should not include any business logic and validation related Engine should not include any business logic and validation related
to Artifacts. Engine should not know any internal details of artifact to artifacts types. Engine should not know any internal details of artifact
type, because this part of the work is done by Base artifact type. type, because this part of the work is done by Base artifact type.
""" """
def __init__(self): def __init__(self):
@ -143,7 +145,7 @@ class Engine(object):
def _apply_patch(self, context, af, patch): def _apply_patch(self, context, af, patch):
# This function is a collection of hacks and workarounds to make # This function is a collection of hacks and workarounds to make
# json patch apply changes to oslo_vo object. # json patch apply changes to artifact object.
action_names = ['update'] action_names = ['update']
af_dict = af.to_dict() af_dict = af.to_dict()
policy.authorize('artifact:update', af_dict, context) policy.authorize('artifact:update', af_dict, context)
@ -285,19 +287,17 @@ class Engine(object):
context, type_name, updates.get('name', af.name), context, type_name, updates.get('name', af.name),
updates.get('version', af.version), af.owner, updates.get('version', af.version), af.owner,
updates.get('visibility', af.visibility)): updates.get('visibility', af.visibility)):
modified_af = af.save(context) af = af.save(context)
else: else:
modified_af = af.save(context) af = af.save(context)
# call post hooks for all operations when data is written in db and # call post hooks for all operations when data is written in db and
# send broadcast notifications # send broadcast notifications
for action_name in action_names: for action_name in action_names:
getattr(modified_af, 'post_%s_hook' % action_name)( getattr(af, 'post_%s_hook' % action_name)(context, af)
context, modified_af) Notifier.notify(context, 'artifact:' + action_name, af)
Notifier.notify(
context, 'artifact:' + action_name, modified_af)
return modified_af.to_dict() return af.to_dict()
def show(self, context, type_name, artifact_id): def show(self, context, type_name, artifact_id):
"""Show detailed artifact info. """Show detailed artifact info.
@ -390,7 +390,7 @@ class Engine(object):
@staticmethod @staticmethod
def _get_blob_info(af, field_name, blob_key=None): def _get_blob_info(af, field_name, blob_key=None):
"""Return requested blob info""" """Return requested blob info."""
if blob_key: if blob_key:
if not af.is_blob_dict(field_name): if not af.is_blob_dict(field_name):
msg = _("%s is not a blob dict") % field_name msg = _("%s is not a blob dict") % field_name
@ -469,18 +469,16 @@ class Engine(object):
utils.validate_change_allowed(af, field_name) utils.validate_change_allowed(af, field_name)
af.pre_add_location_hook( af.pre_add_location_hook(
context, af, field_name, location, blob_key) context, af, field_name, location, blob_key)
modified_af = self._save_blob_info( af = self._save_blob_info(context, af, field_name, blob_key, blob)
context, af, field_name, blob_key, blob)
LOG.info("External location %(location)s has been created " LOG.info("External location %(location)s has been created "
"successfully for artifact %(artifact)s blob %(blob)s", "successfully for artifact %(artifact)s blob %(blob)s",
{'location': location, 'artifact': af.id, {'location': location, 'artifact': af.id,
'blob': blob_name}) 'blob': blob_name})
modified_af.post_add_location_hook( af.post_add_location_hook(context, af, field_name, blob_key)
context, modified_af, field_name, blob_key) Notifier.notify(context, action_name, af)
Notifier.notify(context, action_name, modified_af) return af.to_dict()
return modified_af.to_dict()
def _calculate_allowed_space(self, context, af, field_name, def _calculate_allowed_space(self, context, af, field_name,
content_length=None, blob_key=None): content_length=None, blob_key=None):
@ -541,7 +539,11 @@ class Engine(object):
""" """
blob_name = self._generate_blob_name(field_name, blob_key) blob_name = self._generate_blob_name(field_name, blob_key)
blob_id = uuidutils.generate_uuid() blob_id = uuidutils.generate_uuid()
blob_info = {'url': None, 'size': None, 'md5': None, 'sha1': None,
'sha256': None, 'id': blob_id, 'status': 'saving',
'external': False, 'content_type': content_type}
# Step 1. Initialize blob
lock_key = "%s:%s" % (type_name, artifact_id) lock_key = "%s:%s" % (type_name, artifact_id)
with self.lock_engine.acquire(context, lock_key): with self.lock_engine.acquire(context, lock_key):
af = self._show_artifact(context, type_name, artifact_id) af = self._show_artifact(context, type_name, artifact_id)
@ -554,21 +556,18 @@ class Engine(object):
"%(af)s") % {'blob': field_name, 'af': af.id} "%(af)s") % {'blob': field_name, 'af': af.id}
raise exception.Conflict(message=msg) raise exception.Conflict(message=msg)
utils.validate_change_allowed(af, field_name) utils.validate_change_allowed(af, field_name)
size = self._calculate_allowed_space( blob_info['size'] = self._calculate_allowed_space(
context, af, field_name, content_length, blob_key) context, af, field_name, content_length, blob_key)
blob = {'url': None, 'size': size, 'md5': None, 'sha1': None,
'sha256': None, 'id': blob_id, 'status': 'saving',
'external': False, 'content_type': content_type}
modified_af = self._save_blob_info( af = self._save_blob_info(
context, af, field_name, blob_key, blob) context, af, field_name, blob_key, blob_info)
LOG.debug("Parameters validation for artifact %(artifact)s blob " LOG.debug("Parameters validation for artifact %(artifact)s blob "
"upload passed for blob %(blob_name)s. " "upload passed for blob %(blob_name)s. "
"Start blob uploading to backend.", "Start blob uploading to backend.",
{'artifact': af.id, 'blob_name': blob_name}) {'artifact': af.id, 'blob_name': blob_name})
# try to perform blob uploading to storage # Step 2. Call pre_upload_hook and upload data to the store
try: try:
try: try:
# call upload hook first # call upload hook first
@ -591,38 +590,32 @@ class Engine(object):
default_store = CONF.glance_store.default_store default_store = CONF.glance_store.default_store
location_uri, size, checksums = store_api.save_blob_to_store( location_uri, size, checksums = store_api.save_blob_to_store(
blob_id, fd, context, size, blob_id, fd, context, blob_info['size'],
store_type=default_store) store_type=default_store)
blob_info.update({'url': location_uri,
'status': 'active',
'size': size})
blob_info.update(checksums)
except Exception: except Exception:
# if upload failed remove blob from db and storage # if upload failed remove blob from db and storage
with excutils.save_and_reraise_exception(logger=LOG): with excutils.save_and_reraise_exception(logger=LOG):
if blob_key is None: self._save_blob_info(
af.update_blob(context, af.id, field_name, None) context, af, field_name, blob_key, None)
else:
blob_dict_attr = getattr(modified_af, field_name)
del blob_dict_attr[blob_key]
af.update_blob(context, af.id, field_name, blob_dict_attr)
LOG.info("Successfully finished blob uploading for artifact " LOG.info("Successfully finished blob uploading for artifact "
"%(artifact)s blob field %(blob)s.", "%(artifact)s blob field %(blob)s.",
{'artifact': af.id, 'blob': blob_name}) {'artifact': af.id, 'blob': blob_name})
# update blob info and activate it # Step 3. Change blob status to 'active'
blob.update({'url': location_uri,
'status': 'active',
'size': size})
blob.update(checksums)
with self.lock_engine.acquire(context, lock_key): with self.lock_engine.acquire(context, lock_key):
af = af.show(context, artifact_id) af = af.show(context, artifact_id)
modified_af = self._save_blob_info( af = self._save_blob_info(
context, af, field_name, blob_key, blob) context, af, field_name, blob_key, blob_info)
modified_af.post_upload_hook( af.post_upload_hook(context, af, field_name, blob_key)
context, modified_af, field_name, blob_key)
Notifier.notify(context, action_name, modified_af) Notifier.notify(context, action_name, af)
return modified_af.to_dict() return af.to_dict()
def download_blob(self, context, type_name, artifact_id, field_name, def download_blob(self, context, type_name, artifact_id, field_name,
blob_key=None): blob_key=None):
@ -703,18 +696,17 @@ class Engine(object):
msg = _("Blob %s is not external") % blob_name msg = _("Blob %s is not external") % blob_name
raise exception.Forbidden(message=msg) raise exception.Forbidden(message=msg)
modified_af = self._save_blob_info( af = self._save_blob_info(context, af, field_name, blob_key, None)
context, af, field_name, blob_key, None)
Notifier.notify(context, action_name, modified_af) Notifier.notify(context, action_name, af)
return modified_af.to_dict() return af.to_dict()
@staticmethod @staticmethod
def set_quotas(context, values): def set_quotas(context, values):
"""Set quota records in Glare. """Set quota records in Glare.
:param context: user request context :param context: user request context
:param values: list with quota values to set :param values: dict with quota values to set
""" """
action_name = "artifact:set_quotas" action_name = "artifact:set_quotas"
policy.authorize(action_name, {}, context) policy.authorize(action_name, {}, context)
@ -725,7 +717,8 @@ class Engine(object):
"""Get detailed info about all available quotas. """Get detailed info about all available quotas.
:param context: user request context :param context: user request context
:return: definition of requested quotas for the project :return: dict with definitions of redefined quotas for all projects
and global defaults
""" """
action_name = "artifact:list_all_quotas" action_name = "artifact:list_all_quotas"
policy.authorize(action_name, {}, context) policy.authorize(action_name, {}, context)