Skip to content

Commit fe545db

Browse files
committed
Migrate default policy file from JSON to YAML
Default value of 'CONF.oslo_policy.policy_file' config option has been changed from 'policy.json' to 'policy.yaml'. If new default file 'policy.yaml' does not exist but old default 'policy.json' exist then fallback to use old default file. An upgrade checks is added to check the policy_file format and fail upgrade checks if it is JSON formatted. Added a warning in policy doc about JSON formatted file is deprecated, also removed all the reference to policy.json file in doc as well as in tests. Related Blueprint: policy-json-to-yaml Closes-Bug: #1875418 Change-Id: Ic4d3b998bb9701cb1e3ef12d9bb6f4d91cc19c18
1 parent b0c529a commit fe545db

File tree

11 files changed

+248
-17
lines changed

11 files changed

+248
-17
lines changed

doc/source/cli/nova-status.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ Upgrade
139139
* Checks for the policy files are not automatically overwritten with
140140
new defaults.
141141

142+
**22.0.0 (Victoria)**
143+
144+
* Checks for the policy files is not JSON-formatted.
145+
142146
See Also
143147
========
144148

doc/source/configuration/policy-concepts.rst

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
Understanding Nova Policies
22
===========================
33

4+
.. warning::
5+
6+
JSON formatted policy file is deprecated since Nova 22.0.0(Victoria).
7+
Use YAML formatted file. Use `oslopolicy-convert-json-to-yaml`__ tool
8+
to convert the existing JSON to YAML formatted policy file in backward
9+
compatible way.
10+
11+
.. __: https://docs.openstack.org/oslo.policy/latest/cli/oslopolicy-convert-json-to-yaml.html
12+
413
Nova supports a rich policy system that has evolved significantly over its
514
lifetime. Initially, this took the form of a large, mostly hand-written
6-
``policy.json`` file but, starting in the Newton (14.0.0) release, policy
7-
defaults have been defined in the codebase, requiring the ``policy.json``
15+
``policy.yaml`` file but, starting in the Newton (14.0.0) release, policy
16+
defaults have been defined in the codebase, requiring the ``policy.yaml``
817
file only to override these defaults.
918

1019
In the Ussuri (21.0.0) release, further work was undertaken to address some

doc/source/configuration/policy.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ Nova Policies
44

55
The following is an overview of all available policies in Nova.
66

7+
.. warning::
8+
9+
JSON formatted policy file is deprecated since Nova 22.0.0(Victoria).
10+
Use YAML formatted file. Use `oslopolicy-convert-json-to-yaml`__ tool
11+
to convert the existing JSON to YAML formatted policy file in backward
12+
compatible way.
13+
14+
.. __: https://docs.openstack.org/oslo.policy/latest/cli/oslopolicy-convert-json-to-yaml.html
15+
716
.. only:: html
817

918
For a sample configuration file, refer to :doc:`sample-policy`.

doc/source/install/verify.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,7 @@ Verify operation of the Compute service.
127127
| Result: Success |
128128
| Details: None |
129129
+--------------------------------------------------------------------+
130+
| Check: Policy File JSON to YAML Migration |
131+
| Result: Success |
132+
| Details: None |
133+
+--------------------------------------------------------------------+

lower-constraints.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,21 +69,21 @@ os-xenapi==0.3.4
6969
osc-lib==1.10.0
7070
oslo.cache==1.26.0
7171
oslo.concurrency==3.29.0
72-
oslo.config==6.1.0
72+
oslo.config==6.8.0
7373
oslo.context==2.22.0
7474
oslo.db==4.44.0
7575
oslo.i18n==3.15.3
7676
oslo.log==3.36.0
7777
oslo.messaging==10.3.0
7878
oslo.middleware==3.31.0
79-
oslo.policy==3.1.0
79+
oslo.policy==3.4.0
8080
oslo.privsep==1.33.2
8181
oslo.reports==1.18.0
8282
oslo.rootwrap==5.8.0
8383
oslo.serialization==2.21.1
8484
oslo.service==1.40.1
8585
oslo.upgradecheck==0.1.1
86-
oslo.utils==4.1.0
86+
oslo.utils==4.5.0
8787
oslo.versionedobjects==1.35.0
8888
oslo.vmware==2.17.0
8989
oslotest==3.8.0
@@ -127,11 +127,11 @@ python-subunit==1.4.0
127127
pytz==2018.3
128128
PyYAML==3.13
129129
repoze.lru==0.7
130-
requests==2.14.2
130+
requests==2.23.0
131131
requests-mock==1.2.0
132132
requestsexceptions==1.4.0
133133
retrying==1.3.3
134-
rfc3986==1.1.0
134+
rfc3986==1.2.0
135135
Routes==2.3.1
136136
simplejson==3.13.2
137137
six==1.11.0

nova/cmd/status.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from oslo_config import cfg
2626
from oslo_serialization import jsonutils
2727
from oslo_upgradecheck import upgradecheck
28+
from oslo_utils import fileutils
2829
import pkg_resources
2930
import six
3031
from sqlalchemy import func as sqlfunc
@@ -409,6 +410,23 @@ def _check_policy(self):
409410
policy.reset()
410411
return status
411412

413+
def _check_policy_json(self):
414+
"Checks to see if policy file is JSON-formatted policy file."
415+
msg = _("Your policy file is JSON-formatted which is "
416+
"deprecated since Victoria release (Nova 22.0.0). "
417+
"You need to switch to YAML-formatted file. You can use the "
418+
"``oslopolicy-convert-json-to-yaml`` tool to convert existing "
419+
"JSON-formatted files to YAML-formatted files in a "
420+
"backwards-compatible manner: "
421+
"https://docs.openstack.org/oslo.policy/"
422+
"latest/cli/oslopolicy-convert-json-to-yaml.html.")
423+
status = upgradecheck.Result(upgradecheck.Code.SUCCESS)
424+
# Check if policy file exist and is JSON-formatted.
425+
policy_path = CONF.find_file(CONF.oslo_policy.policy_file)
426+
if policy_path and fileutils.is_json(policy_path):
427+
status = upgradecheck.Result(upgradecheck.Code.FAILURE, msg)
428+
return status
429+
412430
# The format of the check functions is to return an upgradecheck.Result
413431
# object with the appropriate upgradecheck.Code and details set. If the
414432
# check hits warnings or failures then those should be stored in the
@@ -427,6 +445,8 @@ def _check_policy(self):
427445
(_('Cinder API'), _check_cinder),
428446
# Added in Ussuri
429447
(_('Policy Scope-based Defaults'), _check_policy),
448+
# Added in Victoria
449+
(_('Policy File JSON to YAML Migration'), _check_policy_json),
430450
)
431451

432452

nova/policy.py

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
from oslo_config import cfg
2121
from oslo_log import log as logging
22+
from oslo_policy import opts
2223
from oslo_policy import policy
2324
from oslo_utils import excutils
2425

@@ -40,6 +41,35 @@
4041
saved_file_rules = []
4142
KEY_EXPR = re.compile(r'%\((\w+)\)s')
4243

44+
# TODO(gmann): Remove setting the default value of config policy_file
45+
# once oslo_policy change the default value to 'policy.yaml'.
46+
# https://github.com/openstack/oslo.policy/blob/a626ad12fe5a3abd49d70e3e5b95589d279ab578/oslo_policy/opts.py#L49
47+
DEFAULT_POLICY_FILE = 'policy.yaml'
48+
opts.set_defaults(cfg.CONF, DEFAULT_POLICY_FILE)
49+
50+
51+
def pick_policy_file(policy_file):
52+
# TODO(gmann): We have changed the default value of
53+
# CONF.oslo_policy.policy_file option to 'policy.yaml' in Victoria
54+
# release. To avoid breaking any deployment relying on default
55+
# value, we need to add this is fallback logic to pick the old default
56+
# policy file (policy.json) if exist. We can to remove this fallback
57+
# logic sometime in future.
58+
if policy_file:
59+
return policy_file
60+
61+
if CONF.oslo_policy.policy_file == DEFAULT_POLICY_FILE:
62+
location = CONF.get_location('policy_file', 'oslo_policy').location
63+
if CONF.find_file(CONF.oslo_policy.policy_file):
64+
return CONF.oslo_policy.policy_file
65+
elif location in [cfg.Locations.opt_default,
66+
cfg.Locations.set_default]:
67+
old_default = 'policy.json'
68+
if CONF.find_file(old_default):
69+
return old_default
70+
# Return overridden value
71+
return CONF.oslo_policy.policy_file
72+
4373

4474
def reset():
4575
global _ENFORCER
@@ -67,11 +97,12 @@ def init(policy_file=None, rules=None, default_rule=None, use_conf=True,
6797
global saved_file_rules
6898

6999
if not _ENFORCER:
70-
_ENFORCER = policy.Enforcer(CONF,
71-
policy_file=policy_file,
72-
rules=rules,
73-
default_rule=default_rule,
74-
use_conf=use_conf)
100+
_ENFORCER = policy.Enforcer(
101+
CONF,
102+
policy_file=pick_policy_file(policy_file),
103+
rules=rules,
104+
default_rule=default_rule,
105+
use_conf=use_conf)
75106
# NOTE(gmann): Explictly disable the warnings for policies
76107
# changing their default check_str. During policy-defaults-refresh
77108
# work, all the policy defaults have been changed and warning for

nova/tests/unit/cmd/test_status.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,16 @@
2222

2323
import fixtures
2424
import mock
25+
import os
2526
from six.moves import StringIO
27+
import tempfile
28+
import yaml
2629

2730
from keystoneauth1 import exceptions as ks_exc
2831
from keystoneauth1 import loading as keystone
2932
from keystoneauth1 import session
33+
from oslo_config import cfg
34+
from oslo_serialization import jsonutils
3035
from oslo_upgradecheck import upgradecheck
3136
from oslo_utils.fixture import uuidsentinel as uuids
3237
from oslo_utils import uuidutils
@@ -602,3 +607,63 @@ class TestUpgradeCheckPolicyEnableScope(TestUpgradeCheckPolicy):
602607
def setUp(self):
603608
super(TestUpgradeCheckPolicyEnableScope, self).setUp()
604609
self.flags(enforce_scope=True, group="oslo_policy")
610+
611+
612+
class TestUpgradeCheckPolicyJSON(test.NoDBTestCase):
613+
614+
def setUp(self):
615+
super(TestUpgradeCheckPolicyJSON, self).setUp()
616+
self.cmd = status.UpgradeCommands()
617+
policy.CONF.clear_override('policy_file', group='oslo_policy')
618+
self.data = {
619+
'rule_admin': 'True',
620+
'rule_admin2': 'is_admin:True'
621+
}
622+
self.temp_dir = self.useFixture(fixtures.TempDir())
623+
fd, self.json_file = tempfile.mkstemp(dir=self.temp_dir.path)
624+
fd, self.yaml_file = tempfile.mkstemp(dir=self.temp_dir.path)
625+
626+
with open(self.json_file, 'w') as fh:
627+
jsonutils.dump(self.data, fh)
628+
with open(self.yaml_file, 'w') as fh:
629+
yaml.dump(self.data, fh)
630+
631+
original_search_dirs = cfg._search_dirs
632+
633+
def fake_search_dirs(dirs, name):
634+
dirs.append(self.temp_dir.path)
635+
return original_search_dirs(dirs, name)
636+
637+
self.stub_out('oslo_config.cfg._search_dirs', fake_search_dirs)
638+
639+
def test_policy_json_file_fail_upgrade(self):
640+
# Test with policy json file full path set in config.
641+
self.flags(policy_file=self.json_file, group="oslo_policy")
642+
self.assertEqual(upgradecheck.Code.FAILURE,
643+
self.cmd._check_policy_json().code)
644+
645+
def test_policy_yaml_file_pass_upgrade(self):
646+
# Test with full policy yaml file path set in config.
647+
self.flags(policy_file=self.yaml_file, group="oslo_policy")
648+
self.assertEqual(upgradecheck.Code.SUCCESS,
649+
self.cmd._check_policy_json().code)
650+
651+
def test_no_policy_file_pass_upgrade(self):
652+
# Test with no policy file exist.
653+
self.assertEqual(upgradecheck.Code.SUCCESS,
654+
self.cmd._check_policy_json().code)
655+
656+
def test_default_policy_yaml_file_pass_upgrade(self):
657+
tmpfilename = os.path.join(self.temp_dir.path, 'policy.yaml')
658+
with open(tmpfilename, 'w') as fh:
659+
yaml.dump(self.data, fh)
660+
self.assertEqual(upgradecheck.Code.SUCCESS,
661+
self.cmd._check_policy_json().code)
662+
663+
def test_old_default_policy_json_file_fail_upgrade(self):
664+
self.flags(policy_file='policy.json', group="oslo_policy")
665+
tmpfilename = os.path.join(self.temp_dir.path, 'policy.json')
666+
with open(tmpfilename, 'w') as fh:
667+
jsonutils.dump(self.data, fh)
668+
self.assertEqual(upgradecheck.Code.FAILURE,
669+
self.cmd._check_policy_json().code)

nova/tests/unit/test_policy.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717

1818
import os.path
1919

20+
import fixtures
2021
import mock
22+
from oslo_config import cfg
2123
from oslo_policy import policy as oslo_policy
2224
from oslo_serialization import jsonutils
2325
import requests_mock
26+
import yaml
2427

2528
from nova import context
2629
from nova import exception
@@ -572,3 +575,70 @@ def test_rule_missing(self):
572575
self.system_reader_or_owner_rules +
573576
self.allow_nobody_rules + special_rules)
574577
self.assertEqual(set([]), result)
578+
579+
580+
class PickPolicyFileTestCase(test.NoDBTestCase):
581+
582+
def setUp(self):
583+
super(PickPolicyFileTestCase, self).setUp()
584+
self.data = {
585+
'rule_admin': 'True',
586+
'rule_admin2': 'is_admin:True'
587+
}
588+
policy.CONF.clear_override('policy_file', group='oslo_policy')
589+
self.tmpdir = self.useFixture(fixtures.TempDir())
590+
original_search_dirs = cfg._search_dirs
591+
592+
def fake_search_dirs(dirs, name):
593+
dirs.append(self.tmpdir.path)
594+
return original_search_dirs(dirs, name)
595+
596+
self.stub_out('oslo_config.cfg._search_dirs', fake_search_dirs)
597+
598+
def test_non_config_policy_file(self):
599+
tmpfilename = 'nova-policy.yaml'
600+
self.flags(policy_file=tmpfilename, group='oslo_policy')
601+
selected_policy_file = policy.pick_policy_file(
602+
policy_file='non-config-file')
603+
self.assertEqual(policy.CONF.oslo_policy.policy_file, tmpfilename)
604+
self.assertEqual(selected_policy_file, 'non-config-file')
605+
606+
def test_overridden_policy_file(self):
607+
tmpfilename = 'nova-policy.yaml'
608+
self.flags(policy_file=tmpfilename, group='oslo_policy')
609+
selected_policy_file = policy.pick_policy_file(policy_file=None)
610+
self.assertEqual(policy.CONF.oslo_policy.policy_file, tmpfilename)
611+
self.assertEqual(selected_policy_file, tmpfilename)
612+
613+
def test_only_new_default_policy_file_exist(self):
614+
tmpfilename = os.path.join(self.tmpdir.path, 'policy.yaml')
615+
with open(tmpfilename, 'w') as fh:
616+
yaml.dump(self.data, fh)
617+
618+
selected_policy_file = policy.pick_policy_file(policy_file=None)
619+
self.assertEqual(policy.CONF.oslo_policy.policy_file, 'policy.yaml')
620+
self.assertEqual(selected_policy_file, 'policy.yaml')
621+
622+
@mock.patch.object(policy.CONF, 'get_location')
623+
def test_only_old_default_policy_file_exist(self, mock_get):
624+
mock_get.return_value = cfg.LocationInfo(cfg.Locations.set_default,
625+
'None')
626+
tmpfilename = os.path.join(self.tmpdir.path, 'policy.json')
627+
with open(tmpfilename, 'w') as fh:
628+
jsonutils.dump(self.data, fh)
629+
630+
selected_policy_file = policy.pick_policy_file(policy_file=None)
631+
self.assertEqual(policy.CONF.oslo_policy.policy_file, 'policy.yaml')
632+
self.assertEqual(selected_policy_file, 'policy.json')
633+
634+
def test_both_default_policy_file_exist(self):
635+
tmpfilename1 = os.path.join(self.tmpdir.path, 'policy.json')
636+
with open(tmpfilename1, 'w') as fh:
637+
jsonutils.dump(self.data, fh)
638+
tmpfilename2 = os.path.join(self.tmpdir.path, 'policy.yaml')
639+
with open(tmpfilename2, 'w') as fh:
640+
yaml.dump(self.data, fh)
641+
642+
selected_policy_file = policy.pick_policy_file(policy_file=None)
643+
self.assertEqual(policy.CONF.oslo_policy.policy_file, 'policy.yaml')
644+
self.assertEqual(selected_policy_file, 'policy.yaml')
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
upgrade:
3+
- |
4+
The default value of ``[oslo_policy] policy_file`` config option has been
5+
changed from ``policy.json``
6+
to ``policy.yaml``. Nova policy new defaults since 21.0.0 and current
7+
default value of ``[oslo_policy] policy_file`` config option (``policy.json``)
8+
does not work when ``policy.json`` is generated by
9+
`oslopolicy-sample-generator <https://docs.openstack.org/oslo.policy/latest/cli/oslopolicy-sample-generator.html>`_ tool.
10+
Refer to `bug 1875418 <https://bugs.launchpad.net/nova/+bug/1875418>`_
11+
for more details.
12+
Also check `oslopolicy-convert-json-to-yaml <https://docs.openstack.org/oslo.policy/latest/cli/oslopolicy-convert-json-to-yaml.html>`_
13+
tool to convert the JSON to YAML formatted policy file in
14+
backward compatible way.
15+
fixes:
16+
- |
17+
Bug `1875418 <https://bugs.launchpad.net/nova/+bug/1875418>`_ is fixed
18+
by changing the default value of ``[oslo_policy] policy_file`` config
19+
option to YAML format.

0 commit comments

Comments
 (0)