Merge "Add OS::Senlin::Receiver Resource"
This commit is contained in:
commit
861da076fe
|
@ -0,0 +1,131 @@
|
|||
#
|
||||
# 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.
|
||||
|
||||
from heat.common.i18n import _
|
||||
from heat.engine import attributes
|
||||
from heat.engine import constraints
|
||||
from heat.engine import properties
|
||||
from heat.engine import resource
|
||||
from heat.engine import support
|
||||
|
||||
|
||||
class Receiver(resource.Resource):
|
||||
"""A resource that creates Senlin Receiver.
|
||||
|
||||
Receiver is an abstract resource created at the senlin engine
|
||||
that can be used to hook the engine to some external event/alarm sources.
|
||||
"""
|
||||
|
||||
support_status = support.SupportStatus(version='6.0.0')
|
||||
|
||||
default_client_name = 'senlin'
|
||||
|
||||
PROPERTIES = (
|
||||
CLUSTER, ACTION, NAME, TYPE, PARAMS,
|
||||
) = (
|
||||
'cluster', 'action', 'name', 'type', 'params',
|
||||
)
|
||||
|
||||
ATTRIBUTES = (
|
||||
ATTR_CHANNEL,
|
||||
) = (
|
||||
'channel',
|
||||
)
|
||||
|
||||
_ACTIONS = (
|
||||
CLUSTER_SCALE_OUT, CLUSTER_SCALE_IN,
|
||||
) = (
|
||||
'CLUSTER_SCALE_OUT', 'CLUSTER_SCALE_IN',
|
||||
)
|
||||
|
||||
_TYPES = (
|
||||
WEBHOOK,
|
||||
) = (
|
||||
'webhook',
|
||||
)
|
||||
|
||||
properties_schema = {
|
||||
CLUSTER: properties.Schema(
|
||||
properties.Schema.STRING,
|
||||
_('Name or ID of target cluster.'),
|
||||
required=True,
|
||||
constraints=[
|
||||
constraints.CustomConstraint('senlin.cluster')
|
||||
]
|
||||
),
|
||||
ACTION: properties.Schema(
|
||||
properties.Schema.STRING,
|
||||
_('The action to be executed when the receiver is signaled.'),
|
||||
required=True,
|
||||
constraints=[
|
||||
constraints.AllowedValues(_ACTIONS)
|
||||
]
|
||||
),
|
||||
NAME: properties.Schema(
|
||||
properties.Schema.STRING,
|
||||
_('Name of the senlin receiver. By default, '
|
||||
'physical resource name is used.'),
|
||||
),
|
||||
TYPE: properties.Schema(
|
||||
properties.Schema.STRING,
|
||||
_('Type of receiver.'),
|
||||
default=WEBHOOK,
|
||||
constraints=[
|
||||
constraints.AllowedValues(_TYPES)
|
||||
]
|
||||
),
|
||||
PARAMS: properties.Schema(
|
||||
properties.Schema.MAP,
|
||||
_('The parameters passed to action when the receiver '
|
||||
'is signaled.'),
|
||||
),
|
||||
}
|
||||
|
||||
attributes_schema = {
|
||||
ATTR_CHANNEL: attributes.Schema(
|
||||
_("The channel for receiving signals."),
|
||||
type=attributes.Schema.MAP
|
||||
),
|
||||
}
|
||||
|
||||
def handle_create(self):
|
||||
params = {
|
||||
'name': (self.properties[self.NAME] or
|
||||
self.physical_resource_name()),
|
||||
'cluster_id': self.properties[self.CLUSTER],
|
||||
'type': self.properties[self.TYPE],
|
||||
'action': self.properties[self.ACTION],
|
||||
'params': self.properties[self.PARAMS],
|
||||
}
|
||||
|
||||
recv = self.client().create_receiver(**params)
|
||||
self.resource_id_set(recv.id)
|
||||
|
||||
def handle_delete(self):
|
||||
if self.resource_id is not None:
|
||||
with self.client_plugin().ignore_not_found:
|
||||
self.client().delete_receiver(self.resource_id)
|
||||
|
||||
def _show_resource(self):
|
||||
recv = self.client().get_receiver(self.resource_id)
|
||||
return recv.to_dict()
|
||||
|
||||
def _resolve_attribute(self, name):
|
||||
recv = self.client().get_receiver(self.resource_id)
|
||||
return getattr(recv, name, None)
|
||||
|
||||
|
||||
def resource_mapping():
|
||||
return {
|
||||
'OS::Senlin::Receiver': Receiver
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
#
|
||||
# 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 senlinclient.common import exc
|
||||
|
||||
from heat.common import template_format
|
||||
from heat.engine.clients.os import senlin
|
||||
from heat.engine.resources.openstack.senlin import receiver as sr
|
||||
from heat.engine import scheduler
|
||||
from heat.tests import common
|
||||
from heat.tests import utils
|
||||
|
||||
|
||||
receiver_stack_template = """
|
||||
heat_template_version: 2016-04-08
|
||||
description: Senlin Receiver Template
|
||||
resources:
|
||||
senlin-receiver:
|
||||
type: OS::Senlin::Receiver
|
||||
properties:
|
||||
name: SenlinReceiver
|
||||
cluster: fake_cluster
|
||||
action: CLUSTER_SCALE_OUT
|
||||
type: webhook
|
||||
params:
|
||||
foo: bar
|
||||
"""
|
||||
|
||||
|
||||
class FakeReceiver(object):
|
||||
def __init__(self, id='some_id'):
|
||||
self.id = id
|
||||
self.name = "SenlinReceiver"
|
||||
self.cluster_id = "fake_cluster"
|
||||
self.action = "CLUSTER_SCALE_OUT"
|
||||
self.channel = {'alarm_url': "http://foo.bar/webhooks/fake_url"}
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'name': self.name,
|
||||
'cluster_id': self.cluster_id,
|
||||
'action': self.action,
|
||||
'channel': self.channel,
|
||||
'actor': {'trust_id': ['fake_trust_id']}
|
||||
}
|
||||
|
||||
|
||||
class SenlinReceiverTest(common.HeatTestCase):
|
||||
def setUp(self):
|
||||
super(SenlinReceiverTest, self).setUp()
|
||||
self.senlin_mock = mock.MagicMock()
|
||||
self.patchobject(sr.Receiver, 'client',
|
||||
return_value=self.senlin_mock)
|
||||
self.patchobject(senlin.ClusterConstraint, 'validate',
|
||||
return_value=True)
|
||||
self.fake_r = FakeReceiver()
|
||||
self.t = template_format.parse(receiver_stack_template)
|
||||
|
||||
def _init_recv(self, template):
|
||||
self.stack = utils.parse_stack(template)
|
||||
recv = self.stack['senlin-receiver']
|
||||
return recv
|
||||
|
||||
def _create_recv(self, template):
|
||||
recv = self._init_recv(template)
|
||||
self.senlin_mock.create_receiver.return_value = self.fake_r
|
||||
self.senlin_mock.get_receiver.return_value = self.fake_r
|
||||
scheduler.TaskRunner(recv.create)()
|
||||
self.assertEqual((recv.CREATE, recv.COMPLETE),
|
||||
recv.state)
|
||||
self.assertEqual(self.fake_r.id, recv.resource_id)
|
||||
return recv
|
||||
|
||||
def test_recv_create_success(self):
|
||||
self._create_recv(self.t)
|
||||
expect_kwargs = {
|
||||
'name': 'SenlinReceiver',
|
||||
'cluster_id': 'fake_cluster',
|
||||
'action': 'CLUSTER_SCALE_OUT',
|
||||
'type': 'webhook',
|
||||
'params': {'foo': 'bar'},
|
||||
}
|
||||
self.senlin_mock.create_receiver.assert_called_once_with(
|
||||
**expect_kwargs)
|
||||
|
||||
def test_recv_delete_success(self):
|
||||
self.senlin_mock.delete_receiver.return_value = None
|
||||
recv = self._create_recv(self.t)
|
||||
scheduler.TaskRunner(recv.delete)()
|
||||
self.senlin_mock.delete_receiver.assert_called_once_with(
|
||||
recv.resource_id)
|
||||
|
||||
def test_recv_delete_not_found(self):
|
||||
self.senlin_mock.delete_receiver.side_effect = [
|
||||
exc.sdkexc.ResourceNotFound(http_status=404)
|
||||
]
|
||||
recv = self._create_recv(self.t)
|
||||
scheduler.TaskRunner(recv.delete)()
|
||||
self.senlin_mock.delete_receiver.assert_called_once_with(
|
||||
recv.resource_id)
|
||||
|
||||
def test_resource_mapping(self):
|
||||
mapping = sr.resource_mapping()
|
||||
self.assertEqual(1, len(mapping))
|
||||
self.assertEqual(sr.Receiver,
|
||||
mapping['OS::Senlin::Receiver'])
|
||||
|
||||
def test_cluster_resolve_attribute(self):
|
||||
excepted_show = {
|
||||
'id': 'some_id',
|
||||
'name': 'SenlinReceiver',
|
||||
'cluster_id': 'fake_cluster',
|
||||
'action': 'CLUSTER_SCALE_OUT',
|
||||
'channel': {'alarm_url': "http://foo.bar/webhooks/fake_url"},
|
||||
'actor': {'trust_id': ['fake_trust_id']}
|
||||
}
|
||||
recv = self._create_recv(self.t)
|
||||
self.assertEqual(self.fake_r.channel,
|
||||
recv._resolve_attribute('channel'))
|
||||
self.assertEqual(excepted_show,
|
||||
recv._show_resource())
|
Loading…
Reference in New Issue