Sends notifications at lease events
Climate now uses oslo.notify to send notifications when CRUD lease operations are executed and when relevant lease events happen (start_lease, before_end_lease, end_lease). This implementation also adds one new event type called before_end_lease to be sent when a lease is close to be ended. Moreover, a new oslo.notify wrapper class was also added. Change-Id: I861540e5ec5d1309ded2de56b2135bae5b59dad9 Implements: blueprint notifications
This commit is contained in:
parent
07ae1900af
commit
1d1ad49da0
@ -24,6 +24,7 @@ gettext.install('climate', unicode=1)
|
||||
|
||||
from climate.db import api as db_api
|
||||
from climate.manager import service as manager_service
|
||||
from climate.notification import notifier
|
||||
from climate.openstack.common import service
|
||||
from climate.utils import service as service_utils
|
||||
|
||||
@ -32,6 +33,7 @@ def main():
|
||||
cfg.CONF(project='climate', prog='climate-manager')
|
||||
service_utils.prepare_service(sys.argv)
|
||||
db_api.setup_db()
|
||||
notifier.init()
|
||||
service.launch(
|
||||
manager_service.ManagerService()
|
||||
).wait()
|
||||
|
@ -26,6 +26,7 @@ from climate.db import exceptions as db_ex
|
||||
from climate import exceptions as common_ex
|
||||
from climate import manager
|
||||
from climate.manager import exceptions
|
||||
from climate.notification import api as notification_api
|
||||
from climate.openstack.common.gettextutils import _
|
||||
from climate.openstack.common import log as logging
|
||||
from climate.utils import service as service_utils
|
||||
@ -36,6 +37,12 @@ manager_opts = [
|
||||
default=['dummy.vm.plugin'],
|
||||
help='All plugins to use (one for every resource type to '
|
||||
'support.)'),
|
||||
cfg.IntOpt('notify_hours_before_lease_end',
|
||||
default=48,
|
||||
help='Number of hours prior to lease end in which a '
|
||||
'notification of lease close to expire will be sent. If '
|
||||
'this is set to 0, then this notification will '
|
||||
'not be sent.')
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -137,6 +144,11 @@ class ManagerService(service_utils.RPCServer):
|
||||
try:
|
||||
eventlet.spawn_n(service_utils.with_empty_context(event_fn),
|
||||
event['lease_id'], event['id'])
|
||||
lease = db_api.lease_get(event['lease_id'])
|
||||
with trusts.create_ctx_from_trust(lease['trust_id']) as ctx:
|
||||
self._send_notification(lease,
|
||||
ctx,
|
||||
events=['event.%s' % event_type])
|
||||
except Exception:
|
||||
db_api.event_update(event['id'], {'status': 'ERROR'})
|
||||
LOG.exception(_('Error occurred while event handling.'))
|
||||
@ -200,6 +212,15 @@ class ManagerService(service_utils.RPCServer):
|
||||
'time': end_date,
|
||||
'status': 'UNDONE'})
|
||||
|
||||
if CONF.manager.notify_hours_before_lease_end > 0:
|
||||
delta = datetime.timedelta(
|
||||
hours=CONF.manager.notify_hours_before_lease_end)
|
||||
event = {'event_type': 'before_end_lease',
|
||||
'status': 'UNDONE'}
|
||||
lease_values['events'].append(event)
|
||||
|
||||
self._update_before_end_event_date(event, delta, lease_values)
|
||||
|
||||
try:
|
||||
lease = db_api.lease_create(lease_values)
|
||||
lease_id = lease['id']
|
||||
@ -229,7 +250,10 @@ class ManagerService(service_utils.RPCServer):
|
||||
raise
|
||||
|
||||
else:
|
||||
return db_api.lease_get(lease['id'])
|
||||
lease = db_api.lease_get(lease['id'])
|
||||
with trusts.create_ctx_from_trust(lease['trust_id']) as ctx:
|
||||
self._send_notification(lease, ctx, events=['create'])
|
||||
return lease
|
||||
|
||||
def update_lease(self, lease_id, values):
|
||||
if not values:
|
||||
@ -316,14 +340,22 @@ class ManagerService(service_utils.RPCServer):
|
||||
'End lease event not found')
|
||||
db_api.event_update(event['id'], {'time': values['end_date']})
|
||||
|
||||
notifications = ['update']
|
||||
self._update_before_end_event(lease, values, notifications)
|
||||
|
||||
db_api.lease_update(lease_id, values)
|
||||
return db_api.lease_get(lease_id)
|
||||
|
||||
lease = db_api.lease_get(lease_id)
|
||||
with trusts.create_ctx_from_trust(lease['trust_id']) as ctx:
|
||||
self._send_notification(lease, ctx, events=notifications)
|
||||
|
||||
return lease
|
||||
|
||||
def delete_lease(self, lease_id):
|
||||
lease = self.get_lease(lease_id)
|
||||
if (datetime.datetime.utcnow() < lease['start_date'] or
|
||||
datetime.datetime.utcnow() > lease['end_date']):
|
||||
with trusts.create_ctx_from_trust(lease['trust_id']):
|
||||
with trusts.create_ctx_from_trust(lease['trust_id']) as ctx:
|
||||
for reservation in lease['reservations']:
|
||||
try:
|
||||
self.plugins[reservation['resource_type']]\
|
||||
@ -333,6 +365,7 @@ class ManagerService(service_utils.RPCServer):
|
||||
"for a lease.")
|
||||
raise
|
||||
db_api.lease_destroy(lease_id)
|
||||
self._send_notification(lease, ctx, events=['delete'])
|
||||
else:
|
||||
raise common_ex.NotAuthorized(
|
||||
'Already started lease cannot be deleted')
|
||||
@ -347,6 +380,9 @@ class ManagerService(service_utils.RPCServer):
|
||||
with trusts.create_ctx_from_trust(lease['trust_id']):
|
||||
self._basic_action(lease_id, event_id, 'on_end', 'deleted')
|
||||
|
||||
def before_end_lease(self, lease_id, event_id):
|
||||
pass
|
||||
|
||||
def _basic_action(self, lease_id, event_id, action_time,
|
||||
reservation_status=None):
|
||||
"""Commits basic lease actions such as starting and ending."""
|
||||
@ -372,6 +408,39 @@ class ManagerService(service_utils.RPCServer):
|
||||
|
||||
db_api.event_update(event_id, {'status': 'DONE'})
|
||||
|
||||
def _send_notification(self, lease, ctx, events=[]):
|
||||
payload = notification_api.format_lease_payload(lease)
|
||||
|
||||
for event in events:
|
||||
notification_api.send_lease_notification(ctx, payload,
|
||||
'lease.%s' % event)
|
||||
|
||||
def _update_before_end_event_date(self, event, delta, lease):
|
||||
event['time'] = lease['end_date'] - delta
|
||||
if event['time'] < lease['start_date']:
|
||||
event['time'] = lease['start_date']
|
||||
|
||||
def _update_before_end_event(self, old_lease, new_lease, notifications):
|
||||
event = db_api.event_get_first_sorted_by_filters(
|
||||
'lease_id',
|
||||
'asc',
|
||||
{
|
||||
'lease_id': old_lease['id'],
|
||||
'event_type': 'before_end_lease'
|
||||
}
|
||||
)
|
||||
if event:
|
||||
# NOTE(casanch1) do nothing if the event does not exist.
|
||||
# This is for backward compatibility
|
||||
delta = old_lease['end_date'] - event['time']
|
||||
update_values = {}
|
||||
self._update_before_end_event_date(update_values, delta, new_lease)
|
||||
if event['status'] == 'DONE':
|
||||
update_values['status'] = 'UNDONE'
|
||||
notifications.append('event.before_end_lease.stop')
|
||||
|
||||
db_api.event_update(event['id'], update_values)
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""RPC Dispatcher for plugins methods."""
|
||||
|
||||
|
0
climate/notification/__init__.py
Normal file
0
climate/notification/__init__.py
Normal file
32
climate/notification/api.py
Normal file
32
climate/notification/api.py
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright 2014 Intel Corporation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 climate.notification import notifier
|
||||
|
||||
IMPL = notifier.Notifier()
|
||||
|
||||
|
||||
def send_lease_notification(context, lease, notification):
|
||||
IMPL.send_lease_notification(context, lease, notification)
|
||||
|
||||
|
||||
def format_lease_payload(lease):
|
||||
return {
|
||||
'lease_id': lease['id'],
|
||||
'user_id': lease['user_id'],
|
||||
'tenant_id': lease['tenant_id'],
|
||||
'start_date': lease['start_date'],
|
||||
'end_date': lease['end_date']
|
||||
}
|
68
climate/notification/notifier.py
Normal file
68
climate/notification/notifier.py
Normal file
@ -0,0 +1,68 @@
|
||||
# Copyright 2014 Intel Corporation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 climate.openstack.common import log
|
||||
from oslo.config import cfg
|
||||
from oslo import messaging
|
||||
|
||||
notification_opts = [
|
||||
cfg.StrOpt('publisher_id',
|
||||
default="climate.lease",
|
||||
help='Publisher ID for notifications')
|
||||
]
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
SERVICE = 'lease'
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(notification_opts, 'notifications')
|
||||
TRANSPORT = None
|
||||
NOTIFIER = None
|
||||
|
||||
|
||||
def init():
|
||||
global TRANSPORT, NOTIFIER
|
||||
TRANSPORT = messaging.get_transport(CONF)
|
||||
NOTIFIER = messaging.Notifier(TRANSPORT,
|
||||
publisher_id=CONF.notifications.publisher_id)
|
||||
|
||||
|
||||
def cleanup():
|
||||
global TRANSPORT, NOTIFIER
|
||||
assert TRANSPORT is not None
|
||||
assert NOTIFIER is not None
|
||||
TRANSPORT.cleanup()
|
||||
TRANSPORT = NOTIFIER = None
|
||||
|
||||
|
||||
def get_notifier(publisher_id):
|
||||
assert NOTIFIER is not None
|
||||
return NOTIFIER
|
||||
|
||||
|
||||
class Notifier(object):
|
||||
"""Notification class for climate
|
||||
|
||||
Responsible for sending lease events notifications using oslo.nofity
|
||||
"""
|
||||
|
||||
def send_lease_notification(self, context, lease, notification):
|
||||
"""Sends lease notification
|
||||
"""
|
||||
self._notify(context, 'info', notification, lease)
|
||||
|
||||
def _notify(self, context, level, event_type, payload):
|
||||
notifier = get_notifier(CONF.notifications.publisher_id)
|
||||
method = getattr(notifier, level, notifier.info)
|
||||
method(context, event_type, payload)
|
@ -26,6 +26,7 @@ from climate.db import exceptions as db_ex
|
||||
from climate import exceptions
|
||||
from climate.manager import exceptions as manager_ex
|
||||
from climate.manager import service
|
||||
from climate.notification import api as notifier_api
|
||||
from climate.plugins import base
|
||||
from climate.plugins import dummy_vm_plugin
|
||||
from climate.plugins.oshosts import host_plugin
|
||||
@ -80,6 +81,7 @@ class ServiceTestCase(tests.TestCase):
|
||||
self.db_api = db_api
|
||||
self.dummy_plugin = dummy_vm_plugin
|
||||
self.trusts = trusts
|
||||
self.notifier_api = notifier_api
|
||||
|
||||
self.fake_plugin = self.patch(self.dummy_plugin, 'DummyVMPlugin')
|
||||
|
||||
@ -88,10 +90,17 @@ class ServiceTestCase(tests.TestCase):
|
||||
'PhysicalHostPlugin')
|
||||
|
||||
self.ext_manager = self.patch(self.enabled, 'EnabledExtensionManager')
|
||||
self.fake_notifier = self.patch(self.notifier_api,
|
||||
'send_lease_notification')
|
||||
|
||||
self.manager = self.service.ManagerService()
|
||||
|
||||
self.lease_id = '11-22-33'
|
||||
self.user_id = '123'
|
||||
self.tenant_id = '555'
|
||||
self.lease = {'id': self.lease_id,
|
||||
'user_id': self.user_id,
|
||||
'tenant_id': self.tenant_id,
|
||||
'reservations': [{'id': '111',
|
||||
'resource_id': '111',
|
||||
'resource_type': 'virtual:instance',
|
||||
@ -104,7 +113,7 @@ class ServiceTestCase(tests.TestCase):
|
||||
self.good_date = datetime.datetime.strptime('2012-12-13 13:13',
|
||||
'%Y-%m-%d %H:%M')
|
||||
|
||||
self.patch(self.context, 'ClimateContext')
|
||||
self.ctx = self.patch(self.context, 'ClimateContext')
|
||||
self.trust_ctx = self.patch(self.trusts, 'create_ctx_from_trust')
|
||||
self.lease_get = self.patch(self.db_api, 'lease_get')
|
||||
self.lease_get.return_value = self.lease
|
||||
@ -120,6 +129,13 @@ class ServiceTestCase(tests.TestCase):
|
||||
{'on_start': self.fake_plugin.on_start,
|
||||
'on_end': self.fake_plugin.on_end}}
|
||||
|
||||
self.addCleanup(self.cfg.CONF.clear_override,
|
||||
'notify_hours_before_lease_end',
|
||||
group='manager')
|
||||
|
||||
def tearDown(self):
|
||||
super(ServiceTestCase, self).tearDown()
|
||||
|
||||
def test_start(self):
|
||||
#NOTE(starodubcevna): it's useless to test start() now, but may be in
|
||||
#future it become useful
|
||||
@ -178,6 +194,11 @@ class ServiceTestCase(tests.TestCase):
|
||||
|
||||
event_update.assert_called_once_with('111-222-333',
|
||||
{'status': 'IN_PROGRESS'})
|
||||
expected_context = self.trust_ctx.return_value
|
||||
self.fake_notifier.assert_called_once_with(
|
||||
expected_context.__enter__.return_value,
|
||||
notifier_api.format_lease_payload(self.lease),
|
||||
'lease.event.end_lease')
|
||||
|
||||
def test_event_wrong_event_status(self):
|
||||
events = self.patch(self.db_api, 'event_get_first_sorted_by_filters')
|
||||
@ -231,6 +252,11 @@ class ServiceTestCase(tests.TestCase):
|
||||
|
||||
self.lease_create.assert_called_once_with(lease_values)
|
||||
self.assertEqual(lease, self.lease)
|
||||
expected_context = self.trust_ctx.return_value
|
||||
self.fake_notifier.assert_called_once_with(
|
||||
expected_context.__enter__.return_value,
|
||||
notifier_api.format_lease_payload(lease),
|
||||
'lease.create')
|
||||
|
||||
def test_create_lease_some_time(self):
|
||||
lease_values = {
|
||||
@ -248,6 +274,113 @@ class ServiceTestCase(tests.TestCase):
|
||||
self.lease_create.assert_called_once_with(lease_values)
|
||||
self.assertEqual(lease, self.lease)
|
||||
|
||||
def test_create_lease_validate_created_events(self):
|
||||
lease_values = {
|
||||
'id': self.lease_id,
|
||||
'reservations': [{'id': '111',
|
||||
'resource_id': '111',
|
||||
'resource_type': 'virtual:instance',
|
||||
'status': 'FAKE PROGRESS'}],
|
||||
'start_date': '2026-11-13 13:13',
|
||||
'end_date': '2026-12-13 13:13'}
|
||||
self.lease['start_date'] = '2026-11-13 13:13'
|
||||
|
||||
lease = self.manager.create_lease(lease_values)
|
||||
|
||||
self.lease_create.assert_called_once_with(lease_values)
|
||||
self.assertEqual(lease, self.lease)
|
||||
self.assertEqual(3, len(lease_values['events']))
|
||||
|
||||
# start lease event
|
||||
event = lease_values['events'][0]
|
||||
self.assertEqual('start_lease', event['event_type'])
|
||||
self.assertEqual(lease_values['start_date'], event['time'])
|
||||
self.assertEqual('UNDONE', event['status'])
|
||||
|
||||
# end lease event
|
||||
event = lease_values['events'][1]
|
||||
self.assertEqual('end_lease', event['event_type'])
|
||||
self.assertEqual(lease_values['end_date'], event['time'])
|
||||
self.assertEqual('UNDONE', event['status'])
|
||||
|
||||
# end lease event
|
||||
event = lease_values['events'][2]
|
||||
self.assertEqual('before_end_lease', event['event_type'])
|
||||
delta = datetime.timedelta(
|
||||
hours=self.cfg.CONF.manager.notify_hours_before_lease_end)
|
||||
self.assertEqual(lease_values['end_date'] - delta, event['time'])
|
||||
self.assertEqual('UNDONE', event['status'])
|
||||
|
||||
def test_create_lease_before_end_event_is_before_lease_start(self):
|
||||
lease_values = {
|
||||
'id': self.lease_id,
|
||||
'reservations': [{'id': '111',
|
||||
'resource_id': '111',
|
||||
'resource_type': 'virtual:instance',
|
||||
'status': 'FAKE PROGRESS'}],
|
||||
'start_date': '2026-11-13 13:13',
|
||||
'end_date': '2026-11-14 13:13'}
|
||||
self.lease['start_date'] = '2026-11-13 13:13'
|
||||
|
||||
self.cfg.CONF.set_override('notify_hours_before_lease_end', 36,
|
||||
group='manager')
|
||||
|
||||
lease = self.manager.create_lease(lease_values)
|
||||
|
||||
self.lease_create.assert_called_once_with(lease_values)
|
||||
self.assertEqual(lease, self.lease)
|
||||
self.assertEqual(3, len(lease_values['events']))
|
||||
|
||||
# start lease event
|
||||
event = lease_values['events'][0]
|
||||
self.assertEqual('start_lease', event['event_type'])
|
||||
self.assertEqual(lease_values['start_date'], event['time'])
|
||||
self.assertEqual('UNDONE', event['status'])
|
||||
|
||||
# end lease event
|
||||
event = lease_values['events'][1]
|
||||
self.assertEqual('end_lease', event['event_type'])
|
||||
self.assertEqual(lease_values['end_date'], event['time'])
|
||||
self.assertEqual('UNDONE', event['status'])
|
||||
|
||||
# end lease event
|
||||
event = lease_values['events'][2]
|
||||
self.assertEqual('before_end_lease', event['event_type'])
|
||||
self.assertEqual(lease_values['start_date'], event['time'])
|
||||
self.assertEqual('UNDONE', event['status'])
|
||||
|
||||
def test_create_lease_no_before_end_event(self):
|
||||
lease_values = {
|
||||
'id': self.lease_id,
|
||||
'reservations': [{'id': '111',
|
||||
'resource_id': '111',
|
||||
'resource_type': 'virtual:instance',
|
||||
'status': 'FAKE PROGRESS'}],
|
||||
'start_date': '2026-11-13 13:13',
|
||||
'end_date': '2026-11-14 13:13'}
|
||||
self.lease['start_date'] = '2026-11-13 13:13'
|
||||
|
||||
self.cfg.CONF.set_override('notify_hours_before_lease_end', 0,
|
||||
group='manager')
|
||||
|
||||
lease = self.manager.create_lease(lease_values)
|
||||
|
||||
self.lease_create.assert_called_once_with(lease_values)
|
||||
self.assertEqual(lease, self.lease)
|
||||
self.assertEqual(2, len(lease_values['events']))
|
||||
|
||||
# start lease event
|
||||
event = lease_values['events'][0]
|
||||
self.assertEqual('start_lease', event['event_type'])
|
||||
self.assertEqual(lease_values['start_date'], event['time'])
|
||||
self.assertEqual('UNDONE', event['status'])
|
||||
|
||||
# end lease event
|
||||
event = lease_values['events'][1]
|
||||
self.assertEqual('end_lease', event['event_type'])
|
||||
self.assertEqual(lease_values['end_date'], event['time'])
|
||||
self.assertEqual('UNDONE', event['status'])
|
||||
|
||||
def test_create_lease_wrong_date(self):
|
||||
lease_values = {'start_date': '2025-13-35 13:13',
|
||||
'end_date': '2025-12-31 13:13'}
|
||||
@ -305,8 +438,13 @@ class ServiceTestCase(tests.TestCase):
|
||||
def fake_event_get(sort_key, sort_dir, filters):
|
||||
if filters['event_type'] == 'start_lease':
|
||||
return {'id': u'2eeb784a-2d84-4a89-a201-9d42d61eecb1'}
|
||||
else:
|
||||
elif filters['event_type'] == 'end_lease':
|
||||
return {'id': u'7085381b-45e0-4e5d-b24a-f965f5e6e5d7'}
|
||||
elif filters['event_type'] == 'before_end_lease':
|
||||
delta = datetime.timedelta(hours=1)
|
||||
return {'id': u'452bf850-e223-4035-9d13-eb0b0197228f',
|
||||
'time': self.lease['end_date'] - delta,
|
||||
'status': 'UNDONE'}
|
||||
|
||||
lease_values = {
|
||||
'name': 'renamed',
|
||||
@ -343,17 +481,21 @@ class ServiceTestCase(tests.TestCase):
|
||||
calls = [mock.call('2eeb784a-2d84-4a89-a201-9d42d61eecb1',
|
||||
{'time': datetime.datetime(2015, 12, 1, 20, 00)}),
|
||||
mock.call('7085381b-45e0-4e5d-b24a-f965f5e6e5d7',
|
||||
{'time': datetime.datetime(2015, 12, 1, 22, 00)})
|
||||
{'time': datetime.datetime(2015, 12, 1, 22, 00)}),
|
||||
mock.call('452bf850-e223-4035-9d13-eb0b0197228f',
|
||||
{'time': datetime.datetime(2015, 12, 1, 21, 00)})
|
||||
]
|
||||
self.event_update.assert_has_calls(calls)
|
||||
self.lease_update.assert_called_once_with(self.lease_id, lease_values)
|
||||
|
||||
def test_update_lease_started_modify_end_date(self):
|
||||
def test_update_lease_started_modify_end_date_without_before_end(self):
|
||||
def fake_event_get(sort_key, sort_dir, filters):
|
||||
if filters['event_type'] == 'start_lease':
|
||||
return {'id': u'2eeb784a-2d84-4a89-a201-9d42d61eecb1'}
|
||||
else:
|
||||
elif filters['event_type'] == 'end_lease':
|
||||
return {'id': u'7085381b-45e0-4e5d-b24a-f965f5e6e5d7'}
|
||||
else:
|
||||
return None
|
||||
|
||||
lease_values = {
|
||||
'name': 'renamed',
|
||||
@ -394,6 +536,70 @@ class ServiceTestCase(tests.TestCase):
|
||||
self.event_update.assert_has_calls(calls)
|
||||
self.lease_update.assert_called_once_with(self.lease_id, lease_values)
|
||||
|
||||
def test_update_lease_started_modify_end_date_and_before_end(self):
|
||||
def fake_event_get(sort_key, sort_dir, filters):
|
||||
if filters['event_type'] == 'start_lease':
|
||||
return {'id': u'2eeb784a-2d84-4a89-a201-9d42d61eecb1'}
|
||||
elif filters['event_type'] == 'end_lease':
|
||||
return {'id': u'7085381b-45e0-4e5d-b24a-f965f5e6e5d7'}
|
||||
elif filters['event_type'] == 'before_end_lease':
|
||||
delta = datetime.timedelta(hours=1)
|
||||
return {'id': u'452bf850-e223-4035-9d13-eb0b0197228f',
|
||||
'time': self.lease['end_date'] - delta,
|
||||
'status': 'DONE'}
|
||||
|
||||
lease_values = {
|
||||
'name': 'renamed',
|
||||
'end_date': '2013-12-20 16:00'
|
||||
}
|
||||
reservation_get_all = \
|
||||
self.patch(self.db_api, 'reservation_get_all_by_lease_id')
|
||||
reservation_get_all.return_value = [
|
||||
{
|
||||
'id': u'593e7028-c0d1-4d76-8642-2ffd890b324c',
|
||||
'resource_type': 'virtual:instance',
|
||||
'start_date': datetime.datetime(2013, 12, 20, 13, 00),
|
||||
'end_date': datetime.datetime(2013, 12, 20, 15, 00)
|
||||
}
|
||||
]
|
||||
event_get = self.patch(db_api, 'event_get_first_sorted_by_filters')
|
||||
event_get.side_effect = fake_event_get
|
||||
target = datetime.datetime(2013, 12, 20, 14, 00)
|
||||
with mock.patch.object(datetime,
|
||||
'datetime',
|
||||
mock.Mock(wraps=datetime.datetime)) as patched:
|
||||
patched.utcnow.return_value = target
|
||||
self.manager.update_lease(self.lease_id, lease_values)
|
||||
self.fake_plugin.update_reservation.assert_called_with(
|
||||
'593e7028-c0d1-4d76-8642-2ffd890b324c',
|
||||
{
|
||||
'id': '593e7028-c0d1-4d76-8642-2ffd890b324c',
|
||||
'resource_type': 'virtual:instance',
|
||||
'start_date': datetime.datetime(2013, 12, 20, 13, 00),
|
||||
'end_date': datetime.datetime(2013, 12, 20, 16, 00)
|
||||
}
|
||||
)
|
||||
expected_context = self.trust_ctx.return_value
|
||||
calls = [mock.call(expected_context.__enter__.return_value,
|
||||
notifier_api.format_lease_payload(self.lease),
|
||||
'lease.update'),
|
||||
mock.call(expected_context.__enter__.return_value,
|
||||
notifier_api.format_lease_payload(self.lease),
|
||||
'lease.event.before_end_lease.stop'),
|
||||
]
|
||||
self.fake_notifier.assert_has_calls(calls)
|
||||
|
||||
calls = [mock.call('2eeb784a-2d84-4a89-a201-9d42d61eecb1',
|
||||
{'time': datetime.datetime(2013, 12, 20, 13, 00)}),
|
||||
mock.call('7085381b-45e0-4e5d-b24a-f965f5e6e5d7',
|
||||
{'time': datetime.datetime(2013, 12, 20, 16, 00)}),
|
||||
mock.call('452bf850-e223-4035-9d13-eb0b0197228f',
|
||||
{'time': datetime.datetime(2013, 12, 20, 15, 00),
|
||||
'status': 'UNDONE'})
|
||||
]
|
||||
self.event_update.assert_has_calls(calls)
|
||||
self.lease_update.assert_called_once_with(self.lease_id, lease_values)
|
||||
|
||||
def test_update_lease_is_not_values(self):
|
||||
lease_values = None
|
||||
lease = self.manager.update_lease(self.lease_id, lease_values)
|
||||
@ -524,7 +730,12 @@ class ServiceTestCase(tests.TestCase):
|
||||
patched.utcnow.return_value = target
|
||||
self.manager.delete_lease(self.lease_id)
|
||||
|
||||
expected_context = self.trust_ctx.return_value
|
||||
self.lease_destroy.assert_called_once_with(self.lease_id)
|
||||
self.fake_notifier.assert_called_once_with(
|
||||
expected_context.__enter__.return_value,
|
||||
self.notifier_api.format_lease_payload(self.lease),
|
||||
'lease.delete')
|
||||
|
||||
def test_delete_lease_after_starting_date(self):
|
||||
self.patch(self.manager, 'get_lease').\
|
||||
@ -559,6 +770,9 @@ class ServiceTestCase(tests.TestCase):
|
||||
basic_action.assert_called_once_with(self.lease_id, '1', 'on_end',
|
||||
'deleted')
|
||||
|
||||
def test_before_end_lease(self):
|
||||
self.manager.before_end_lease(self.lease_id, '1')
|
||||
|
||||
def test_basic_action_no_res_status(self):
|
||||
self.patch(self.manager, 'get_lease').return_value = self.lease
|
||||
|
||||
|
0
climate/tests/notification/__init__.py
Normal file
0
climate/tests/notification/__init__.py
Normal file
81
climate/tests/notification/test_notifier.py
Normal file
81
climate/tests/notification/test_notifier.py
Normal file
@ -0,0 +1,81 @@
|
||||
# Copyright 2014 Intel Corporation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 oslo.config import cfg
|
||||
from oslo import messaging
|
||||
|
||||
from climate.notification import notifier as notification
|
||||
from climate import tests
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class FakeNotifier(object):
|
||||
def info(self):
|
||||
pass
|
||||
|
||||
|
||||
class NotifierTestCase(tests.TestCase):
|
||||
def setUp(self):
|
||||
super(NotifierTestCase, self).setUp()
|
||||
|
||||
self.group = 'notifications'
|
||||
CONF.set_override('publisher_id', 'lease-service', self.group)
|
||||
|
||||
# Fake Oslo notifier
|
||||
self.fake_notifier = self.patch(messaging, 'Notifier')
|
||||
self.fake_notifier.return_value = FakeNotifier()
|
||||
self.fake_transport = self.patch(messaging,
|
||||
'get_transport').return_value
|
||||
|
||||
self.info_method = self.patch(FakeNotifier, 'info')
|
||||
|
||||
self.context = {'user_id': 1, 'token': 'aabbcc'}
|
||||
self.payload = {'id': 1, 'name': 'Lease1', 'start-date': 'now'}
|
||||
|
||||
notification.init()
|
||||
self.notifier = notification.Notifier()
|
||||
|
||||
def test_notify_with_wrong_level(self):
|
||||
self.notifier._notify(self.context, 'wrong', 'event', self.payload)
|
||||
self.info_method.assert_called_once_with(self.context,
|
||||
'event', self.payload)
|
||||
|
||||
def test_send_lease_event(self):
|
||||
self.notifier.send_lease_notification(self.context, self.payload,
|
||||
'start')
|
||||
self.info_method.assert_called_once_with(self.context,
|
||||
'start',
|
||||
self.payload)
|
||||
|
||||
def test_cleanup(self):
|
||||
notification.cleanup()
|
||||
|
||||
self.fake_transport.cleanup.assert_called_once_with()
|
||||
self.assertIsNone(notification.NOTIFIER)
|
||||
self.assertIsNone(notification.TRANSPORT)
|
||||
|
||||
def test_init(self):
|
||||
self.fake_transport.called_once
|
||||
self.fake_notifier.called_once_with(self.fake_transport,
|
||||
publisher_id='lease-service')
|
||||
|
||||
def test_init_called_twice_returns_same_instance(self):
|
||||
prev_notifier = notification.NOTIFIER
|
||||
prev_transport = notification.TRANSPORT
|
||||
|
||||
notification.init()
|
||||
self.assertIs(prev_notifier, notification.NOTIFIER)
|
||||
self.assertIs(prev_transport, notification.TRANSPORT)
|
@ -704,6 +704,11 @@
|
||||
# (list value)
|
||||
#plugins=dummy.vm.plugin
|
||||
|
||||
# Number of hours prior to lease end in which a notification
|
||||
# of lease close to expire will be sent. If this is set to 0,
|
||||
# then this notification will not be sent. (integer value)
|
||||
#notify_hours_before_lease_end=48
|
||||
|
||||
|
||||
[matchmaker_ring]
|
||||
|
||||
@ -716,6 +721,16 @@
|
||||
#ringfile=/etc/oslo/matchmaker_ring.json
|
||||
|
||||
|
||||
[notifications]
|
||||
|
||||
#
|
||||
# Options defined in climate.notification.notifier
|
||||
#
|
||||
|
||||
# Publisher ID for notifications (string value)
|
||||
#publisher_id=climate.lease
|
||||
|
||||
|
||||
[physical:host]
|
||||
|
||||
#
|
||||
|
Loading…
x
Reference in New Issue
Block a user