Remove OS::Heat::HARestarter
The OS::Heat::HARestarter has been deprecated since Kilo. Now is the time to eliminate support and hide it from the documentation. This replaces it with a placeholder resource (like OS::Heat::None) and marks it as hidden. Change-Id: I56cd1f2d0b3323399ef02c3a0a05d79cc69af956
This commit is contained in:
parent
2c0797b73e
commit
7b56e0e008
@ -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():
|
||||
|
@ -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:
|
||||
|
@ -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',
|
||||
|
@ -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)
|
@ -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…
Reference in New Issue
Block a user