Skip to content

Commit fdcb1e3

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Add nova-status upgrade check and reno for policy new defaults"
2 parents d078ecc + d4af91f commit fdcb1e3

File tree

5 files changed

+163
-0
lines changed

5 files changed

+163
-0
lines changed

doc/source/cli/nova-status.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ Upgrade
143143
**21.0.0 (Ussuri)**
144144
* Checks for the Placement API are modified to require version 1.35.
145145

146+
**21.0.0 (Ussuri)**
147+
148+
* Checks for the policy files are not automatically overwritten with
149+
new defaults.
150+
146151
See Also
147152
========
148153

doc/source/install/verify.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,7 @@ Verify operation of the Compute service.
123123
| Result: Success |
124124
| Details: None |
125125
+--------------------------------------------------------------------+
126+
| Check: Policy Scope-based Defaults |
127+
| Result: Success |
128+
| Details: None |
129+
+--------------------------------------------------------------------+

nova/cmd/status.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
from nova import exception
4141
from nova.i18n import _
4242
from nova.objects import cell_mapping as cell_mapping_obj
43+
from nova import policy
4344
from nova import utils
4445
from nova import version
4546
from nova.volume import cinder
@@ -346,6 +347,70 @@ def _check_cinder(self):
346347
six.text_type(ex))
347348
return upgradecheck.Result(upgradecheck.Code.SUCCESS)
348349

350+
def _check_policy(self):
351+
"""Checks to see if policy file is overwritten with the new
352+
defaults.
353+
"""
354+
msg = _("Your policy file contains rules which examine token scope, "
355+
"which may be due to generation with the new defaults. "
356+
"If that is done intentionally to migrate to the new rule "
357+
"format, then you are required to enable the flag "
358+
"'oslo_policy.enforce_scope=True' and educate end users on "
359+
"how to request scoped tokens from Keystone. Another easy "
360+
"and recommended way for you to achieve the same is via two "
361+
"flags, 'oslo_policy.enforce_scope=True' and "
362+
"'oslo_policy.enforce_new_defaults=True' and avoid "
363+
"overwriting the file. Please refer to this document to "
364+
"know the complete migration steps: "
365+
"https://docs.openstack.org/nova/latest/configuration"
366+
"/policy-concepts.html. If you did not intend to migrate "
367+
"to new defaults in this upgrade, then with your current "
368+
"policy file the scope checking rule will fail. A possible "
369+
"reason for such a policy file is that you generated it with "
370+
"'oslopolicy-sample-generator' in json format. "
371+
"Three ways to fix this until you are ready to migrate to "
372+
"scoped policies: 1. Generate the policy file with "
373+
"'oslopolicy-sample-generator' in yaml format, keep "
374+
"the generated content commented out, and update "
375+
"the generated policy.yaml location in "
376+
"``oslo_policy.policy_file``. "
377+
"2. Use a pre-existing sample config file from the Train "
378+
"release. 3. Use an empty or non-existent file to take all "
379+
"the defaults.")
380+
rule = "system_admin_api"
381+
rule_new_default = "role:admin and system_scope:all"
382+
status = upgradecheck.Result(upgradecheck.Code.SUCCESS)
383+
# NOTE(gmann): Initialise the policy if it not initialized.
384+
# We need policy enforcer with all the rules loaded to check
385+
# their value with defaults.
386+
try:
387+
if policy._ENFORCER is None:
388+
policy.init(suppress_deprecation_warnings=True)
389+
390+
# For safer side, recheck that the enforcer is available before
391+
# upgrade checks. If something is wrong on oslo side and enforcer
392+
# is still not available the return warning to avoid any false
393+
# result.
394+
if policy._ENFORCER is not None:
395+
current_rule = str(policy._ENFORCER.rules[rule]).strip("()")
396+
if (current_rule == rule_new_default and
397+
not CONF.oslo_policy.enforce_scope):
398+
status = upgradecheck.Result(upgradecheck.Code.WARNING,
399+
msg)
400+
else:
401+
status = upgradecheck.Result(
402+
upgradecheck.Code.WARNING,
403+
_('Policy is not initialized to check the policy rules'))
404+
except Exception as ex:
405+
status = upgradecheck.Result(
406+
upgradecheck.Code.WARNING,
407+
_('Unable to perform policy checks due to error: %s') %
408+
six.text_type(ex))
409+
# reset the policy state so that it can be initialized from fresh if
410+
# operator changes policy file after running this upgrade checks.
411+
policy.reset()
412+
return status
413+
349414
# The format of the check functions is to return an upgradecheck.Result
350415
# object with the appropriate upgradecheck.Code and details set. If the
351416
# check hits warnings or failures then those should be stored in the
@@ -362,6 +427,8 @@ def _check_cinder(self):
362427
(_('Ironic Flavor Migration'), _check_ironic_flavor_migration),
363428
# Added in Train
364429
(_('Cinder API'), _check_cinder),
430+
# Added in Ussuri
431+
(_('Policy Scope-based Defaults'), _check_policy),
365432
)
366433

367434

nova/tests/unit/cmd/test_status.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@
3939
# NOTE(mriedem): We only use objects as a convenience to populate the database
4040
# in the tests, we don't use them in the actual CLI.
4141
from nova import objects
42+
from nova import policy
4243
from nova import test
4344
from nova.tests import fixtures as nova_fixtures
45+
from nova.tests.unit import policy_fixture
4446

4547

4648
CONF = nova.conf.CONF
@@ -546,3 +548,57 @@ def test_microversion_available(self, mock_version_check):
546548
result = self.cmd._check_cinder()
547549
mock_version_check.assert_called_once()
548550
self.assertEqual(upgradecheck.Code.SUCCESS, result.code)
551+
552+
553+
class TestUpgradeCheckPolicy(test.NoDBTestCase):
554+
555+
new_default_status = upgradecheck.Code.WARNING
556+
557+
def setUp(self):
558+
super(TestUpgradeCheckPolicy, self).setUp()
559+
self.cmd = status.UpgradeCommands()
560+
self.rule_name = "system_admin_api"
561+
562+
def tearDown(self):
563+
super(TestUpgradeCheckPolicy, self).tearDown()
564+
# Check if policy is reset back after the upgrade check
565+
self.assertIsNone(policy._ENFORCER)
566+
567+
def test_policy_rule_with_new_defaults(self):
568+
new_default = "role:admin and system_scope:all"
569+
rule = {self.rule_name: new_default}
570+
self.policy.set_rules(rule, overwrite=False)
571+
self.assertEqual(self.new_default_status,
572+
self.cmd._check_policy().code)
573+
574+
def test_policy_rule_with_old_defaults(self):
575+
new_default = "is_admin:True"
576+
rule = {self.rule_name: new_default}
577+
self.policy.set_rules(rule, overwrite=False)
578+
579+
self.assertEqual(upgradecheck.Code.SUCCESS,
580+
self.cmd._check_policy().code)
581+
582+
def test_policy_rule_with_both_defaults(self):
583+
new_default = "(role:admin and system_scope:all) or is_admin:True"
584+
rule = {self.rule_name: new_default}
585+
self.policy.set_rules(rule, overwrite=False)
586+
587+
self.assertEqual(upgradecheck.Code.SUCCESS,
588+
self.cmd._check_policy().code)
589+
590+
def test_policy_checks_with_fresh_init_and_no_policy_override(self):
591+
self.policy = self.useFixture(policy_fixture.OverridePolicyFixture(
592+
rules_in_file={}))
593+
policy.reset()
594+
self.assertEqual(upgradecheck.Code.SUCCESS,
595+
self.cmd._check_policy().code)
596+
597+
598+
class TestUpgradeCheckPolicyEnableScope(TestUpgradeCheckPolicy):
599+
600+
new_default_status = upgradecheck.Code.SUCCESS
601+
602+
def setUp(self):
603+
super(TestUpgradeCheckPolicyEnableScope, self).setUp()
604+
self.flags(enforce_scope=True, group="oslo_policy")
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
upgrade:
3+
- |
4+
Nova policies implemented the ``scope_type`` and new defaults
5+
provided by keystone. Old defaults are deprecated and still work
6+
if rules are not overridden in the policy file. If you don't override
7+
any policies at all, then you don't need to do anything different until the
8+
W release when old deprecated rules are removed and tokens need to be
9+
scoped to work with new defaults and scope of policies. For migration
10+
to new policies you can refer to `this document
11+
<https://docs.openstack.org/nova/latest/configuration/policy-concepts.html#migration-plan>`_.
12+
13+
If you are overwriting the policy rules (all or some of them) in the policy
14+
file with new default values or any new value that requires scoped tokens,
15+
then non-scoped tokens will not work. Also if you generate the policy
16+
file with 'oslopolicy-sample-generator' json format or any other tool,
17+
you will get rules defaulted in the new format, which examines the token
18+
scope. Unless you turn on ``oslo_policy.enforce_scope``, scope-checking
19+
rules will fail. Thus, be sure to enable ``oslo_policy.enforce_scope`` and
20+
`educate <https://docs.openstack.org/nova/latest/configuration/policy-concepts.html>`_
21+
end users on how to request scoped tokens from Keystone, or
22+
use a pre-existing sample config file from the Train release until you are
23+
ready to migrate to scoped policies. Another way is to generate the policy
24+
file in yaml format as described `here
25+
<https://docs.openstack.org/oslo.policy/latest/cli/index.html#oslopolicy-policy-generator>`_
26+
and update the policy.yaml location in ``oslo_policy.policy_file``.
27+
28+
For more background about the possible problem, check `this bug
29+
<https://bugs.launchpad.net/nova/+bug/1875418>`_.
30+
A upgrade check has been added to the ``nova-status upgrade check``
31+
command for this.

0 commit comments

Comments
 (0)