Merge "Add OS::Senlin::Receiver Resource"

This commit is contained in:
Jenkins 2016-02-19 04:20:32 +00:00 committed by Gerrit Code Review
commit 861da076fe
2 changed files with 266 additions and 0 deletions

View File

@ -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
}

View File

@ -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())