天天看點

OpenStack中keystone元件源碼流程

此處以OpenStack mitaka版本為例,實際最新的Ocata版本也差不多,keystone的管理端口為35357,公共服務端口為5000,使用者認證的方式包括使用者密碼認證和admin_token認證兩種方式。用戶端的authenticate()方法主要完成三個主要工作:a.嘗試從本地擷取token。b.本地沒有token設定為強制更新,從伺服器擷取token。c.将新的token儲存在本地。伺服器端的admin_token認證方式判斷用戶端發傳來的token與配置檔案裡的admin_token是否一緻,使用者密碼認證方式authenticate()方法主要完成三個工作:a.如果封包中有token這個字段,則進行token認證。b.嘗試外部認證。c.嘗試本地認證。一個token有三個重要的屬性:ID、使用者資訊、服務目錄。

以擷取某個使用者資訊為例分析keystonev2.0源碼。

用戶端:

加載使用者資源。

/keystoneclient/v2_0/client.py

class Client(httpclient.HTTPClient):
     def __init__(self, **kwargs):
         ...
         self.users = users.UserManager(self._adapter, self.roles)
         ...
           

設定請求的url和userid參數。

/keystoneclient/v2_0/users.py

class UserManager(base.ManagerWithFind):
     ...
     def get(self, user):
         return self._get("/users/%s" % base.getid(user), "user")
     ...
           

最終調用HTTPClient發送GET請求

class Manager(object):
    ...
    def _get(self, url, response_key, **kwargs):
        resp, body = self.client.get(url, **kwargs)
        return self.resource_class(self, body[response_key], loaded=True)
    ...
           

伺服器端:

通過wsgi完成keystone元件中所有資源與用戶端請求的映射,此處的routers包含identity_routers.Admin(),

assignment_routers.Admin(),

token_routers.Router(),

resource_routers.Admin(),

admin_crud.Router(),

routers.VersionV2(‘admin’),

routers.Extension()

管理服務的routers定義在/keystone/version/service.py中的admin_app.factory()方法中

公共服務的routers定義在/keystone/version/service.py中的public_app.factory()方法中

/keystone/common/wsgi.py

class ComposingRouter(Router):
    def __init__(self, mapper=None, routers=None):
        if mapper is None:
            mapper = routes.Mapper()
        if routers is None:
            routers = []
        for router in routers:
            router.add_routes(mapper)
        super(ComposingRouter, self).__init__(mapper)
           

以identity.routers.Admin()為例,完成對用戶端請求資源的響應,可以看到對應請求的url為’/users/{user_id}’,業務處理的控制器為user_controller,處理方法為get_user,請求為GET類型。

/keystone/identity/routers.py

class Admin(wsgi.ComposableRouter):
    def add_routes(self, mapper):
        # User Operations
        user_controller = controllers.User()
        mapper.connect('/users/{user_id}',
                       controller=user_controller,
                       action='get_user',
                       conditions=dict(method=['GET']))
           

調用API接口查詢ID為{user_id}的使用者

/keystone/identity/controllers.py

def get_user(self, context, user_id):
        self.assert_admin(context)
        ref = self.identity_api.get_user(user_id)
        return {'user': self.v3_to_v2_user(ref)}
           

此處的identity_api是通過裝飾器模式将其定義為類的成員變量

@dependency.requires('assignment_api', 'identity_api', 'resource_api')
           

/keystone/common/dependency.py

def requires(*dependencies):
    def wrapper(self, *args, **kwargs):
        """Inject each dependency from the registry."""
        self.__wrapped_init__(*args, **kwargs)
        _process_dependencies(self)

    def wrapped(cls):
        existing_dependencies = getattr(cls, '_dependencies', set())
        cls._dependencies = existing_dependencies.union(dependencies)
        if not hasattr(cls, '__wrapped_init__'):
            cls.__wrapped_init__ = cls.__init__
            cls.__init__ = wrapper
        return cls

    return wrapped
           

其中,identity_api會通過父類的構造方法完成預設驅動的加載

class Manager(object):
       driver_namespace = None
    def __init__(self, driver_name):
        self.driver = load_driver(self.driver_namespace, driver_name)
           

此處的driver_namespace為keystone.identity,driver_name為keystone.conf配置檔案中的identity鍵值

keystone中重要的API

名稱 驅動 描述
catalog_api keystone.catalog.Manager keystone.catalog.backends.sql.Catalog endpoint管理
identity_api keystone.identity.Manager keystone.identity.backends.sql.Catalog user、tenant管理
token_api keystone.token.Manager keystone.catalog.backends.kvs.Token token管理
policy_api keystone.policy.Manager keystone.policy.backends.sql.Policy policy管理

繼續閱讀