Merge yagni-db-adapter and resolve conflicts.
This commit is contained in:
commit
8cd4bc1899
@ -21,11 +21,7 @@
|
||||
DB abstraction for Nova and Glance
|
||||
"""
|
||||
|
||||
from glance.registry.db.api import *
|
||||
from glance.registry.db import models
|
||||
|
||||
# attributes common to all models
|
||||
BASE_MODEL_ATTRS = set(['id', 'created_at', 'updated_at', 'deleted_at',
|
||||
'deleted'])
|
||||
|
||||
IMAGE_ATTRS = BASE_MODEL_ATTRS | set(['name', 'type', 'status', 'size',
|
||||
'is_public', 'location'])
|
||||
models.register_models()
|
||||
|
@ -21,46 +21,27 @@
|
||||
Defines interface for DB access
|
||||
"""
|
||||
|
||||
from sqlalchemy.orm import joinedload
|
||||
|
||||
from glance.common import exception
|
||||
from glance.common import utils
|
||||
|
||||
from glance.registry.db.sqlalchemy import api
|
||||
from glance.common.db.sqlalchemy.session import get_session
|
||||
from glance.registry.db import models
|
||||
|
||||
|
||||
IMPL = api
|
||||
# attributes common to all models
|
||||
BASE_MODEL_ATTRS = set(['id', 'created_at', 'updated_at', 'deleted_at',
|
||||
'deleted'])
|
||||
|
||||
IMAGE_ATTRS = BASE_MODEL_ATTRS | set(['name', 'type', 'status', 'size',
|
||||
'is_public', 'location'])
|
||||
|
||||
###################
|
||||
|
||||
|
||||
def image_create(context, values):
|
||||
"""Create an image from the values dictionary."""
|
||||
return IMPL.image_create(context, values)
|
||||
|
||||
|
||||
def image_destroy(context, image_id):
|
||||
"""Destroy the image or raise if it does not exist."""
|
||||
return IMPL.image_destroy(context, image_id)
|
||||
|
||||
|
||||
def image_get(context, image_id):
|
||||
"""Get an image or raise if it does not exist."""
|
||||
return IMPL.image_get(context, image_id)
|
||||
|
||||
|
||||
def image_get_all(context):
|
||||
"""Get all images."""
|
||||
return IMPL.image_get_all(context)
|
||||
|
||||
|
||||
def image_get_all_public(context, public=True):
|
||||
"""Get all public images."""
|
||||
return IMPL.image_get_all_public(context, public=public)
|
||||
|
||||
|
||||
def image_get_by_str(context, str_id):
|
||||
"""Get an image by string id."""
|
||||
return IMPL.image_get_by_str(context, str_id)
|
||||
return _image_update(context, values, None)
|
||||
|
||||
|
||||
def image_update(context, image_id, values):
|
||||
@ -69,20 +50,131 @@ def image_update(context, image_id, values):
|
||||
Raises NotFound if image does not exist.
|
||||
|
||||
"""
|
||||
return IMPL.image_update(context, image_id, values)
|
||||
return _image_update(context, values, image_id)
|
||||
|
||||
|
||||
###################
|
||||
def image_destroy(context, image_id):
|
||||
"""Destroy the image or raise if it does not exist."""
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
image_ref = image_get(context, image_id, session=session)
|
||||
image_ref.delete(session=session)
|
||||
|
||||
|
||||
def image_file_create(context, values):
|
||||
"""Create an image file from the values dictionary."""
|
||||
return IMPL.image_file_create(context, values)
|
||||
def image_get(context, image_id, session=None):
|
||||
"""Get an image or raise if it does not exist."""
|
||||
session = session or get_session()
|
||||
try:
|
||||
return session.query(models.Image).\
|
||||
options(joinedload(models.Image.properties)).\
|
||||
filter_by(deleted=_deleted(context)).\
|
||||
filter_by(id=image_id).\
|
||||
one()
|
||||
except exc.NoResultFound:
|
||||
new_exc = exception.NotFound("No model for id %s" % image_id)
|
||||
raise new_exc.__class__, new_exc, sys.exc_info()[2]
|
||||
|
||||
|
||||
###################
|
||||
def image_get_all_public(context):
|
||||
"""Get all public images."""
|
||||
session = get_session()
|
||||
return session.query(models.Image).\
|
||||
options(joinedload(models.Image.properties)).\
|
||||
filter_by(deleted=_deleted(context)).\
|
||||
filter_by(is_public=True).\
|
||||
all()
|
||||
|
||||
|
||||
def image_property_create(context, values):
|
||||
"""Create an image property from the values dictionary."""
|
||||
return IMPL.image_property_create(context, values)
|
||||
def _drop_protected_attrs(model_class, values):
|
||||
"""Removed protected attributes from values dictionary using the models
|
||||
__protected_attributes__ field.
|
||||
"""
|
||||
for attr in model_class.__protected_attributes__:
|
||||
if attr in values:
|
||||
del values[attr]
|
||||
|
||||
|
||||
def _image_update(context, values, image_id):
|
||||
"""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():
|
||||
_drop_protected_attrs(models.Image, values)
|
||||
|
||||
if 'size' in values:
|
||||
values['size'] = int(values['size'])
|
||||
|
||||
values['is_public'] = bool(values.get('is_public', False))
|
||||
properties = values.pop('properties', {})
|
||||
|
||||
if image_id:
|
||||
image_ref = image_get(context, image_id, session=session)
|
||||
else:
|
||||
image_ref = models.Image()
|
||||
|
||||
image_ref.update(values)
|
||||
image_ref.save(session=session)
|
||||
|
||||
_set_properties_for_image(context, image_ref, properties, session)
|
||||
|
||||
return image_get(context, image_ref.id)
|
||||
|
||||
|
||||
def _set_properties_for_image(context, image_ref, properties, session=None):
|
||||
"""
|
||||
Create or update a set of image_properties for a given image
|
||||
|
||||
:param context: Request context
|
||||
:param image_ref: An Image object
|
||||
:param properties: A dict of properties to set
|
||||
:param session: A SQLAlchemy session to use (if present)
|
||||
"""
|
||||
orig_properties = {}
|
||||
for prop_ref in image_ref.properties:
|
||||
orig_properties[prop_ref.key] = prop_ref
|
||||
|
||||
for key, value in properties.iteritems():
|
||||
prop_values = {'image_id': image_ref.id,
|
||||
'key': key,
|
||||
'value': value}
|
||||
if key in orig_properties:
|
||||
prop_ref = orig_properties[key]
|
||||
image_property_update(context, prop_ref, prop_values,
|
||||
session=session)
|
||||
else:
|
||||
image_property_create(context, prop_values, session=session)
|
||||
|
||||
|
||||
def image_property_create(context, values, session=None):
|
||||
"""Create an ImageProperty object"""
|
||||
prop_ref = models.ImageProperty()
|
||||
return _image_property_update(context, prop_ref, values, session=session)
|
||||
|
||||
|
||||
def image_property_update(context, prop_ref, values, session=None):
|
||||
"""Update an ImageProperty object"""
|
||||
return _image_property_update(context, prop_ref, values, session=session)
|
||||
|
||||
|
||||
def _image_property_update(context, prop_ref, values, session=None):
|
||||
"""Used internally by image_property_create and image_property_update
|
||||
"""
|
||||
_drop_protected_attrs(models.ImageProperty, values)
|
||||
prop_ref.update(values)
|
||||
prop_ref.save(session=session)
|
||||
return prop_ref
|
||||
|
||||
|
||||
# pylint: disable-msg=C0111
|
||||
def _deleted(context):
|
||||
"""Calculates whether to include deleted objects based on context.
|
||||
|
||||
Currently just looks for a flag called deleted in the context dict.
|
||||
"""
|
||||
if not hasattr(context, 'get'):
|
||||
return False
|
||||
return context.get('deleted', False)
|
||||
|
@ -30,18 +30,15 @@ from sqlalchemy import UniqueConstraint
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
||||
from glance.common.db.sqlalchemy.session import get_session, get_engine
|
||||
|
||||
from glance.common import exception
|
||||
|
||||
BASE = declarative_base()
|
||||
|
||||
|
||||
#TODO(sirp): ModelBase should be moved out so Glance and Nova can share it
|
||||
class ModelBase(object):
|
||||
"""Base class for Nova and Glance Models"""
|
||||
__table_args__ = {'mysql_engine': 'InnoDB'}
|
||||
__table_initialized__ = False
|
||||
__prefix__ = 'none'
|
||||
__protected_attributes__ = set([
|
||||
"created_at", "updated_at", "deleted_at", "deleted"])
|
||||
|
||||
@ -50,53 +47,9 @@ class ModelBase(object):
|
||||
deleted_at = Column(DateTime)
|
||||
deleted = Column(Boolean, default=False)
|
||||
|
||||
@classmethod
|
||||
def all(cls, session=None, deleted=False):
|
||||
"""Get all objects of this type"""
|
||||
if not session:
|
||||
session = get_session()
|
||||
return session.query(cls).\
|
||||
filter_by(deleted=deleted).\
|
||||
all()
|
||||
|
||||
@classmethod
|
||||
def count(cls, session=None, deleted=False):
|
||||
"""Count objects of this type"""
|
||||
if not session:
|
||||
session = get_session()
|
||||
return session.query(cls).\
|
||||
filter_by(deleted=deleted).\
|
||||
count()
|
||||
|
||||
@classmethod
|
||||
def find(cls, obj_id, session=None, deleted=False):
|
||||
"""Find object by id"""
|
||||
if not session:
|
||||
session = get_session()
|
||||
try:
|
||||
return session.query(cls).\
|
||||
filter_by(id=obj_id).\
|
||||
filter_by(deleted=deleted).\
|
||||
one()
|
||||
except exc.NoResultFound:
|
||||
new_exc = exception.NotFound("No model for id %s" % obj_id)
|
||||
raise new_exc.__class__, new_exc, sys.exc_info()[2]
|
||||
|
||||
@classmethod
|
||||
def find_by_str(cls, str_id, session=None, deleted=False):
|
||||
"""Find object by str_id"""
|
||||
int_id = int(str_id.rpartition('-')[2])
|
||||
return cls.find(int_id, session=session, deleted=deleted)
|
||||
|
||||
@property
|
||||
def str_id(self):
|
||||
"""Get string id of object (generally prefix + '-' + id)"""
|
||||
return "%s-%s" % (self.__prefix__, self.id)
|
||||
|
||||
def save(self, session=None):
|
||||
"""Save this object"""
|
||||
if not session:
|
||||
session = get_session()
|
||||
session = session or get_session()
|
||||
session.add(self)
|
||||
session.flush()
|
||||
|
||||
@ -138,7 +91,6 @@ class ModelBase(object):
|
||||
class Image(BASE, ModelBase):
|
||||
"""Represents an image in the datastore"""
|
||||
__tablename__ = 'images'
|
||||
__prefix__ = 'img'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(String(255))
|
||||
@ -165,7 +117,6 @@ class Image(BASE, ModelBase):
|
||||
class ImageProperty(BASE, ModelBase):
|
||||
"""Represents an image properties in the datastore"""
|
||||
__tablename__ = 'image_properties'
|
||||
__prefix__ = 'img-prop'
|
||||
__table_args__ = (UniqueConstraint('image_id', 'key'), {})
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
@ -1,26 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
SQLAlchemy models for glance data
|
||||
"""
|
||||
|
||||
from glance.registry.db.sqlalchemy import models
|
||||
|
||||
|
||||
models.register_models()
|
@ -1,186 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# Copyright 2011 OpenStack LLC.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
Implementation of SQLAlchemy backend
|
||||
"""
|
||||
|
||||
import sys
|
||||
from glance.common import db
|
||||
from glance.common import exception
|
||||
from glance.common.db.sqlalchemy.session import get_session
|
||||
from glance.registry.db.sqlalchemy import models
|
||||
from sqlalchemy.orm import exc
|
||||
|
||||
#from sqlalchemy.orm import joinedload_all
|
||||
# TODO(sirp): add back eager loading
|
||||
from sqlalchemy.orm import joinedload
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
|
||||
# NOTE(vish): disabling docstring pylint because the docstrings are
|
||||
# in the interface definition
|
||||
# pylint: disable-msg=C0111
|
||||
def _deleted(context):
|
||||
"""Calculates whether to include deleted objects based on context.
|
||||
|
||||
Currently just looks for a flag called deleted in the context dict.
|
||||
"""
|
||||
if not hasattr(context, 'get'):
|
||||
return False
|
||||
return context.get('deleted', False)
|
||||
|
||||
|
||||
###################
|
||||
|
||||
|
||||
def image_create(_context, values):
|
||||
return _image_update(_context, values, None)
|
||||
|
||||
|
||||
def image_destroy(_context, image_id):
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
image_ref = models.Image.find(image_id, session=session)
|
||||
image_ref.delete(session=session)
|
||||
|
||||
|
||||
def image_get(context, image_id):
|
||||
session = get_session()
|
||||
try:
|
||||
return session.query(models.Image).\
|
||||
options(joinedload(models.Image.properties)).\
|
||||
filter_by(deleted=_deleted(context)).\
|
||||
filter_by(id=image_id).\
|
||||
one()
|
||||
except exc.NoResultFound:
|
||||
new_exc = exception.NotFound("No model for id %s" % image_id)
|
||||
raise new_exc.__class__, new_exc, sys.exc_info()[2]
|
||||
|
||||
|
||||
def image_get_all(context):
|
||||
session = get_session()
|
||||
return session.query(models.Image).\
|
||||
options(joinedload(models.Image.properties)).\
|
||||
filter_by(deleted=_deleted(context)).\
|
||||
all()
|
||||
|
||||
|
||||
def image_get_all_public(context, public):
|
||||
session = get_session()
|
||||
return session.query(models.Image).\
|
||||
options(joinedload(models.Image.properties)).\
|
||||
filter_by(deleted=_deleted(context)).\
|
||||
filter_by(is_public=public).\
|
||||
all()
|
||||
|
||||
|
||||
def image_get_by_str(context, str_id):
|
||||
return models.Image.find_by_str(str_id, deleted=_deleted(context))
|
||||
|
||||
|
||||
def image_update(_context, image_id, values):
|
||||
return _image_update(_context, values, image_id)
|
||||
|
||||
|
||||
###################
|
||||
|
||||
|
||||
def image_property_create(_context, values, session=None):
|
||||
"""Create an ImageProperty object"""
|
||||
prop_ref = models.ImageProperty()
|
||||
return _image_property_update(_context, prop_ref, values, session=session)
|
||||
|
||||
|
||||
def image_property_update(_context, prop_ref, values, session=None):
|
||||
"""Update an ImageProperty object"""
|
||||
return _image_property_update(_context, prop_ref, values, session=session)
|
||||
|
||||
|
||||
def _image_property_update(_context, prop_ref, values, session=None):
|
||||
"""Used internally by image_property_create and image_property_update
|
||||
"""
|
||||
_drop_protected_attrs(models.ImageProperty, values)
|
||||
prop_ref.update(values)
|
||||
prop_ref.save(session=session)
|
||||
return prop_ref
|
||||
|
||||
|
||||
def _drop_protected_attrs(model_class, values):
|
||||
"""Removed protected attributes from values dictionary using the models
|
||||
__protected_attributes__ field.
|
||||
"""
|
||||
for attr in model_class.__protected_attributes__:
|
||||
if attr in values:
|
||||
del values[attr]
|
||||
|
||||
|
||||
def _image_update(_context, values, image_id):
|
||||
"""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():
|
||||
_drop_protected_attrs(models.Image, values)
|
||||
|
||||
if 'size' in values:
|
||||
values['size'] = int(values['size'])
|
||||
|
||||
values['is_public'] = bool(values.get('is_public', False))
|
||||
properties = values.pop('properties', {})
|
||||
|
||||
if image_id:
|
||||
image_ref = models.Image.find(image_id, session=session)
|
||||
else:
|
||||
image_ref = models.Image()
|
||||
|
||||
image_ref.update(values)
|
||||
image_ref.save(session=session)
|
||||
|
||||
_set_properties_for_image(_context, image_ref, properties, session)
|
||||
|
||||
return image_get(_context, image_ref.id)
|
||||
|
||||
|
||||
def _set_properties_for_image(_context, image_ref, properties, session=None):
|
||||
"""
|
||||
Create or update a set of image_properties for a given image
|
||||
|
||||
:param _context: Request context
|
||||
:param image_ref: An Image object
|
||||
:param properties: A dict of properties to set
|
||||
:param session: A SQLAlchemy session to use (if present)
|
||||
"""
|
||||
orig_properties = {}
|
||||
for prop_ref in image_ref.properties:
|
||||
orig_properties[prop_ref.key] = prop_ref
|
||||
|
||||
for key, value in properties.iteritems():
|
||||
prop_values = {'image_id': image_ref.id,
|
||||
'key': key,
|
||||
'value': value}
|
||||
if key in orig_properties:
|
||||
prop_ref = orig_properties[key]
|
||||
image_property_update(_context, prop_ref, prop_values,
|
||||
session=session)
|
||||
else:
|
||||
image_property_create(_context, prop_values, session=session)
|
@ -24,7 +24,7 @@ from webob import exc
|
||||
|
||||
from glance.common import wsgi
|
||||
from glance.common import exception
|
||||
import glance.registry.db as db
|
||||
from glance.registry.db import api as db_api
|
||||
|
||||
|
||||
class Controller(wsgi.Controller):
|
||||
@ -46,7 +46,7 @@ class Controller(wsgi.Controller):
|
||||
{'id': image_id, 'name': image_name}
|
||||
|
||||
"""
|
||||
images = db.image_get_all_public(None)
|
||||
images = db_api.image_get_all_public(None)
|
||||
image_dicts = [dict(id=i['id'],
|
||||
name=i['name'],
|
||||
type=i['type'],
|
||||
@ -65,14 +65,14 @@ class Controller(wsgi.Controller):
|
||||
all image model fields.
|
||||
|
||||
"""
|
||||
images = db.image_get_all_public(None)
|
||||
images = db_api.image_get_all_public(None)
|
||||
image_dicts = [make_image_dict(i) for i in images]
|
||||
return dict(images=image_dicts)
|
||||
|
||||
def show(self, req, id):
|
||||
"""Return data about the given image id."""
|
||||
try:
|
||||
image = db.image_get(None, id)
|
||||
image = db_api.image_get(None, id)
|
||||
except exception.NotFound:
|
||||
raise exc.HTTPNotFound()
|
||||
|
||||
@ -90,7 +90,7 @@ class Controller(wsgi.Controller):
|
||||
"""
|
||||
context = None
|
||||
try:
|
||||
db.image_destroy(context, id)
|
||||
db_api.image_destroy(context, id)
|
||||
except exception.NotFound:
|
||||
return exc.HTTPNotFound()
|
||||
|
||||
@ -113,7 +113,7 @@ class Controller(wsgi.Controller):
|
||||
|
||||
context = None
|
||||
try:
|
||||
image_data = db.image_create(context, image_data)
|
||||
image_data = db_api.image_create(context, image_data)
|
||||
return dict(image=make_image_dict(image_data))
|
||||
except exception.Duplicate:
|
||||
return exc.HTTPConflict()
|
||||
@ -135,7 +135,7 @@ class Controller(wsgi.Controller):
|
||||
|
||||
context = None
|
||||
try:
|
||||
updated_image = db.image_update(context, id, image_data)
|
||||
updated_image = db_api.image_update(context, id, image_data)
|
||||
return dict(image=make_image_dict(updated_image))
|
||||
except exception.NotFound:
|
||||
return exc.HTTPNotFound()
|
||||
@ -169,7 +169,7 @@ def make_image_dict(image):
|
||||
properties = dict((p['key'], p['value'])
|
||||
for p in image['properties'] if not p['deleted'])
|
||||
|
||||
image_dict = _fetch_attrs(image, db.IMAGE_ATTRS)
|
||||
image_dict = _fetch_attrs(image, db_api.IMAGE_ATTRS)
|
||||
|
||||
image_dict['properties'] = properties
|
||||
return image_dict
|
||||
|
@ -34,7 +34,7 @@ import glance.store
|
||||
import glance.store.filesystem
|
||||
import glance.store.http
|
||||
import glance.store.swift
|
||||
import glance.registry.db.sqlalchemy.api
|
||||
import glance.registry.db.api
|
||||
|
||||
|
||||
FAKE_FILESYSTEM_ROOTDIR = os.path.join('/tmp', 'glance-tests')
|
||||
@ -441,18 +441,18 @@ def stub_out_registry_db_image_api(stubs):
|
||||
else:
|
||||
return images[0]
|
||||
|
||||
def image_get_all_public(self, _context, public):
|
||||
def image_get_all_public(self, _context, public=True):
|
||||
return [f for f in self.images
|
||||
if f['is_public'] == public]
|
||||
|
||||
fake_datastore = FakeDatastore()
|
||||
stubs.Set(glance.registry.db.sqlalchemy.api, 'image_create',
|
||||
stubs.Set(glance.registry.db.api, 'image_create',
|
||||
fake_datastore.image_create)
|
||||
stubs.Set(glance.registry.db.sqlalchemy.api, 'image_update',
|
||||
stubs.Set(glance.registry.db.api, 'image_update',
|
||||
fake_datastore.image_update)
|
||||
stubs.Set(glance.registry.db.sqlalchemy.api, 'image_destroy',
|
||||
stubs.Set(glance.registry.db.api, 'image_destroy',
|
||||
fake_datastore.image_destroy)
|
||||
stubs.Set(glance.registry.db.sqlalchemy.api, 'image_get',
|
||||
stubs.Set(glance.registry.db.api, 'image_get',
|
||||
fake_datastore.image_get)
|
||||
stubs.Set(glance.registry.db.sqlalchemy.api, 'image_get_all_public',
|
||||
stubs.Set(glance.registry.db.api, 'image_get_all_public',
|
||||
fake_datastore.image_get_all_public)
|
||||
|
Loading…
x
Reference in New Issue
Block a user