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.
|
# under the License.
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
import six
|
|
||||||
|
|
||||||
from heat.common.i18n import _
|
from heat.common.i18n import _
|
||||||
from heat.engine import attributes
|
from heat.engine.resources.openstack.heat import none_resource
|
||||||
from heat.engine import constraints
|
|
||||||
from heat.engine import properties
|
|
||||||
from heat.engine.resources import signal_responder
|
|
||||||
from heat.engine import support
|
from heat.engine import support
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Restarter(signal_responder.SignalResponder):
|
class Restarter(none_resource.NoneResource):
|
||||||
|
|
||||||
support_status = support.SupportStatus(
|
support_status = support.SupportStatus(
|
||||||
support.DEPRECATED,
|
status=support.HIDDEN,
|
||||||
_('The HARestarter resource type is deprecated and will be removed '
|
version='10.0.0',
|
||||||
'in a future release of Heat, once it has support for auto-healing '
|
message=_('The HARestarter resource type has been removed. Existing '
|
||||||
'any type of resource. Note that HARestarter does *not* actually '
|
'stacks containing HARestarter resources can still be '
|
||||||
'restart servers - it deletes and then recreates them. It also does '
|
'used, but the HARestarter resource will be a placeholder '
|
||||||
'the same to all dependent resources, and may therefore exhibit '
|
'that does nothing.'),
|
||||||
'unexpected and undesirable behaviour. Instead, use the '
|
previous_status=support.SupportStatus(
|
||||||
'mark-unhealthy API to mark a resource as needing replacement, and '
|
status=support.DEPRECATED,
|
||||||
'then a stack update to perform the replacement while respecting '
|
message=_('The HARestarter resource type is deprecated and will '
|
||||||
'the dependencies and not deleting them unnecessarily.'),
|
'be removed in a future release of Heat, once it has '
|
||||||
version='2015.1'
|
'support for auto-healing any type of resource. Note '
|
||||||
)
|
'that HARestarter does *not* actually restart '
|
||||||
|
'servers - it deletes and then recreates them. It also '
|
||||||
PROPERTIES = (
|
'does the same to all dependent resources, and may '
|
||||||
INSTANCE_ID,
|
'therefore exhibit unexpected and undesirable '
|
||||||
) = (
|
'behaviour. Instead, use the mark-unhealthy API to '
|
||||||
'InstanceId',
|
'mark a resource as needing replacement, and then a '
|
||||||
)
|
'stack update to perform the replacement while '
|
||||||
|
'respecting the dependencies and not deleting them '
|
||||||
ATTRIBUTES = (
|
'unnecessarily.'),
|
||||||
ALARM_URL,
|
version='2015.1'))
|
||||||
) = (
|
|
||||||
'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())
|
|
||||||
|
|
||||||
|
|
||||||
def resource_mapping():
|
def resource_mapping():
|
||||||
|
@ -1987,44 +1987,6 @@ class Stack(collections.Mapping):
|
|||||||
action=self.RESTORE)
|
action=self.RESTORE)
|
||||||
updater()
|
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):
|
def get_availability_zones(self):
|
||||||
nova = self.clients.client('nova')
|
nova = self.clients.client('nova')
|
||||||
if self._zones is None:
|
if self._zones is None:
|
||||||
|
@ -44,7 +44,6 @@ class ResourceTypeTest(common.HeatTestCase):
|
|||||||
mock_is_service_available.return_value = (True, None)
|
mock_is_service_available.return_value = (True, None)
|
||||||
resources = self.eng.list_resource_types(self.ctx, "DEPRECATED")
|
resources = self.eng.list_resource_types(self.ctx, "DEPRECATED")
|
||||||
self.assertEqual(set(['OS::Aodh::Alarm',
|
self.assertEqual(set(['OS::Aodh::Alarm',
|
||||||
'OS::Heat::HARestarter',
|
|
||||||
'OS::Magnum::Bay',
|
'OS::Magnum::Bay',
|
||||||
'OS::Magnum::BayModel',
|
'OS::Magnum::BayModel',
|
||||||
'OS::Glance::Image',
|
'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