Merge "Add new default roles in hosts policies"

This commit is contained in:
Zuul 2020-08-07 17:54:25 +00:00 committed by Gerrit Code Review
commit 09ed4c21db
5 changed files with 203 additions and 35 deletions

View File

@ -71,7 +71,8 @@ class HostController(wsgi.Controller):
"""
context = req.environ['nova.context']
context.can(hosts_policies.BASE_POLICY_NAME)
context.can(hosts_policies.POLICY_NAME % 'list',
target={})
filters = {'disabled': False}
zone = req.GET.get('zone', None)
if zone:
@ -108,7 +109,8 @@ class HostController(wsgi.Controller):
return val == "enable"
context = req.environ['nova.context']
context.can(hosts_policies.BASE_POLICY_NAME)
context.can(hosts_policies.POLICY_NAME % 'update',
target={})
# See what the user wants to 'update'
status = body.get('status')
maint_mode = body.get('maintenance_mode')
@ -168,7 +170,6 @@ class HostController(wsgi.Controller):
def _host_power_action(self, req, host_name, action):
"""Reboots, shuts down or powers up the host."""
context = req.environ['nova.context']
context.can(hosts_policies.BASE_POLICY_NAME)
try:
result = self.api.host_power_action(context, host_name, action)
except NotImplementedError:
@ -182,16 +183,25 @@ class HostController(wsgi.Controller):
@wsgi.Controller.api_version("2.1", "2.42")
@wsgi.expected_errors((400, 404, 501))
def startup(self, req, id):
context = req.environ['nova.context']
context.can(hosts_policies.POLICY_NAME % 'start',
target={})
return self._host_power_action(req, host_name=id, action="startup")
@wsgi.Controller.api_version("2.1", "2.42")
@wsgi.expected_errors((400, 404, 501))
def shutdown(self, req, id):
context = req.environ['nova.context']
context.can(hosts_policies.POLICY_NAME % 'shutdown',
target={})
return self._host_power_action(req, host_name=id, action="shutdown")
@wsgi.Controller.api_version("2.1", "2.42")
@wsgi.expected_errors((400, 404, 501))
def reboot(self, req, id):
context = req.environ['nova.context']
context.can(hosts_policies.POLICY_NAME % 'reboot',
target={})
return self._host_power_action(req, host_name=id, action="reboot")
@staticmethod
@ -257,7 +267,8 @@ class HostController(wsgi.Controller):
'cpu': 1, 'memory_mb': 2048, 'disk_gb': 30}
"""
context = req.environ['nova.context']
context.can(hosts_policies.BASE_POLICY_NAME)
context.can(hosts_policies.POLICY_NAME % 'show',
target={})
host_name = id
try:
mapping = objects.HostMapping.get_by_host(context, host_name)

View File

@ -20,41 +20,116 @@ from nova.policies import base
BASE_POLICY_NAME = 'os_compute_api:os-hosts'
POLICY_NAME = 'os_compute_api:os-hosts:%s'
DEPRECATED_POLICY = policy.DeprecatedRule(
BASE_POLICY_NAME,
base.RULE_ADMIN_API,
)
DEPRECATED_REASON = """
Nova API policies are introducing new default roles with scope_type
capabilities. Old policies are deprecated and silently going to be ignored
in nova 23.0.0 release.
"""
hosts_policies = [
policy.DocumentedRuleDefault(
name=BASE_POLICY_NAME,
check_str=base.RULE_ADMIN_API,
description="""List, show and manage physical hosts.
name=POLICY_NAME % 'list',
check_str=base.SYSTEM_READER,
description="""List physical hosts.
These APIs are all deprecated in favor of os-hypervisors and os-services.""",
This API is deprecated in favor of os-hypervisors and os-services.""",
operations=[
{
'method': 'GET',
'path': '/os-hosts'
},
],
scope_types=['system'],
deprecated_rule=DEPRECATED_POLICY,
deprecated_reason=DEPRECATED_REASON,
deprecated_since='22.0.0'),
policy.DocumentedRuleDefault(
name=POLICY_NAME % 'show',
check_str=base.SYSTEM_READER,
description="""Show physical host.
This API is deprecated in favor of os-hypervisors and os-services.""",
operations=[
{
'method': 'GET',
'path': '/os-hosts/{host_name}'
},
}
],
scope_types=['system'],
deprecated_rule=DEPRECATED_POLICY,
deprecated_reason=DEPRECATED_REASON,
deprecated_since='22.0.0'),
policy.DocumentedRuleDefault(
name=POLICY_NAME % 'update',
check_str=base.SYSTEM_ADMIN,
description="""Update physical host.
This API is deprecated in favor of os-hypervisors and os-services.""",
operations=[
{
'method': 'PUT',
'path': '/os-hosts/{host_name}'
},
],
scope_types=['system'],
deprecated_rule=DEPRECATED_POLICY,
deprecated_reason=DEPRECATED_REASON,
deprecated_since='22.0.0'),
policy.DocumentedRuleDefault(
name=POLICY_NAME % 'reboot',
check_str=base.SYSTEM_ADMIN,
description="""Reboot physical host.
This API is deprecated in favor of os-hypervisors and os-services.""",
operations=[
{
'method': 'GET',
'path': '/os-hosts/{host_name}/reboot'
},
],
scope_types=['system'],
deprecated_rule=DEPRECATED_POLICY,
deprecated_reason=DEPRECATED_REASON,
deprecated_since='22.0.0'),
policy.DocumentedRuleDefault(
name=POLICY_NAME % 'shutdown',
check_str=base.SYSTEM_ADMIN,
description="""Shutdown physical host.
This API is deprecated in favor of os-hypervisors and os-services.""",
operations=[
{
'method': 'GET',
'path': '/os-hosts/{host_name}/shutdown'
},
],
scope_types=['system'],
deprecated_rule=DEPRECATED_POLICY,
deprecated_reason=DEPRECATED_REASON,
deprecated_since='22.0.0'),
policy.DocumentedRuleDefault(
name=POLICY_NAME % 'start',
check_str=base.SYSTEM_ADMIN,
description="""Start physical host.
This API is deprecated in favor of os-hypervisors and os-services.""",
operations=[
{
'method': 'GET',
'path': '/os-hosts/{host_name}/startup'
}
],
scope_types=['system']),
scope_types=['system'],
deprecated_rule=DEPRECATED_POLICY,
deprecated_reason=DEPRECATED_REASON,
deprecated_since='22.0.0'),
]

View File

@ -105,6 +105,12 @@ policy_data = """
"os_compute_api:os-keypairs:create": "",
"os_compute_api:os-keypairs:show": "",
"os_compute_api:os-keypairs:delete": "",
"os_compute_api:os-hosts:list": "",
"os_compute_api:os-hosts:show": "",
"os_compute_api:os-hosts:update": "",
"os_compute_api:os-hosts:reboot": "",
"os_compute_api:os-hosts:shutdown": "",
"os_compute_api:os-hosts:start": "",
"os_compute_api:os-hypervisors:list": "",
"os_compute_api:os-hypervisors:list-detail": "",
"os_compute_api:os-hypervisors:statistics": "",

View File

@ -13,6 +13,7 @@
import mock
from nova.api.openstack.compute import hosts
from nova.policies import base as base_policy
from nova.policies import hosts as policies
from nova.tests.unit.api.openstack import fakes
from nova.tests.unit.policies import base
@ -32,22 +33,34 @@ class HostsPolicyTest(base.BasePolicyTest):
self.req = fakes.HTTPRequest.blank('')
# Check that admin is able to perform operations on hosts.
self.admin_authorized_contexts = [
self.system_admin_authorized_contexts = [
self.system_admin_context, self.legacy_admin_context,
self.project_admin_context]
# Check that non-admin is not able to perform operations
# on hosts.
self.admin_unauthorized_contexts = [
self.system_admin_unauthorized_contexts = [
self.system_member_context, self.system_reader_context,
self.system_foo_context, self.other_project_member_context,
self.project_foo_context, self.project_member_context,
self.project_reader_context, self.other_project_reader_context]
self.project_reader_context, self.other_project_reader_context
]
self.system_reader_authorized_contexts = [
self.system_admin_context, self.system_member_context,
self.system_reader_context, self.legacy_admin_context,
self.project_admin_context
]
self.system_reader_unauthorized_contexts = [
self.project_foo_context, self.system_foo_context,
self.project_member_context, self.project_reader_context,
self.other_project_member_context,
self.other_project_reader_context
]
@mock.patch('nova.compute.api.HostAPI.service_get_all')
def test_list_hosts_policy(self, mock_get):
rule_name = policies.BASE_POLICY_NAME
self.common_policy_check(self.admin_authorized_contexts,
self.admin_unauthorized_contexts,
rule_name = policies.POLICY_NAME % 'list'
self.common_policy_check(self.system_reader_authorized_contexts,
self.system_reader_unauthorized_contexts,
rule_name, self.controller.index,
self.req)
@ -57,40 +70,40 @@ class HostsPolicyTest(base.BasePolicyTest):
'get_first_node_by_host_for_old_compat')
@mock.patch('nova.compute.api.HostAPI.instance_get_all_by_host')
def test_show_host_policy(self, mock_get, mock_node, mock_map, mock_set):
rule_name = policies.BASE_POLICY_NAME
self.common_policy_check(self.admin_authorized_contexts,
self.admin_unauthorized_contexts,
rule_name = policies.POLICY_NAME % 'show'
self.common_policy_check(self.system_reader_authorized_contexts,
self.system_reader_unauthorized_contexts,
rule_name, self.controller.show,
self.req, 11111)
def test_update_host_policy(self):
rule_name = policies.BASE_POLICY_NAME
self.common_policy_check(self.admin_authorized_contexts,
self.admin_unauthorized_contexts,
rule_name = policies.POLICY_NAME % 'update'
self.common_policy_check(self.system_admin_authorized_contexts,
self.system_admin_unauthorized_contexts,
rule_name, self.controller.update,
self.req, 11111, body={})
@mock.patch('nova.compute.api.HostAPI.host_power_action')
def test_reboot_host_policy(self, mock_action):
rule_name = policies.BASE_POLICY_NAME
self.common_policy_check(self.admin_authorized_contexts,
self.admin_unauthorized_contexts,
rule_name = policies.POLICY_NAME % 'reboot'
self.common_policy_check(self.system_admin_authorized_contexts,
self.system_admin_unauthorized_contexts,
rule_name, self.controller.reboot,
self.req, 11111)
@mock.patch('nova.compute.api.HostAPI.host_power_action')
def test_shutdown_host_policy(self, mock_action):
rule_name = policies.BASE_POLICY_NAME
self.common_policy_check(self.admin_authorized_contexts,
self.admin_unauthorized_contexts,
rule_name = policies.POLICY_NAME % 'shutdown'
self.common_policy_check(self.system_admin_authorized_contexts,
self.system_admin_unauthorized_contexts,
rule_name, self.controller.shutdown,
self.req, 11111)
@mock.patch('nova.compute.api.HostAPI.host_power_action')
def test_startup_host_policy(self, mock_action):
rule_name = policies.BASE_POLICY_NAME
self.common_policy_check(self.admin_authorized_contexts,
self.admin_unauthorized_contexts,
rule_name = policies.POLICY_NAME % 'start'
self.common_policy_check(self.system_admin_authorized_contexts,
self.system_admin_unauthorized_contexts,
rule_name, self.controller.startup,
self.req, 11111)
@ -110,13 +123,71 @@ class HostsScopeTypePolicyTest(HostsPolicyTest):
self.flags(enforce_scope=True, group="oslo_policy")
# Check that system admin is able to perform operations on hosts.
self.admin_authorized_contexts = [
self.system_admin_authorized_contexts = [
self.system_admin_context]
# Check that system non-admin is not able to perform operations
# on hosts.
self.admin_unauthorized_contexts = [
self.system_admin_unauthorized_contexts = [
self.legacy_admin_context, self.project_admin_context,
self.system_member_context, self.system_reader_context,
self.system_foo_context, self.other_project_member_context,
self.project_foo_context, self.project_member_context,
self.project_reader_context, self.other_project_reader_context]
self.project_reader_context, self.other_project_reader_context
]
self.system_reader_authorized_contexts = [
self.system_admin_context, self.system_member_context,
self.system_reader_context
]
self.system_reader_unauthorized_contexts = [
self.legacy_admin_context, self.project_foo_context,
self.system_foo_context, self.project_admin_context,
self.project_member_context, self.project_reader_context,
self.other_project_member_context,
self.other_project_reader_context
]
class HostsNoLegacyPolicyTest(HostsScopeTypePolicyTest):
"""Test Hosts APIs policies with system scope enabled,
and no more deprecated rules that allow the legacy admin API to
access system_admin_or_owner APIs.
"""
without_deprecated_rules = True
rules_without_deprecation = {
policies.POLICY_NAME % 'list':
base_policy.SYSTEM_READER,
policies.POLICY_NAME % 'show':
base_policy.SYSTEM_READER,
policies.POLICY_NAME % 'update':
base_policy.SYSTEM_ADMIN,
policies.POLICY_NAME % 'reboot':
base_policy.SYSTEM_ADMIN,
policies.POLICY_NAME % 'shutdown':
base_policy.SYSTEM_ADMIN,
policies.POLICY_NAME % 'startup':
base_policy.SYSTEM_ADMIN}
def setUp(self):
super(HostsNoLegacyPolicyTest, self).setUp()
self.system_reader_authorized_contexts = [
self.system_admin_context, self.system_member_context,
self.system_reader_context
]
self.system_reader_unauthorized_contexts = [
self.legacy_admin_context, self.project_foo_context,
self.system_foo_context, self.project_admin_context,
self.project_member_context, self.project_reader_context,
self.other_project_member_context,
self.other_project_reader_context
]
self.system_admin_authorized_contexts = [
self.system_admin_context
]
self.system_admin_unauthorized_contexts = [
self.system_member_context, self.system_reader_context,
self.project_admin_context, self.project_member_context,
self.legacy_admin_context, self.other_project_member_context,
self.project_reader_context, self.project_foo_context,
self.system_foo_context, self.other_project_reader_context
]

View File

@ -348,7 +348,10 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
"os_compute_api:os-flavor-manage:create",
"os_compute_api:os-flavor-manage:update",
"os_compute_api:os-flavor-manage:delete",
"os_compute_api:os-hosts",
"os_compute_api:os-hosts:update",
"os_compute_api:os-hosts:reboot",
"os_compute_api:os-hosts:shutdown",
"os_compute_api:os-hosts:start",
"os_compute_api:os-instance-actions:events",
"os_compute_api:os-lock-server:unlock:unlock_override",
"os_compute_api:os-migrate-server:migrate",
@ -475,6 +478,8 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
"os_compute_api:os-instance-usage-audit-log:list",
"os_compute_api:os-instance-usage-audit-log:show",
"os_compute_api:os-agents:list",
"os_compute_api:os-hosts:list",
"os_compute_api:os-hosts:show",
"os_compute_api:os-hypervisors:list",
"os_compute_api:os-hypervisors:list-detail",
"os_compute_api:os-hypervisors:show",