summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZiad Sawalha <ziad.sawalha@rackspace.com>2011-06-29 02:15:02 -0700
committerZiad Sawalha <ziad.sawalha@rackspace.com>2011-06-29 02:15:02 -0700
commit5661cf0cbd0ac6abbbdea78d71ef0a9beea0db44 (patch)
treecd99357cf4c16d427b0614494b6a47d3cf085231
parentbb7303d96e65226ad428e08db9463231bcb4274c (diff)
parente3f07c770720532ff48210797073fa34420e69ab (diff)
downloadkeystone-5661cf0cbd0ac6abbbdea78d71ef0a9beea0db44.tar.gz
keystone-5661cf0cbd0ac6abbbdea78d71ef0a9beea0db44.tar.xz
keystone-5661cf0cbd0ac6abbbdea78d71ef0a9beea0db44.zip
Merge pull request #73 from yogirackspace/master
Initial changes to support multiple back ends.
-rw-r--r--.gitignore1
-rwxr-xr-xbin/keystone1
-rwxr-xr-xbin/keystone-manage10
-rwxr-xr-xetc/keystone.conf34
-rw-r--r--keystone/backends/__init__.py30
-rwxr-xr-x[-rw-r--r--]keystone/backends/alterdb/__init__.py (renamed from keystone/db/sqlalchemy/__init__.py)30
-rw-r--r--keystone/backends/alterdb/api/__init__.py1
-rwxr-xr-x[-rw-r--r--]keystone/backends/alterdb/api/token.py (renamed from keystone/db/sqlalchemy/api/token.py)2
-rwxr-xr-xkeystone/backends/alterdb/models.py85
-rwxr-xr-xkeystone/backends/api.py47
-rw-r--r--keystone/backends/models.py28
-rwxr-xr-xkeystone/backends/sqlalchemy/__init__.py95
-rwxr-xr-x[-rw-r--r--]keystone/backends/sqlalchemy/api/__init__.py (renamed from keystone/db/sqlalchemy/api/__init__.py)0
-rwxr-xr-xkeystone/backends/sqlalchemy/api/endpoint_template.py (renamed from keystone/db/sqlalchemy/api/endpoint_template.py)2
-rw-r--r--keystone/backends/sqlalchemy/api/group.py (renamed from keystone/db/sqlalchemy/api/group.py)2
-rw-r--r--keystone/backends/sqlalchemy/api/role.py (renamed from keystone/db/sqlalchemy/api/role.py)2
-rwxr-xr-xkeystone/backends/sqlalchemy/api/tenant.py (renamed from keystone/db/sqlalchemy/api/tenant.py)2
-rwxr-xr-x[-rw-r--r--]keystone/backends/sqlalchemy/api/tenant_group.py (renamed from keystone/db/sqlalchemy/api/tenant_group.py)2
-rwxr-xr-xkeystone/backends/sqlalchemy/api/token.py61
-rwxr-xr-xkeystone/backends/sqlalchemy/api/user.py (renamed from keystone/db/sqlalchemy/api/user.py)2
-rwxr-xr-x[-rw-r--r--]keystone/backends/sqlalchemy/models.py (renamed from keystone/db/sqlalchemy/models.py)20
-rwxr-xr-xkeystone/common/config.py28
-rw-r--r--keystone/db/__init__.py0
-rwxr-xr-xkeystone/logic/service.py6
-rwxr-xr-xkeystone/server.py12
-rw-r--r--keystone/test/unit/base.py4
-rwxr-xr-x[-rw-r--r--]keystone/utils.py18
-rwxr-xr-x[-rw-r--r--]setup.py0
28 files changed, 469 insertions, 56 deletions
diff --git a/.gitignore b/.gitignore
index 94c324b9..c4dff7bb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
.pydevproject/
.settings/
keystone.db
+keystone.token.db
.*.swp
*.log
*.pid
diff --git a/bin/keystone b/bin/keystone
index 3349f634..4664f80d 100755
--- a/bin/keystone
+++ b/bin/keystone
@@ -38,7 +38,6 @@ import tools.tracer #@UnusedImport # module runs on import
import keystone
from keystone.common import config, wsgi
-
if __name__ == '__main__':
# Initialize a parser for our configuration paramaters
parser = optparse.OptionParser(version='%%prog %s' % keystone.version)
diff --git a/bin/keystone-manage b/bin/keystone-manage
index e3208f40..0475b99b 100755
--- a/bin/keystone-manage
+++ b/bin/keystone-manage
@@ -38,9 +38,9 @@ if os.path.exists(os.path.join(possible_topdir, 'keystone', '__init__.py')):
import tools.tracer #@UnusedImport # module runs on import
import keystone
from keystone.common import config
-import keystone.db.sqlalchemy as db
-import keystone.db.sqlalchemy.api as db_api
-import keystone.db.sqlalchemy.models as db_models
+import keystone.backends as db
+import keystone.backends.api as db_api
+import keystone.backends.sqlalchemy.models as db_models
def Main():
@@ -72,7 +72,6 @@ def Main():
# Parse command-line and load config
(options, args) = config.parse_options(parser)
config_file, conf = config.load_paste_config('admin', options, args)
-
# Check arguments
if len(args) == 0:
parser.error('No object type specified for first argument')
@@ -105,11 +104,10 @@ def Main():
verbose = verbose in [True, "True", "1"]
if debug or verbose:
config_file = config.find_config_file(options, args)
- print "Using config file:", config_file
config.setup_logging(options, conf)
- db.configure_db(conf)
+ db.configure_backends(conf.global_conf)
if object_type == "user":
if command == "add":
diff --git a/etc/keystone.conf b/etc/keystone.conf
index c2f30556..4d81f48d 100755
--- a/etc/keystone.conf
+++ b/etc/keystone.conf
@@ -3,7 +3,7 @@
verbose = False
# Show debugging output in logs (sets DEBUG log level output)
-debug = False
+debug = True
# Which backend store should Keystone use by default.
# Default: 'sqlite'
@@ -14,15 +14,8 @@ default_store = sqlite
# file for both the API and registry servers!
#log_file = /var/log/keystone.log
log_file = keystone.log
-
-# SQLAlchemy connection string for the reference implementation
-# registry server. Any valid SQLAlchemy connection string is fine.
-# See: http://www.sqlalchemy.org/docs/05/reference/sqlalchemy/connections.html#sqlalchemy.create_engine
-sql_connection = sqlite:///keystone.db
-
-# Period in seconds after which SQLAlchemy should reestablish its connection
-# to the database.
-sql_idle_timeout = 30
+#List of backends to be configured
+backends = keystone.backends.sqlalchemy,keystone.backends.alterdb
#Dictionary Maps every service to a header.Missing services would get header X_(SERVICE_NAME) Key => Service Name, Value => Header Name
service-header-mappings = {'nova' : 'X-Server-Management-Url' , 'swift' : 'X-Storage-Url', 'cdn' : 'X-CDN-Management-Url'}
@@ -33,6 +26,27 @@ server_bind_host = 0.0.0.0
# Port the bind the API server to
server_bind_port = 5000
+
+[keystone.backends.sqlalchemy]
+# SQLAlchemy connection string for the reference implementation
+# registry server. Any valid SQLAlchemy connection string is fine.
+# See: http://www.sqlalchemy.org/docs/05/reference/sqlalchemy/connections.html#sqlalchemy.create_engine
+sql_connection = sqlite:///keystone.db
+backend_entities = ['UserGroupAssociation', 'UserRoleAssociation', 'Endpoints', 'Role', 'Tenant', 'User', 'Credentials', 'Group', 'EndpointTemplates']
+# Period in seconds after which SQLAlchemy should reestablish its connection
+# to the database.
+sql_idle_timeout = 30
+
+[keystone.backends.alterdb]
+# SQLAlchemy connection string for the reference implementation
+# registry server. Any valid SQLAlchemy connection string is fine.
+# See: http://www.sqlalchemy.org/docs/05/reference/sqlalchemy/connections.html#sqlalchemy.create_engine
+sql_connection = sqlite:///keystone.token.db
+backend_entities = ['Token']
+# Period in seconds after which SQLAlchemy should reestablish its connection
+# to the database.
+sql_idle_timeout = 30
+
[app:admin]
paste.app_factory = keystone.server:admin_app_factory
diff --git a/keystone/backends/__init__.py b/keystone/backends/__init__.py
new file mode 100644
index 00000000..89b3afb1
--- /dev/null
+++ b/keystone/backends/__init__.py
@@ -0,0 +1,30 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 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 ast
+import logging
+import keystone.utils as utils
+from keystone.backends import models as models
+from keystone.backends import api as api
+
+DEFAULT_BACKENDS = 'keystone.backends.sqlalchemy'
+
+def configure_backends(options):
+ '''Load backends given in the 'backends' option.'''
+ backend_names = options.get('backends', DEFAULT_BACKENDS)
+ for backend in backend_names.split(','):
+ backend_module = utils.import_module(backend)
+ backend_module.configure_backend(options[backend])
diff --git a/keystone/db/sqlalchemy/__init__.py b/keystone/backends/alterdb/__init__.py
index bdb9a5ba..fc7275cc 100644..100755
--- a/keystone/db/sqlalchemy/__init__.py
+++ b/keystone/backends/alterdb/__init__.py
@@ -15,20 +15,24 @@
# License for the specific language governing permissions and limitations
# under the License.
+import ast
import logging
from sqlalchemy import create_engine
from sqlalchemy.orm import joinedload, aliased, sessionmaker
from keystone.common import config
-from keystone.db.sqlalchemy import models
+from keystone.backends.alterdb import models
+import keystone.utils as utils
+import keystone.backends.api as top_api
_ENGINE = None
_MAKER = None
BASE = models.Base
+MODEL_PREFIX = 'keystone.backends.alterdb.models.'
+API_PREFIX = 'keystone.backends.alterdb.api.'
-
-def configure_db(options):
+def configure_backend(options):
"""
Establish the database, create an engine if needed, and
register the models.
@@ -50,7 +54,7 @@ def configure_db(options):
logger.setLevel(logging.DEBUG)
elif verbose:
logger.setLevel(logging.INFO)
- register_models()
+ register_models(options)
def get_session(autocommit=True, expire_on_commit=False):
@@ -64,12 +68,24 @@ def get_session(autocommit=True, expire_on_commit=False):
return _MAKER()
-def register_models():
+def register_models(options):
"""Register Models and create properties"""
global _ENGINE
assert _ENGINE
- BASE.metadata.create_all(_ENGINE)
-
+ supported_alchemy_models = ast.literal_eval(
+ options["backend_entities"])
+ supported_alchemy_tables = []
+ for supported_alchemy_model in supported_alchemy_models:
+ model = utils.import_module(MODEL_PREFIX + supported_alchemy_model)
+ supported_alchemy_tables.append(model.__table__)
+ if model.__api__ != None:
+ model_api = utils.import_module(API_PREFIX + model.__api__)
+ top_api.set_value(model.__api__, model_api)
+ creation_tables = []
+ for table in reversed(BASE.metadata.sorted_tables):
+ if table in supported_alchemy_tables:
+ creation_tables.append(table)
+ BASE.metadata.create_all(_ENGINE, tables=creation_tables, checkfirst=True)
def unregister_models():
"""Unregister Models, useful clearing out data before testing"""
diff --git a/keystone/backends/alterdb/api/__init__.py b/keystone/backends/alterdb/api/__init__.py
new file mode 100644
index 00000000..5e662f40
--- /dev/null
+++ b/keystone/backends/alterdb/api/__init__.py
@@ -0,0 +1 @@
+import token
diff --git a/keystone/db/sqlalchemy/api/token.py b/keystone/backends/alterdb/api/token.py
index 0c43af67..d7496ec9 100644..100755
--- a/keystone/db/sqlalchemy/api/token.py
+++ b/keystone/backends/alterdb/api/token.py
@@ -15,7 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from keystone.db.sqlalchemy import get_session, models
+from keystone.backends.alterdb import get_session, models
def create(values):
token_ref = models.Token()
diff --git a/keystone/backends/alterdb/models.py b/keystone/backends/alterdb/models.py
new file mode 100755
index 00000000..7aa30c18
--- /dev/null
+++ b/keystone/backends/alterdb/models.py
@@ -0,0 +1,85 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+# Copyright (c) 2010-2011 OpenStack, LLC.
+#
+# 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.
+# Not Yet PEP8 standardized
+from sqlalchemy import Column, String, Integer, ForeignKey, \
+ UniqueConstraint, Boolean, DateTime
+from sqlalchemy.exc import IntegrityError
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy.orm import relationship, object_mapper
+Base = declarative_base()
+
+
+class KeystoneBase(object):
+ """Base class for Keystone Models."""
+ __api__ = None
+ def save(self, session=None):
+ """Save this object."""
+
+ if not session:
+ from keystone.backends.alterdb import get_session
+ session = get_session()
+ session.add(self)
+ try:
+ session.flush()
+ except IntegrityError:
+ raise
+
+ def delete(self, session=None):
+ """Delete this object."""
+ self.save(session=session)
+
+ def __setitem__(self, key, value):
+ setattr(self, key, value)
+
+ def __getitem__(self, key):
+ return getattr(self, key)
+
+ def get(self, key, default=None):
+ return getattr(self, key, default)
+
+ def __iter__(self):
+ self._i = iter(object_mapper(self).columns)
+ return self
+
+ def next(self):
+ n = self._i.next().name
+ return n, getattr(self, n)
+
+ def update(self, values):
+ """Make the model object behave like a dict"""
+ for k, v in values.iteritems():
+ setattr(self, k, v)
+
+ def iteritems(self):
+ """Make the model object behave like a dict.
+
+ Includes attributes from joins."""
+ local = dict(self)
+ joined = dict([(k, v) for k, v in self.__dict__.iteritems()
+ if not k[0] == '_'])
+ local.update(joined)
+ return local.iteritems()
+
+
+
+class Token(Base, KeystoneBase):
+ __tablename__ = 'token'
+ __api__ ='token'
+ id = Column(String(255), primary_key=True, unique=True)
+ user_id = Column(String(255))
+ tenant_id = Column(String(255))
+ expires = Column(DateTime)
+
diff --git a/keystone/backends/api.py b/keystone/backends/api.py
new file mode 100755
index 00000000..9bb23ae8
--- /dev/null
+++ b/keystone/backends/api.py
@@ -0,0 +1,47 @@
+#
+# 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.
+# Not Yet PEP8 standardized
+#API
+#TODO(Yogi) Refactor all API to separate classes specific to models.
+endpoint_template = None
+group = None
+role = None
+tenant_group = None
+tenant = None
+token = None
+user = None
+
+# Function to dynamically set module references.
+def set_value(variable_name, value):
+ if variable_name == 'endpoint_template':
+ global endpoint_template
+ endpoint_template = value
+ elif variable_name == 'group':
+ global group
+ group = value
+ elif variable_name == 'role':
+ global role
+ role = value
+ elif variable_name == 'tenant_group':
+ global tenant_group
+ tenant_group = value
+ elif variable_name == 'tenant':
+ global tenant
+ tenant = value
+ elif variable_name == 'token':
+ global token
+ token = value
+ elif variable_name == 'user':
+ global user
+ user = value
diff --git a/keystone/backends/models.py b/keystone/backends/models.py
new file mode 100644
index 00000000..dc35361f
--- /dev/null
+++ b/keystone/backends/models.py
@@ -0,0 +1,28 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+# Copyright (c) 2010-2011 OpenStack, LLC.
+#
+# 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.
+# Not Yet PEP8 standardized
+#Models
+UserGroupAssociation = None
+UserRoleAssociation = None
+Endpoints = None
+Role = None
+Tenant = None
+User = None
+Credentials = None
+Group = None
+Token = None
+EndpointTemplates = None
+
diff --git a/keystone/backends/sqlalchemy/__init__.py b/keystone/backends/sqlalchemy/__init__.py
new file mode 100755
index 00000000..6b3e52d1
--- /dev/null
+++ b/keystone/backends/sqlalchemy/__init__.py
@@ -0,0 +1,95 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 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 ast
+import logging
+
+from sqlalchemy import create_engine
+from sqlalchemy.orm import joinedload, aliased, sessionmaker
+
+from keystone.common import config
+from keystone.backends.sqlalchemy import models
+import keystone.utils as utils
+import keystone.backends.api as top_api
+_ENGINE = None
+_MAKER = None
+BASE = models.Base
+
+MODEL_PREFIX = 'keystone.backends.sqlalchemy.models.'
+API_PREFIX = 'keystone.backends.sqlalchemy.api.'
+
+def configure_backend(options):
+ """
+ Establish the database, create an engine if needed, and
+ register the models.
+
+ :param options: Mapping of configuration options
+ """
+ global _ENGINE
+ if not _ENGINE:
+ debug = config.get_option(
+ options, 'debug', type='bool', default=False)
+ verbose = config.get_option(
+ options, 'verbose', type='bool', default=False)
+ timeout = config.get_option(
+ options, 'sql_idle_timeout', type='int', default=3600)
+ _ENGINE = create_engine(options['sql_connection'],
+ pool_recycle=timeout)
+ logger = logging.getLogger('sqlalchemy.engine')
+ if debug:
+ logger.setLevel(logging.DEBUG)
+ elif verbose:
+ logger.setLevel(logging.INFO)
+ register_models(options)
+
+
+def get_session(autocommit=True, expire_on_commit=False):
+ """Helper method to grab session"""
+ global _MAKER, _ENGINE
+ if not _MAKER:
+ assert _ENGINE
+ _MAKER = sessionmaker(bind=_ENGINE,
+ autocommit=autocommit,
+ expire_on_commit=expire_on_commit)
+ return _MAKER()
+
+
+def register_models(options):
+ """Register Models and create properties"""
+ global _ENGINE
+ assert _ENGINE
+ supported_alchemy_models = ast.literal_eval(
+ options["backend_entities"])
+ supported_alchemy_tables = []
+ for supported_alchemy_model in supported_alchemy_models:
+ model = utils.import_module(MODEL_PREFIX + supported_alchemy_model)
+ supported_alchemy_tables.append(model.__table__)
+ if model.__api__ != None:
+ model_api = utils.import_module(API_PREFIX + model.__api__)
+ top_api.set_value(model.__api__, model_api)
+ creation_tables = []
+ for table in reversed(BASE.metadata.sorted_tables):
+ if table in supported_alchemy_tables:
+ creation_tables.append(table)
+ BASE.metadata.create_all(_ENGINE, tables=creation_tables, checkfirst=True)
+
+
+def unregister_models():
+ """Unregister Models, useful clearing out data before testing"""
+ global _ENGINE
+ assert _ENGINE
+ BASE.metadata.drop_all(_ENGINE)
diff --git a/keystone/db/sqlalchemy/api/__init__.py b/keystone/backends/sqlalchemy/api/__init__.py
index 657621a6..657621a6 100644..100755
--- a/keystone/db/sqlalchemy/api/__init__.py
+++ b/keystone/backends/sqlalchemy/api/__init__.py
diff --git a/keystone/db/sqlalchemy/api/endpoint_template.py b/keystone/backends/sqlalchemy/api/endpoint_template.py
index f09479e5..135cf0a6 100755
--- a/keystone/db/sqlalchemy/api/endpoint_template.py
+++ b/keystone/backends/sqlalchemy/api/endpoint_template.py
@@ -15,7 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from keystone.db.sqlalchemy import get_session, models, aliased
+from keystone.backends.sqlalchemy import get_session, models, aliased
def create(values):
endpoint_template = models.EndpointTemplates()
diff --git a/keystone/db/sqlalchemy/api/group.py b/keystone/backends/sqlalchemy/api/group.py
index dbc75752..54b6ff09 100644
--- a/keystone/db/sqlalchemy/api/group.py
+++ b/keystone/backends/sqlalchemy/api/group.py
@@ -15,7 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from keystone.db.sqlalchemy import get_session, models, aliased
+from keystone.backends.sqlalchemy import get_session, models, aliased
def get(id, session=None):
if not session:
diff --git a/keystone/db/sqlalchemy/api/role.py b/keystone/backends/sqlalchemy/api/role.py
index 1d39be0a..d7dff110 100644
--- a/keystone/db/sqlalchemy/api/role.py
+++ b/keystone/backends/sqlalchemy/api/role.py
@@ -15,7 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from keystone.db.sqlalchemy import get_session, models
+from keystone.backends.sqlalchemy import get_session, models
def create(values):
role_ref = models.Role()
diff --git a/keystone/db/sqlalchemy/api/tenant.py b/keystone/backends/sqlalchemy/api/tenant.py
index 6617cb68..fe8b41cd 100755
--- a/keystone/db/sqlalchemy/api/tenant.py
+++ b/keystone/backends/sqlalchemy/api/tenant.py
@@ -15,7 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from keystone.db.sqlalchemy import get_session, models, aliased
+from keystone.backends.sqlalchemy import get_session, models, aliased
def create(values):
diff --git a/keystone/db/sqlalchemy/api/tenant_group.py b/keystone/backends/sqlalchemy/api/tenant_group.py
index 4efce544..21f466de 100644..100755
--- a/keystone/db/sqlalchemy/api/tenant_group.py
+++ b/keystone/backends/sqlalchemy/api/tenant_group.py
@@ -15,7 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from keystone.db.sqlalchemy import get_session, models
+from keystone.backends.sqlalchemy import get_session, models
def create(values):
group_ref = models.Group()
diff --git a/keystone/backends/sqlalchemy/api/token.py b/keystone/backends/sqlalchemy/api/token.py
new file mode 100755
index 00000000..19c4b8b3
--- /dev/null
+++ b/keystone/backends/sqlalchemy/api/token.py
@@ -0,0 +1,61 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 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.
+
+from keystone.backends.sqlalchemy import get_session, models
+
+def create(values):
+ token_ref = models.Token()
+ token_ref.update(values)
+ token_ref.save()
+ return token_ref
+
+
+def get(id, session=None):
+ if not session:
+ session = get_session()
+ result = session.query(models.Token).filter_by(id=id).first()
+ return result
+
+
+def delete(id, session=None):
+ if not session:
+ session = get_session()
+ with session.begin():
+ token_ref = get(id, session)
+ session.delete(token_ref)
+
+
+def get_for_user(user_id, session=None):
+ if not session:
+ session = get_session()
+ result = session.query(models.Token).filter_by(
+ user_id=user_id, tenant_id=None).order_by("expires desc").first()
+ return result
+
+
+def get_for_user_by_tenant(user_id, tenant_id, session=None):
+ if not session:
+ session = get_session()
+ result = session.query(models.Token).filter_by(
+ user_id=user_id, tenant_id=tenant_id).order_by("expires desc").first()
+ return result
+
+
+def get_all(session=None):
+ if not session:
+ session = get_session()
+ return session.query(models.Token).all()
diff --git a/keystone/db/sqlalchemy/api/user.py b/keystone/backends/sqlalchemy/api/user.py
index d3d31387..5550a106 100755
--- a/keystone/db/sqlalchemy/api/user.py
+++ b/keystone/backends/sqlalchemy/api/user.py
@@ -16,7 +16,7 @@
# under the License.
import keystone.utils as utils
-from keystone.db.sqlalchemy import get_session, models, aliased, joinedload
+from keystone.backends.sqlalchemy import get_session, models, aliased, joinedload
def get_all(session=None):
if not session:
diff --git a/keystone/db/sqlalchemy/models.py b/keystone/backends/sqlalchemy/models.py
index 427e2507..16bc7a75 100644..100755
--- a/keystone/db/sqlalchemy/models.py
+++ b/keystone/backends/sqlalchemy/models.py
@@ -20,18 +20,18 @@ from sqlalchemy import Column, String, Integer, ForeignKey, \
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, object_mapper
-
Base = declarative_base()
class KeystoneBase(object):
"""Base class for Keystone Models."""
+ __api__ = None
def save(self, session=None):
"""Save this object."""
if not session:
- from keystone.db.sqlalchemy import get_session
+ from keystone.backends.sqlalchemy import get_session
session = get_session()
session.add(self)
try:
@@ -79,7 +79,7 @@ class KeystoneBase(object):
# Define associations first
class UserGroupAssociation(Base, KeystoneBase):
__tablename__ = 'user_group_association'
-
+ __api__ ='tenant_group'
user_id = Column(String(255), ForeignKey('users.id'), primary_key=True)
group_id = Column(String(255), ForeignKey('groups.id'), primary_key=True)
@@ -105,14 +105,14 @@ class Endpoints(Base, KeystoneBase):
# Define objects
class Role(Base, KeystoneBase):
__tablename__ = 'roles'
-
+ __api__ ='role'
id = Column(String(255), primary_key=True, unique=True)
desc = Column(String(255))
class Tenant(Base, KeystoneBase):
__tablename__ = 'tenants'
-
+ __api__ ='tenant'
id = Column(String(255), primary_key=True, unique=True)
desc = Column(String(255))
enabled = Column(Integer)
@@ -123,7 +123,7 @@ class Tenant(Base, KeystoneBase):
class User(Base, KeystoneBase):
__tablename__ = 'users'
-
+ __api__ ='user'
id = Column(String(255), primary_key=True, unique=True)
password = Column(String(255))
email = Column(String(255))
@@ -145,24 +145,22 @@ class Credentials(Base, KeystoneBase):
class Group(Base, KeystoneBase):
__tablename__ = 'groups'
-
+ __api__ ='group'
id = Column(String(255), primary_key=True, unique=True)
desc = Column(String(255))
tenant_id = Column(String(255), ForeignKey('tenants.id'))
-
class Token(Base, KeystoneBase):
__tablename__ = 'token'
-
+ __api__ ='token'
id = Column(String(255), primary_key=True, unique=True)
user_id = Column(String(255))
tenant_id = Column(String(255))
expires = Column(DateTime)
-
class EndpointTemplates(Base, KeystoneBase):
__tablename__ = 'endpoint_templates'
-
+ __api__ ='endpoint_template'
id = Column(Integer, primary_key=True)
region = Column(String(255))
service = Column(String(255))
diff --git a/keystone/common/config.py b/keystone/common/config.py
index 592e6cdd..e38c60a9 100755
--- a/keystone/common/config.py
+++ b/keystone/common/config.py
@@ -25,6 +25,7 @@ import optparse
import os
from paste import deploy
import sys
+import ConfigParser
DEFAULT_LOG_FORMAT = "%(asctime)s %(levelname)8s [%(name)s] %(message)s"
DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
@@ -294,11 +295,36 @@ def load_paste_config(app_name, options, args):
"Cannot load application %s" % app_name)
try:
conf = deploy.appconfig("config:%s" % conf_file, name=app_name)
+ conf.global_conf.update(get_non_paste_configs(conf_file))
return conf_file, conf
except Exception, e:
raise RuntimeError("Error trying to load config %s: %s"
% (conf_file, e))
+def get_non_paste_configs(conf_file):
+ load_config_files(conf_file)
+ complete_conf = load_config_files(conf_file)
+ #Add Non Paste global sections.Need to find a better way.
+ global_conf = {}
+ if complete_conf != None:
+ for section in complete_conf.sections():
+ if not (section.startswith('filter:') or section.startswith('app:') or section.startswith('pipeline:')):
+ section_items = complete_conf.items(section)
+ section_items_dict = {}
+ for section_item in section_items:
+ section_items_dict[section_item[0]] = section_item[1]
+ global_conf[section] = section_items_dict
+ return global_conf
+
+
+def load_config_files(config_files):
+ '''Load the config files.'''
+ config = ConfigParser.ConfigParser()
+ if config_files is not None:
+ config.read(config_files)
+ return config
+
+
def load_paste_app(app_name, options, args):
"""
@@ -348,7 +374,7 @@ def load_paste_app(app_name, options, args):
for key, value in sorted(items.items()):
logger.info("%(key)-20s %(value)s" % locals())
logger.info("*" * 50)
- app = deploy.loadapp("config:%s" % conf_file, name=app_name)
+ app = deploy.loadapp("config:%s" % conf_file, name=app_name, global_conf= conf.global_conf)
except (LookupError, ImportError), e:
raise RuntimeError("Unable to load %(app_name)s from "
"configuration file %(conf_file)s."
diff --git a/keystone/db/__init__.py b/keystone/db/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/keystone/db/__init__.py
+++ /dev/null
diff --git a/keystone/logic/service.py b/keystone/logic/service.py
index be99a13a..59fc30d0 100755
--- a/keystone/logic/service.py
+++ b/keystone/logic/service.py
@@ -19,14 +19,15 @@ import uuid
import keystone.logic.types.auth as auth
import keystone.logic.types.atom as atom
-import keystone.db.sqlalchemy.api as db_api
-import keystone.db.sqlalchemy.models as db_models
+import keystone.backends.api as db_api
+import keystone.backends.sqlalchemy.models as db_models
import keystone.logic.types.fault as fault
import keystone.logic.types.tenant as tenants
import keystone.logic.types.role as roles
import keystone.logic.types.user as get_users
import keystone.logic.types.endpoint as endpoints
import keystone.utils as utils
+#TODO(Yogi) Remove references to specific backend model and move them to generic models.
class IdentityService(object):
@@ -35,7 +36,6 @@ class IdentityService(object):
#
# Token Operations
#
-
def authenticate(self, credentials):
# Check credentials
if not isinstance(credentials, auth.PasswordCredentials):
diff --git a/keystone/server.py b/keystone/server.py
index acf595ea..4200342d 100755
--- a/keystone/server.py
+++ b/keystone/server.py
@@ -49,7 +49,8 @@ if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'keystone', '__init__.py')):
from keystone.common import wsgi
-import keystone.db.sqlalchemy as db
+import keystone.backends as db
+import keystone.backends.alterdb
import keystone.logic.service as serv
import keystone.logic.types.tenant as tenants
import keystone.logic.types.role as roles
@@ -64,6 +65,7 @@ logger = logging.getLogger('keystone.server')
VERSION_STATUS = "ALPHA"
VERSION_DATE = "2011-04-23T00:00:00Z"
+
service = serv.IdentityService()
@@ -530,14 +532,12 @@ def get_url(req):
class KeystoneAPI(wsgi.Router):
- """WSGI entry point for public Keystone API requests."""
+ """WSGI entry point for public Keystone API requests."""
def __init__(self, options):
self.options = options
mapper = routes.Mapper()
-
- db.configure_db(options)
-
+ db.configure_backends(options)
# Token Operations
auth_controller = AuthController(options)
mapper.connect("/v2.0/tokens", controller=auth_controller,
@@ -587,7 +587,7 @@ class KeystoneAdminAPI(wsgi.Router):
self.options = options
mapper = routes.Mapper()
- db.configure_db(options)
+ db.configure_backends(options)
# Token Operations
auth_controller = AuthController(options)
mapper.connect("/v2.0/tokens", controller=auth_controller,
diff --git a/keystone/test/unit/base.py b/keystone/test/unit/base.py
index 631e6cd3..c2dff063 100644
--- a/keystone/test/unit/base.py
+++ b/keystone/test/unit/base.py
@@ -27,8 +27,8 @@ from lxml import etree, objectify
import webob
from keystone import server
-import keystone.db.sqlalchemy as db
-import keystone.db.sqlalchemy.api as db_api
+import keystone.backends.sqlalchemy as db
+import keystone.backends.sqlalchemy.api as db_api
logger = logging.getLogger('test.unit.base')
diff --git a/keystone/utils.py b/keystone/utils.py
index eb90b326..ddd63760 100644..100755
--- a/keystone/utils.py
+++ b/keystone/utils.py
@@ -165,6 +165,20 @@ def send_legacy_result(code, headers):
#Currently using sha1 to hash.Need to figure if there is an openstack standard.Not using salt val as of now.
def get_hashed_password(password):
if password != None and len(password) > 0:
- return hashlib.sha1(password).hexdigest()
+ return password
+ #return hashlib.sha1(password).hexdigest()
else:
- return None \ No newline at end of file
+ return None
+
+def import_module(module_name, class_name=None):
+ '''Import a class given a full module.class name or seperate
+ module and options. If no class_name is given, it is assumed to
+ be the last part of the module_name string.'''
+ if class_name is None:
+ module_name, _separator, class_name = module_name.rpartition('.')
+ try:
+ __import__(module_name)
+ return getattr(sys.modules[module_name], class_name)
+ except (ImportError, ValueError, AttributeError), exception:
+ raise ImportError(_('Class %s.%s cannot be found (%s)') %
+ (module_name, class_name, exception)) \ No newline at end of file
diff --git a/setup.py b/setup.py
index f936b418..f936b418 100644..100755
--- a/setup.py
+++ b/setup.py