Browse Source

Merge "Remove OS::Heat::HARestarter"

changes/41/521641/3
Zuul 4 years ago
committed by Gerrit Code Review
parent
commit
fb79011451
  1. 109
      heat/engine/resources/openstack/heat/ha_restarter.py
  2. 38
      heat/engine/stack.py
  3. 1
      heat/tests/engine/test_resource_type.py
  4. 101
      heat/tests/openstack/heat/test_restarter.py
  5. 12
      releasenotes/notes/hidden-heat-harestarter-resource-a123479c317886a3.yaml

109
heat/engine/resources/openstack/heat/ha_restarter.py

@ -12,101 +12,38 @@
# under the License.
from oslo_log import log as logging
import six
from heat.common.i18n import _
from heat.engine import attributes
from heat.engine import constraints
from heat.engine import properties
from heat.engine.resources import signal_responder
from heat.engine.resources.openstack.heat import none_resource
from heat.engine import support
LOG = logging.getLogger(__name__)
class Restarter(signal_responder.SignalResponder):
class Restarter(none_resource.NoneResource):
support_status = support.SupportStatus(
support.DEPRECATED,
_('The HARestarter resource type is deprecated and will be removed '
'in a future release of Heat, once it has support for auto-healing '
'any type of resource. Note that HARestarter does *not* actually '
'restart servers - it deletes and then recreates them. It also does '
'the same to all dependent resources, and may therefore exhibit '
'unexpected and undesirable behaviour. Instead, use the '
'mark-unhealthy API to mark a resource as needing replacement, and '
'then a stack update to perform the replacement while respecting '
'the dependencies and not deleting them unnecessarily.'),
version='2015.1'
)
PROPERTIES = (
INSTANCE_ID,
) = (
'InstanceId',
)
ATTRIBUTES = (
ALARM_URL,
) = (
'AlarmUrl',
)
properties_schema = {
INSTANCE_ID: properties.Schema(
properties.Schema.STRING,
_('Instance ID to be restarted.'),
required=True,
constraints=[
constraints.CustomConstraint('nova.server')
]
),
}
attributes_schema = {
ALARM_URL: attributes.Schema(
_("A signed url to handle the alarm (Heat extension)."),
type=attributes.Schema.STRING
),
}
def handle_create(self):
super(Restarter, self).handle_create()
self.resource_id_set(self._get_user_id())
def handle_signal(self, details=None):
if details is None:
alarm_state = 'alarm'
else:
alarm_state = details.get('state', 'alarm').lower()
LOG.info('%(name)s Alarm, new state %(state)s',
{'name': self.name, 'state': alarm_state})
if alarm_state != 'alarm':
return
target_id = self.properties[self.INSTANCE_ID]
victim = self.stack.resource_by_refid(target_id)
if victim is None:
LOG.info('%(name)s Alarm, can not find instance '
'%(instance)s',
{'name': self.name,
'instance': target_id})
return
LOG.info('%(name)s Alarm, restarting resource: %(victim)s',
{'name': self.name, 'victim': victim.name})
self.stack.restart_resource(victim.name)
def _resolve_attribute(self, name):
"""Resolves the resource's attributes.
Heat extension: "AlarmUrl" returns the url to post to the policy
when there is an alarm.
"""
if name == self.ALARM_URL and self.resource_id is not None:
return six.text_type(self._get_ec2_signed_url())
status=support.HIDDEN,
version='10.0.0',
message=_('The HARestarter resource type has been removed. Existing '
'stacks containing HARestarter resources can still be '
'used, but the HARestarter resource will be a placeholder '
'that does nothing.'),
previous_status=support.SupportStatus(
status=support.DEPRECATED,
message=_('The HARestarter resource type is deprecated and will '
'be removed in a future release of Heat, once it has '
'support for auto-healing any type of resource. Note '
'that HARestarter does *not* actually restart '
'servers - it deletes and then recreates them. It also '
'does the same to all dependent resources, and may '
'therefore exhibit unexpected and undesirable '
'behaviour. Instead, use the mark-unhealthy API to '
'mark a resource as needing replacement, and then a '
'stack update to perform the replacement while '
'respecting the dependencies and not deleting them '
'unnecessarily.'),
version='2015.1'))
def resource_mapping():

38
heat/engine/stack.py

@ -1987,44 +1987,6 @@ class Stack(collections.Mapping):
action=self.RESTORE)
updater()
def restart_resource(self, resource_name):
"""Restart the resource specified by resource_name.
stop resource_name and all that depend on it
start resource_name and all that depend on it
"""
warnings.warn("Stack.restart_resource() is horribly broken and will "
"never be fixed. If you're using it in a resource type "
"other than HARestarter, don't. And don't use "
"HARestarter either.",
DeprecationWarning)
deps = self.dependencies[self[resource_name]]
failed = False
for res in reversed(deps):
try:
scheduler.TaskRunner(res.destroy)()
except exception.ResourceFailure as ex:
failed = True
LOG.info('Resource %(name)s delete failed: %(ex)s',
{'name': res.name, 'ex': ex})
for res in deps:
if not failed:
try:
res.state_reset()
scheduler.TaskRunner(res.create)()
except exception.ResourceFailure as ex:
failed = True
LOG.info('Resource %(name)s create failed: '
'%(ex)s', {'name': res.name, 'ex': ex})
else:
res.state_set(res.CREATE, res.FAILED,
'Resource restart aborted')
# TODO(asalkeld) if any of this fails we Should
# restart the whole stack
def get_availability_zones(self):
nova = self.clients.client('nova')
if self._zones is None:

1
heat/tests/engine/test_resource_type.py

@ -44,7 +44,6 @@ class ResourceTypeTest(common.HeatTestCase):
mock_is_service_available.return_value = (True, None)
resources = self.eng.list_resource_types(self.ctx, "DEPRECATED")
self.assertEqual(set(['OS::Aodh::Alarm',
'OS::Heat::HARestarter',
'OS::Magnum::Bay',
'OS::Magnum::BayModel',
'OS::Glance::Image',

101
heat/tests/openstack/heat/test_restarter.py

@ -1,101 +0,0 @@
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
from heat.common import template_format
from heat.engine.clients.os import nova
from heat.tests import common
from heat.tests import utils
restarter_template = '''
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "Template to test HARestarter",
"Parameters" : {},
"Resources" : {
"instance": {
"Type": "OS::Heat::None"
},
"restarter": {
"Type": "OS::Heat::HARestarter",
"Properties": {
"InstanceId": {"Ref": "instance"}
}
}
}
}
'''
bogus_template = '''
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "Template to test HARestarter",
"Parameters" : {},
"Resources" : {
"restarter": {
"Type": "OS::Heat::HARestarter",
"Properties": {
"InstanceId": "instance"
}
}
}
}
'''
class RestarterTest(common.HeatTestCase):
def create_restarter(self, template=restarter_template):
snippet = template_format.parse(template)
self.stack = utils.parse_stack(snippet)
restarter = self.stack['restarter']
self.patchobject(nova.NovaClientPlugin, 'get_server',
return_value=mock.MagicMock())
restarter.handle_create = mock.Mock(return_value=None)
self.stack.create()
return restarter
def test_create(self):
rsrc = self.create_restarter()
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
rsrc.handle_create.assert_called_once_with()
def test_handle_signal(self):
rsrc = self.create_restarter()
with mock.patch.object(rsrc.stack, 'restart_resource') as rr:
self.assertIsNone(rsrc.handle_signal())
rr.assert_called_once_with('instance')
def test_handle_signal_alarm(self):
rsrc = self.create_restarter()
with mock.patch.object(rsrc.stack, 'restart_resource') as rr:
self.assertIsNone(rsrc.handle_signal({'state': 'Alarm'}))
rr.assert_called_once_with('instance')
def test_handle_signal_not_alarm(self):
rsrc = self.create_restarter()
with mock.patch.object(rsrc.stack, 'restart_resource') as rr:
self.assertIsNone(rsrc.handle_signal({'state': 'spam'}))
self.assertEqual([], rr.mock_calls)
def test_handle_signal_no_instance(self):
rsrc = self.create_restarter(bogus_template)
with mock.patch.object(rsrc.stack, 'restart_resource') as rr:
self.assertIsNone(rsrc.handle_signal())
self.assertEqual([], rr.mock_calls)

12
releasenotes/notes/hidden-heat-harestarter-resource-a123479c317886a3.yaml

@ -0,0 +1,12 @@
---
upgrade:
- |
The ``OS::Heat::HARestarter`` resource type is no longer supported. This
resource type is now hidden from the documentation. HARestarter resources
in stacks, including pre-existing ones, are now only placeholders and will
no longer do anything. The recommended alternative is to mark a resource
unhealthy and then do a stack update to replace it. This still correctly
manages dependencies but, unlike HARestarter, also avoid replacing
dependent resources unnecessarily. An example of this technique can be
seen in the autohealing sample templates at
https://git.openstack.org/cgit/openstack/heat-templates/tree/hot/autohealing
Loading…
Cancel
Save