Create 'simple' db driver

Move the core of glance.tests.unit.utils:FakeDB to glance.db.simple.
This 'simple' driver is an alternative to the traditional sqlalchemy
driver. Additionally, the sqlalchemy driver has been moved from
glance.db to glance.db.sqlalchemy. The simple db driver is only
available to be used by tests for now.

Related to bp refactor-db-layer

Change-Id: I9d33a433c0c03e53fb5a3491076086427ae694b3
This commit is contained in:
Brian Waldon 2012-05-31 15:39:33 -07:00
parent 82dbff4380
commit a68eb24431
49 changed files with 244 additions and 187 deletions

View File

@ -43,22 +43,21 @@ gettext.install('glance', unicode=1)
from glance.common import config
from glance.common import exception
from glance.openstack.common import cfg
import glance.db
import glance.db.api
import glance.db.migration
import glance.db.sqlalchemy.api
import glance.db.sqlalchemy.migration
CONF = cfg.CONF
def do_db_version(args):
"""Print database's current migration level"""
print glance.db.migration.db_version(CONF)
print glance.db.sqlalchemy.migration.db_version(CONF)
def do_upgrade(args):
"""Upgrade the database's migration level"""
version = args.pop(0) if args else None
glance.db.migration.upgrade(CONF, version)
glance.db.sqlalchemy.migration.upgrade(CONF, version)
def do_downgrade(args):
@ -68,13 +67,13 @@ def do_downgrade(args):
"downgrade requires a version argument")
version = args.pop(0)
glance.db.migration.downgrade(CONF, version)
glance.db.sqlalchemy.migration.downgrade(CONF, version)
def do_version_control(args):
"""Place a database under migration control"""
version = args.pop(0) if args else None
glance.db.migration.version_control(CONF, version)
glance.db.sqlalchemy.migration.version_control(CONF, version)
def do_db_sync(args):
@ -85,10 +84,10 @@ def do_db_sync(args):
# override auto-create flag, as complete DB should always
# be created on sync if not already existing
CONF.db_auto_create = True
glance.db.api.configure_db(CONF)
glance.db.sqlalchemy.api.configure_db(CONF)
version = args.pop(0) if args else None
current_version = args.pop(0) if args else None
glance.db.migration.db_sync(CONF, version, current_version)
glance.db.sqlalchemy.migration.db_sync(CONF, version, current_version)
def dispatch_cmd(args):

View File

@ -21,13 +21,13 @@ from glance.api.v2 import base
from glance.common import exception
from glance.common import utils
from glance.common import wsgi
import glance.db.api
import glance.db.sqlalchemy.api
class Controller(base.Controller):
def __init__(self, conf, db=None):
super(Controller, self).__init__(conf)
self.db_api = db or glance.db.api
self.db_api = db or glance.db.sqlalchemy.api
self.db_api.configure_db(conf)
def index(self, req, image_id):

View File

@ -19,14 +19,14 @@ from glance.api.v2 import base
from glance.common import exception
from glance.common import utils
from glance.common import wsgi
import glance.db.api
import glance.db.sqlalchemy.api
import glance.store
class ImageDataController(base.Controller):
def __init__(self, conf, db_api=None, store_api=None):
super(ImageDataController, self).__init__(conf)
self.db_api = db_api or glance.db.api
self.db_api = db_api or glance.db.sqlalchemy.api
self.db_api.configure_db(conf)
self.store_api = store_api or glance.store
self.store_api.create_stores(conf)

View File

@ -21,13 +21,13 @@ from glance.api.v2 import base
from glance.common import exception
from glance.common import utils
from glance.common import wsgi
import glance.db.api
import glance.db.sqlalchemy.api
class Controller(base.Controller):
def __init__(self, conf, db=None):
super(Controller, self).__init__(conf)
self.db_api = db or glance.db.api
self.db_api = db or glance.db.sqlalchemy.api
self.db_api.configure_db(conf)
def index(self, req, image_id):

View File

@ -22,14 +22,14 @@ from glance.api.v2 import base
from glance.common import exception
from glance.common import utils
from glance.common import wsgi
import glance.db.api
import glance.db.sqlalchemy.api
from glance.openstack.common import timeutils
class ImagesController(base.Controller):
def __init__(self, conf, db_api=None):
super(ImagesController, self).__init__(conf)
self.db_api = db_api or glance.db.api
self.db_api = db_api or glance.db.sqlalchemy.api
self.db_api.configure_db(conf)
def _normalize_properties(self, image):

View File

@ -20,7 +20,7 @@ import webob.exc
from glance.common import exception
from glance.common import wsgi
from glance.openstack.common import cfg
from glance.db import api as db_api
from glance.db.sqlalchemy import api as db_api
context_opts = [
cfg.BoolOpt('owner_is_tenant', default=True),

View File

164
glance/db/simple/api.py Normal file
View File

@ -0,0 +1,164 @@
# Copyright 2012 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.
import datetime
import logging
import uuid
from glance.common import exception
LOG = logging.getLogger(__name__)
DATA = {
'images': {},
'members': {},
'tags': {},
}
def configure_db(*args, **kwargs):
pass
def get_session():
return DATA
def _image_member_format(image_id, tenant_id, can_share):
return {
'image_id': image_id,
'member': tenant_id,
'can_share': can_share,
'deleted': False,
}
def _image_format(image_id, **values):
dt = datetime.datetime.now()
image = {
'id': image_id,
'name': 'image-name',
'owner': None,
'location': None,
'status': 'queued',
'is_public': False,
'created_at': dt,
'updated_at': dt,
'tags': [],
'properties': [],
}
image.update(values)
return image
def image_get(context, image_id, session=None):
try:
image = DATA['images'][image_id]
LOG.info('Found image %s: %s' % (image_id, str(image)))
except KeyError:
LOG.info('Could not find image %s' % image_id)
raise exception.NotFound(image_id=image_id)
#NOTE(bcwaldon: this is a hack until we can get image members with
# a direct db call
image['members'] = DATA['members'].get(image_id, [])
return image
def image_get_all(context, filters=None):
images = DATA['images'].values()
LOG.info('Listing images: %s' % (images))
return images
def image_member_find(context, image_id, tenant_id):
image_get(context, image_id)
print DATA['members']
for member in DATA['members'].get(image_id, []):
if member['member'] == tenant_id:
return member
raise exception.NotFound()
def image_member_create(context, values):
member = _image_member_format(values['image_id'],
values['member'],
values['can_share'])
global DATA
DATA['members'].setdefault(values['image_id'], [])
DATA['members'][values['image_id']].append(member)
return member
def image_create(context, image_values):
image_id = image_values.get('id', str(uuid.uuid4()))
image = _image_format(image_id, **image_values)
DATA['images'][image_id] = image
DATA['tags'][image_id] = image.pop('tags', [])
LOG.info('Created image %s with values %s' %
(image_id, str(image_values)))
return image
def image_update(context, image_id, image_values):
LOG.info('Updating image %s with values %s' %
(image_id, str(image_values)))
global DATA
try:
image = DATA['images'][image_id]
LOG.info('Found image %s: %s' % (image_id, str(image)))
except KeyError:
raise exception.NotFound(image_id=image_id)
image.update(image_values)
DATA['images'][image_id] = image
LOG.info('Image %s updated to %s' % (image_id, str(image)))
return image
def image_tag_get_all(context, image_id):
image_get(context, image_id)
return DATA['tags'].get(image_id, [])
def image_tag_get(context, image_id, value):
tags = image_tag_get_all(context, image_id)
if value in tags:
return value
else:
raise exception.NotFound()
def image_tag_set_all(context, image_id, values):
global DATA
DATA['tags'][image_id] = values
def image_tag_create(context, image_id, value):
global DATA
DATA['tags'][image_id].append(value)
return value
def image_tag_delete(context, image_id, value):
global DATA
try:
DATA['tags'][image_id].remove(value)
except ValueError:
raise exception.NotFound()

View File

View File

@ -36,11 +36,12 @@ from sqlalchemy.sql import or_, and_
from glance.common import exception
from glance import db
from glance.db import migration
from glance.db import models
from glance.db.sqlalchemy import migration
from glance.db.sqlalchemy import models
from glance.openstack.common import cfg
from glance.openstack.common import timeutils
_ENGINE = None
_MAKER = None
_MAX_RETRIES = None

View File

@ -24,7 +24,7 @@ import logging
import sqlalchemy.types
logger = logging.getLogger('glance.db.migrate_repo.schema')
logger = logging.getLogger(__name__)
String = lambda length: sqlalchemy.types.String(
@ -85,7 +85,7 @@ def from_migration_import(module_name, fromlist):
# Refer to images table
"""
module_path = 'glance.db.migrate_repo.versions.%s' % module_name
module_path = 'glance.db.sqlalchemy.migrate_repo.versions.%s' % module_name
module = __import__(module_path, globals(), locals(), fromlist, -1)
return [getattr(module, item) for item in fromlist]

View File

@ -17,7 +17,7 @@
from sqlalchemy.schema import (Column, MetaData, Table)
from glance.db.migrate_repo.schema import (
from glance.db.sqlalchemy.migrate_repo.schema import (
Boolean, DateTime, Integer, String, Text, create_tables, drop_tables)

View File

@ -18,7 +18,7 @@
from sqlalchemy.schema import (
Column, ForeignKey, Index, MetaData, Table, UniqueConstraint)
from glance.db.migrate_repo.schema import (
from glance.db.sqlalchemy.migrate_repo.schema import (
Boolean, DateTime, Integer, String, Text, create_tables, drop_tables,
from_migration_import)

View File

@ -19,7 +19,7 @@ from migrate.changeset import *
from sqlalchemy import *
from sqlalchemy.sql import and_, not_
from glance.db.migrate_repo.schema import (
from glance.db.sqlalchemy.migrate_repo.schema import (
Boolean, DateTime, Integer, String, Text, from_migration_import)

View File

@ -19,7 +19,7 @@ from migrate.changeset import *
from sqlalchemy import *
from sqlalchemy.sql import and_, not_
from glance.db.migrate_repo.schema import (
from glance.db.sqlalchemy.migrate_repo.schema import (
Boolean, DateTime, Integer, String, Text, from_migration_import)

View File

@ -18,7 +18,7 @@
from migrate.changeset import *
from sqlalchemy import *
from glance.db.migrate_repo.schema import (
from glance.db.sqlalchemy.migrate_repo.schema import (
Boolean, DateTime, BigInteger, Integer, String,
Text, from_migration_import)

View File

@ -19,7 +19,7 @@ from migrate.changeset import *
from sqlalchemy import *
from sqlalchemy.sql import and_, not_
from glance.db.migrate_repo.schema import (
from glance.db.sqlalchemy.migrate_repo.schema import (
Boolean, DateTime, Integer, String, Text, from_migration_import)

View File

@ -19,7 +19,7 @@ from migrate.changeset import *
from sqlalchemy import *
from sqlalchemy.sql import and_, not_
from glance.db.migrate_repo.schema import (
from glance.db.sqlalchemy.migrate_repo.schema import (
Boolean, DateTime, BigInteger, Integer, String,
Text, from_migration_import)

View File

@ -18,7 +18,7 @@
from migrate.changeset import *
from sqlalchemy import *
from glance.db.migrate_repo.schema import (
from glance.db.sqlalchemy.migrate_repo.schema import (
Boolean, DateTime, BigInteger, Integer, String, Text,
create_tables, drop_tables, from_migration_import)

View File

@ -19,7 +19,7 @@ from migrate.changeset import *
from sqlalchemy import *
from sqlalchemy.sql import and_, not_
from glance.db.migrate_repo.schema import (
from glance.db.sqlalchemy.migrate_repo.schema import (
Boolean, DateTime, Integer, String, Text, from_migration_import)

View File

@ -18,7 +18,7 @@
from migrate.changeset import *
from sqlalchemy import *
from glance.db.migrate_repo.schema import from_migration_import
from glance.db.sqlalchemy.migrate_repo.schema import from_migration_import
def get_images_table(meta):

View File

@ -15,7 +15,7 @@
from sqlalchemy import schema
from glance.db.migrate_repo import schema as glance_schema
from glance.db.sqlalchemy.migrate_repo import schema as glance_schema
def define_image_tags_table(meta):

View File

@ -30,7 +30,7 @@ from migrate.versioning import repository as versioning_repository
from glance.common import exception
logger = logging.getLogger('glance.db.migration')
logger = logging.getLogger(__name__)
def db_version(conf):

View File

@ -27,7 +27,7 @@ from sqlalchemy import UniqueConstraint
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.ext.declarative import declarative_base
import glance.db.api
import glance.db.sqlalchemy.api
from glance.common import utils
from glance.openstack.common import timeutils
@ -55,7 +55,7 @@ class ModelBase(object):
def save(self, session=None):
"""Save this object"""
session = session or glance.db.api.get_session()
session = session or glance.db.sqlalchemy.api.get_session()
session.add(self)
session.flush()

View File

@ -27,8 +27,9 @@ from glance.common import exception
from glance.common import utils
from glance.common import wsgi
from glance.openstack.common import cfg
from glance.db.sqlalchemy import api as db_api
from glance.openstack.common import timeutils
from glance.db import api as db_api
logger = logging.getLogger('glance.registry.api.v1.images')

View File

@ -22,7 +22,7 @@ import webob.exc
from glance.common import exception
from glance.common import utils
from glance.common import wsgi
from glance.db import api as db_api
from glance.db.sqlalchemy import api as db_api
logger = logging.getLogger('glance.registry.api.v1.members')

View File

@ -24,13 +24,14 @@ from glance.common import client as base_client
from glance.common import context
from glance.common import exception
from glance.common import utils
from glance.db import api as db_api
from glance.db import models as db_models
from glance.db.sqlalchemy import api as db_api
from glance.db.sqlalchemy import models as db_models
from glance.openstack.common import timeutils
from glance.registry import client as rclient
from glance.tests.unit import base
from glance.tests import utils as test_utils
_gen_uuid = utils.generate_uuid
UUID1 = _gen_uuid()

View File

@ -22,11 +22,10 @@ import random
from glance.common import context
from glance.common import exception
from glance.common import utils
from glance.db import api as db_api
from glance.db import models as db_models
from glance.db.sqlalchemy import api as db_api
from glance.db.sqlalchemy import models as db_models
from glance.openstack.common import timeutils
from glance.tests.unit import base
from glance.tests import utils as test_utils
_gen_uuid = utils.generate_uuid

View File

@ -21,7 +21,7 @@ import stubout
from glance.common import config
from glance.common import exception, context
from glance.db import api as db_api
from glance.db.sqlalchemy import api as db_api
from glance.registry import configure_registry_client
from glance.store import (delete_from_backend,
schedule_delete_from_backend)

View File

@ -35,8 +35,8 @@ from sqlalchemy.pool import NullPool
from glance.common import exception
from glance.openstack.common import cfg
import glance.db.migration as migration_api
from glance.db import models
import glance.db.sqlalchemy.migration as migration_api
from glance.db.sqlalchemy import models
from glance.tests import utils
@ -50,7 +50,7 @@ class TestMigrations(utils.BaseTestCase):
CONFIG_FILE_PATH = os.environ.get('GLANCE_TEST_MIGRATIONS_CONF',
os.path.join('glance', 'tests', 'unit',
'test_migrations.conf'))
REPOSITORY_PATH = os.path.join('glance', 'db', 'migrate_repo')
REPOSITORY_PATH = 'glance/db/sqlalchemy/migrate_repo'
REPOSITORY = Repository(REPOSITORY_PATH)
def __init__(self, *args, **kwargs):

View File

@ -13,13 +13,13 @@
# License for the specific language governing permissions and limitations
# under the License.
import datetime
import logging
import uuid
import glance.common.context
from glance.common import exception
from glance.common import wsgi
import glance.db.simple.api as simple_db
LOG = logging.getLogger(__name__)
@ -50,143 +50,35 @@ class FakeRequest(wsgi.Request):
class FakeDB(object):
def __init__(self):
self.images = {
UUID1: self._image_format(UUID1, location=UUID1),
UUID2: self._image_format(UUID2),
}
self.members = {
UUID1: [
self._image_member_format(UUID1, TENANT1, True),
self._image_member_format(UUID1, TENANT2, False),
],
UUID2: [],
}
self.tags = {
UUID1: ['ping', 'pong'],
UUID2: [],
self.reset()
self.init_db()
@staticmethod
def init_db():
images = [
{'id': UUID1, 'owner': TENANT1, 'location': UUID1},
{'id': UUID2, 'owner': TENANT1},
]
[simple_db.image_create(None, image) for image in images]
members = [
{'image_id': UUID1, 'member': TENANT1, 'can_share': True},
{'image_id': UUID1, 'member': TENANT2, 'can_share': False},
]
[simple_db.image_member_create(None, member) for member in members]
simple_db.image_tag_set_all(None, UUID1, ['ping', 'pong'])
@staticmethod
def reset():
simple_db.DATA = {
'images': {},
'members': {},
'tags': {},
}
def reset(self):
self.images = {}
self.members = {}
self.tags = {}
def configure_db(*args, **kwargs):
pass
def get_session(self):
pass
def _image_member_format(self, image_id, tenant_id, can_share):
return {
'image_id': image_id,
'member': tenant_id,
'can_share': can_share,
'deleted': False,
}
def _image_format(self, image_id, **values):
dt = datetime.datetime.now()
image = {
'id': image_id,
'name': 'image-name',
'owner': TENANT1,
'location': None,
'status': 'queued',
'is_public': False,
'created_at': dt,
'updated_at': dt,
'tags': [],
'properties': [],
}
image.update(values)
return image
def image_get(self, context, image_id, session=None):
try:
image = self.images[image_id]
LOG.info('Found image %s: %s' % (image_id, str(image)))
except KeyError:
raise exception.NotFound(image_id=image_id)
#NOTE(bcwaldon: this is a hack until we can get image members with
# a direct db call
image['members'] = self.members.get(image_id, [])
return image
def image_get_all(self, context, filters=None):
return self.images.values()
def image_member_find(self, context, image_id, tenant_id):
try:
self.images[image_id]
except KeyError:
raise exception.NotFound()
for member in self.members.get(image_id, []):
if member['member'] == tenant_id:
return member
raise exception.NotFound()
def image_member_create(self, context, values):
member = self._image_member_format(values['image_id'],
values['member'],
values['can_share'])
self.members[values['image_id']] = member
return member
def image_create(self, context, image_values):
new_uuid = str(uuid.uuid4())
image = self._image_format(new_uuid, **image_values)
self.images[new_uuid] = image
self.tags[new_uuid] = image.pop('tags', [])
LOG.info('Created image %s with values %s' %
(new_uuid, str(image_values)))
return image
def image_update(self, context, image_id, image_values):
LOG.info('Updating image %s with values %s' %
(image_id, str(image_values)))
try:
image = self.images[image_id]
LOG.info('Found image %s: %s' % (image_id, str(image)))
except KeyError:
raise exception.NotFound(image_id=image_id)
image.update(image_values)
self.images[image_id] = image
LOG.info('Image %s updated to %s' % (image_id, str(image)))
return image
def image_tag_get_all(self, context, image_id):
try:
return self.tags[image_id]
except KeyError:
raise exception.NotFound()
def image_tag_get(self, context, image_id, value):
tags = self.image_tag_get_all(context, image_id)
if value in tags:
return value
else:
raise exception.NotFound()
def image_tag_set_all(self, context, image_id, values):
self.tags[image_id] = values
def image_tag_create(self, context, image_id, value):
tags = self.image_tag_get_all(context, image_id)
tags.append(value)
return value
def image_tag_delete(self, context, image_id, value):
tags = self.image_tag_get_all(context, image_id)
try:
tags.remove(value)
except ValueError:
raise exception.NotFound()
def __getattr__(self, key):
return getattr(simple_db, key)
class FakeStoreAPI(object):

View File

@ -30,8 +30,8 @@ from glance.common import context
from glance.common import utils
from glance.openstack.common import timeutils
from glance.registry.api import v1 as rserver
from glance.db import api as db_api
from glance.db import models as db_models
from glance.db.sqlalchemy import api as db_api
from glance.db.sqlalchemy import models as db_models
from glance.tests import utils as test_utils
from glance.tests.unit import base

View File

@ -8,7 +8,7 @@ import keystoneclient.v2_0.client
import glance.common.context
from glance.openstack.common import cfg
import glance.registry.context
import glance.db.api as db_api
import glance.db.sqlalchemy.api as db_api
logger = logging.getLogger(__name__)