OpenStack版本比较之Keystone
目的
本文主要比较OpenStack中Essex与Folsom版本的Keystone在依赖包、数据库结构、配置方面的差异,为Keystone从Essex向Folsom升级做些前期准备工作。这些比较大部分是在源代码库上通过git命令进行的,首先要clone一个keystone的本地库,命令如下:
- git clone git://github.com/openstack/keystone.git
- cd keystone
git clone git://github.com/openstack/keystone.git
cd keystone
依赖包的差异
tools/pip-requires文件包含keystone的依赖库文件信息,通过以下命令比较发现Folsom版只是添加了一个依赖包iso8601版本须>=0.1.4,该包同时也是nova E版和F版的依赖包,因此依赖包的差异可以忽略,升级Keystone可以不安装其它依赖包。
- [ugyn@localhost keystone]$ git diff 2012.1:tools/pip-requires 2012.2:tools/pip-requires
- diff --git a/2012.1:tools/pip-requires b/2012.2:tools/pip-requires
- index 0e13534..ec5562d 100644
- --- a/2012.1:tools/pip-requires
- +++ b/2012.2:tools/pip-requires
- @@ -1,4 +1,4 @@
- -# keystonelight dependencies
- +# keystone dependencies
- pam==0.1.4
- WebOb==1.0.8
- eventlet
- @@ -10,3 +10,4 @@ sqlalchemy
- sqlalchemy-migrate
- passlib
- lxml
- +iso8601>=0.1.4
[ugyn@localhost keystone]$ git diff 2012.1:tools/pip-requires 2012.2:tools/pip-requires
diff --git a/2012.1:tools/pip-requires b/2012.2:tools/pip-requires
index 0e13534..ec5562d 100644
--- a/2012.1:tools/pip-requires
+++ b/2012.2:tools/pip-requires
@@ -1,4 +1,4 @@
-# keystonelight dependencies
+# keystone dependenciespam==0.1.4WebOb==1.0.8eventlet
@@ -10,3 +10,4 @@ sqlalchemysqlalchemy-migratepassliblxml
+iso8601>=0.1.4
数据库结构的差异
与数据库相关的源文件
要比较数据库结构的差异首先要找到keystone中与数据库相关的源文件,可通过以下命令实现:
- [ugyn@localhost keystone]$ git grep "sql.ModelBase"
- keystone/catalog/backends/sql.py:class Service(sql.ModelBase, sql.DictBase):
- keystone/catalog/backends/sql.py:class Endpoint(sql.ModelBase, sql.DictBase):
- keystone/common/sql/migrate_repo/versions/001_add_initial_tables.py: sql.ModelBase.metadata.create_all(migrate_engine)
- keystone/contrib/ec2/backends/sql.py:class Ec2Credential(sql.ModelBase, sql.DictBase):
- keystone/identity/backends/sql.py:class User(sql.ModelBase, sql.DictBase):
- keystone/identity/backends/sql.py:class Tenant(sql.ModelBase, sql.DictBase):
- keystone/identity/backends/sql.py:class Role(sql.ModelBase, sql.DictBase):
- keystone/identity/backends/sql.py:class Metadata(sql.ModelBase, sql.DictBase):
- keystone/identity/backends/sql.py:class UserTenantMembership(sql.ModelBase, sql.DictBase):
- keystone/token/backends/sql.py:class TokenModel(sql.ModelBase, sql.DictBase):
- tests/test_backend_sql.py: sql.ModelBase.metadata.bind = engine
- tests/test_backend_sql.py: sql.ModelBase.metadata.create_all(engine)
[ugyn@localhost keystone]$ git grep "sql.ModelBase"
keystone/catalog/backends/sql.py:class Service(sql.ModelBase, sql.DictBase):
keystone/catalog/backends/sql.py:class Endpoint(sql.ModelBase, sql.DictBase):
keystone/common/sql/migrate_repo/versions/001_add_initial_tables.py: sql.ModelBase.metadata.create_all(migrate_engine)
keystone/contrib/ec2/backends/sql.py:class Ec2Credential(sql.ModelBase, sql.DictBase):
keystone/identity/backends/sql.py:class User(sql.ModelBase, sql.DictBase):
keystone/identity/backends/sql.py:class Tenant(sql.ModelBase, sql.DictBase):
keystone/identity/backends/sql.py:class Role(sql.ModelBase, sql.DictBase):
keystone/identity/backends/sql.py:class Metadata(sql.ModelBase, sql.DictBase):
keystone/identity/backends/sql.py:class UserTenantMembership(sql.ModelBase, sql.DictBase):
keystone/token/backends/sql.py:class TokenModel(sql.ModelBase, sql.DictBase):
tests/test_backend_sql.py: sql.ModelBase.metadata.bind = engine
tests/test_backend_sql.py: sql.ModelBase.metadata.create_all(engine)
service及endpoint表比较
这两个表的定义在源文件keystone/catalog/backends/sql.py中,分别为Service及Endpoint类,从下面的结果可以看出这两个类完全没变,只是在类Catalog中对它们的操作做了些修改,因此在数据库方面这两个表应该是没在差异的。
- [ugyn@localhost keystone]$ git diff 2012.1:keystone/catalog/backends/sql.py 2012.2:keystone/catalog/backends/sql.py > tables_diff
- [ugyn@localhost keystone]$ cat tables_diff
- diff --git a/2012.1:keystone/catalog/backends/sql.py b/2012.2:keystone/catalog/backends/sql.py
- index 3c553e0..bd0f687 100644
- --- a/2012.1:keystone/catalog/backends/sql.py
- +++ b/2012.2:keystone/catalog/backends/sql.py
- @@ -15,14 +15,11 @@
- # License for the specific language governing permissions and limitations
- # under the License.
- -import sqlalchemy.exc
- -import webob.exc
- -
- from keystone import catalog
- -from keystone import config
- -from keystone import exception
- from keystone.common import sql
- from keystone.common.sql import migration
- +from keystone import config
- +from keystone import exception
- CONF = config.CONF
- @@ -96,11 +93,9 @@ class Catalog(sql.Base, catalog.Driver):
- def delete_service(self, service_id):
- session = self.get_session()
- - service_ref = session.query(Service).filter_by(id=service_id).first()
- - if not service_ref:
- - raise exception.ServiceNotFound(service_id=service_id)
- with session.begin():
- - session.delete(service_ref)
- + if not session.query(Service).filter_by(id=service_id).delete():
- + raise exception.ServiceNotFound(service_id=service_id)
- session.flush()
- def create_service(self, service_id, service_ref):
- @@ -114,6 +109,7 @@ class Catalog(sql.Base, catalog.Driver):
- # Endpoints
- def create_endpoint(self, endpoint_id, endpoint_ref):
- session = self.get_session()
- + self.get_service(endpoint_ref['service_id'])
- new_endpoint = Endpoint.from_dict(endpoint_ref)
- with session.begin():
- session.add(new_endpoint)
- @@ -122,18 +118,17 @@ class Catalog(sql.Base, catalog.Driver):
- def delete_endpoint(self, endpoint_id):
- session = self.get_session()
- - endpoint_ref = session.query(Endpoint)
- - endpoint_ref = endpoint_ref.filter_by(id=endpoint_id).first()
- - if not endpoint_ref:
- - raise exception.EndpointNotFound(endpoint_id=endpoint_id)
- with session.begin():
- - session.delete(endpoint_ref)
- + if not session.query(Endpoint).filter_by(id=endpoint_id).delete():
- + raise exception.EndpointNotFound(endpoint_id=endpoint_id)
- session.flush()
- def get_endpoint(self, endpoint_id):
- session = self.get_session()
- endpoint_ref = session.query(Endpoint)
- endpoint_ref = endpoint_ref.filter_by(id=endpoint_id).first()
- + if not endpoint_ref:
- + raise exception.EndpointNotFound(endpoint_id=endpoint_id)
- return endpoint_ref.to_dict()
- def list_endpoints(self):
- @@ -163,6 +158,7 @@ class Catalog(sql.Base, catalog.Driver):
- internal_url = ep['internalurl'].replace('$(', '%(')
- public_url = ep['publicurl'].replace('$(', '%(')
- admin_url = ep['adminurl'].replace('$(', '%(')
- + catalog[region][srv_type]['id'] = ep['id']
- catalog[region][srv_type]['name'] = srv_name
- catalog[region][srv_type]['publicURL'] = public_url % d
- catalog[region][srv_type]['adminURL'] = admin_url % d
[ugyn@localhost keystone]$ git diff 2012.1:keystone/catalog/backends/sql.py 2012.2:keystone/catalog/backends/sql.py > tables_diff
[ugyn@localhost keystone]$ cat tables_diff
diff --git a/2012.1:keystone/catalog/backends/sql.py b/2012.2:keystone/catalog/backends/sql.py
index 3c553e0..bd0f687 100644
--- a/2012.1:keystone/catalog/backends/sql.py
+++ b/2012.2:keystone/catalog/backends/sql.py
@@ -15,14 +15,11 @@# License for the specific language governing permissions and limitations# under the License.-import sqlalchemy.exc
-import webob.exc
-from keystone import catalog
-from keystone import config
-from keystone import exceptionfrom keystone.common import sqlfrom keystone.common.sql import migration
+from keystone import config
+from keystone import exceptionCONF = config.CONF
@@ -96,11 +93,9 @@ class Catalog(sql.Base, catalog.Driver):def delete_service(self, service_id):session = self.get_session()
- service_ref = session.query(Service).filter_by(id=service_id).first()
- if not service_ref:
- raise exception.ServiceNotFound(service_id=service_id)with session.begin():
- session.delete(service_ref)
+ if not session.query(Service).filter_by(id=service_id).delete():
+ raise exception.ServiceNotFound(service_id=service_id)session.flush()def create_service(self, service_id, service_ref):
@@ -114,6 +109,7 @@ class Catalog(sql.Base, catalog.Driver):# Endpointsdef create_endpoint(self, endpoint_id, endpoint_ref):session = self.get_session()
+ self.get_service(endpoint_ref['service_id'])new_endpoint = Endpoint.from_dict(endpoint_ref)with session.begin():session.add(new_endpoint)
@@ -122,18 +118,17 @@ class Catalog(sql.Base, catalog.Driver):def delete_endpoint(self, endpoint_id):session = self.get_session()
- endpoint_ref = session.query(Endpoint)
- endpoint_ref = endpoint_ref.filter_by(id=endpoint_id).first()
- if not endpoint_ref:
- raise exception.EndpointNotFound(endpoint_id=endpoint_id)with session.begin():
- session.delete(endpoint_ref)
+ if not session.query(Endpoint).filter_by(id=endpoint_id).delete():
+ raise exception.EndpointNotFound(endpoint_id=endpoint_id)session.flush()def get_endpoint(self, endpoint_id):session = self.get_session()endpoint_ref = session.query(Endpoint)endpoint_ref = endpoint_ref.filter_by(id=endpoint_id).first()
+ if not endpoint_ref:
+ raise exception.EndpointNotFound(endpoint_id=endpoint_id)return endpoint_ref.to_dict()def list_endpoints(self):
@@ -163,6 +158,7 @@ class Catalog(sql.Base, catalog.Driver):internal_url = ep['internalurl'].replace('$(', '%(')public_url = ep['publicurl'].replace('$(', '%(')admin_url = ep['adminurl'].replace('$(', '%(')
+ catalog[region][srv_type]['id'] = ep['id']catalog[region][srv_type]['name'] = srv_namecatalog[region][srv_type]['publicURL'] = public_url % dcatalog[region][srv_type]['adminURL'] = admin_url % d
user、tenant、role、metadata、user_tenant_membership表的比较
这几个表的定义均在源文件keystone/identity/backends/sql.py的相关类中。从下面的输出来看,在F版中的主要变化是给表user、tenant、role的name列均添加了not null属性,另外在Identity类中对这些表的操作做了不少修改,但应该不会导致相关表的结构变化。
- [ugyn@localhost keystone]$ git diff 2012.1:keystone/identity/backends/sql.py 2012.2:keystone/identity/backends/sql.py > tables_diff
- [ugyn@localhost keystone]$ cat tables_diff
- diff --git a/2012.1:keystone/identity/backends/sql.py b/2012.2:keystone/identity/backends/sql.py
- index e4281a8..a3c8d1f 100644
- --- a/2012.1:keystone/identity/backends/sql.py
- +++ b/2012.2:keystone/identity/backends/sql.py
- @@ -17,11 +17,12 @@
- import copy
- import functools
- -from keystone import identity
- -from keystone import exception
- +from keystone import clean
- from keystone.common import sql
- -from keystone.common import utils
- from keystone.common.sql import migration
- +from keystone.common import utils
- +from keystone import exception
- +from keystone import identity
- def _filter_user(user_ref):
- @@ -45,7 +46,7 @@ def handle_conflicts(type='object'):
- try:
- return method(*args, **kwargs)
- except sql.IntegrityError as e:
- - raise exception.Conflict(type=type, details=str(e))
- + raise exception.Conflict(type=type, details=e.message)
- return wrapper
- return decorator
- @@ -53,7 +54,7 @@ def handle_conflicts(type='object'):
- class User(sql.ModelBase, sql.DictBase):
- __tablename__ = 'user'
- id = sql.Column(sql.String(64), primary_key=True)
- - name = sql.Column(sql.String(64), unique=True)
- + name = sql.Column(sql.String(64), unique=True, nullable=False)
- #password = sql.Column(sql.String(64))
- extra = sql.Column(sql.JsonBlob())
- @@ -79,7 +80,7 @@ class User(sql.ModelBase, sql.DictBase):
- class Tenant(sql.ModelBase, sql.DictBase):
- __tablename__ = 'tenant'
- id = sql.Column(sql.String(64), primary_key=True)
- - name = sql.Column(sql.String(64), unique=True)
- + name = sql.Column(sql.String(64), unique=True, nullable=False)
- extra = sql.Column(sql.JsonBlob())
- @classmethod
- @@ -104,7 +105,7 @@ class Tenant(sql.ModelBase, sql.DictBase):
- class Role(sql.ModelBase, sql.DictBase):
- __tablename__ = 'role'
- id = sql.Column(sql.String(64), primary_key=True)
- - name = sql.Column(sql.String(64), unique=True)
- + name = sql.Column(sql.String(64), unique=True, nullable=False)
- class Metadata(sql.ModelBase, sql.DictBase):
- @@ -134,6 +135,20 @@ class Identity(sql.Base, identity.Driver):
- def db_sync(self):
- migration.db_sync()
- + def _check_password(self, password, user_ref):
- + """Check the specified password against the data store.
- +
- + This is modeled on ldap/core.py. The idea is to make it easier to
- + subclass Identity so that you can still use it to store all the data,
- + but use some other means to check the password.
- + Note that we'll pass in the entire user_ref in case the subclass
- + needs things like user_ref.get('name')
- + For further justification, please see the follow up suggestion at
- + https://blueprints.launchpad.net/keystone/+spec/sql-identiy-pam
- +
- + """
- + return utils.check_password(password, user_ref.get('password'))
- +
- # Identity interface
- def authenticate(self, user_id=None, tenant_id=None, password=None):
- """Authenticate based on a user, tenant and password.
- @@ -142,56 +157,69 @@ class Identity(sql.Base, identity.Driver):
- in the list of tenants on the user.
- """
- - user_ref = self._get_user(user_id)
- - if (not user_ref
- - or not utils.check_password(password, user_ref.get('password'))):
- + user_ref = None
- + tenant_ref = None
- + metadata_ref = {}
- +
- + try:
- + user_ref = self._get_user(user_id)
- + except exception.UserNotFound:
- raise AssertionError('Invalid user / password')
- - tenants = self.get_tenants_for_user(user_id)
- - if tenant_id and tenant_id not in tenants:
- - raise AssertionError('Invalid tenant')
- + if not utils.check_password(password, user_ref.get('password')):
- + raise AssertionError('Invalid user / password')
- +
- + if tenant_id is not None:
- + if tenant_id not in self.get_tenants_for_user(user_id):
- + raise AssertionError('Invalid tenant')
- +
- + try:
- + tenant_ref = self.get_tenant(tenant_id)
- + metadata_ref = self.get_metadata(user_id, tenant_id)
- + except exception.TenantNotFound:
- + tenant_ref = None
- + metadata_ref = {}
- + except exception.MetadataNotFound:
- + metadata_ref = {}
- - tenant_ref = self.get_tenant(tenant_id)
- - if tenant_ref:
- - metadata_ref = self.get_metadata(user_id, tenant_id)
- - else:
- - metadata_ref = {}
- return (_filter_user(user_ref), tenant_ref, metadata_ref)
- def get_tenant(self, tenant_id):
- session = self.get_session()
- tenant_ref = session.query(Tenant).filter_by(id=tenant_id).first()
- - if not tenant_ref:
- - return
- + if tenant_ref is None:
- + raise exception.TenantNotFound(tenant_id=tenant_id)
- return tenant_ref.to_dict()
- def get_tenant_by_name(self, tenant_name):
- session = self.get_session()
- tenant_ref = session.query(Tenant).filter_by(name=tenant_name).first()
- if not tenant_ref:
- - return
- + raise exception.TenantNotFound(tenant_id=tenant_name)
- return tenant_ref.to_dict()
- def get_tenant_users(self, tenant_id):
- session = self.get_session()
- + self.get_tenant(tenant_id)
- user_refs = session.query(User)\
- - .join(UserTenantMembership)\
- - .filter(UserTenantMembership.tenant_id == tenant_id)\
- - .all()
- + .join(UserTenantMembership)\
- + .filter(UserTenantMembership.tenant_id ==
- + tenant_id)\
- + .all()
- return [_filter_user(user_ref.to_dict()) for user_ref in user_refs]
- def _get_user(self, user_id):
- session = self.get_session()
- user_ref = session.query(User).filter_by(id=user_id).first()
- if not user_ref:
- - return
- + raise exception.UserNotFound(user_id=user_id)
- return user_ref.to_dict()
- def _get_user_by_name(self, user_name):
- session = self.get_session()
- user_ref = session.query(User).filter_by(name=user_name).first()
- if not user_ref:
- - return
- + raise exception.UserNotFound(user_id=user_name)
- return user_ref.to_dict()
- def get_user(self, user_id):
- @@ -206,11 +234,16 @@ class Identity(sql.Base, identity.Driver):
- .filter_by(user_id=user_id)\
- .filter_by(tenant_id=tenant_id)\
- .first()
- - return getattr(metadata_ref, 'data', {})
- + if metadata_ref is None:
- + raise exception.MetadataNotFound()
- + return metadata_ref.data
- def get_role(self, role_id):
- session = self.get_session()
- - return session.query(Role).filter_by(id=role_id).first()
- + role_ref = session.query(Role).filter_by(id=role_id).first()
- + if role_ref is None:
- + raise exception.RoleNotFound(role_id=role_id)
- + return role_ref
- def list_users(self):
- session = self.get_session()
- @@ -225,6 +258,8 @@ class Identity(sql.Base, identity.Driver):
- # These should probably be part of the high-level API
- def add_user_to_tenant(self, tenant_id, user_id):
- session = self.get_session()
- + self.get_tenant(tenant_id)
- + self.get_user(user_id)
- q = session.query(UserTenantMembership)\
- .filter_by(user_id=user_id)\
- .filter_by(tenant_id=tenant_id)
- @@ -239,10 +274,14 @@ class Identity(sql.Base, identity.Driver):
- def remove_user_from_tenant(self, tenant_id, user_id):
- session = self.get_session()
- + self.get_tenant(tenant_id)
- + self.get_user(user_id)
- membership_ref = session.query(UserTenantMembership)\
- .filter_by(user_id=user_id)\
- .filter_by(tenant_id=tenant_id)\
- .first()
- + if membership_ref is None:
- + raise exception.NotFound('User not found in tenant')
- with session.begin():
- session.delete(membership_ref)
- session.flush()
- @@ -254,37 +293,50 @@ class Identity(sql.Base, identity.Driver):
- def get_tenants_for_user(self, user_id):
- session = self.get_session()
- + self.get_user(user_id)
- membership_refs = session.query(UserTenantMembership)\
- - .filter_by(user_id=user_id)\
- - .all()
- + .filter_by(user_id=user_id)\
- + .all()
- return [x.tenant_id for x in membership_refs]
- def get_roles_for_user_and_tenant(self, user_id, tenant_id):
- - metadata_ref = self.get_metadata(user_id, tenant_id)
- - if not metadata_ref:
- + self.get_user(user_id)
- + self.get_tenant(tenant_id)
- + try:
- + metadata_ref = self.get_metadata(user_id, tenant_id)
- + except exception.MetadataNotFound:
- metadata_ref = {}
- return metadata_ref.get('roles', [])
- def add_role_to_user_and_tenant(self, user_id, tenant_id, role_id):
- - metadata_ref = self.get_metadata(user_id, tenant_id)
- - is_new = False
- - if not metadata_ref:
- - is_new = True
- + self.get_user(user_id)
- + self.get_tenant(tenant_id)
- + self.get_role(role_id)
- + try:
- + metadata_ref = self.get_metadata(user_id, tenant_id)
- + is_new = False
- + except exception.MetadataNotFound:
- metadata_ref = {}
- + is_new = True
- roles = set(metadata_ref.get('roles', []))
- + if role_id in roles:
- + msg = ('User %s already has role %s in tenant %s'
- + % (user_id, role_id, tenant_id))
- + raise exception.Conflict(type='role grant', details=msg)
- roles.add(role_id)
- metadata_ref['roles'] = list(roles)
- - if not is_new:
- - self.update_metadata(user_id, tenant_id, metadata_ref)
- - else:
- + if is_new:
- self.create_metadata(user_id, tenant_id, metadata_ref)
- + else:
- + self.update_metadata(user_id, tenant_id, metadata_ref)
- def remove_role_from_user_and_tenant(self, user_id, tenant_id, role_id):
- - metadata_ref = self.get_metadata(user_id, tenant_id)
- - is_new = False
- - if not metadata_ref:
- - is_new = True
- + try:
- + metadata_ref = self.get_metadata(user_id, tenant_id)
- + is_new = False
- + except exception.MetadataNotFound:
- metadata_ref = {}
- + is_new = True
- roles = set(metadata_ref.get('roles', []))
- if role_id not in roles:
- msg = 'Cannot remove role that has not been granted, %s' % role_id
- @@ -292,14 +344,15 @@ class Identity(sql.Base, identity.Driver):
- roles.remove(role_id)
- metadata_ref['roles'] = list(roles)
- - if not is_new:
- - self.update_metadata(user_id, tenant_id, metadata_ref)
- - else:
- + if is_new:
- self.create_metadata(user_id, tenant_id, metadata_ref)
- + else:
- + self.update_metadata(user_id, tenant_id, metadata_ref)
- # CRUD
- @handle_conflicts(type='user')
- def create_user(self, user_id, user):
- + user['name'] = clean.user_name(user['name'])
- user = _ensure_hashed_password(user)
- session = self.get_session()
- with session.begin():
- @@ -310,9 +363,15 @@ class Identity(sql.Base, identity.Driver):
- @handle_conflicts(type='user')
- def update_user(self, user_id, user):
- + if 'name' in user:
- + user['name'] = clean.user_name(user['name'])
- session = self.get_session()
- + if 'id' in user and user_id != user['id']:
- + raise exception.ValidationError('Cannot change user ID')
- with session.begin():
- user_ref = session.query(User).filter_by(id=user_id).first()
- + if user_ref is None:
- + raise exception.UserNotFound(user_id=user_id)
- old_user_dict = user_ref.to_dict()
- user = _ensure_hashed_password(user)
- for k in user:
- @@ -326,21 +385,17 @@ class Identity(sql.Base, identity.Driver):
- def delete_user(self, user_id):
- session = self.get_session()
- - user_ref = session.query(User).filter_by(id=user_id).first()
- - membership_refs = session.query(UserTenantMembership)\
- - .filter_by(user_id=user_id)\
- - .all()
- -
- with session.begin():
- - if membership_refs:
- - for membership_ref in membership_refs:
- - session.delete(membership_ref)
- -
- - session.delete(user_ref)
- - session.flush()
- + session.query(UserTenantMembership)\
- + .filter_by(user_id=user_id).delete(False)
- + session.query(Metadata)\
- + .filter_by(user_id=user_id).delete(False)
- + if not session.query(User).filter_by(id=user_id).delete(False):
- + raise exception.UserNotFound(user_id=user_id)
- @handle_conflicts(type='tenant')
- def create_tenant(self, tenant_id, tenant):
- + tenant['name'] = clean.tenant_name(tenant['name'])
- session = self.get_session()
- with session.begin():
- tenant_ref = Tenant.from_dict(tenant)
- @@ -350,9 +405,13 @@ class Identity(sql.Base, identity.Driver):
- @handle_conflicts(type='tenant')
- def update_tenant(self, tenant_id, tenant):
- + if 'name' in tenant:
- + tenant['name'] = clean.tenant_name(tenant['name'])
- session = self.get_session()
- with session.begin():
- tenant_ref = session.query(Tenant).filter_by(id=tenant_id).first()
- + if tenant_ref is None:
- + raise exception.TenantNotFound(tenant_id=tenant_id)
- old_tenant_dict = tenant_ref.to_dict()
- for k in tenant:
- old_tenant_dict[k] = tenant[k]
- @@ -365,10 +424,13 @@ class Identity(sql.Base, identity.Driver):
- def delete_tenant(self, tenant_id):
- session = self.get_session()
- - tenant_ref = session.query(Tenant).filter_by(id=tenant_id).first()
- with session.begin():
- - session.delete(tenant_ref)
- - session.flush()
- + session.query(UserTenantMembership)\
- + .filter_by(tenant_id=tenant_id).delete(False)
- + session.query(Metadata)\
- + .filter_by(tenant_id=tenant_id).delete(False)
- + if not session.query(Tenant).filter_by(id=tenant_id).delete(False):
- + raise exception.TenantNotFound(tenant_id=tenant_id)
- @handle_conflicts(type='metadata')
- def create_metadata(self, user_id, tenant_id, metadata):
- @@ -412,6 +474,8 @@ class Identity(sql.Base, identity.Driver):
- session = self.get_session()
- with session.begin():
- role_ref = session.query(Role).filter_by(id=role_id).first()
- + if role_ref is None:
- + raise exception.RoleNotFound(role_id=role_id)
- for k in role:
- role_ref[k] = role[k]
- session.flush()
- @@ -419,6 +483,7 @@ class Identity(sql.Base, identity.Driver):
- def delete_role(self, role_id):
- session = self.get_session()
- - role_ref = session.query(Role).filter_by(id=role_id).first()
- with session.begin():
- - session.delete(role_ref)
- + if not session.query(Role).filter_by(id=role_id).delete():
- + raise exception.RoleNotFound(role_id=role_id)
- + session.flush()
[ugyn@localhost keystone]$ git diff 2012.1:keystone/identity/backends/sql.py 2012.2:keystone/identity/backends/sql.py > tables_diff
[ugyn@localhost keystone]$ cat tables_diff
diff --git a/2012.1:keystone/identity/backends/sql.py b/2012.2:keystone/identity/backends/sql.py
index e4281a8..a3c8d1f 100644
--- a/2012.1:keystone/identity/backends/sql.py
+++ b/2012.2:keystone/identity/backends/sql.py
@@ -17,11 +17,12 @@import copyimport functools-from keystone import identity
-from keystone import exception
+from keystone import cleanfrom keystone.common import sql
-from keystone.common import utilsfrom keystone.common.sql import migration
+from keystone.common import utils
+from keystone import exception
+from keystone import identitydef _filter_user(user_ref):
@@ -45,7 +46,7 @@ def handle_conflicts(type='object'):try:return method(*args, **kwargs)except sql.IntegrityError as e:
- raise exception.Conflict(type=type, details=str(e))
+ raise exception.Conflict(type=type, details=e.message)return wrapperreturn decorator@@ -53,7 +54,7 @@ def handle_conflicts(type='object'):class User(sql.ModelBase, sql.DictBase):__tablename__ = 'user'id = sql.Column(sql.String(64), primary_key=True)
- name = sql.Column(sql.String(64), unique=True)
+ name = sql.Column(sql.String(64), unique=True, nullable=False)#password = sql.Column(sql.String(64))extra = sql.Column(sql.JsonBlob())@@ -79,7 +80,7 @@ class User(sql.ModelBase, sql.DictBase):class Tenant(sql.ModelBase, sql.DictBase):__tablename__ = 'tenant'id = sql.Column(sql.String(64), primary_key=True)
- name = sql.Column(sql.String(64), unique=True)
+ name = sql.Column(sql.String(64), unique=True, nullable=False)extra = sql.Column(sql.JsonBlob())@classmethod
@@ -104,7 +105,7 @@ class Tenant(sql.ModelBase, sql.DictBase):class Role(sql.ModelBase, sql.DictBase):__tablename__ = 'role'id = sql.Column(sql.String(64), primary_key=True)
- name = sql.Column(sql.String(64), unique=True)
+ name = sql.Column(sql.String(64), unique=True, nullable=False)class Metadata(sql.ModelBase, sql.DictBase):
@@ -134,6 +135,20 @@ class Identity(sql.Base, identity.Driver):def db_sync(self):migration.db_sync()+ def _check_password(self, password, user_ref):
+ """Check the specified password against the data store.
+
+ This is modeled on ldap/core.py. The idea is to make it easier to
+ subclass Identity so that you can still use it to store all the data,
+ but use some other means to check the password.
+ Note that we'll pass in the entire user_ref in case the subclass
+ needs things like user_ref.get('name')
+ For further justification, please see the follow up suggestion at
+ https://blueprints.launchpad.net/keystone/+spec/sql-identiy-pam
+
+ """
+ return utils.check_password(password, user_ref.get('password'))
+# Identity interfacedef authenticate(self, user_id=None, tenant_id=None, password=None):"""Authenticate based on a user, tenant and password.
@@ -142,56 +157,69 @@ class Identity(sql.Base, identity.Driver):in the list of tenants on the user."""
- user_ref = self._get_user(user_id)
- if (not user_ref
- or not utils.check_password(password, user_ref.get('password'))):
+ user_ref = None
+ tenant_ref = None
+ metadata_ref = {}
+
+ try:
+ user_ref = self._get_user(user_id)
+ except exception.UserNotFound:raise AssertionError('Invalid user / password')- tenants = self.get_tenants_for_user(user_id)
- if tenant_id and tenant_id not in tenants:
- raise AssertionError('Invalid tenant')
+ if not utils.check_password(password, user_ref.get('password')):
+ raise AssertionError('Invalid user / password')
+
+ if tenant_id is not None:
+ if tenant_id not in self.get_tenants_for_user(user_id):
+ raise AssertionError('Invalid tenant')
+
+ try:
+ tenant_ref = self.get_tenant(tenant_id)
+ metadata_ref = self.get_metadata(user_id, tenant_id)
+ except exception.TenantNotFound:
+ tenant_ref = None
+ metadata_ref = {}
+ except exception.MetadataNotFound:
+ metadata_ref = {}- tenant_ref = self.get_tenant(tenant_id)
- if tenant_ref:
- metadata_ref = self.get_metadata(user_id, tenant_id)
- else:
- metadata_ref = {}return (_filter_user(user_ref), tenant_ref, metadata_ref)def get_tenant(self, tenant_id):session = self.get_session()tenant_ref = session.query(Tenant).filter_by(id=tenant_id).first()
- if not tenant_ref:
- return
+ if tenant_ref is None:
+ raise exception.TenantNotFound(tenant_id=tenant_id)return tenant_ref.to_dict()def get_tenant_by_name(self, tenant_name):session = self.get_session()tenant_ref = session.query(Tenant).filter_by(name=tenant_name).first()if not tenant_ref:
- return
+ raise exception.TenantNotFound(tenant_id=tenant_name)return tenant_ref.to_dict()def get_tenant_users(self, tenant_id):session = self.get_session()
+ self.get_tenant(tenant_id)user_refs = session.query(User)\
- .join(UserTenantMembership)\
- .filter(UserTenantMembership.tenant_id == tenant_id)\
- .all()
+ .join(UserTenantMembership)\
+ .filter(UserTenantMembership.tenant_id ==
+ tenant_id)\
+ .all()return [_filter_user(user_ref.to_dict()) for user_ref in user_refs]def _get_user(self, user_id):session = self.get_session()user_ref = session.query(User).filter_by(id=user_id).first()if not user_ref:
- return
+ raise exception.UserNotFound(user_id=user_id)return user_ref.to_dict()def _get_user_by_name(self, user_name):session = self.get_session()user_ref = session.query(User).filter_by(name=user_name).first()if not user_ref:
- return
+ raise exception.UserNotFound(user_id=user_name)return user_ref.to_dict()def get_user(self, user_id):
@@ -206,11 +234,16 @@ class Identity(sql.Base, identity.Driver):.filter_by(user_id=user_id)\.filter_by(tenant_id=tenant_id)\.first()
- return getattr(metadata_ref, 'data', {})
+ if metadata_ref is None:
+ raise exception.MetadataNotFound()
+ return metadata_ref.datadef get_role(self, role_id):session = self.get_session()
- return session.query(Role).filter_by(id=role_id).first()
+ role_ref = session.query(Role).filter_by(id=role_id).first()
+ if role_ref is None:
+ raise exception.RoleNotFound(role_id=role_id)
+ return role_refdef list_users(self):session = self.get_session()
@@ -225,6 +258,8 @@ class Identity(sql.Base, identity.Driver):# These should probably be part of the high-level APIdef add_user_to_tenant(self, tenant_id, user_id):session = self.get_session()
+ self.get_tenant(tenant_id)
+ self.get_user(user_id)q = session.query(UserTenantMembership)\.filter_by(user_id=user_id)\.filter_by(tenant_id=tenant_id)
@@ -239,10 +274,14 @@ class Identity(sql.Base, identity.Driver):def remove_user_from_tenant(self, tenant_id, user_id):session = self.get_session()+ self.get_tenant(tenant_id)
+ self.get_user(user_id)membership_ref = session.query(UserTenantMembership)\.filter_by(user_id=user_id)\.filter_by(tenant_id=tenant_id)\.first()
+ if membership_ref is None:
+ raise exception.NotFound('User not found in tenant')with session.begin():session.delete(membership_ref)session.flush()
@@ -254,37 +293,50 @@ class Identity(sql.Base, identity.Driver):def get_tenants_for_user(self, user_id):session = self.get_session()
+ self.get_user(user_id)membership_refs = session.query(UserTenantMembership)\
- .filter_by(user_id=user_id)\
- .all()
+ .filter_by(user_id=user_id)\
+ .all()return [x.tenant_id for x in membership_refs]def get_roles_for_user_and_tenant(self, user_id, tenant_id):
- metadata_ref = self.get_metadata(user_id, tenant_id)
- if not metadata_ref:
+ self.get_user(user_id)
+ self.get_tenant(tenant_id)
+ try:
+ metadata_ref = self.get_metadata(user_id, tenant_id)
+ except exception.MetadataNotFound:metadata_ref = {}return metadata_ref.get('roles', [])def add_role_to_user_and_tenant(self, user_id, tenant_id, role_id):
- metadata_ref = self.get_metadata(user_id, tenant_id)
- is_new = False
- if not metadata_ref:
- is_new = True
+ self.get_user(user_id)
+ self.get_tenant(tenant_id)
+ self.get_role(role_id)
+ try:
+ metadata_ref = self.get_metadata(user_id, tenant_id)
+ is_new = False
+ except exception.MetadataNotFound:metadata_ref = {}
+ is_new = Trueroles = set(metadata_ref.get('roles', []))
+ if role_id in roles:
+ msg = ('User %s already has role %s in tenant %s'
+ % (user_id, role_id, tenant_id))
+ raise exception.Conflict(type='role grant', details=msg)roles.add(role_id)metadata_ref['roles'] = list(roles)
- if not is_new:
- self.update_metadata(user_id, tenant_id, metadata_ref)
- else:
+ if is_new:self.create_metadata(user_id, tenant_id, metadata_ref)
+ else:
+ self.update_metadata(user_id, tenant_id, metadata_ref)def remove_role_from_user_and_tenant(self, user_id, tenant_id, role_id):
- metadata_ref = self.get_metadata(user_id, tenant_id)
- is_new = False
- if not metadata_ref:
- is_new = True
+ try:
+ metadata_ref = self.get_metadata(user_id, tenant_id)
+ is_new = False
+ except exception.MetadataNotFound:metadata_ref = {}
+ is_new = Trueroles = set(metadata_ref.get('roles', []))if role_id not in roles:msg = 'Cannot remove role that has not been granted, %s' % role_id
@@ -292,14 +344,15 @@ class Identity(sql.Base, identity.Driver):roles.remove(role_id)metadata_ref['roles'] = list(roles)
- if not is_new:
- self.update_metadata(user_id, tenant_id, metadata_ref)
- else:
+ if is_new:self.create_metadata(user_id, tenant_id, metadata_ref)
+ else:
+ self.update_metadata(user_id, tenant_id, metadata_ref)# CRUD@handle_conflicts(type='user')def create_user(self, user_id, user):
+ user['name'] = clean.user_name(user['name'])user = _ensure_hashed_password(user)session = self.get_session()with session.begin():
@@ -310,9 +363,15 @@ class Identity(sql.Base, identity.Driver):@handle_conflicts(type='user')def update_user(self, user_id, user):
+ if 'name' in user:
+ user['name'] = clean.user_name(user['name'])session = self.get_session()
+ if 'id' in user and user_id != user['id']:
+ raise exception.ValidationError('Cannot change user ID')with session.begin():user_ref = session.query(User).filter_by(id=user_id).first()
+ if user_ref is None:
+ raise exception.UserNotFound(user_id=user_id)old_user_dict = user_ref.to_dict()user = _ensure_hashed_password(user)for k in user:
@@ -326,21 +385,17 @@ class Identity(sql.Base, identity.Driver):def delete_user(self, user_id):session = self.get_session()
- user_ref = session.query(User).filter_by(id=user_id).first()
- membership_refs = session.query(UserTenantMembership)\
- .filter_by(user_id=user_id)\
- .all()
-with session.begin():
- if membership_refs:
- for membership_ref in membership_refs:
- session.delete(membership_ref)
-
- session.delete(user_ref)
- session.flush()
+ session.query(UserTenantMembership)\
+ .filter_by(user_id=user_id).delete(False)
+ session.query(Metadata)\
+ .filter_by(user_id=user_id).delete(False)
+ if not session.query(User).filter_by(id=user_id).delete(False):
+ raise exception.UserNotFound(user_id=user_id)@handle_conflicts(type='tenant')def create_tenant(self, tenant_id, tenant):
+ tenant['name'] = clean.tenant_name(tenant['name'])session = self.get_session()with session.begin():tenant_ref = Tenant.from_dict(tenant)
@@ -350,9 +405,13 @@ class Identity(sql.Base, identity.Driver):@handle_conflicts(type='tenant')def update_tenant(self, tenant_id, tenant):
+ if 'name' in tenant:
+ tenant['name'] = clean.tenant_name(tenant['name'])session = self.get_session()with session.begin():tenant_ref = session.query(Tenant).filter_by(id=tenant_id).first()
+ if tenant_ref is None:
+ raise exception.TenantNotFound(tenant_id=tenant_id)old_tenant_dict = tenant_ref.to_dict()for k in tenant:old_tenant_dict[k] = tenant[k]
@@ -365,10 +424,13 @@ class Identity(sql.Base, identity.Driver):def delete_tenant(self, tenant_id):session = self.get_session()
- tenant_ref = session.query(Tenant).filter_by(id=tenant_id).first()with session.begin():
- session.delete(tenant_ref)
- session.flush()
+ session.query(UserTenantMembership)\
+ .filter_by(tenant_id=tenant_id).delete(False)
+ session.query(Metadata)\
+ .filter_by(tenant_id=tenant_id).delete(False)
+ if not session.query(Tenant).filter_by(id=tenant_id).delete(False):
+ raise exception.TenantNotFound(tenant_id=tenant_id)@handle_conflicts(type='metadata')def create_metadata(self, user_id, tenant_id, metadata):
@@ -412,6 +474,8 @@ class Identity(sql.Base, identity.Driver):session = self.get_session()with session.begin():role_ref = session.query(Role).filter_by(id=role_id).first()
+ if role_ref is None:
+ raise exception.RoleNotFound(role_id=role_id)for k in role:role_ref[k] = role[k]session.flush()
@@ -419,6 +483,7 @@ class Identity(sql.Base, identity.Driver):def delete_role(self, role_id):session = self.get_session()
- role_ref = session.query(Role).filter_by(id=role_id).first()with session.begin():
- session.delete(role_ref)
+ if not session.query(Role).filter_by(id=role_id).delete():
+ raise exception.RoleNotFound(role_id=role_id)
+ session.flush()
ec2_credential表比较
该表在源文件keystone/contrib/ec2/backends/sql.py文件中定义,从下面的输出来看该表没有变化。
- [ugyn@localhost keystone]$ git diff 2012.1:keystone/contrib/ec2/backends/sql.py 2012.2:keystone/contrib/ec2/backends/sql.py > tables_diff
- [ugyn@localhost keystone]$ cat tables_diff
- diff --git a/2012.1:keystone/contrib/ec2/backends/sql.py b/2012.2:keystone/contrib/ec2/backends/sql.py
- index d84c381..c3af464 100644
- --- a/2012.1:keystone/contrib/ec2/backends/sql.py
- +++ b/2012.2:keystone/contrib/ec2/backends/sql.py
- @@ -15,7 +15,6 @@
- # under the License.
- from keystone.common import sql
- -from keystone.common.sql import migration
- class Ec2Credential(sql.ModelBase, sql.DictBase):
[ugyn@localhost keystone]$ git diff 2012.1:keystone/contrib/ec2/backends/sql.py 2012.2:keystone/contrib/ec2/backends/sql.py > tables_diff
[ugyn@localhost keystone]$ cat tables_diff
diff --git a/2012.1:keystone/contrib/ec2/backends/sql.py b/2012.2:keystone/contrib/ec2/backends/sql.py
index d84c381..c3af464 100644
--- a/2012.1:keystone/contrib/ec2/backends/sql.py
+++ b/2012.2:keystone/contrib/ec2/backends/sql.py
@@ -15,7 +15,6 @@# under the License.from keystone.common import sql
-from keystone.common.sql import migrationclass Ec2Credential(sql.ModelBase, sql.DictBase):
token表的差异
该表在源文件keystone/token/backends/sql.py中定义,从下面的输出来看F版中该表添加了一个新的布尔列valid默认值为True。
- [ugyn@localhost keystone]$ git diff 2012.1:keystone/token/backends/sql.py 2012.2:keystone/token/backends/sql.py > tables_diff
- [ugyn@localhost keystone]$ cat tables_diff
- diff --git a/2012.1:keystone/token/backends/sql.py b/2012.2:keystone/token/backends/sql.py
- index 7a9a551..02e8947 100644
- --- a/2012.1:keystone/token/backends/sql.py
- +++ b/2012.2:keystone/token/backends/sql.py
- @@ -16,9 +16,12 @@
- import copy
- import datetime
- +import hashlib
- +from keystone.common import cms
- from keystone.common import sql
- from keystone import exception
- +from keystone.openstack.common import timeutils
- from keystone import token
- @@ -27,6 +30,7 @@ class TokenModel(sql.ModelBase, sql.DictBase):
- id = sql.Column(sql.String(64), primary_key=True)
- expires = sql.Column(sql.DateTime(), default=None)
- extra = sql.Column(sql.JsonBlob())
- + valid = sql.Column(sql.Boolean(), default=True)
- @classmethod
- def from_dict(cls, token_dict):
- @@ -49,21 +53,31 @@ class Token(sql.Base, token.Driver):
- # Public interface
- def get_token(self, token_id):
- session = self.get_session()
- - token_ref = session.query(TokenModel).filter_by(id=token_id).first()
- + token_ref = session.query(TokenModel)\
- + .filter_by(id=self.token_to_key(token_id),
- + valid=True).first()
- now = datetime.datetime.utcnow()
- if token_ref and (not token_ref.expires or now < token_ref.expires):
- return token_ref.to_dict()
- else:
- raise exception.TokenNotFound(token_id=token_id)
- + def token_to_key(self, token_id):
- + if len(token_id) > cms.UUID_TOKEN_LENGTH:
- + hash = hashlib.md5()
- + hash.update(token_id)
- + return hash.hexdigest()
- + else:
- + return token_id
- +
- def create_token(self, token_id, data):
- data_copy = copy.deepcopy(data)
- if 'expires' not in data_copy:
- data_copy['expires'] = self._get_default_expire_time()
- token_ref = TokenModel.from_dict(data_copy)
- - token_ref.id = token_id
- -
- + token_ref.id = self.token_to_key(token_id)
- + token_ref.valid = True
- session = self.get_session()
- with session.begin():
- session.add(token_ref)
- @@ -72,12 +86,45 @@ class Token(sql.Base, token.Driver):
- def delete_token(self, token_id):
- session = self.get_session()
- - token_ref = session.query(TokenModel)\
- - .filter_by(id=token_id)\
- - .first()
- - if not token_ref:
- - raise exception.TokenNotFound(token_id=token_id)
- -
- + key = self.token_to_key(token_id)
- with session.begin():
- - session.delete(token_ref)
- + token_ref = session.query(TokenModel).filter_by(id=key,
- + valid=True).first()
- + if not token_ref:
- + raise exception.TokenNotFound(token_id=token_id)
- + token_ref.valid = False
- session.flush()
- +
- + def list_tokens(self, user_id, tenant_id=None):
- + session = self.get_session()
- + tokens = []
- + now = timeutils.utcnow()
- + for token_ref in session.query(TokenModel)\
- + .filter(TokenModel.expires > now)\
- + .filter_by(valid=True):
- + token_ref_dict = token_ref.to_dict()
- + if 'user' not in token_ref_dict:
- + continue
- + if token_ref_dict['user'].get('id') != user_id:
- + continue
- + if tenant_id is not None:
- + if 'tenant' not in token_ref_dict:
- + continue
- + if token_ref_dict['tenant'].get('id') != tenant_id:
- + continue
- + tokens.append(token_ref['id'])
- + return tokens
- +
- + def list_revoked_tokens(self):
- + session = self.get_session()
- + tokens = []
- + now = timeutils.utcnow()
- + for token_ref in session.query(TokenModel)\
- + .filter(TokenModel.expires > now)\
- + .filter_by(valid=False):
- + record = {
- + 'id': token_ref['id'],
- + 'expires': token_ref['expires'],
- + }
- + tokens.append(record)
- + return tokens
[ugyn@localhost keystone]$ git diff 2012.1:keystone/token/backends/sql.py 2012.2:keystone/token/backends/sql.py > tables_diff
[ugyn@localhost keystone]$ cat tables_diff
diff --git a/2012.1:keystone/token/backends/sql.py b/2012.2:keystone/token/backends/sql.py
index 7a9a551..02e8947 100644
--- a/2012.1:keystone/token/backends/sql.py
+++ b/2012.2:keystone/token/backends/sql.py
@@ -16,9 +16,12 @@import copyimport datetime
+import hashlib+from keystone.common import cmsfrom keystone.common import sqlfrom keystone import exception
+from keystone.openstack.common import timeutilsfrom keystone import token@@ -27,6 +30,7 @@ class TokenModel(sql.ModelBase, sql.DictBase):id = sql.Column(sql.String(64), primary_key=True)expires = sql.Column(sql.DateTime(), default=None)extra = sql.Column(sql.JsonBlob())
+ valid = sql.Column(sql.Boolean(), default=True)@classmethoddef from_dict(cls, token_dict):
@@ -49,21 +53,31 @@ class Token(sql.Base, token.Driver):# Public interfacedef get_token(self, token_id):session = self.get_session()
- token_ref = session.query(TokenModel).filter_by(id=token_id).first()
+ token_ref = session.query(TokenModel)\
+ .filter_by(id=self.token_to_key(token_id),
+ valid=True).first()now = datetime.datetime.utcnow()if token_ref and (not token_ref.expires or now < token_ref.expires):return token_ref.to_dict()else:raise exception.TokenNotFound(token_id=token_id)+ def token_to_key(self, token_id):
+ if len(token_id) > cms.UUID_TOKEN_LENGTH:
+ hash = hashlib.md5()
+ hash.update(token_id)
+ return hash.hexdigest()
+ else:
+ return token_id
+def create_token(self, token_id, data):data_copy = copy.deepcopy(data)if 'expires' not in data_copy:data_copy['expires'] = self._get_default_expire_time()token_ref = TokenModel.from_dict(data_copy)
- token_ref.id = token_id
-
+ token_ref.id = self.token_to_key(token_id)
+ token_ref.valid = Truesession = self.get_session()with session.begin():session.add(token_ref)
@@ -72,12 +86,45 @@ class Token(sql.Base, token.Driver):def delete_token(self, token_id):session = self.get_session()
- token_ref = session.query(TokenModel)\
- .filter_by(id=token_id)\
- .first()
- if not token_ref:
- raise exception.TokenNotFound(token_id=token_id)
-
+ key = self.token_to_key(token_id)with session.begin():
- session.delete(token_ref)
+ token_ref = session.query(TokenModel).filter_by(id=key,
+ valid=True).first()
+ if not token_ref:
+ raise exception.TokenNotFound(token_id=token_id)
+ token_ref.valid = Falsesession.flush()
+
+ def list_tokens(self, user_id, tenant_id=None):
+ session = self.get_session()
+ tokens = []
+ now = timeutils.utcnow()
+ for token_ref in session.query(TokenModel)\
+ .filter(TokenModel.expires > now)\
+ .filter_by(valid=True):
+ token_ref_dict = token_ref.to_dict()
+ if 'user' not in token_ref_dict:
+ continue
+ if token_ref_dict['user'].get('id') != user_id:
+ continue
+ if tenant_id is not None:
+ if 'tenant' not in token_ref_dict:
+ continue
+ if token_ref_dict['tenant'].get('id') != tenant_id:
+ continue
+ tokens.append(token_ref['id'])
+ return tokens
+
+ def list_revoked_tokens(self):
+ session = self.get_session()
+ tokens = []
+ now = timeutils.utcnow()
+ for token_ref in session.query(TokenModel)\
+ .filter(TokenModel.expires > now)\
+ .filter_by(valid=False):
+ record = {
+ 'id': token_ref['id'],
+ 'expires': token_ref['expires'],
+ }
+ tokens.append(record)
+ return tokens
migrate_version表的差异
该表似乎跟Keystone进行数据库升级有关,具体差异不清楚。
配置差异
从下面的示例配置文件的比较来看主要是增加了几个filter中间件
- [ugyn@localhost keystone]$ git diff 2012.1:etc/keystone.conf 2012.2:etc/keystone.conf.sample > tables_diff
- [ugyn@localhost keystone]$ cat tables_diff
- diff --git a/2012.1:etc/keystone.conf b/2012.2:etc/keystone.conf.sample
- index 3ecf641..1d48676 100644
- --- a/2012.1:etc/keystone.conf
- +++ b/2012.2:etc/keystone.conf.sample
- @@ -1,53 +1,128 @@
- [DEFAULT]
- -#bind_host = 0.0.0.0
- -public_port = 5000
- -admin_port = 35357
- -admin_token = ADMIN
- -compute_port = 8774
- -verbose = True
- -debug = True
- -#log_config = ./etc/logging.conf.sample
- -
- -# ================= Syslog Options ============================
- -# Send logs to syslog (/dev/log) instead of to file specified
- -# by `log-file`
- -use_syslog = False
- -
- -# Facility to use. If unset defaults to LOG_USER.
- -# syslog_log_facility = LOG_LOCAL0
- +# A "shared secret" between keystone and other openstack services
- +# admin_token = ADMIN
- +
- +# The IP address of the network interface to listen on
- +# bind_host = 0.0.0.0
- +
- +# The port number which the public service listens on
- +# public_port = 5000
- +
- +# The port number which the public admin listens on
- +# admin_port = 35357
- +
- +# The port number which the OpenStack Compute service listens on
- +# compute_port = 8774
- +
- +# === Logging Options ===
- +# Print debugging output
- +# verbose = False
- +
- +# Print more verbose output
- +# (includes plaintext request logging, potentially including passwords)
- +# debug = False
- +
- +# Name of log file to output to. If not set, logging will go to stdout.
- +# log_file = keystone.log
- +
- +# The directory to keep log files in (will be prepended to --logfile)
- +# log_dir = /var/log/keystone
- +
- +# Use syslog for logging.
- +# use_syslog = False
- +
- +# syslog facility to receive log lines
- +# syslog_log_facility = LOG_USER
- +
- +# If this option is specified, the logging configuration file specified is
- +# used and overrides any other logging options specified. Please see the
- +# Python logging module documentation for details on logging configuration
- +# files.
- +# log_config = logging.conf
- +
- +# A logging.Formatter log message format string which may use any of the
- +# available logging.LogRecord attributes.
- +# log_format = %(asctime)s %(levelname)8s [%(name)s] %(message)s
- +
- +# Format string for %(asctime)s in log records.
- +# log_date_format = %Y-%m-%d %H:%M:%S
- +
- +# onready allows you to send a notification when the process is ready to serve
- +# For example, to have it notify using systemd, one could set shell command:
- +# onready = systemd-notify --ready
- +# or a module with notify() method:
- +# onready = keystone.common.systemd
- [sql]
- -connection = sqlite:///keystone.db
- -idle_timeout = 200
- +# The SQLAlchemy connection string used to connect to the database
- +# connection = sqlite:///keystone.db
- -[ldap]
- -#url = ldap://localhost
- -#tree_dn = dc=example,dc=com
- -#user_tree_dn = ou=Users,dc=example,dc=com
- -#role_tree_dn = ou=Roles,dc=example,dc=com
- -#tenant_tree_dn = ou=Groups,dc=example,dc=com
- -#user = dc=Manager,dc=example,dc=com
- -#password = freeipa4all
- -#suffix = cn=example,cn=com
- +# the timeout before idle sql connections are reaped
- +# idle_timeout = 200
- [identity]
- -driver = keystone.identity.backends.sql.Identity
- +# driver = keystone.identity.backends.sql.Identity
- [catalog]
- -driver = keystone.catalog.backends.templated.TemplatedCatalog
- -template_file = ./etc/default_catalog.templates
- +# dynamic, sql-based backend (supports API/CLI-based management commands)
- +# driver = keystone.catalog.backends.sql.Catalog
- +
- +# static, file-based backend (does *NOT* support any management commands)
- +# driver = keystone.catalog.backends.templated.TemplatedCatalog
- +
- +# template_file = default_catalog.templates
- [token]
- -driver = keystone.token.backends.kvs.Token
- +# driver = keystone.token.backends.kvs.Token
- # Amount of time a token should remain valid (in seconds)
- -expiration = 86400
- +# expiration = 86400
- [policy]
- -driver = keystone.policy.backends.rules.Policy
- +# driver = keystone.policy.backends.rules.Policy
- [ec2]
- -driver = keystone.contrib.ec2.backends.kvs.Ec2
- +# driver = keystone.contrib.ec2.backends.kvs.Ec2
- +
- +[ssl]
- +#enable = True
- +#certfile = /etc/keystone/ssl/certs/keystone.pem
- +#keyfile = /etc/keystone/ssl/private/keystonekey.pem
- +#ca_certs = /etc/keystone/ssl/certs/ca.pem
- +#cert_required = True
- +
- +[signing]
- +#token_format = UUID
- +#certfile = /etc/keystone/ssl/certs/signing_cert.pem
- +#keyfile = /etc/keystone/ssl/private/signing_key.pem
- +#ca_certs = /etc/keystone/ssl/certs/ca.pem
- +#key_size = 1024
- +#valid_days = 3650
- +#ca_password = None
- +#token_format = PKI
- +
- +[ldap]
- +# url = ldap://localhost
- +# user = dc=Manager,dc=example,dc=com
- +# password = None
- +# suffix = cn=example,cn=com
- +# use_dumb_member = False
- +
- +# user_tree_dn = ou=Users,dc=example,dc=com
- +# user_objectclass = inetOrgPerson
- +# user_id_attribute = cn
- +# user_name_attribute = sn
- +
- +# tenant_tree_dn = ou=Groups,dc=example,dc=com
- +# tenant_objectclass = groupOfNames
- +# tenant_id_attribute = cn
- +# tenant_member_attribute = member
- +# tenant_name_attribute = ou
- +
- +# role_tree_dn = ou=Roles,dc=example,dc=com
- +# role_objectclass = organizationalRole
- +# role_id_attribute = cn
- +# role_member_attribute = roleOccupant
- [filter:debug]
- paste.filter_factory = keystone.common.wsgi:Debug.factory
- @@ -64,12 +139,27 @@ paste.filter_factory = keystone.middleware:XmlBodyMiddleware.factory
- [filter:json_body]
- paste.filter_factory = keystone.middleware:JsonBodyMiddleware.factory
- +[filter:user_crud_extension]
- +paste.filter_factory = keystone.contrib.user_crud:CrudExtension.factory
- +
- [filter:crud_extension]
- paste.filter_factory = keystone.contrib.admin_crud:CrudExtension.factory
- [filter:ec2_extension]
- paste.filter_factory = keystone.contrib.ec2:Ec2Extension.factory
- +[filter:s3_extension]
- +paste.filter_factory = keystone.contrib.s3:S3Extension.factory
- +
- +[filter:url_normalize]
- +paste.filter_factory = keystone.middleware:NormalizingFilter.factory
- +
- +[filter:stats_monitoring]
- +paste.filter_factory = keystone.contrib.stats:StatsMiddleware.factory
- +
- +[filter:stats_reporting]
- +paste.filter_factory = keystone.contrib.stats:StatsExtension.factory
- +
- [app:public_service]
- paste.app_factory = keystone.service:public_app_factory
- @@ -77,10 +167,10 @@ paste.app_factory = keystone.service:public_app_factory
- paste.app_factory = keystone.service:admin_app_factory
- [pipeline:public_api]
- -pipeline = token_auth admin_token_auth xml_body json_body debug ec2_extension public_service
- +pipeline = stats_monitoring url_normalize token_auth admin_token_auth xml_body json_body debug ec2_extension user_crud_extension public_service
- [pipeline:admin_api]
- -pipeline = token_auth admin_token_auth xml_body json_body debug ec2_extension crud_extension admin_service
- +pipeline = stats_monitoring url_normalize token_auth admin_token_auth xml_body json_body debug stats_reporting ec2_extension s3_extension crud_extension admin_service
- [app:public_version_service]
- paste.app_factory = keystone.service:public_version_app_factory
- @@ -89,10 +179,10 @@ paste.app_factory = keystone.service:public_version_app_factory
- paste.app_factory = keystone.service:admin_version_app_factory
- [pipeline:public_version_api]
- -pipeline = xml_body public_version_service
- +pipeline = stats_monitoring url_normalize xml_body public_version_service
- [pipeline:admin_version_api]
- -pipeline = xml_body admin_version_service
- +pipeline = stats_monitoring url_normalize xml_body admin_version_service
- [composite:main]
- use = egg:Paste#urlmap
转载于:https://www.cnblogs.com/wencangz/archive/2012/11/07/2758937.html
OpenStack版本比较之Keystone相关推荐
- (原创)OpenStack服务如何使用Keystone(三)---详细配置Keystone中间件
(一)Keystone端的操作 (二)如何在OpenStack服务上部署Keystone中间件 (三)详细配置keystonemiddleware 前文我们介绍了如何部署Keystone中间件以及中间 ...
- OpenStack实践系列②认证服务Keystone
OpenStack实践系列②认证服务Keystone 三.实战OpenStack之控制节点 3.1 CentOS7的时间同步服务器chrony 下载chrony # yum install -y ch ...
- 查看OpenStack版本
可以根据nova版本反查openstack版本 1.查看nova版本 cd /usr/lib/python2.7/dist-packagesls -a | grep nova 我的是这样的,nova版 ...
- OpenStack(二)——Keystone组件
OpenStack(二)--Keystone组件 一.OpenStack组件之间的通信关系 二.OpenStack物理构架 三.Keystone组件 1.Keystone身份服务 2.管理对象 3.K ...
- OpenStack集群部署——Keystone部署(二)
三.Keyston-认证服务 3.1 Keyston介绍 Keyston介绍 补充 3.2 安装时间同步器 ---------------------------------------------- ...
- Openstack组件实现原理 — Keystone认证功能
前言 Keystone实现始终围绕着Keystone所实现的功能来展开,所以在理解其实现之前,建议大家尝试通过安装Keystone这一个过程来感受Keystone在Openstack架构中所充当的角色 ...
- 【原创-长文】openstack 版本D安装配置及本次安装中遇到的问题
openstack配置 一.硬件及操作系统要求 硬件:IBM服务器R410 两台.网线.显示器.键盘若干,100M光纤(硬性要求) 操作系统:两台服务器均安装Ubuntu server 12.04 L ...
- OpenStack手动分布式部署Keystone【Queens版】
目录 Keystone简介 1.登录数据库配置(在controller执行) 1.1登录数据库 1.2数据库里创建keystone 1.3授权对keystone数据库的正确访问 1.4退出数据库 2. ...
- OpenStack版本 - 发布时间 - 及其组件
Austin(2010.10):Nova.Glance.Keystone.Horizon.Swift.Quantum Bexar(2011.02):Nova.Glance.Keystone.Horiz ...
最新文章
- 常用Intent调用(摘自网络)
- javascript 将内容复制到剪贴板
- P2408 不同子串个数
- Kali Linux 自定义分辨率
- button标签设置隐藏和显示_让你更高效的功能——设置、预设的妙用【动态数学软件GeoGebra】...
- web与app开发java_移动web开发和移动app开发的区分
- excel转html不显示图片,excel表格怎么把0显示出来/为什么在excel插入背景后预览看不到图片...
- 大学生计算机系统推荐,上大学买电脑?最适合大学生学习用的Windows笔记本电脑推荐!...
- 前端面试题 ~ 移动端注意
- 我做了一款iOS12捷径市场,也许是目前最好看也是最具技术含量的ShortCuts小程序
- 虚拟机介绍与使用(VMware Workstation)
- jmap常用命令以及dump文件查看
- 爬虫内容学习-工具类---xpath-1
- 项目4:后台管理的开发和使用(前端)
- 小萌库- 新海诚那些唯美感人的动漫
- VR全景在线虚拟展厅实现全方位沉浸式互动体验
- Mysql数据库经验总结
- 设置邮件规则,轻松整理你的收件箱!
- Kepware通过OPCUA链接WinCC(Kepware作为客户端)
- CoreAnimation动画(CALayer动画)
热门文章
- 06-02 Jenkins job 机制
- 金融数据分析与挖掘实战练习-1.9
- 零基础学web前端难吗?新手该怎么学?
- 现在转行前端,该怎么学习呢?怎么学好基础html、css、js
- 如何成为一名Web前端开发人员?入行学习完整指南
- 我可能不适合做前端,你呢?
- java des 0填充方式_DES填充方式与初始向量IV的作用
- 前窗玻璃膜贴了一周还有气泡_汽车玻璃膜贴全部好还是贴局部好?
- 业余学python 树莓派_厉害了!小伙自学Python一个月,利用树莓派制作了黑客优盘工具!...
- php 类自动执行,php类中的魔术方法及类的自动加载