EPEL版 OpenStack folsomの設定(Horizon編)
Horizonのlocal_settings.pyでハマったのでメモ。
Horizonの設定ファイル
Horizonは、PythonのWebアプリケーションフレームワークであるdjangoの上に構成されており、EPEL版のパッケージでインストールした場合、設定ファイルは以下に置かれています。
- /usr/share/openstack-dashboard/openstack_dashboard/local/local_settings.py
設定すべきパラメータ
設定すべきパラメータは以下の通り多くはありません。
※修正後はhttpdのrestartを忘れずに!
KEYSTONE_HOST = "Kenstoneが稼動しているホスト名またはIPアドレス" OPENSTACK_KEYSTONE_URL = "http://%s:5000/v2.0" % KEYSTONE_HOST OPENSTACK_KEYSTONE_DEFAULT_ROLE = "Keystoneで作成した管理者ロール名"
OPENSTACK_KEYSTONE_DEFAULT_ROLE について
どうも、このパラメータを参照しているのは、Horizonの機能のなかでもUpdateProjectMembersActionクラスだけのようです。
このクラスは、テナント情報を参照したり、テナントを作成したりする際に利用されます。でもなぜかテナントを削除する際には呼ばれない...
/usr/lib/python2.6/site-packages/horizon/dashboards/syspanel/projects/workflows.py
OPENSTACK_KEYSTONE_DEFAULT_ROLEは、__init__()内で呼ばれているapi.get_default_role()が利用しているのみ(たぶん)です。もっといい方法あるんじゃないかなこれ...
class UpdateProjectMembersAction(workflows.Action): default_role = forms.CharField(required=False) def __init__(self, request, *args, **kwargs): super(UpdateProjectMembersAction, self).__init__(request, *args, **kwargs) err_msg = _('Unable to retrieve user list. Please try again later.') project_id = '' if 'project_id' in args[0]: project_id = args[0]['project_id'] # Get the default role try: default_role = api.get_default_role(self.request).id <== ココで呼ばれるget_default_role()が見ている except: exceptions.handle(self.request, err_msg, redirect=reverse(INDEX_URL)) self.fields['default_role'].initial = default_role # Get list of available users all_users = [] try: all_users = api.keystone.user_list(request) except: exceptions.handle(request, err_msg) users_list = [(user.id, user.name) for user in all_users] # Get list of roles role_list = [] try: role_list = api.keystone.role_list(request) except: exceptions.handle(request, err_msg, redirect=reverse(INDEX_URL)) for role in role_list: field_name = "role_" + role.id label = _(role.name) self.fields[field_name] = forms.MultipleChoiceField(required=False, label=label) self.fields[field_name].choices = users_list self.fields[field_name].initial = [] # Figure out users & roles if project_id: for user in all_users: try: roles = api.roles_for_user(self.request, user.id, project_id) except: exceptions.handle(request, err_msg, redirect=reverse(INDEX_URL)) if roles: primary_role = roles[0].id self.fields["role_" + primary_role].initial.append(user.id) class Meta: name = _("Project Members") slug = "update_members"
/usr/lib/python2.6/site-packages/horizon/api/keystone.py
ここで、ユーザが持っているロールがOPENSTACK_KEYSTONE_DEFAULT_ROLEにマッチしているかどうかをチェックしています。
マッチしていない場合は...UpdateProjectMembersActionクラスインスタンスを生成する(つまりテナントの参照や作成をする)際に、default_role = api.get_default_role(self.request).id)部分で
AttributeError: 'NoneType' object has no attribute 'id'
となってテナントの参照及び作成機能が利用できません。
その際、Horizon上にはError: An error occurred. Please try again.というエラーメッセージが出力されます。
もちろん、OPENSTACK_KEYSTONE_DEFAULT_ROLEに適切なロール名を設定しない限り、try againしても無駄です:)
これ、なんかやっぱりイマイチな気がする...
def get_default_role(request): """ Gets the default role object from Keystone and saves it as a global since this is configured in settings and should not change from request to request. Supports lookup by name or id. """ global DEFAULT_ROLE default = getattr(settings, "OPENSTACK_KEYSTONE_DEFAULT_ROLE", None) if default and DEFAULT_ROLE is None: try: roles = keystoneclient(request, admin=True).roles.list() except: roles = [] exceptions.handle(request) for role in roles: if role.id == default or role.name == default: <== ココでチェックしている DEFAULT_ROLE = role break return DEFAULT_ROLE