def _image_update(context, values, image_id, purge_props=False): """ Used internally by image_create and image_update :param context: Request context :param values: A dict of attributes to set :param image_id: If None, create the image, otherwise, find and update it """ session = get_session() with session.begin(): # Remove the properties passed in the values mapping. We # handle properties separately from base image attributes, # and leaving properties in the values mapping will cause # a SQLAlchemy model error because SQLAlchemy expects the # properties attribute of an Image model to be a list and # not a dict. properties = values.pop('properties', {}) if image_id: image_ref = image_get(context, image_id, session=session) # Perform authorization check check_mutate_authorization(context, image_ref) else: if 'size' in values: values['size'] = int(values['size']) if 'min_ram' in values: values['min_ram'] = int(values['min_ram'] or 0) if 'min_disk' in values: values['min_disk'] = int(values['min_disk'] or 0) values['is_public'] = bool(values.get('is_public', False)) values['protected'] = bool(values.get('protected', False)) image_ref = models.Image() # Need to canonicalize ownership if 'owner' in values and not values['owner']: values['owner'] = None if image_id: # Don't drop created_at if we're passing it in... _drop_protected_attrs(models.Image, values) #NOTE(iccha-sethi): updated_at must be explicitly set in case # only ImageProperty table was modifited values['updated_at'] = timeutils.utcnow() image_ref.update(values) # Validate the attributes before we go any further. From my # investigation, the @validates decorator does not validate # on new records, only on existing records, which is, well, # idiotic. values = validate_image(image_ref.to_dict()) _update_values(image_ref, values) try: image_ref.save(session=session) except sqlalchemy.exc.IntegrityError: raise exception.Duplicate("Image ID %s already exists!" % values['id']) _set_properties_for_image(context, image_ref, properties, purge_props, session) return image_get(context, image_ref.id)
def _image_update(context, values, image_id, purge_props=False, from_state=None): """ Used internally by image_create and image_update :param context: Request context :param values: A dict of attributes to set :param image_id: If None, create the image, otherwise, find and update it """ #NOTE(jbresnah) values is altered in this so a copy is needed values = values.copy() session = get_session() with session.begin(): # Remove the properties passed in the values mapping. We # handle properties separately from base image attributes, # and leaving properties in the values mapping will cause # a SQLAlchemy model error because SQLAlchemy expects the # properties attribute of an Image model to be a list and # not a dict. properties = values.pop('properties', {}) location_data = values.pop('locations', None) new_status = values.get('status', None) if image_id: image_ref = _image_get(context, image_id, session=session) current = image_ref.status # Perform authorization check _check_mutate_authorization(context, image_ref) else: if values.get('size') is not None: values['size'] = int(values['size']) if 'min_ram' in values: values['min_ram'] = int(values['min_ram'] or 0) if 'min_disk' in values: values['min_disk'] = int(values['min_disk'] or 0) values['is_public'] = bool(values.get('is_public', False)) values['protected'] = bool(values.get('protected', False)) image_ref = models.Image() # Need to canonicalize ownership if 'owner' in values and not values['owner']: values['owner'] = None if image_id: # Don't drop created_at if we're passing it in... _drop_protected_attrs(models.Image, values) #NOTE(iccha-sethi): updated_at must be explicitly set in case # only ImageProperty table was modifited values['updated_at'] = timeutils.utcnow() if image_id: query = session.query(models.Image).filter_by(id=image_id) if from_state: query = query.filter_by(status=from_state) if new_status: _validate_image(values) # Validate fields for Images table. This is similar to what is done # for the query result update except that we need to do it prior # in this case. # TODO(dosaboy): replace this with a dict comprehension once py26 # support is deprecated. keys = values.keys() for k in keys: if k not in image_ref.to_dict(): del values[k] updated = query.update(values, synchronize_session='fetch') if not updated: msg = (_('cannot transition from %(current)s to ' '%(next)s in update (wanted ' 'from_state=%(from)s)') % { 'current': current, 'next': new_status, 'from': from_state }) raise exception.Conflict(msg) image_ref = _image_get(context, image_id, session=session) else: image_ref.update(values) # Validate the attributes before we go any further. From my # investigation, the @validates decorator does not validate # on new records, only on existing records, which is, well, # idiotic. values = _validate_image(image_ref.to_dict()) _update_values(image_ref, values) try: image_ref.save(session=session) except db_exception.DBDuplicateEntry: raise exception.Duplicate("Image ID %s already exists!" % values['id']) _set_properties_for_image(context, image_ref, properties, purge_props, session) if location_data is not None: _image_locations_set(image_ref.id, location_data, session) return image_get(context, image_ref.id)