Enable new defaults and scope checks by default
As discussed in PTG, we need to test the new RBAC in the integrated gate and accordingly enable the new defaults and scope check by default. A new integrated testing job has been added and results show that the new defaults and scope checks are working fine. During testing, we found a few bugs in neutron policies but all are fixed now. enforce_scope and enforce_new_defaults are oslo policy config options but they are per service level and the default value can be overridden. Oslo policy 3.11.0 version allows to override the default value for these config options[1] so upgrading the oslo policy version in requirements.txt Depends-On: https://review.opendev.org/c/openstack/devstack/+/869781 Depends-On: https://review.opendev.org/c/openstack/placement/+/869525 [1] https://github.com/openstack/oslo.policy/blob/3.11.0/oslo_policy/opts.py#L125 Change-Id: I977b2daedf880229c8d364ca011f2ea965b86e3a
This commit is contained in:
parent
5e5b6751d3
commit
d97af33c06
34
.zuul.yaml
34
.zuul.yaml
@ -665,6 +665,36 @@
|
|||||||
parent: tempest-integrated-compute
|
parent: tempest-integrated-compute
|
||||||
nodeset: openstack-single-node-focal
|
nodeset: openstack-single-node-focal
|
||||||
|
|
||||||
|
# TODO(gmann): Remove this jobs once all the required services for intergrate
|
||||||
|
# compute gate (Cinder, Glance, Neutron) by default enable scope and new
|
||||||
|
# defaults which means all the nova jobs will be tested with new RBAC in
|
||||||
|
# integrated way and we do not need this separate job.
|
||||||
|
- job:
|
||||||
|
name: tempest-integrated-compute-enforce-scope-new-defaults
|
||||||
|
parent: tempest-integrated-compute
|
||||||
|
description: |
|
||||||
|
This job runs the Tempest tests with scope and new defaults enabled
|
||||||
|
for Nova, Neutron, Glance, and Cinder services.
|
||||||
|
# TODO (gmann): There were few fixes in neutron and neutron-lib for the
|
||||||
|
# RBAC but they are not yet released so we need to add both projcts as
|
||||||
|
# the required-projects. Those can be removed once new version of neutron
|
||||||
|
# and neutron-lib is released.
|
||||||
|
required-projects:
|
||||||
|
- openstack/neutron
|
||||||
|
- openstack/neutron-lib
|
||||||
|
vars:
|
||||||
|
devstack_localrc:
|
||||||
|
# Enabeling the scope and new defaults for services implemented it.
|
||||||
|
# NOTE (gmann): We need to keep keystone scope check disable as
|
||||||
|
# services (except ironic) does not support the system scope and
|
||||||
|
# they need keystone to continue working with project scope. Until
|
||||||
|
# Keystone policies are changed to work for project scoped also, we
|
||||||
|
# need to keep scope check disable for keystone.
|
||||||
|
NOVA_ENFORCE_SCOPE: true
|
||||||
|
CINDER_ENFORCE_SCOPE: true
|
||||||
|
GLANCE_ENFORCE_SCOPE: true
|
||||||
|
NEUTRON_ENFORCE_SCOPE: true
|
||||||
|
|
||||||
- project:
|
- project:
|
||||||
# Please try to keep the list of job names sorted alphabetically.
|
# Please try to keep the list of job names sorted alphabetically.
|
||||||
templates:
|
templates:
|
||||||
@ -723,6 +753,8 @@
|
|||||||
- ^tox.ini$
|
- ^tox.ini$
|
||||||
- tempest-integrated-compute-ubuntu-focal:
|
- tempest-integrated-compute-ubuntu-focal:
|
||||||
irrelevant-files: *policies-irrelevant-files
|
irrelevant-files: *policies-irrelevant-files
|
||||||
|
- tempest-integrated-compute-enforce-scope-new-defaults:
|
||||||
|
irrelevant-files: *policies-irrelevant-files
|
||||||
- grenade-skip-level:
|
- grenade-skip-level:
|
||||||
irrelevant-files: *policies-irrelevant-files
|
irrelevant-files: *policies-irrelevant-files
|
||||||
- nova-grenade-multinode:
|
- nova-grenade-multinode:
|
||||||
@ -758,6 +790,8 @@
|
|||||||
irrelevant-files: *policies-irrelevant-files
|
irrelevant-files: *policies-irrelevant-files
|
||||||
- tempest-integrated-compute-ubuntu-focal:
|
- tempest-integrated-compute-ubuntu-focal:
|
||||||
irrelevant-files: *policies-irrelevant-files
|
irrelevant-files: *policies-irrelevant-files
|
||||||
|
- tempest-integrated-compute-enforce-scope-new-defaults:
|
||||||
|
irrelevant-files: *policies-irrelevant-files
|
||||||
- nova-grenade-multinode:
|
- nova-grenade-multinode:
|
||||||
irrelevant-files: *policies-irrelevant-files
|
irrelevant-files: *policies-irrelevant-files
|
||||||
- tempest-ipv6-only:
|
- tempest-ipv6-only:
|
||||||
|
@ -41,11 +41,15 @@ USER_BASED_RESOURCES = ['os-keypairs']
|
|||||||
saved_file_rules = []
|
saved_file_rules = []
|
||||||
KEY_EXPR = re.compile(r'%\((\w+)\)s')
|
KEY_EXPR = re.compile(r'%\((\w+)\)s')
|
||||||
|
|
||||||
# TODO(gmann): Remove setting the default value of config policy_file
|
# TODO(gmann): Remove overriding the default value of config options
|
||||||
# once oslo_policy change the default value to 'policy.yaml'.
|
# 'policy_file', 'enforce_scope', and 'enforce_new_defaults' once
|
||||||
# https://github.com/openstack/oslo.policy/blob/a626ad12fe5a3abd49d70e3e5b95589d279ab578/oslo_policy/opts.py#L49
|
# oslo_policy change their default value to what is overridden here.
|
||||||
DEFAULT_POLICY_FILE = 'policy.yaml'
|
DEFAULT_POLICY_FILE = 'policy.yaml'
|
||||||
opts.set_defaults(cfg.CONF, DEFAULT_POLICY_FILE)
|
opts.set_defaults(
|
||||||
|
cfg.CONF,
|
||||||
|
DEFAULT_POLICY_FILE,
|
||||||
|
enforce_scope=True,
|
||||||
|
enforce_new_defaults=True)
|
||||||
|
|
||||||
|
|
||||||
def reset():
|
def reset():
|
||||||
|
@ -87,7 +87,8 @@ class ServerGroupTestV21(test.NoDBTestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(ServerGroupTestV21, self).setUp()
|
super(ServerGroupTestV21, self).setUp()
|
||||||
self._setup_controller()
|
self._setup_controller()
|
||||||
self.req = fakes.HTTPRequest.blank('')
|
self.member_req = fakes.HTTPRequest.member_req('')
|
||||||
|
self.reader_req = fakes.HTTPRequest.reader_req('')
|
||||||
self.admin_req = fakes.HTTPRequest.blank('', use_admin_context=True)
|
self.admin_req = fakes.HTTPRequest.blank('', use_admin_context=True)
|
||||||
self.foo_req = fakes.HTTPRequest.blank('', project_id='foo')
|
self.foo_req = fakes.HTTPRequest.blank('', project_id='foo')
|
||||||
self.policy = self.useFixture(fixtures.RealPolicyFixture())
|
self.policy = self.useFixture(fixtures.RealPolicyFixture())
|
||||||
@ -114,20 +115,20 @@ class ServerGroupTestV21(test.NoDBTestCase):
|
|||||||
def test_create_server_group_with_no_policies(self):
|
def test_create_server_group_with_no_policies(self):
|
||||||
sgroup = server_group_template()
|
sgroup = server_group_template()
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
self.req, body={'server_group': sgroup})
|
self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
def _create_server_group_normal(self, policies=None, policy=None,
|
def _create_server_group_normal(self, policies=None, policy=None,
|
||||||
rules=None):
|
rules=None):
|
||||||
sgroup = server_group_template()
|
sgroup = server_group_template()
|
||||||
sgroup['policies'] = policies
|
sgroup['policies'] = policies
|
||||||
res_dict = self.controller.create(self.req,
|
res_dict = self.controller.create(self.member_req,
|
||||||
body={'server_group': sgroup})
|
body={'server_group': sgroup})
|
||||||
self.assertEqual(res_dict['server_group']['name'], 'test')
|
self.assertEqual(res_dict['server_group']['name'], 'test')
|
||||||
self.assertTrue(uuidutils.is_uuid_like(res_dict['server_group']['id']))
|
self.assertTrue(uuidutils.is_uuid_like(res_dict['server_group']['id']))
|
||||||
self.assertEqual(res_dict['server_group']['policies'], policies)
|
self.assertEqual(res_dict['server_group']['policies'], policies)
|
||||||
|
|
||||||
def test_create_server_group_with_new_policy_before_264(self):
|
def test_create_server_group_with_new_policy_before_264(self):
|
||||||
req = fakes.HTTPRequest.blank('', version='2.63')
|
req = fakes.HTTPRequest.member_req('', version='2.63')
|
||||||
policy = 'anti-affinity'
|
policy = 'anti-affinity'
|
||||||
rules = {'max_server_per_host': 3}
|
rules = {'max_server_per_host': 3}
|
||||||
# 'policy' isn't an acceptable request key before 2.64
|
# 'policy' isn't an acceptable request key before 2.64
|
||||||
@ -162,7 +163,7 @@ class ServerGroupTestV21(test.NoDBTestCase):
|
|||||||
self.controller.create(self.admin_req, body={'server_group': sgroup})
|
self.controller.create(self.admin_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
# test as non-admin
|
# test as non-admin
|
||||||
self.controller.create(self.req, body={'server_group': sgroup})
|
self.controller.create(self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
def _create_instance(self, ctx, cell):
|
def _create_instance(self, ctx, cell):
|
||||||
with context.target_cell(ctx, cell) as cctx:
|
with context.target_cell(ctx, cell) as cctx:
|
||||||
@ -289,7 +290,7 @@ class ServerGroupTestV21(test.NoDBTestCase):
|
|||||||
path = path or '/os-server-groups?all_projects=True'
|
path = path or '/os-server-groups?all_projects=True'
|
||||||
if limited:
|
if limited:
|
||||||
path += limited
|
path += limited
|
||||||
req = fakes.HTTPRequest.blank(path, version=api_version)
|
reader_req = fakes.HTTPRequest.reader_req(path, version=api_version)
|
||||||
admin_req = fakes.HTTPRequest.blank(path, use_admin_context=True,
|
admin_req = fakes.HTTPRequest.blank(path, use_admin_context=True,
|
||||||
version=api_version)
|
version=api_version)
|
||||||
|
|
||||||
@ -298,7 +299,7 @@ class ServerGroupTestV21(test.NoDBTestCase):
|
|||||||
self.assertEqual(all, res_dict)
|
self.assertEqual(all, res_dict)
|
||||||
|
|
||||||
# test as non-admin
|
# test as non-admin
|
||||||
res_dict = self.controller.index(req)
|
res_dict = self.controller.index(reader_req)
|
||||||
self.assertEqual(tenant_specific, res_dict)
|
self.assertEqual(tenant_specific, res_dict)
|
||||||
|
|
||||||
@mock.patch('nova.objects.InstanceGroupList.get_by_project_id')
|
@mock.patch('nova.objects.InstanceGroupList.get_by_project_id')
|
||||||
@ -347,25 +348,27 @@ class ServerGroupTestV21(test.NoDBTestCase):
|
|||||||
return_get_by_project = return_server_groups()
|
return_get_by_project = return_server_groups()
|
||||||
mock_get_by_project.return_value = return_get_by_project
|
mock_get_by_project.return_value = return_get_by_project
|
||||||
path = '/os-server-groups'
|
path = '/os-server-groups'
|
||||||
req = fakes.HTTPRequest.blank(path, version=api_version)
|
req = fakes.HTTPRequest.reader_req(path, version=api_version)
|
||||||
res_dict = self.controller.index(req)
|
res_dict = self.controller.index(req)
|
||||||
self.assertEqual(expected, res_dict)
|
self.assertEqual(expected, res_dict)
|
||||||
|
|
||||||
def test_display_members(self):
|
def test_display_members(self):
|
||||||
ctx = context.RequestContext('fake_user', fakes.FAKE_PROJECT_ID)
|
ctx = context.RequestContext('fake_user', fakes.FAKE_PROJECT_ID)
|
||||||
(ig_uuid, instances, members) = self._create_groups_and_instances(ctx)
|
(ig_uuid, instances, members) = self._create_groups_and_instances(ctx)
|
||||||
res_dict = self.controller.show(self.req, ig_uuid)
|
res_dict = self.controller.show(self.reader_req, ig_uuid)
|
||||||
result_members = res_dict['server_group']['members']
|
result_members = res_dict['server_group']['members']
|
||||||
self.assertEqual(3, len(result_members))
|
self.assertEqual(3, len(result_members))
|
||||||
for member in members:
|
for member in members:
|
||||||
self.assertIn(member, result_members)
|
self.assertIn(member, result_members)
|
||||||
|
|
||||||
def test_display_members_with_nonexistent_group(self):
|
def test_display_members_with_nonexistent_group(self):
|
||||||
self.assertRaises(webob.exc.HTTPNotFound,
|
self.assertRaises(
|
||||||
self.controller.show, self.req, uuidsentinel.group)
|
webob.exc.HTTPNotFound,
|
||||||
|
self.controller.show, self.reader_req, uuidsentinel.group)
|
||||||
|
|
||||||
def test_display_active_members_only(self):
|
def test_display_active_members_only(self):
|
||||||
ctx = context.RequestContext('fake_user', fakes.FAKE_PROJECT_ID)
|
ctx = context.RequestContext('fake_user', fakes.FAKE_PROJECT_ID,
|
||||||
|
roles=['member', 'reader'])
|
||||||
(ig_uuid, instances, members) = self._create_groups_and_instances(ctx)
|
(ig_uuid, instances, members) = self._create_groups_and_instances(ctx)
|
||||||
|
|
||||||
# delete an instance
|
# delete an instance
|
||||||
@ -379,7 +382,7 @@ class ServerGroupTestV21(test.NoDBTestCase):
|
|||||||
self.assertRaises(exception.InstanceNotFound,
|
self.assertRaises(exception.InstanceNotFound,
|
||||||
objects.Instance.get_by_uuid,
|
objects.Instance.get_by_uuid,
|
||||||
ctx, instances[1].uuid)
|
ctx, instances[1].uuid)
|
||||||
res_dict = self.controller.show(self.req, ig_uuid)
|
res_dict = self.controller.show(self.reader_req, ig_uuid)
|
||||||
result_members = res_dict['server_group']['members']
|
result_members = res_dict['server_group']['members']
|
||||||
# check that only the active instance is displayed
|
# check that only the active instance is displayed
|
||||||
self.assertEqual(2, len(result_members))
|
self.assertEqual(2, len(result_members))
|
||||||
@ -393,7 +396,7 @@ class ServerGroupTestV21(test.NoDBTestCase):
|
|||||||
self.controller.show(self.admin_req, ig_uuid)
|
self.controller.show(self.admin_req, ig_uuid)
|
||||||
|
|
||||||
# test as non-admin, same project
|
# test as non-admin, same project
|
||||||
self.controller.show(self.req, ig_uuid)
|
self.controller.show(self.reader_req, ig_uuid)
|
||||||
|
|
||||||
# test as non-admin, different project
|
# test as non-admin, different project
|
||||||
self.assertRaises(webob.exc.HTTPNotFound,
|
self.assertRaises(webob.exc.HTTPNotFound,
|
||||||
@ -406,7 +409,7 @@ class ServerGroupTestV21(test.NoDBTestCase):
|
|||||||
|
|
||||||
sgroup = server_group_template(name='good* $%name',
|
sgroup = server_group_template(name='good* $%name',
|
||||||
policies=['affinity'])
|
policies=['affinity'])
|
||||||
res_dict = self.controller.create(self.req,
|
res_dict = self.controller.create(self.member_req,
|
||||||
body={'server_group': sgroup})
|
body={'server_group': sgroup})
|
||||||
self.assertEqual(res_dict['server_group']['name'], 'good* $%name')
|
self.assertEqual(res_dict['server_group']['name'], 'good* $%name')
|
||||||
|
|
||||||
@ -414,99 +417,99 @@ class ServerGroupTestV21(test.NoDBTestCase):
|
|||||||
# blank name
|
# blank name
|
||||||
sgroup = server_group_template(name='', policies=['test_policy'])
|
sgroup = server_group_template(name='', policies=['test_policy'])
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
self.req, body={'server_group': sgroup})
|
self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
# name with length 256
|
# name with length 256
|
||||||
sgroup = server_group_template(name='1234567890' * 26,
|
sgroup = server_group_template(name='1234567890' * 26,
|
||||||
policies=['test_policy'])
|
policies=['test_policy'])
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
self.req, body={'server_group': sgroup})
|
self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
# non-string name
|
# non-string name
|
||||||
sgroup = server_group_template(name=12, policies=['test_policy'])
|
sgroup = server_group_template(name=12, policies=['test_policy'])
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
self.req, body={'server_group': sgroup})
|
self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
# name with leading spaces
|
# name with leading spaces
|
||||||
sgroup = server_group_template(name=' leading spaces',
|
sgroup = server_group_template(name=' leading spaces',
|
||||||
policies=['test_policy'])
|
policies=['test_policy'])
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
self.req, body={'server_group': sgroup})
|
self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
# name with trailing spaces
|
# name with trailing spaces
|
||||||
sgroup = server_group_template(name='trailing space ',
|
sgroup = server_group_template(name='trailing space ',
|
||||||
policies=['test_policy'])
|
policies=['test_policy'])
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
self.req, body={'server_group': sgroup})
|
self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
# name with all spaces
|
# name with all spaces
|
||||||
sgroup = server_group_template(name=' ',
|
sgroup = server_group_template(name=' ',
|
||||||
policies=['test_policy'])
|
policies=['test_policy'])
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
self.req, body={'server_group': sgroup})
|
self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
# name with unprintable character
|
# name with unprintable character
|
||||||
sgroup = server_group_template(name='bad\x00name',
|
sgroup = server_group_template(name='bad\x00name',
|
||||||
policies=['test_policy'])
|
policies=['test_policy'])
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
self.req, body={'server_group': sgroup})
|
self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
# name with out of range char U0001F4A9
|
# name with out of range char U0001F4A9
|
||||||
sgroup = server_group_template(name=u"\U0001F4A9",
|
sgroup = server_group_template(name=u"\U0001F4A9",
|
||||||
policies=['affinity'])
|
policies=['affinity'])
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
self.req, body={'server_group': sgroup})
|
self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
def test_create_server_group_with_illegal_policies(self):
|
def test_create_server_group_with_illegal_policies(self):
|
||||||
# blank policy
|
# blank policy
|
||||||
sgroup = server_group_template(name='fake-name', policies='')
|
sgroup = server_group_template(name='fake-name', policies='')
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
self.req, body={'server_group': sgroup})
|
self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
# policy as integer
|
# policy as integer
|
||||||
sgroup = server_group_template(name='fake-name', policies=7)
|
sgroup = server_group_template(name='fake-name', policies=7)
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
self.req, body={'server_group': sgroup})
|
self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
# policy as string
|
# policy as string
|
||||||
sgroup = server_group_template(name='fake-name', policies='invalid')
|
sgroup = server_group_template(name='fake-name', policies='invalid')
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
self.req, body={'server_group': sgroup})
|
self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
# policy as None
|
# policy as None
|
||||||
sgroup = server_group_template(name='fake-name', policies=None)
|
sgroup = server_group_template(name='fake-name', policies=None)
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
self.req, body={'server_group': sgroup})
|
self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
def test_create_server_group_conflicting_policies(self):
|
def test_create_server_group_conflicting_policies(self):
|
||||||
sgroup = server_group_template()
|
sgroup = server_group_template()
|
||||||
policies = ['anti-affinity', 'affinity']
|
policies = ['anti-affinity', 'affinity']
|
||||||
sgroup['policies'] = policies
|
sgroup['policies'] = policies
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
self.req, body={'server_group': sgroup})
|
self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
def test_create_server_group_with_duplicate_policies(self):
|
def test_create_server_group_with_duplicate_policies(self):
|
||||||
sgroup = server_group_template()
|
sgroup = server_group_template()
|
||||||
policies = ['affinity', 'affinity']
|
policies = ['affinity', 'affinity']
|
||||||
sgroup['policies'] = policies
|
sgroup['policies'] = policies
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
self.req, body={'server_group': sgroup})
|
self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
def test_create_server_group_not_supported(self):
|
def test_create_server_group_not_supported(self):
|
||||||
sgroup = server_group_template()
|
sgroup = server_group_template()
|
||||||
policies = ['storage-affinity', 'anti-affinity', 'rack-affinity']
|
policies = ['storage-affinity', 'anti-affinity', 'rack-affinity']
|
||||||
sgroup['policies'] = policies
|
sgroup['policies'] = policies
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
self.req, body={'server_group': sgroup})
|
self.member_req, body={'server_group': sgroup})
|
||||||
|
|
||||||
def test_create_server_group_with_no_body(self):
|
def test_create_server_group_with_no_body(self):
|
||||||
self.assertRaises(self.validation_error,
|
self.assertRaises(self.validation_error,
|
||||||
self.controller.create, self.req, body=None)
|
self.controller.create, self.member_req, body=None)
|
||||||
|
|
||||||
def test_create_server_group_with_no_server_group(self):
|
def test_create_server_group_with_no_server_group(self):
|
||||||
body = {'no-instanceGroup': None}
|
body = {'no-instanceGroup': None}
|
||||||
self.assertRaises(self.validation_error,
|
self.assertRaises(self.validation_error,
|
||||||
self.controller.create, self.req, body=body)
|
self.controller.create, self.member_req, body=body)
|
||||||
|
|
||||||
def test_list_server_group_by_tenant(self):
|
def test_list_server_group_by_tenant(self):
|
||||||
self._test_list_server_group_by_tenant(
|
self._test_list_server_group_by_tenant(
|
||||||
@ -528,7 +531,7 @@ class ServerGroupTestV21(test.NoDBTestCase):
|
|||||||
self.controller.index(self.admin_req)
|
self.controller.index(self.admin_req)
|
||||||
|
|
||||||
# test as non-admin
|
# test as non-admin
|
||||||
self.controller.index(self.req)
|
self.controller.index(self.reader_req)
|
||||||
|
|
||||||
def test_list_server_group_multiple_param(self):
|
def test_list_server_group_multiple_param(self):
|
||||||
self._test_list_server_group(api_version=self.wsgi_api_version,
|
self._test_list_server_group(api_version=self.wsgi_api_version,
|
||||||
@ -598,7 +601,7 @@ class ServerGroupTestV21(test.NoDBTestCase):
|
|||||||
self.stub_out('nova.objects.InstanceGroup.get_by_uuid',
|
self.stub_out('nova.objects.InstanceGroup.get_by_uuid',
|
||||||
return_server_group)
|
return_server_group)
|
||||||
|
|
||||||
resp = self.controller.delete(self.req, uuidsentinel.sg1_id)
|
resp = self.controller.delete(self.member_req, uuidsentinel.sg1_id)
|
||||||
mock_destroy.assert_called_once_with()
|
mock_destroy.assert_called_once_with()
|
||||||
|
|
||||||
# NOTE: on v2.1, http status code is set as wsgi_code of API
|
# NOTE: on v2.1, http status code is set as wsgi_code of API
|
||||||
@ -611,7 +614,7 @@ class ServerGroupTestV21(test.NoDBTestCase):
|
|||||||
|
|
||||||
def test_delete_non_existing_server_group(self):
|
def test_delete_non_existing_server_group(self):
|
||||||
self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete,
|
self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete,
|
||||||
self.req, 'invalid')
|
self.member_req, 'invalid')
|
||||||
|
|
||||||
def test_delete_server_group_rbac_default(self):
|
def test_delete_server_group_rbac_default(self):
|
||||||
ctx = context.RequestContext('fake_user', fakes.FAKE_PROJECT_ID)
|
ctx = context.RequestContext('fake_user', fakes.FAKE_PROJECT_ID)
|
||||||
@ -622,7 +625,7 @@ class ServerGroupTestV21(test.NoDBTestCase):
|
|||||||
|
|
||||||
# test as non-admin
|
# test as non-admin
|
||||||
ig_uuid = self._create_groups_and_instances(ctx)[0]
|
ig_uuid = self._create_groups_and_instances(ctx)[0]
|
||||||
self.controller.delete(self.req, ig_uuid)
|
self.controller.delete(self.member_req, ig_uuid)
|
||||||
|
|
||||||
|
|
||||||
class ServerGroupTestV213(ServerGroupTestV21):
|
class ServerGroupTestV213(ServerGroupTestV21):
|
||||||
@ -649,7 +652,7 @@ class ServerGroupTestV264(ServerGroupTestV213):
|
|||||||
|
|
||||||
def _create_server_group_normal(self, policies=None, policy=None,
|
def _create_server_group_normal(self, policies=None, policy=None,
|
||||||
rules=None):
|
rules=None):
|
||||||
req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version)
|
req = fakes.HTTPRequest.member_req('', version=self.wsgi_api_version)
|
||||||
sgroup = server_group_template()
|
sgroup = server_group_template()
|
||||||
sgroup['rules'] = rules or {}
|
sgroup['rules'] = rules or {}
|
||||||
sgroup['policy'] = policy
|
sgroup['policy'] = policy
|
||||||
@ -674,7 +677,7 @@ class ServerGroupTestV264(ServerGroupTestV213):
|
|||||||
self.assertEqual(res_dict['server_group']['rules'], {})
|
self.assertEqual(res_dict['server_group']['rules'], {})
|
||||||
|
|
||||||
def _display_server_group(self, uuid):
|
def _display_server_group(self, uuid):
|
||||||
req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version)
|
req = fakes.HTTPRequest.reader_req('', version=self.wsgi_api_version)
|
||||||
group = self.controller.show(req, uuid)
|
group = self.controller.show(req, uuid)
|
||||||
return group
|
return group
|
||||||
|
|
||||||
@ -690,7 +693,7 @@ class ServerGroupTestV264(ServerGroupTestV213):
|
|||||||
self.assertEqual(res_dict['server_group']['rules'], rules)
|
self.assertEqual(res_dict['server_group']['rules'], rules)
|
||||||
|
|
||||||
def test_create_affinity_server_group_with_invalid_policy(self):
|
def test_create_affinity_server_group_with_invalid_policy(self):
|
||||||
req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version)
|
req = fakes.HTTPRequest.member_req('', version=self.wsgi_api_version)
|
||||||
sgroup = server_group_template(policy='affinity',
|
sgroup = server_group_template(policy='affinity',
|
||||||
rules={'max_server_per_host': 3})
|
rules={'max_server_per_host': 3})
|
||||||
result = self.assertRaises(webob.exc.HTTPBadRequest,
|
result = self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
@ -698,7 +701,7 @@ class ServerGroupTestV264(ServerGroupTestV213):
|
|||||||
self.assertIn("Only anti-affinity policy supports rules", str(result))
|
self.assertIn("Only anti-affinity policy supports rules", str(result))
|
||||||
|
|
||||||
def test_create_anti_affinity_server_group_with_invalid_rules(self):
|
def test_create_anti_affinity_server_group_with_invalid_rules(self):
|
||||||
req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version)
|
req = fakes.HTTPRequest.member_req('', version=self.wsgi_api_version)
|
||||||
# A negative test for key is unknown, the value is not positive
|
# A negative test for key is unknown, the value is not positive
|
||||||
# and not integer
|
# and not integer
|
||||||
invalid_rules = [{'unknown_key': '3'},
|
invalid_rules = [{'unknown_key': '3'},
|
||||||
@ -718,7 +721,7 @@ class ServerGroupTestV264(ServerGroupTestV213):
|
|||||||
return_value=32)
|
return_value=32)
|
||||||
def test_create_server_group_with_low_version_compute_service(self,
|
def test_create_server_group_with_low_version_compute_service(self,
|
||||||
mock_get_v):
|
mock_get_v):
|
||||||
req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version)
|
req = fakes.HTTPRequest.member_req('', version=self.wsgi_api_version)
|
||||||
sgroup = server_group_template(policy='anti-affinity',
|
sgroup = server_group_template(policy='anti-affinity',
|
||||||
rules={'max_server_per_host': 3})
|
rules={'max_server_per_host': 3})
|
||||||
result = self.assertRaises(
|
result = self.assertRaises(
|
||||||
@ -734,7 +737,7 @@ class ServerGroupTestV264(ServerGroupTestV213):
|
|||||||
self._create_server_group_normal(policy=policy)
|
self._create_server_group_normal(policy=policy)
|
||||||
|
|
||||||
def test_policies_since_264(self):
|
def test_policies_since_264(self):
|
||||||
req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version)
|
req = fakes.HTTPRequest.member_req('', version=self.wsgi_api_version)
|
||||||
# 'policies' isn't allowed in request >= 2.64
|
# 'policies' isn't allowed in request >= 2.64
|
||||||
sgroup = server_group_template(policies=['anti-affinity'])
|
sgroup = server_group_template(policies=['anti-affinity'])
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
@ -742,14 +745,14 @@ class ServerGroupTestV264(ServerGroupTestV213):
|
|||||||
req, body={'server_group': sgroup})
|
req, body={'server_group': sgroup})
|
||||||
|
|
||||||
def test_create_server_group_without_policy(self):
|
def test_create_server_group_without_policy(self):
|
||||||
req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version)
|
req = fakes.HTTPRequest.member_req('', version=self.wsgi_api_version)
|
||||||
# 'policy' is required request key in request >= 2.64
|
# 'policy' is required request key in request >= 2.64
|
||||||
sgroup = server_group_template()
|
sgroup = server_group_template()
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
req, body={'server_group': sgroup})
|
req, body={'server_group': sgroup})
|
||||||
|
|
||||||
def test_create_server_group_with_illegal_policies(self):
|
def test_create_server_group_with_illegal_policies(self):
|
||||||
req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version)
|
req = fakes.HTTPRequest.member_req('', version=self.wsgi_api_version)
|
||||||
# blank policy
|
# blank policy
|
||||||
sgroup = server_group_template(policy='')
|
sgroup = server_group_template(policy='')
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
@ -771,7 +774,7 @@ class ServerGroupTestV264(ServerGroupTestV213):
|
|||||||
req, body={'server_group': sgroup})
|
req, body={'server_group': sgroup})
|
||||||
|
|
||||||
def test_additional_params(self):
|
def test_additional_params(self):
|
||||||
req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version)
|
req = fakes.HTTPRequest.member_req('', version=self.wsgi_api_version)
|
||||||
sgroup = server_group_template(unknown='unknown')
|
sgroup = server_group_template(unknown='unknown')
|
||||||
self.assertRaises(self.validation_error, self.controller.create,
|
self.assertRaises(self.validation_error, self.controller.create,
|
||||||
req, body={'server_group': sgroup})
|
req, body={'server_group': sgroup})
|
||||||
@ -786,7 +789,7 @@ class ServerGroupTestV275(ServerGroupTestV264):
|
|||||||
path='/os-server-groups?dummy=False&all_projects=True')
|
path='/os-server-groups?dummy=False&all_projects=True')
|
||||||
|
|
||||||
def test_list_server_group_additional_param(self):
|
def test_list_server_group_additional_param(self):
|
||||||
req = fakes.HTTPRequest.blank('/os-server-groups?dummy=False',
|
req = fakes.HTTPRequest.reader_req('/os-server-groups?dummy=False',
|
||||||
version=self.wsgi_api_version)
|
version=self.wsgi_api_version)
|
||||||
self.assertRaises(self.validation_error, self.controller.index,
|
self.assertRaises(self.validation_error, self.controller.index,
|
||||||
req)
|
req)
|
||||||
|
@ -240,6 +240,9 @@ class HTTPRequest(os_wsgi.Request):
|
|||||||
def blank(cls, *args, **kwargs):
|
def blank(cls, *args, **kwargs):
|
||||||
defaults = {'base_url': 'http://localhost/v2'}
|
defaults = {'base_url': 'http://localhost/v2'}
|
||||||
use_admin_context = kwargs.pop('use_admin_context', False)
|
use_admin_context = kwargs.pop('use_admin_context', False)
|
||||||
|
roles = kwargs.pop('roles', [])
|
||||||
|
if use_admin_context:
|
||||||
|
roles.append('admin')
|
||||||
project_id = kwargs.pop('project_id', FAKE_PROJECT_ID)
|
project_id = kwargs.pop('project_id', FAKE_PROJECT_ID)
|
||||||
version = kwargs.pop('version', os_wsgi.DEFAULT_API_VERSION)
|
version = kwargs.pop('version', os_wsgi.DEFAULT_API_VERSION)
|
||||||
defaults.update(kwargs)
|
defaults.update(kwargs)
|
||||||
@ -247,10 +250,19 @@ class HTTPRequest(os_wsgi.Request):
|
|||||||
out.environ['nova.context'] = FakeRequestContext(
|
out.environ['nova.context'] = FakeRequestContext(
|
||||||
user_id='fake_user',
|
user_id='fake_user',
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
is_admin=use_admin_context)
|
is_admin=use_admin_context,
|
||||||
|
roles=roles)
|
||||||
out.api_version_request = api_version.APIVersionRequest(version)
|
out.api_version_request = api_version.APIVersionRequest(version)
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def member_req(cls, *args, **kwargs):
|
||||||
|
return cls.blank(*args, roles=['member', 'reader'], **kwargs)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def reader_req(cls, *args, **kwargs):
|
||||||
|
return cls.blank(*args, roles=['reader'], **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class HTTPRequestV21(HTTPRequest):
|
class HTTPRequestV21(HTTPRequest):
|
||||||
pass
|
pass
|
||||||
|
@ -128,20 +128,21 @@ class TestPolicyCheck(test.NoDBTestCase):
|
|||||||
self.assertEqual(set(expected_rules), set(passing_rules))
|
self.assertEqual(set(expected_rules), set(passing_rules))
|
||||||
|
|
||||||
def test_filter_rules_non_admin(self):
|
def test_filter_rules_non_admin(self):
|
||||||
context = nova_context.RequestContext()
|
context = nova_context.RequestContext(roles=['reader'])
|
||||||
rule_conditions = [base_policies.PROJECT_READER_OR_ADMIN]
|
rule_conditions = [base_policies.PROJECT_READER_OR_ADMIN]
|
||||||
expected_rules = [r.name for r in ia_policies.list_rules() if
|
expected_rules = [r.name for r in ia_policies.list_rules() if
|
||||||
r.check_str in rule_conditions]
|
r.check_str in rule_conditions]
|
||||||
self._check_filter_rules(context, expected_rules=expected_rules)
|
self._check_filter_rules(context, expected_rules=expected_rules)
|
||||||
|
|
||||||
def test_filter_rules_admin(self):
|
def test_filter_rules_admin(self):
|
||||||
self._check_filter_rules()
|
context = nova_context.RequestContext(roles=['admin'])
|
||||||
|
self._check_filter_rules(context)
|
||||||
|
|
||||||
def test_filter_rules_instance_non_admin(self):
|
def test_filter_rules_instance_non_admin(self):
|
||||||
db_context = nova_context.RequestContext(user_id='fake-user',
|
db_context = nova_context.RequestContext(user_id='fake-user',
|
||||||
project_id='fake-project')
|
project_id='fake-project')
|
||||||
instance = fake_instance.fake_instance_obj(db_context)
|
instance = fake_instance.fake_instance_obj(db_context)
|
||||||
context = nova_context.RequestContext()
|
context = nova_context.RequestContext(roles=['reader'])
|
||||||
expected_rules = [r.name for r in ia_policies.list_rules() if
|
expected_rules = [r.name for r in ia_policies.list_rules() if
|
||||||
r.check_str == base_policies.RULE_ANY]
|
r.check_str == base_policies.RULE_ANY]
|
||||||
self._check_filter_rules(context, instance, expected_rules)
|
self._check_filter_rules(context, instance, expected_rules)
|
||||||
@ -150,11 +151,13 @@ class TestPolicyCheck(test.NoDBTestCase):
|
|||||||
db_context = nova_context.RequestContext(user_id='fake-user',
|
db_context = nova_context.RequestContext(user_id='fake-user',
|
||||||
project_id='fake-project')
|
project_id='fake-project')
|
||||||
instance = fake_instance.fake_instance_obj(db_context)
|
instance = fake_instance.fake_instance_obj(db_context)
|
||||||
self._check_filter_rules(target=instance)
|
context = nova_context.RequestContext(roles=['admin'])
|
||||||
|
self._check_filter_rules(context, target=instance)
|
||||||
|
|
||||||
def test_filter_rules_instance_owner(self):
|
def test_filter_rules_instance_owner(self):
|
||||||
db_context = nova_context.RequestContext(user_id='fake-user',
|
db_context = nova_context.RequestContext(user_id='fake-user',
|
||||||
project_id='fake-project')
|
project_id='fake-project',
|
||||||
|
roles=['reader'])
|
||||||
instance = fake_instance.fake_instance_obj(db_context)
|
instance = fake_instance.fake_instance_obj(db_context)
|
||||||
rule_conditions = [base_policies.PROJECT_READER_OR_ADMIN]
|
rule_conditions = [base_policies.PROJECT_READER_OR_ADMIN]
|
||||||
expected_rules = [r.name for r in ia_policies.list_rules() if
|
expected_rules = [r.name for r in ia_policies.list_rules() if
|
||||||
|
@ -58,6 +58,16 @@ class BasePolicyTest(test.TestCase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(BasePolicyTest, self).setUp()
|
super(BasePolicyTest, self).setUp()
|
||||||
|
# TODO(gmann): enforce_scope and enforce_new_defaults are enabled
|
||||||
|
# by default in the code so disable them in base test class until
|
||||||
|
# we have deprecated rules and their tests. We have enforce_scope
|
||||||
|
# and no-legacy tests which are explicitly enabling scope and new
|
||||||
|
# defaults to test the new defaults and scope. In future, once
|
||||||
|
# we remove the deprecated rules, along with refactoring the unit
|
||||||
|
# tests we can remove overriding the oslo policy flags.
|
||||||
|
self.flags(enforce_scope=False, group="oslo_policy")
|
||||||
|
if not self.without_deprecated_rules:
|
||||||
|
self.flags(enforce_new_defaults=False, group="oslo_policy")
|
||||||
self.useFixture(fixtures.NeutronFixture(self))
|
self.useFixture(fixtures.NeutronFixture(self))
|
||||||
self.policy = self.useFixture(fixtures.RealPolicyFixture())
|
self.policy = self.useFixture(fixtures.RealPolicyFixture())
|
||||||
|
|
||||||
|
@ -303,10 +303,10 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(RealRolePolicyTestCase, self).setUp()
|
super(RealRolePolicyTestCase, self).setUp()
|
||||||
self.policy = self.useFixture(nova_fixtures.RealPolicyFixture())
|
self.policy = self.useFixture(nova_fixtures.RealPolicyFixture())
|
||||||
self.non_admin_context = context.RequestContext('fake', 'fake',
|
self.non_admin_context = context.RequestContext(
|
||||||
roles=['member'])
|
'fake', 'fake', roles=['member', 'reader'])
|
||||||
self.admin_context = context.RequestContext('fake', 'fake', True,
|
self.admin_context = context.RequestContext(
|
||||||
roles=['admin', 'member'])
|
'fake', 'fake', True, roles=['admin', 'member', 'reader'])
|
||||||
self.target = {}
|
self.target = {}
|
||||||
self.fake_policy = jsonutils.loads(fake_policy.policy_data)
|
self.fake_policy = jsonutils.loads(fake_policy.policy_data)
|
||||||
|
|
||||||
@ -387,6 +387,7 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
|
|||||||
"os_compute_api:os-hypervisors:search",
|
"os_compute_api:os-hypervisors:search",
|
||||||
"os_compute_api:os-hypervisors:servers",
|
"os_compute_api:os-hypervisors:servers",
|
||||||
"os_compute_api:limits:other_project",
|
"os_compute_api:limits:other_project",
|
||||||
|
"os_compute_api:os-flavor-access",
|
||||||
)
|
)
|
||||||
|
|
||||||
self.admin_or_owner_rules = (
|
self.admin_or_owner_rules = (
|
||||||
@ -440,7 +441,6 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
|
|||||||
"os_compute_api:os-remote-consoles",
|
"os_compute_api:os-remote-consoles",
|
||||||
"os_compute_api:os-deferred-delete:restore",
|
"os_compute_api:os-deferred-delete:restore",
|
||||||
"os_compute_api:os-deferred-delete:force",
|
"os_compute_api:os-deferred-delete:force",
|
||||||
"os_compute_api:os-flavor-access",
|
|
||||||
"os_compute_api:os-flavor-extra-specs:index",
|
"os_compute_api:os-flavor-extra-specs:index",
|
||||||
"os_compute_api:os-flavor-extra-specs:show",
|
"os_compute_api:os-flavor-extra-specs:show",
|
||||||
"os_compute_api:os-floating-ips:add",
|
"os_compute_api:os-floating-ips:add",
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
upgrade:
|
||||||
|
- |
|
||||||
|
The Nova service enable the API policies (RBAC) new defaults and scope by
|
||||||
|
default. The Default value of config options ``[oslo_policy] enforce_scope``
|
||||||
|
and ``[oslo_policy] oslo_policy.enforce_new_defaults`` have been changed
|
||||||
|
to ``True``.
|
||||||
|
|
||||||
|
This means if you are using system scope token to access Nova API then
|
||||||
|
the request will be failed with 403 error code. Also, new defaults will be
|
||||||
|
enforced by default. To know about the new defaults of each policy
|
||||||
|
rule, refer to the `Policy New Defaults`_. For more detail about the Nova
|
||||||
|
API policies changes, refer to `Policy Concepts`_.
|
||||||
|
|
||||||
|
If you want to disable them then modify the below config options value in
|
||||||
|
``nova.conf`` file::
|
||||||
|
|
||||||
|
[oslo_policy]
|
||||||
|
enforce_new_defaults=False
|
||||||
|
enforce_scope=False
|
||||||
|
|
||||||
|
.. _`Policy New Defaults`: https://docs.openstack.org/nova/latest/configuration/policy.html
|
||||||
|
.. _`Policy Concepts`: https://docs.openstack.org/nova/latest/configuration/policy-concepts.html
|
@ -43,7 +43,7 @@ oslo.utils>=4.12.1 # Apache-2.0
|
|||||||
oslo.db>=10.0.0 # Apache-2.0
|
oslo.db>=10.0.0 # Apache-2.0
|
||||||
oslo.rootwrap>=5.15.0 # Apache-2.0
|
oslo.rootwrap>=5.15.0 # Apache-2.0
|
||||||
oslo.messaging>=10.3.0 # Apache-2.0
|
oslo.messaging>=10.3.0 # Apache-2.0
|
||||||
oslo.policy>=3.7.0 # Apache-2.0
|
oslo.policy>=3.11.0 # Apache-2.0
|
||||||
oslo.privsep>=2.6.2 # Apache-2.0
|
oslo.privsep>=2.6.2 # Apache-2.0
|
||||||
oslo.i18n>=5.1.0 # Apache-2.0
|
oslo.i18n>=5.1.0 # Apache-2.0
|
||||||
oslo.service>=2.8.0 # Apache-2.0
|
oslo.service>=2.8.0 # Apache-2.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user