Added provision notifications

Added notification of provisioning results. Success and errors.

Change-Id: Ia500a9c2c36d146d0ba9dba008502801fccd9ca3
Partial-Bug: 1515891
This commit is contained in:
Valentin Kaplov 2015-11-16 20:27:47 +03:00
parent 54b0a43628
commit 83225f87f3
3 changed files with 257 additions and 33 deletions

View File

@ -314,8 +314,9 @@ class NailgunReceiver(object):
node_db.error_msg = u"Node is offline"
# Notification on particular node failure
notifier.notify(
"error",
u"Failed to deploy node '{0}': {1}".format(
consts.NOTIFICATION_TOPICS.error,
u"Failed to {0} node '{1}': {2}".format(
consts.TASK_NAMES.deploy,
node_db.name,
node_db.error_msg or "Unknown error"
),
@ -331,15 +332,7 @@ class NailgunReceiver(object):
if master.get('status') == consts.TASK_STATUSES.error:
status = consts.TASK_STATUSES.error
# Let's check the whole task status
if status == consts.TASK_STATUSES.error:
cls._error_action(task, status, progress, message)
elif status == consts.TASK_STATUSES.ready:
cls._success_action(task, status, progress)
else:
data = {'status': status, 'progress': progress, 'message': message}
objects.Task.update(task, data)
cls._update_task_status(task, status, progress, message)
cls._update_action_log_entry(status, task.name, task_uuid, nodes)
@classmethod
@ -392,7 +385,7 @@ class NailgunReceiver(object):
if node.get('status') == consts.TASK_STATUSES.error:
node_db.status = consts.TASK_STATUSES.error
node_db.progress = 100
node_db.error_type = 'provision'
node_db.error_type = consts.TASK_NAMES.provision
node_db.error_msg = node.get('error_msg', 'Unknown error')
else:
node_db.status = node.get('status')
@ -402,9 +395,7 @@ class NailgunReceiver(object):
if nodes and not progress:
progress = TaskHelper.recalculate_provisioning_task_progress(task)
data = {'status': status, 'progress': progress, 'message': message}
objects.Task.update(task, data)
cls._update_task_status(task, status, progress, message)
cls._update_action_log_entry(status, task.name, task_uuid, nodes)
@classmethod
@ -448,6 +439,48 @@ class NailgunReceiver(object):
cls._update_action_log_entry(status, task.name, task_uuid, nodes)
@classmethod
def _notify(cls, task, topic, message, node_id=None, task_uuid=None):
"""Send notification.
:param task: objects.Task object
:param topic: consts.NOTIFICATION_TOPICS value
:param message: message text
:param node_id: node identifier
:param task_uuid: task uuid. specify task_uuid if necessary to pass it
"""
# Due to design of UI, that shows all notifications,
# we should notify provision task only then the task is top-level task
if task.name == consts.TASK_NAMES.provision \
and task.parent_id is not None:
return
notifier.notify(
topic,
message,
task.cluster_id,
node_id=node_id,
task_uuid=task_uuid
)
@classmethod
def _update_task_status(cls, task, status, progress, message):
"""Do update task status actions.
:param task: objects.Task object
:param status: consts.TASK_STATUSES value
:param progress: progress number value
:param message: message text
"""
# Let's check the whole task status
if status == consts.TASK_STATUSES.error:
cls._error_action(task, status, progress, message)
elif status == consts.TASK_STATUSES.ready:
cls._success_action(task, status, progress)
else:
data = {'status': status, 'progress': progress, 'message': message}
objects.Task.update(task, data)
@classmethod
def _update_action_log_entry(cls, task_status, task_name, task_uuid,
nodes_from_resp):
@ -527,11 +560,7 @@ class NailgunReceiver(object):
)
notify_message = message
notifier.notify(
"error",
notify_message,
task.cluster_id
)
cls._notify(task, consts.NOTIFICATION_TOPICS.error, notify_message)
data = {'status': status, 'progress': progress, 'message': message}
objects.Task.update(task, data)
@ -574,7 +603,7 @@ class NailgunReceiver(object):
if plugins_msg:
message = '{0}\n\n{1}'.format(message, plugins_msg)
notifier.notify("done", message, task.cluster_id)
cls._notify(task, consts.NOTIFICATION_TOPICS.done, message)
data = {'status': status, 'progress': progress, 'message': message}
objects.Task.update(task, data)

View File

@ -1176,35 +1176,153 @@ class TestConsumer(BaseReciverTestCase):
self.assertEqual(supertask.progress, calculated_progress)
def test_error_node_progress(self):
def _prepare_task(self, name):
self.env.create(
cluster_kwargs={},
nodes_kwargs=[
{"api": False},
{"api": False}
]
)
task = Task(
uuid=str(uuid.uuid4()),
name="super",
status="running",
name=name,
status=consts.TASK_STATUSES.running,
cluster_id=self.env.clusters[0].id
)
self.db.add(task)
self.db.commit()
kwargs = {
'task_uuid': task.uuid,
'progress': 20,
self.db.flush()
return task
def _prepare_sub_task(self, name):
task = self._prepare_task(consts.TASK_NAMES.super)
sub_task = Task(
uuid=str(uuid.uuid4()),
name=name,
status=consts.TASK_STATUSES.running,
cluster_id=self.env.clusters[0].id,
parent_id=task.id
)
self.db.add(sub_task)
self.db.flush()
return sub_task
def _create_resp_kwargs(
self,
task_uuid,
status,
progress,
node_status,
node_progress
):
return {
'task_uuid': task_uuid,
'progress': progress,
'status': status,
'nodes': [
{
'uid': self.env.nodes[0].id,
'status': 'error',
'status': node_status,
'progress': node_progress
}
]
}
def test_deploy_resp_error_node_progress(self):
task = self._prepare_task(consts.TASK_NAMES.deployment)
kwargs = self._create_resp_kwargs(
task.uuid, consts.TASK_STATUSES.running, 20,
consts.TASK_STATUSES.error, 50
)
self.receiver.deploy_resp(**kwargs)
self.db.refresh(self.env.nodes[0])
self.assertEqual(self.env.nodes[0].progress, 100)
def test_provision_resp_error_node_progress(self):
task = self._prepare_task(consts.TASK_NAMES.provision)
kwargs = self._create_resp_kwargs(
task.uuid, consts.TASK_STATUSES.running, 20,
consts.TASK_STATUSES.error, 50
)
self.receiver.provision_resp(**kwargs)
self.db.refresh(self.env.nodes[0])
self.assertEqual(self.env.nodes[0].progress, 100)
def test_provision_resp_error_notification(self):
task = self._prepare_task(consts.TASK_NAMES.provision)
kwargs = self._create_resp_kwargs(
task.uuid, consts.TASK_STATUSES.error, 20,
consts.TASK_STATUSES.error, 50
)
self.receiver.provision_resp(**kwargs)
notifications_number = self.db.query(Notification).filter_by(
cluster_id=task.cluster_id
).count()
self.assertEqual(1, notifications_number)
def test_provision_resp_sub_task_no_error_notification(self):
sub_task = self._prepare_sub_task(consts.TASK_NAMES.provision)
kwargs = self._create_resp_kwargs(
sub_task.uuid, consts.TASK_STATUSES.error, 20,
consts.TASK_STATUSES.error, 50
)
self.receiver.provision_resp(**kwargs)
notifications_number = self.db.query(Notification).filter_by(
cluster_id=sub_task.cluster_id
).count()
self.assertEqual(0, notifications_number)
def test_provision_resp_success_notification(self):
task = self._prepare_task(consts.TASK_NAMES.provision)
kwargs = self._create_resp_kwargs(
task.uuid, consts.TASK_STATUSES.ready, 100,
consts.TASK_STATUSES.ready, 100
)
self.receiver.provision_resp(**kwargs)
notifications_number = self.db.query(Notification).filter_by(
cluster_id=task.cluster_id
).count()
self.assertEqual(1, notifications_number)
def test_provision_resp_sub_task_no_success_notification(self):
sub_task = self._prepare_sub_task(consts.TASK_NAMES.provision)
kwargs = self._create_resp_kwargs(
sub_task.uuid, consts.TASK_STATUSES.ready, 100,
consts.TASK_STATUSES.ready, 100
)
self.receiver.provision_resp(**kwargs)
notifications_number = self.db.query(Notification).filter_by(
cluster_id=sub_task.cluster_id
).count()
self.assertEqual(0, notifications_number)
def test_provision_resp_nodes_failed(self):
task = self._prepare_task(consts.TASK_NAMES.provision)
kwargs = {
'task_uuid': task.uuid,
'progress': 20,
'status': consts.TASK_STATUSES.ready,
'nodes': [
{
'uid': self.env.nodes[0].id,
'status': consts.TASK_STATUSES.error,
'progress': 50
},
{
'uid': self.env.nodes[1].id,
'status': consts.TASK_STATUSES.error,
'progress': 50
}
]
}
self.receiver.deploy_resp(**kwargs)
self.db.refresh(self.env.nodes[0])
self.assertEqual(self.env.nodes[0].progress, 100)
self.receiver.provision_resp(**kwargs)
notifications_number = self.db.query(Notification).filter_by(
cluster_id=task.cluster_id).count()
self.assertEqual(1, notifications_number)
self.assertRegexpMatches(
task.message,
u"Provision has failed\. Check these nodes:\n'(.*)', '(.*)'")
def test_remove_nodes_resp(self):
self.env.create(

View File

@ -90,7 +90,10 @@ class TestNailgunReceiver(base.BaseTestCase):
mnotify.assert_called_with(
task_resp['status'],
u'Deployment has failed. Method granular_deploy.',
self.cluster.id)
self.cluster.id,
task_uuid=None,
node_id=None
)
@patch('nailgun.objects.Task.update_verify_networks')
def test_check_repositories_resp_success(self, update_verify_networks):
@ -158,3 +161,77 @@ class TestNailgunReceiver(base.BaseTestCase):
self.db.flush()
NailgunReceiver.task_in_orchestrator(**resp)
self.assertEqual(status, self.task.status)
@patch('nailgun.rpc.receiver.notifier.notify')
def test_notify_provision(self, notify_checker):
NailgunReceiver._notify(
self.task,
"done",
"Test error.",
"123",
self.task.uuid
)
notify_checker.assert_called_with(
"done",
u'Test error.',
self.task.cluster_id,
node_id="123",
task_uuid=self.task.uuid
)
@patch('nailgun.rpc.receiver.notifier.notify')
def test_notify_provision_sub_task(self, notify_checker):
sub_task = self.env.create_task(
name=consts.TASK_NAMES.provision,
status=consts.TASK_STATUSES.ready,
cluster_id=self.cluster.id,
parent_id=self.task.id
)
NailgunReceiver._notify(
sub_task,
"done",
"Test error.",
"123",
sub_task.uuid
)
self.assertEqual(0, notify_checker.call_count)
@patch('nailgun.rpc.receiver.notifier.notify')
def test_notify_deployment(self, notify_checker):
NailgunReceiver._notify(
self.task,
"done",
"Test error.",
"123",
self.task.uuid
)
notify_checker.assert_called_with(
"done",
u'Test error.',
self.task.cluster_id,
node_id="123",
task_uuid=self.task.uuid
)
@patch('nailgun.rpc.receiver.notifier.notify')
def test_notify_deployment_sub_task(self, notify_checker):
sub_task = self.env.create_task(
name=consts.TASK_NAMES.deployment,
status=consts.TASK_STATUSES.ready,
cluster_id=self.cluster.id,
parent_id=self.task.id
)
NailgunReceiver._notify(
sub_task,
"done",
"Test error.",
"123",
sub_task.uuid
)
notify_checker.assert_called_with(
"done",
u'Test error.',
sub_task.cluster_id,
node_id="123",
task_uuid=sub_task.uuid
)