Skip to content

Commit 8c12eae

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Migrate default policy file from JSON to YAML"
2 parents 7db4c64 + fe545db commit 8c12eae

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)