diff options
| author | Ziad Sawalha <ziad.sawalha@rackspace.com> | 2011-06-29 02:15:02 -0700 |
|---|---|---|
| committer | Ziad Sawalha <ziad.sawalha@rackspace.com> | 2011-06-29 02:15:02 -0700 |
| commit | 5661cf0cbd0ac6abbbdea78d71ef0a9beea0db44 (patch) | |
| tree | cd99357cf4c16d427b0614494b6a47d3cf085231 | |
| parent | bb7303d96e65226ad428e08db9463231bcb4274c (diff) | |
| parent | e3f07c770720532ff48210797073fa34420e69ab (diff) | |
| download | keystone-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-- | .gitignore | 1 | ||||
| -rwxr-xr-x | bin/keystone | 1 | ||||
| -rwxr-xr-x | bin/keystone-manage | 10 | ||||
| -rwxr-xr-x | etc/keystone.conf | 34 | ||||
| -rw-r--r-- | keystone/backends/__init__.py | 30 | ||||
| -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__.py | 1 | ||||
| -rwxr-xr-x[-rw-r--r--] | keystone/backends/alterdb/api/token.py (renamed from keystone/db/sqlalchemy/api/token.py) | 2 | ||||
| -rwxr-xr-x | keystone/backends/alterdb/models.py | 85 | ||||
| -rwxr-xr-x | keystone/backends/api.py | 47 | ||||
| -rw-r--r-- | keystone/backends/models.py | 28 | ||||
| -rwxr-xr-x | keystone/backends/sqlalchemy/__init__.py | 95 | ||||
| -rwxr-xr-x[-rw-r--r--] | keystone/backends/sqlalchemy/api/__init__.py (renamed from keystone/db/sqlalchemy/api/__init__.py) | 0 | ||||
| -rwxr-xr-x | keystone/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-x | keystone/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-x | keystone/backends/sqlalchemy/api/token.py | 61 | ||||
| -rwxr-xr-x | keystone/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-x | keystone/common/config.py | 28 | ||||
| -rw-r--r-- | keystone/db/__init__.py | 0 | ||||
| -rwxr-xr-x | keystone/logic/service.py | 6 | ||||
| -rwxr-xr-x | keystone/server.py | 12 | ||||
| -rw-r--r-- | keystone/test/unit/base.py | 4 | ||||
| -rwxr-xr-x[-rw-r--r--] | keystone/utils.py | 18 | ||||
| -rwxr-xr-x[-rw-r--r--] | setup.py | 0 |
28 files changed, 469 insertions, 56 deletions
@@ -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 |
