# -*- coding: utf-8 -*- # Copyright 2013 Mirantis, Inc. # # 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 mock import patch import nailgun from nailgun import consts from nailgun.db.sqlalchemy.models.notification import Notification from nailgun.db.sqlalchemy.models.task import Task from nailgun import objects from nailgun.rpc.receiver import NailgunReceiver from nailgun.test.base import BaseIntegrationTest from nailgun.test.base import fake_tasks from nailgun.test.base import reverse class TestStopDeployment(BaseIntegrationTest): def setUp(self): super(TestStopDeployment, self).setUp() self.cluster = self.env.create( nodes_kwargs=[ {"name": "First", "pending_addition": True}, {"name": "Second", "roles": ["compute"], "pending_addition": True} ] ) self.controller = self.env.nodes[0] self.compute = self.env.nodes[1] self.node_uids = [n.uid for n in self.cluster.nodes][:3] @fake_tasks(fake_rpc=False) def test_stop_deployment(self, _): supertask = self.env.launch_deployment() self.assertEqual(supertask.status, consts.TASK_STATUSES.pending) deploy_task = [t for t in supertask.subtasks if t.name == consts.TASK_NAMES.deployment][0] NailgunReceiver.deploy_resp( task_uuid=deploy_task.uuid, status=consts.TASK_STATUSES.running, progress=50, ) stop_task = self.env.stop_deployment() NailgunReceiver.stop_deployment_resp( task_uuid=stop_task.uuid, status=consts.TASK_STATUSES.ready, progress=100, nodes=[{'uid': n.uid} for n in self.env.nodes], ) self.assertEqual(stop_task.status, consts.TASK_STATUSES.ready) self.assertTrue(self.db().query(Task).filter_by( uuid=deploy_task.uuid ).first()) self.assertIsNone(objects.Task.get_by_uuid(deploy_task.uuid)) self.assertEqual(self.cluster.status, consts.CLUSTER_STATUSES.stopped) self.assertEqual(stop_task.progress, 100) self.assertFalse(self.cluster.is_locked) for n in self.cluster.nodes: self.assertEqual(n.roles, []) self.assertNotEqual(n.pending_roles, []) notification = self.db.query(Notification).filter_by( cluster_id=stop_task.cluster_id ).order_by( Notification.datetime.desc() ).first() self.assertRegexpMatches( notification.message, 'was successfully stopped') # FIXME(aroma): remove when stop action will be reworked for ha # cluster. To get more details, please, refer to [1] # [1]: https://bugs.launchpad.net/fuel/+bug/1529691 @fake_tasks(fake_rpc=False) def test_stop_deployment_fail_if_deployed_before(self, _): task = self.env.launch_deployment() deploy_task = [t for t in task.subtasks if t.name == consts.TASK_NAMES.deployment][0] # In objects/task.py cluster status is set to operational. Cluster # function __update_cluster_status checks if nodes are in # expected_node_status, and if they are - then # set_deployed_before_flag is set. This flag is used to determine if # cluster was ever deployed before. NailgunReceiver.deploy_resp( task_uuid=deploy_task.uuid, status=consts.TASK_STATUSES.ready, progress=100, nodes=[{'uid': n.uid, 'status': consts.NODE_STATUSES.ready} for n in self.env.nodes], ) # If we don't send 'ready' for main task, then redeploy can't be # started - as we still have deployment running # TODO(mihgen): investigate why DeploymentAlreadyStarted is unhandled NailgunReceiver.deploy_resp( task_uuid=task.uuid, status=consts.TASK_STATUSES.ready, ) # changes to deploy self.env.create_node( cluster_id=self.cluster.id, roles=["controller"], pending_addition=True ) supertask = self.env.launch_deployment() redeploy_task = [t for t in supertask.subtasks if t.name == consts.TASK_NAMES.deployment][0] NailgunReceiver.deploy_resp( task_uuid=redeploy_task.uuid, status=consts.TASK_STATUSES.running, progress=50, ) # stop task will not be created as in this situation # the error will be raised by validator thus we cannot use # self.env.stop_deployment to check the result resp = self.app.put( reverse( 'ClusterStopDeploymentHandler', kwargs={'cluster_id': self.cluster.id}), expect_errors=True, headers=self.default_headers ) self.assertEqual(resp.status_code, 400) self.assertEqual(resp.json_body['message'], 'Stop action is forbidden for the cluster') @fake_tasks(fake_rpc=False, mock_rpc=False) @patch('nailgun.rpc.cast') def test_admin_ip_in_args(self, mocked_rpc): deploy_task = self.env.launch_deployment() provision_task = objects.TaskCollection.filter_by( None, name=consts.TASK_NAMES.provision, parent_id=deploy_task.id).first() provision_task.status = consts.TASK_STATUSES.running self.env.db.flush() self.env.stop_deployment() args, kwargs = nailgun.task.manager.rpc.cast.call_args for n in args[1]["args"]["nodes"]: self.assertIn("admin_ip", n) n_db = objects.Node.get_by_uid(n["uid"]) self.assertEqual( n["admin_ip"], objects.Cluster.get_network_manager( n_db.cluster ).get_admin_ip_for_node(n_db) ) @fake_tasks(fake_rpc=False) def test_stop_provisioning(self, _): provision_task = self.env.launch_provisioning_selected( self.node_uids ) provision_task_uuid = provision_task.uuid NailgunReceiver.provision_resp( task_uuid=provision_task.uuid, status=consts.TASK_STATUSES.running, progress=50, ) stop_task = self.env.stop_deployment() NailgunReceiver.stop_deployment_resp( task_uuid=stop_task.uuid, status=consts.TASK_STATUSES.ready, progress=100, nodes=[{'uid': n.uid} for n in self.env.nodes], ) self.assertEqual(stop_task.status, consts.TASK_STATUSES.ready) self.assertTrue(self.db().query(Task).filter_by( uuid=provision_task_uuid ).first()) self.assertIsNone(objects.Task.get_by_uuid(provision_task_uuid)) self.assertEqual(self.cluster.status, consts.CLUSTER_STATUSES.stopped) self.assertEqual(stop_task.progress, 100) self.assertFalse(self.cluster.is_locked) @patch('nailgun.rpc.cast') def test_latest_task_is_sent(self, mocked_rpc): for uuid, status in [(1, consts.TASK_STATUSES.ready), (2, consts.TASK_STATUSES.running)]: self.env.create_task( name=consts.TASK_NAMES.deployment, uuid="deploy-{0}".format(uuid), status=status, cluster_id=self.cluster.id) self.env.create_task( name=consts.TASK_NAMES.provision, uuid="provision-{0}".format(uuid), status=status, cluster_id=self.cluster.id) self.env.stop_deployment() rpc_args_list = nailgun.task.manager.rpc.cast.call_args_list self.assertEqual(len(rpc_args_list), 2) provision, deploy = rpc_args_list (_, deploy_args), _ = deploy (_, provision_args), _ = provision self.assertEqual(deploy_args['args']['stop_task_uuid'], 'deploy-2') self.assertEqual(provision_args['args']['stop_task_uuid'], 'provision-2')