OpenStackの各コンポーネントの設定ファイルを規程外のパスに置く場合はpolicy_file設定を忘れずに

ハマったのでメモしておく。
1台のノードに複数バージョンのOpenStackコンポーネント(例えばneutron)などをインストールして選択起動するような場合、インストールパスも設定ファイル群のパスも当然ながら分けることになるはず。
例えば、

- grizzly
  /usr/local/grizzly/quantum/etc/

- folsom
  /usr/local/folsom/quantum/etc/

みたいな感じに。
この時、quantum.confは

quantum-server --config-file /usr/local/grizzly/quantum/etc/quantum.conf

のように指定してやれば良いんだけれど、policy.jsonは起動時に指定できない(たぶん)。
ポリシーチェックが入ると、quantumクライアント側でこんなエラーが...

$ quantum --os-user=admin --os-password=adminpasswd --os-tenant-name=admin agent-list
Policy configuration policy.json could not be found     <-- くっ...orz

どこを参照するかというと、例えばneutronではAPIのControllerクラスでポリシーチェックをする(※1)際に都度呼ばれているみたい。

quantum/api/v2/base.py
class Controller(object):
    <...省略...>
    def _items(self, request, do_authz=False, parent_id=None):
        <...省略...>
            obj_list = [obj for obj in obj_list
                        if policy.check(request.context,
                                        self._plugin_handlers[self.SHOW],
                                        obj,
                                        plugin=self._plugin)]
    <...省略...>
quantum/policy.py

policyモジュールではcheck()が呼ばれる度にpolicy.jsonがチェックされる。

<...省略...>

 45 def init():    <--※1 定義
 46     global _POLICY_PATH
 47     global _POLICY_CACHE
 48     if not _POLICY_PATH:
 49         _POLICY_PATH = utils.find_config_file({}, cfg.CONF.policy_file)   <--※2
 50         if not _POLICY_PATH:
 51             raise exceptions.PolicyNotFound(path=cfg.CONF.policy_file)
 52     # pass _set_brain to read_cached_file so that the policy brain
 53     # is reset only if the file has changed
 54     LOG.debug(_("loading policy file at %s"), _POLICY_PATH)
 55     utils.read_cached_file(_POLICY_PATH, _POLICY_CACHE,
 56                            reload_func=_set_rules)

<...省略...>

162 def check(context, action, target, plugin=None):
163     """Verifies that the action is valid on the target in this context.
164 
165     :param context: quantum context
166     :param action: string representing the action to be checked
167         this should be colon separated for clarity.
168     :param target: dictionary representing the object of the action
169         for object creation this should be a dictionary representing the
170         location of the object e.g. ``{'project_id': context.project_id}``
171     :param plugin: quantum plugin used to retrieve information required
172         for augmenting the target
173 
174     :return: Returns True if access is permitted else False.
175     """
176     init()               <--※1 呼び出し
177     real_target = _build_target(action, target, plugin, context)
178     match_rule = _build_match_rule(action, real_target)
179     credentials = context.to_dict()
180     return policy.check(match_rule, real_target, credentia

<...省略...>
では設定ファイル(ここではquantum.conf)のpolicy_fileに何も指定しないときの動きは?

utils.pyのfind_config_file()が呼ばれて規程のパス上からpolicy.jsonをロードする(※2)
という動きになって、例えば/usr/local/grizzly/quantum/etc/policy.jsonのような規程から外れたパスからは当然ながら拾ってくれず、

Traceback (most recent call last):
  File "/home/saitou/grizzly/quantum/quantum/api/v2/resource.py", line 82, in resource
    result = method(request=request, **args)
  File "/home/saitou/grizzly/quantum/quantum/api/v2/base.py", line 240, in index
    return self._items(request, True, parent_id)
  File "/home/saitou/grizzly/quantum/quantum/api/v2/base.py", line 206, in _items
    plugin=self._plugin)]
  File "/home/saitou/grizzly/quantum/quantum/policy.py", line 182, in check
    init()
  File "/home/saitou/grizzly/quantum/quantum/policy.py", line 56, in init
    raise exceptions.PolicyNotFound(path=cfg.CONF.policy_file)
PolicyNotFound: Policy configuration policy.json could not be found

というようにエラーになり、クライアント側では

Policy configuration policy.json could not be found

というエラーになると。

policy_fileの指定方法
  • quantum.confの場合はこんな感じ
[DEFAULT]
policy_file = /usr/local/grizzly/quantum/etc/policy.json

これで解決。
先は長いぜ...最初はクライアント側の問題かと思った...