Allow mark-unhealthy by physical resource ID
If the name passed into mark-unhealthy is not a valid resource name, check if it is a valid resource id and retrieve the resource via id instead of name. Change-Id: Ie28ed102665b2c6379d1f55b7a02b76d05e38ddd Co-Authored-By: Zane Bitter <zbitter@redhat.com> Closes-Bug: #1635295
This commit is contained in:
parent
f310a1f6bc
commit
4e465402d0
|
@ -54,6 +54,13 @@ resource_name_url:
|
||||||
in: path
|
in: path
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
|
resource_name_or_physical_id_url:
|
||||||
|
description: |
|
||||||
|
The name of a resource in the stack, or the ID of its underlying physical
|
||||||
|
resource.
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
snapshot_id_url:
|
snapshot_id_url:
|
||||||
description: |
|
description: |
|
||||||
The UUID of the snapshot.
|
The UUID of the snapshot.
|
||||||
|
|
|
@ -263,7 +263,7 @@ This operation does not return a response body.
|
||||||
Mark a resource as unhealthy
|
Mark a resource as unhealthy
|
||||||
============================
|
============================
|
||||||
|
|
||||||
.. rest_method:: PATCH /v1/{tenant_id}/stacks/{stack_name}/{stack_id}/resources/{resource_name}
|
.. rest_method:: PATCH /v1/{tenant_id}/stacks/{stack_name}/{stack_id}/resources/{resource_name_or_physical_id}
|
||||||
|
|
||||||
Mark the specified resource in the stack as unhealthy.
|
Mark the specified resource in the stack as unhealthy.
|
||||||
|
|
||||||
|
@ -288,7 +288,7 @@ Request Parameters
|
||||||
- tenant_id: tenant_id
|
- tenant_id: tenant_id
|
||||||
- stack_name: stack_name_url
|
- stack_name: stack_name_url
|
||||||
- stack_id: stack_id_url
|
- stack_id: stack_id_url
|
||||||
- resource_name: resource_name_url
|
- resource_name_or_physical_id: resource_name_or_physical_id_url
|
||||||
- mark_unhealthy: mark_unhealthy
|
- mark_unhealthy: mark_unhealthy
|
||||||
- resource_status_reason: resource_update_status_reason
|
- resource_status_reason: resource_update_status_reason
|
||||||
|
|
||||||
|
|
|
@ -1866,6 +1866,8 @@ class EngineService(service.ServiceBase):
|
||||||
is false and the resource is in CHECK_FAILED state.
|
is false and the resource is in CHECK_FAILED state.
|
||||||
Otherwise, make no change.
|
Otherwise, make no change.
|
||||||
|
|
||||||
|
:param resource_name: either the logical name of the resource or the
|
||||||
|
physical resource ID.
|
||||||
:param mark_unhealthy: indicates whether the resource is unhealthy.
|
:param mark_unhealthy: indicates whether the resource is unhealthy.
|
||||||
:param resource_status_reason: reason for health change.
|
:param resource_status_reason: reason for health change.
|
||||||
"""
|
"""
|
||||||
|
@ -1877,22 +1879,21 @@ class EngineService(service.ServiceBase):
|
||||||
rsrc.stack.id,
|
rsrc.stack.id,
|
||||||
self.engine_id)
|
self.engine_id)
|
||||||
|
|
||||||
s = self._get_stack(cnxt, stack_identity)
|
|
||||||
stack = parser.Stack.load(cnxt, stack=s)
|
|
||||||
if resource_name not in stack:
|
|
||||||
raise exception.ResourceNotFound(resource_name=resource_name,
|
|
||||||
stack_name=stack.name)
|
|
||||||
|
|
||||||
if not isinstance(mark_unhealthy, bool):
|
if not isinstance(mark_unhealthy, bool):
|
||||||
raise exception.Invalid(reason="mark_unhealthy is not a boolean")
|
raise exception.Invalid(reason="mark_unhealthy is not a boolean")
|
||||||
|
|
||||||
rsrc = stack[resource_name]
|
s = self._get_stack(cnxt, stack_identity)
|
||||||
|
stack = parser.Stack.load(cnxt, stack=s)
|
||||||
|
|
||||||
|
rsrc = self._find_resource_in_stack(cnxt, resource_name, stack)
|
||||||
|
|
||||||
reason = (resource_status_reason or
|
reason = (resource_status_reason or
|
||||||
"state changed by resource_mark_unhealthy api")
|
"state changed by resource_mark_unhealthy api")
|
||||||
try:
|
try:
|
||||||
with lock(rsrc):
|
with lock(rsrc):
|
||||||
if mark_unhealthy:
|
if mark_unhealthy:
|
||||||
rsrc.state_set(rsrc.CHECK, rsrc.FAILED, reason=reason)
|
if rsrc.action != rsrc.DELETE:
|
||||||
|
rsrc.state_set(rsrc.CHECK, rsrc.FAILED, reason=reason)
|
||||||
elif rsrc.state == (rsrc.CHECK, rsrc.FAILED):
|
elif rsrc.state == (rsrc.CHECK, rsrc.FAILED):
|
||||||
rsrc.state_set(rsrc.CHECK, rsrc.COMPLETE, reason=reason)
|
rsrc.state_set(rsrc.CHECK, rsrc.COMPLETE, reason=reason)
|
||||||
|
|
||||||
|
@ -1900,6 +1901,29 @@ class EngineService(service.ServiceBase):
|
||||||
raise exception.ActionInProgress(stack_name=stack.name,
|
raise exception.ActionInProgress(stack_name=stack.name,
|
||||||
action=stack.action)
|
action=stack.action)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _find_resource_in_stack(cnxt, resource_name, stack):
|
||||||
|
"""Find a resource in a stack by either name or physical ID."""
|
||||||
|
if resource_name in stack:
|
||||||
|
return stack[resource_name]
|
||||||
|
|
||||||
|
rsrcs = resource_objects.Resource.get_all_by_physical_resource_id(
|
||||||
|
cnxt,
|
||||||
|
resource_name)
|
||||||
|
|
||||||
|
def in_stack(rs):
|
||||||
|
return rs.stack_id == stack.id and stack[rs.name].id == rs.id
|
||||||
|
|
||||||
|
matches = [stack[rs.name] for rs in rsrcs if in_stack(rs)]
|
||||||
|
|
||||||
|
if not matches:
|
||||||
|
raise exception.ResourceNotFound(resource_name=resource_name,
|
||||||
|
stack_name=stack.name)
|
||||||
|
if len(matches) > 1:
|
||||||
|
raise exception.PhysicalResourceIDAmbiguity(phys_id=resource_name)
|
||||||
|
|
||||||
|
return matches[0]
|
||||||
|
|
||||||
@context.request_context
|
@context.request_context
|
||||||
def find_physical_resource(self, cnxt, physical_resource_id):
|
def find_physical_resource(self, cnxt, physical_resource_id):
|
||||||
"""Return an identifier for the specified resource.
|
"""Return an identifier for the specified resource.
|
||||||
|
|
|
@ -536,6 +536,28 @@ class StackResourcesServiceTest(common.HeatTestCase):
|
||||||
self.assertIsInstance(stack_dependencies, dependencies.Dependencies)
|
self.assertIsInstance(stack_dependencies, dependencies.Dependencies)
|
||||||
self.assertEqual(2, len(stack_dependencies.graph()))
|
self.assertEqual(2, len(stack_dependencies.graph()))
|
||||||
|
|
||||||
|
@tools.stack_context('service_find_resource_logical_name')
|
||||||
|
def test_find_resource_logical_name(self):
|
||||||
|
rsrc = self.stack['WebServer']
|
||||||
|
physical_rsrc = self.eng._find_resource_in_stack(self.ctx,
|
||||||
|
'WebServer',
|
||||||
|
self.stack)
|
||||||
|
self.assertEqual(rsrc.id, physical_rsrc.id)
|
||||||
|
|
||||||
|
@tools.stack_context('service_find_resource_physical_id')
|
||||||
|
def test_find_resource_physical_id(self):
|
||||||
|
rsrc = self.stack['WebServer']
|
||||||
|
physical_rsrc = self.eng._find_resource_in_stack(self.ctx,
|
||||||
|
rsrc.resource_id,
|
||||||
|
self.stack)
|
||||||
|
self.assertEqual(rsrc.id, physical_rsrc.id)
|
||||||
|
|
||||||
|
@tools.stack_context('service_find_resource_not_found')
|
||||||
|
def test_find_resource_nonexist(self):
|
||||||
|
self.assertRaises(exception.ResourceNotFound,
|
||||||
|
self.eng._find_resource_in_stack,
|
||||||
|
self.ctx, 'wibble', self.stack)
|
||||||
|
|
||||||
@tools.stack_context('service_mark_healthy_create_complete_test_stk')
|
@tools.stack_context('service_mark_healthy_create_complete_test_stk')
|
||||||
def test_mark_healthy_in_create_complete(self):
|
def test_mark_healthy_in_create_complete(self):
|
||||||
self.eng.resource_mark_unhealthy(self.ctx, self.stack.identifier(),
|
self.eng.resource_mark_unhealthy(self.ctx, self.stack.identifier(),
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- The ``resource mark unhealthy`` command now accepts either a logical resource name (as it did previously) or a physical resource ID to identify the resource to be marked unhealthy.
|
Loading…
Reference in New Issue