diff options
author | Zane Bitter <zbitter@redhat.com> | 2019-10-25 17:07:12 -0400 |
---|---|---|
committer | ramishra <ramishra@redhat.com> | 2021-03-15 17:38:14 +0530 |
commit | af7f8e380a7425c65ac88f5bc68e57757d9b2cc1 (patch) | |
tree | 819e3fee67e3e52a6d7e5738c8ac576cf4152bac | |
parent | 34ecc26a116ee603a3b40d51c00962d2bd26d5bc (diff) | |
download | heat-af7f8e380a7425c65ac88f5bc68e57757d9b2cc1.tar.gz |
Add separate policy for updates with no changes
Allow operators to set a different (presumably looser) policy on PATCH
updates that don't make any changes to the stack, but just retrigger a
new update traversal (that will result in e.g. replacing any unhealthy
resources).
Change-Id: Id29e7ec7f6cf127177ea7ab29127b0568afaa18b
Task: 37305
-rw-r--r-- | heat/api/openstack/v1/stacks.py | 25 | ||||
-rw-r--r-- | heat/api/openstack/v1/util.py | 18 | ||||
-rw-r--r-- | heat/policies/stacks.py | 12 | ||||
-rw-r--r-- | releasenotes/notes/update-no-change-policy-728ed49e6b81da53.yaml | 6 |
4 files changed, 60 insertions, 1 deletions
diff --git a/heat/api/openstack/v1/stacks.py b/heat/api/openstack/v1/stacks.py index d84adbc92..1da826509 100644 --- a/heat/api/openstack/v1/stacks.py +++ b/heat/api/openstack/v1/stacks.py @@ -166,6 +166,17 @@ class InstantiationData(object): params = self.data.items() return dict((k, v) for k, v in params if k not in self.PARAMS) + def no_change(self): + assert self.patch + return ((self.template() is None) and + (self.environment() == + environment_format.default_for_missing({})) and + (not self.files()) and + (not self.environment_files()) and + (self.files_container() is None) and + (not any(k != rpc_api.PARAM_EXISTING + for k in self.args().keys()))) + class StackController(object): """WSGI controller for stacks resource in Heat v1 API. @@ -496,7 +507,8 @@ class StackController(object): raise exc.HTTPAccepted() - @util.registered_identified_stack + @util.no_policy_enforce + @util._identified_stack def update_patch(self, req, identity, body): """Update an existing stack with a new template. @@ -504,6 +516,17 @@ class StackController(object): Add the flag patch to the args so the engine code can distinguish """ data = InstantiationData(body, patch=True) + _target = {"project_id": req.context.tenant_id} + + policy_act = 'update_no_change' if data.no_change() else 'update_patch' + allowed = req.context.policy.enforce( + context=req.context, + action=policy_act, + scope=self.REQUEST_SCOPE, + target=_target, + is_registered_policy=True) + if not allowed: + raise exc.HTTPForbidden() args = self.prepare_args(data, is_update=True) self.rpc_client.update_stack( diff --git a/heat/api/openstack/v1/util.py b/heat/api/openstack/v1/util.py index 70a22d420..46ae955eb 100644 --- a/heat/api/openstack/v1/util.py +++ b/heat/api/openstack/v1/util.py @@ -48,6 +48,24 @@ def registered_policy_enforce(handler): return handle_stack_method +def no_policy_enforce(handler): + """Decorator that does *not* enforce policies. + + Checks the path matches the request context. + + This is a handler method decorator. + """ + @functools.wraps(handler) + def handle_stack_method(controller, req, tenant_id, **kwargs): + if req.context.tenant_id != tenant_id and not ( + req.context.is_admin or + req.context.system_scope == all): + raise exc.HTTPForbidden() + return handler(controller, req, **kwargs) + + return handle_stack_method + + def registered_identified_stack(handler): """Decorator that passes a stack identifier instead of path components. diff --git a/heat/policies/stacks.py b/heat/policies/stacks.py index 5591ba5ff..cebcf5af5 100644 --- a/heat/policies/stacks.py +++ b/heat/policies/stacks.py @@ -472,6 +472,18 @@ stacks_policies = [ deprecated_rule=deprecated_update_patch ), policy.DocumentedRuleDefault( + name=POLICY_ROOT % 'update_no_change', + check_str='rule:%s' % (POLICY_ROOT % 'update_patch'), + scope_types=['system', 'project'], + description='Update stack (PATCH) with no changes.', + operations=[ + { + 'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}', + 'method': 'PATCH' + } + ] + ), + policy.DocumentedRuleDefault( name=POLICY_ROOT % 'preview_update', check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER, scope_types=['system', 'project'], diff --git a/releasenotes/notes/update-no-change-policy-728ed49e6b81da53.yaml b/releasenotes/notes/update-no-change-policy-728ed49e6b81da53.yaml new file mode 100644 index 000000000..cc237e6ac --- /dev/null +++ b/releasenotes/notes/update-no-change-policy-728ed49e6b81da53.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Operators can now set a separate ``stacks:update_no_change`` policy for + PATCH updates that don't modify the stack, independently of the existing + ``stacks:update_patch`` policy. |