Fuel UI
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_task.py 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2013 Mirantis, Inc.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. # not use this file except in compliance with the License. You may obtain
  6. # a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. # License for the specific language governing permissions and limitations
  14. # under the License.
  15. import mock
  16. import six
  17. from oslo_serialization import jsonutils
  18. from nailgun import consts
  19. from nailgun.db.sqlalchemy.models import Task
  20. from nailgun import errors
  21. from nailgun import objects
  22. from nailgun.task import task
  23. from nailgun.test.base import BaseTestCase
  24. from nailgun.utils import reverse
  25. class TestClusterDeletionTask(BaseTestCase):
  26. def create_cluster_and_execute_deletion_task(
  27. self, attributes=None, os=consts.RELEASE_OS.centos):
  28. cluster = self.env.create(
  29. cluster_kwargs={
  30. 'editable_attributes': attributes,
  31. },
  32. release_kwargs={
  33. 'operating_system': os,
  34. 'version': '2025-7.0',
  35. },
  36. )
  37. self.fake_task = Task(name=consts.TASK_NAMES.cluster_deletion,
  38. cluster=cluster)
  39. task.ClusterDeletionTask.execute(self.fake_task)
  40. @mock.patch('nailgun.task.task.DeletionTask', autospec=True)
  41. @mock.patch.object(task.DeleteIBPImagesTask, 'execute')
  42. def test_target_images_deletion_skipped_empty_attributes(
  43. self, mock_img_task, mock_del):
  44. self.create_cluster_and_execute_deletion_task({})
  45. self.assertTrue(mock_del.execute.called)
  46. self.assertFalse(mock_img_task.called)
  47. @mock.patch('nailgun.task.task.DeletionTask', autospec=True)
  48. @mock.patch.object(task.DeleteIBPImagesTask, 'execute')
  49. def test_target_images_deletion_skipped_os_centos(
  50. self, mock_img_task, mock_del):
  51. attributes = {'provision': {
  52. 'method': consts.PROVISION_METHODS.image,
  53. }}
  54. self.create_cluster_and_execute_deletion_task(attributes)
  55. self.assertTrue(mock_del.execute.called)
  56. self.assertFalse(mock_img_task.called)
  57. @mock.patch('nailgun.task.task.DeletionTask', autospec=True)
  58. @mock.patch.object(task.DeleteIBPImagesTask, 'execute')
  59. def test_target_images_deletion_skipped_os_ubuntu_cobbler(
  60. self, mock_img_task, mock_del):
  61. os = consts.RELEASE_OS.ubuntu
  62. attributes = {'provision': {
  63. 'method': consts.PROVISION_METHODS.cobbler,
  64. }}
  65. self.create_cluster_and_execute_deletion_task(attributes, os)
  66. self.assertTrue(mock_del.execute.called)
  67. self.assertFalse(mock_img_task.called)
  68. @mock.patch('nailgun.task.task.DeletionTask', autospec=True)
  69. @mock.patch.object(task.DeleteIBPImagesTask, 'execute')
  70. def test_target_images_deletion_executed(self, mock_img_task, mock_del):
  71. os = consts.RELEASE_OS.ubuntu
  72. attributes = {'provision': {
  73. 'method': consts.PROVISION_METHODS.image,
  74. }}
  75. self.create_cluster_and_execute_deletion_task(attributes, os)
  76. self.assertTrue(mock_del.execute.called)
  77. self.assertTrue(mock_img_task.called)
  78. fake_attrs = objects.Attributes.merged_attrs_values(
  79. self.fake_task.cluster.attributes)
  80. mock_img_task.assert_called_once_with(
  81. mock.ANY, fake_attrs['provision']['image_data'])
  82. class TestDeleteIBPImagesTask(BaseTestCase):
  83. @mock.patch('nailgun.task.task.settings')
  84. @mock.patch('nailgun.task.task.make_astute_message')
  85. def test_message(self, mock_astute, mock_settings):
  86. mock_settings.PROVISIONING_IMAGES_PATH = '/fake/path'
  87. mock_settings.REMOVE_IMAGES_TIMEOUT = 'fake_timeout'
  88. task_mock = mock.Mock()
  89. task_mock.cluster.id = '123'
  90. task_mock.uuid = 'fake_uuid'
  91. fake_image_data = {'/': {'uri': 'http://a.b/fake.img'},
  92. '/boot': {'uri': 'http://c.d/fake-boot.img'}}
  93. task.DeleteIBPImagesTask.message(task_mock, fake_image_data)
  94. rpc_message = mock_astute.call_args[0][3]
  95. rm_cmd = rpc_message['tasks'][0]['parameters'].pop('cmd')
  96. mock_astute.assert_called_once_with(
  97. mock.ANY, 'execute_tasks', 'remove_images_resp', mock.ANY)
  98. self.assertEqual(rpc_message, {
  99. 'tasks': [{
  100. 'id': None,
  101. 'type': 'shell',
  102. 'uids': [consts.MASTER_NODE_UID],
  103. 'parameters': {
  104. 'retries': 3,
  105. 'cwd': '/',
  106. 'timeout': 'fake_timeout',
  107. 'interval': 1}}]})
  108. self.assertTrue(rm_cmd.startswith('rm -f'))
  109. self.assertIn('/fake/path/fake-boot.img', rm_cmd)
  110. self.assertIn('/fake/path/fake.img', rm_cmd)
  111. self.assertIn('/fake/path/fake.yaml', rm_cmd)
  112. class TestHelperUpdateClusterStatus(BaseTestCase):
  113. def setUp(self):
  114. super(TestHelperUpdateClusterStatus, self).setUp()
  115. self.cluster = self.env.create(
  116. nodes_kwargs=[
  117. {'roles': ['controller']},
  118. {'roles': ['compute', 'virt']},
  119. {'roles': ['cinder']}])
  120. def node_should_be_error_with_type(self, node, error_type):
  121. self.assertEqual(node.status, 'error')
  122. self.assertEqual(node.error_type, error_type)
  123. self.assertEqual(node.progress, 0)
  124. def nodes_should_not_be_error(self, nodes):
  125. for node in nodes:
  126. self.assertEqual(node.status, 'discover')
  127. def test_update_nodes_to_error_if_deployment_task_failed(self):
  128. self.cluster.nodes[0].status = 'deploying'
  129. self.cluster.nodes[0].progress = 12
  130. deployment_task = Task(name='deployment', cluster=self.cluster,
  131. status='error')
  132. self.db.add(deployment_task)
  133. self.db.commit()
  134. objects.Task._update_cluster_data(deployment_task)
  135. self.db.flush()
  136. self.assertEqual(self.cluster.status, 'error')
  137. self.assertFalse(self.cluster.is_locked)
  138. self.node_should_be_error_with_type(self.cluster.nodes[0], 'deploy')
  139. self.nodes_should_not_be_error(self.cluster.nodes[1:])
  140. def test_update_cluster_to_error_if_deploy_task_failed(self):
  141. deploy_task = Task(name='deploy', cluster=self.cluster, status='error')
  142. self.db.add(deploy_task)
  143. self.db.commit()
  144. objects.Task._update_cluster_data(deploy_task)
  145. self.db.flush()
  146. self.assertEqual(self.cluster.status, 'error')
  147. self.assertFalse(self.cluster.is_locked)
  148. def test_update_nodes_to_error_if_provision_task_failed(self):
  149. self.cluster.nodes[0].status = 'provisioning'
  150. self.cluster.nodes[0].progress = 12
  151. provision_task = Task(name='provision', cluster=self.cluster,
  152. status='error')
  153. self.db.add(provision_task)
  154. self.db.commit()
  155. objects.Task._update_cluster_data(provision_task)
  156. self.db.flush()
  157. self.assertEqual(self.cluster.status, 'error')
  158. self.assertFalse(self.cluster.is_locked)
  159. self.node_should_be_error_with_type(self.cluster.nodes[0], 'provision')
  160. self.nodes_should_not_be_error(self.cluster.nodes[1:])
  161. def test_update_cluster_to_operational(self):
  162. deploy_task = Task(
  163. name=consts.TASK_NAMES.deployment,
  164. cluster=self.cluster, status=consts.TASK_STATUSES.ready
  165. )
  166. for node in self.env.nodes:
  167. node.status = consts.NODE_STATUSES.ready
  168. self.db.add(deploy_task)
  169. self.db.commit()
  170. objects.Task._update_cluster_data(deploy_task)
  171. self.db.flush()
  172. self.assertEqual(
  173. self.cluster.status, consts.CLUSTER_STATUSES.operational)
  174. self.assertFalse(self.cluster.is_locked)
  175. def test_update_if_parent_task_is_ready_all_nodes_should_be_ready(self):
  176. for node in self.cluster.nodes:
  177. node.status = consts.NODE_STATUSES.ready
  178. node.progress = 100
  179. self.cluster.nodes[0].status = consts.NODE_STATUSES.deploying
  180. self.cluster.nodes[0].progress = 24
  181. deploy_task = Task(
  182. name=consts.TASK_NAMES.deployment,
  183. cluster=self.cluster, status=consts.TASK_STATUSES.ready
  184. )
  185. self.db.add(deploy_task)
  186. self.db.commit()
  187. objects.Task._update_cluster_data(deploy_task)
  188. self.db.flush()
  189. self.assertEqual(
  190. self.cluster.status, consts.CLUSTER_STATUSES.operational)
  191. self.assertFalse(self.cluster.is_locked)
  192. for node in self.cluster.nodes:
  193. self.assertEqual(node.status, consts.NODE_STATUSES.ready)
  194. self.assertEqual(node.progress, 100)
  195. def test_update_cluster_status_if_task_was_already_in_error_status(self):
  196. for node in self.cluster.nodes:
  197. node.status = 'provisioning'
  198. node.progress = 12
  199. provision_task = Task(name='provision', cluster=self.cluster,
  200. status='error')
  201. self.db.add(provision_task)
  202. self.db.commit()
  203. data = {'status': 'error', 'progress': 100}
  204. objects.Task.update(provision_task, data)
  205. self.db.flush()
  206. self.assertEqual(self.cluster.status, 'error')
  207. self.assertEqual(provision_task.status, 'error')
  208. self.assertFalse(self.cluster.is_locked)
  209. for node in self.cluster.nodes:
  210. self.assertEqual(node.status, 'error')
  211. self.assertEqual(node.progress, 0)
  212. def test_do_not_set_cluster_to_error_if_validation_failed(self):
  213. for task_name in ['check_before_deployment', 'check_networks']:
  214. supertask = Task(
  215. name='deploy',
  216. cluster=self.cluster,
  217. status='error')
  218. check_task = Task(
  219. name=task_name,
  220. cluster=self.cluster,
  221. status='error')
  222. supertask.subtasks.append(check_task)
  223. self.db.add(check_task)
  224. self.db.commit()
  225. objects.Task._update_cluster_data(supertask)
  226. self.db.flush()
  227. self.assertEqual(self.cluster.status, 'new')
  228. self.assertFalse(self.cluster.is_locked)
  229. class TestCheckBeforeDeploymentTask(BaseTestCase):
  230. def setUp(self):
  231. super(TestCheckBeforeDeploymentTask, self).setUp()
  232. self.cluster = self.env.create(
  233. release_kwargs={'version': '1111-8.0'},
  234. cluster_kwargs={
  235. 'net_provider': 'neutron',
  236. 'net_segment_type': 'vlan',
  237. 'editable_attributes': {
  238. 'common': {
  239. 'libvirt_type': {
  240. 'value': consts.HYPERVISORS.qemu
  241. }
  242. }
  243. }
  244. },
  245. nodes_kwargs=[{'roles': ['controller']}])
  246. self.env.create_node()
  247. self.node = self.env.nodes[0]
  248. self.task = Task(cluster_id=self.cluster.id)
  249. self.env.db.add(self.task)
  250. self.env.db.commit()
  251. def set_node_status(self, status):
  252. self.node.status = status
  253. self.env.db.commit()
  254. self.assertEqual(self.node.status, status)
  255. def set_node_error_type(self, error_type):
  256. self.node.error_type = error_type
  257. self.env.db.commit()
  258. self.assertEqual(self.node.error_type, error_type)
  259. @mock.patch('nailgun.task.task.assignment.NodeAssignmentValidator')
  260. def test_not_yet_provisioned_nodes_roles_are_validated(self, validator):
  261. self.set_node_status(consts.NODE_STATUSES.discover)
  262. task.CheckBeforeDeploymentTask._check_nodes_roles(self.task)
  263. validator.check_roles_for_conflicts.assert_called_once()
  264. validator.check_roles_requirement.assert_called_once()
  265. def test_check_nodes_online_raises_exception(self):
  266. self.node.online = False
  267. self.env.db.commit()
  268. self.assertRaises(
  269. errors.NodeOffline,
  270. task.CheckBeforeDeploymentTask._check_nodes_are_online,
  271. self.task)
  272. def test_check_nodes_online_do_not_raise_exception_node_to_deletion(self):
  273. self.node.online = False
  274. self.node.pending_deletion = True
  275. self.env.db.commit()
  276. task.CheckBeforeDeploymentTask._check_nodes_are_online(self.task)
  277. def find_net_by_name(self, nets, name):
  278. for net in nets['networks']:
  279. if net['name'] == name:
  280. return net
  281. def test_missing_network_group_with_template(self):
  282. net_template = self.env.read_fixtures(['network_template_80'])[0]
  283. objects.Cluster.set_network_template(
  284. self.cluster,
  285. net_template
  286. )
  287. public = [n for n in self.cluster.network_groups
  288. if n.name == consts.NETWORKS.public][0]
  289. self.env._delete_network_group(public.id)
  290. self.assertRaisesRegexp(
  291. errors.NetworkTemplateMissingNetworkGroup,
  292. "The following network groups are missing: public",
  293. task.CheckBeforeDeploymentTask._validate_network_template,
  294. self.task)
  295. def test_missing_node_role_from_template(self):
  296. net_template = self.env.read_fixtures(['network_template_80'])[0]
  297. objects.Cluster.set_network_template(
  298. self.cluster,
  299. net_template
  300. )
  301. cluster_assigned_roles = \
  302. objects.Cluster.get_assigned_roles(self.cluster)
  303. conf_template = self.cluster.network_config.configuration_template
  304. for net_group in six.itervalues(conf_template['adv_net_template']):
  305. template_node_roles = net_group['templates_for_node_role']
  306. for assigned_role in cluster_assigned_roles:
  307. if assigned_role in template_node_roles:
  308. del template_node_roles[assigned_role]
  309. self.assertRaises(
  310. errors.NetworkTemplateMissingRoles,
  311. task.CheckBeforeDeploymentTask._validate_network_template,
  312. self.task
  313. )
  314. def test_missing_network_group_with_template_multi_ng(self):
  315. net_template = self.env.read_fixtures(['network_template_80'])[0]
  316. resp = self.env.create_node_group(name='group-custom-1',
  317. cluster_id=self.cluster.id)
  318. del self.cluster.nodes[0]
  319. ng = objects.NodeGroup.get_by_uid(resp.json_body['id'])
  320. self.env.create_nodes_w_interfaces_count(
  321. 1, 5,
  322. roles=['controller'],
  323. cluster_id=self.cluster.id,
  324. group_id=ng.id
  325. )
  326. objects.Cluster.set_network_template(
  327. self.cluster,
  328. net_template
  329. )
  330. public = [n for n in ng.networks
  331. if n.name == consts.NETWORKS.public][0]
  332. self.env._delete_network_group(public.id)
  333. self.assertRaisesRegexp(
  334. errors.NetworkTemplateMissingNetworkGroup,
  335. ("The following network groups are missing: public "
  336. ".* group-custom-1"),
  337. task.CheckBeforeDeploymentTask._validate_network_template,
  338. self.task)
  339. def test_default_net_data_used_for_checking_absent_node_groups(self):
  340. self.env.create_node_group(api=False, name='new_group',
  341. cluster_id=self.cluster.id)
  342. # template validation should pass without errors
  343. # as the 'default' sub-template must be used for 'new_group'
  344. # (same as for 'default' node group)
  345. self.assertNotRaises(
  346. Exception,
  347. task.CheckBeforeDeploymentTask._validate_network_template,
  348. self.task
  349. )
  350. def test_sriov_is_enabled_with_non_kvm_hypervisor(self):
  351. objects.NIC.update(self.node.nic_interfaces[0], {
  352. 'attributes': {
  353. 'sriov': {
  354. 'enabled': {'value': True},
  355. 'numfs': {'value': 2}
  356. }
  357. },
  358. 'meta': {
  359. 'sriov': {
  360. 'available': True,
  361. 'totalvfs': 4,
  362. }
  363. }
  364. })
  365. self.assertRaisesRegexp(
  366. errors.InvalidData,
  367. 'Only KVM hypervisor works with SRIOV',
  368. task.CheckBeforeDeploymentTask._check_sriov_properties,
  369. self.task,
  370. )
  371. def test_wrong_net_role_for_dpdk(self):
  372. objects.Cluster.set_network_template(
  373. self.cluster,
  374. self.env.read_fixtures(['network_template_90'])[0]
  375. )
  376. conf_template = self.cluster.network_config.configuration_template
  377. template = conf_template['adv_net_template']['default']
  378. network_scheme = template['network_scheme']['private']
  379. network_scheme['roles'] = {'test': 'br-prv'}
  380. self.assertRaisesRegexp(
  381. errors.NetworkCheckError,
  382. 'Only neutron/private network role .* with DPDK',
  383. task.CheckBeforeDeploymentTask._validate_network_template,
  384. self.task,
  385. )
  386. def test_wrong_dpdk_endpoints_count(self):
  387. objects.Cluster.set_network_template(
  388. self.cluster,
  389. self.env.read_fixtures(['network_template_90'])[0],
  390. )
  391. conf_template = self.cluster.network_config.configuration_template
  392. template = conf_template['adv_net_template']['default']
  393. network_scheme = template['network_scheme']['private']
  394. network_scheme['transformations'].append({
  395. 'action': 'add-port',
  396. 'bridge': 'br-derp',
  397. 'name': '<% if3 %>.101',
  398. 'provider': 'dpdkovs',
  399. })
  400. self.assertRaisesRegexp(
  401. errors.NetworkCheckError,
  402. 'dpdkovs provider can be assigned only for one endpoint',
  403. task.CheckBeforeDeploymentTask._validate_network_template,
  404. self.task,
  405. )
  406. def test_dpdk_hugepages_are_not_configured(self):
  407. net_template = self.env.read_fixtures(['network_template_90'])[0]
  408. del self.cluster.nodes[0]
  409. self.env.create_nodes_w_interfaces_count(
  410. 1, 6,
  411. roles=['compute'],
  412. cluster_id=self.cluster.id
  413. )
  414. self.node = self.cluster.nodes[0]
  415. objects.Cluster.set_network_template(
  416. self.cluster,
  417. net_template
  418. )
  419. objects.Node.update_attributes(
  420. self.node, {'hugepages': {'dpdk': {'value': 0}}})
  421. objects.NIC.update(self.node.nic_interfaces[0],
  422. {'interface_properties':
  423. {
  424. 'dpdk': {'enabled': True,
  425. 'available': True},
  426. }})
  427. self.assertRaisesRegexp(
  428. errors.InvalidData,
  429. 'Hugepages for DPDK are not configured',
  430. task.CheckBeforeDeploymentTask._check_dpdk_properties,
  431. self.task,
  432. )
  433. def test_nova_hugepages_are_not_configured_with_dpdk_enabled(self):
  434. net_template = self.env.read_fixtures(['network_template_90'])[0]
  435. del self.cluster.nodes[0]
  436. self.env.create_nodes_w_interfaces_count(
  437. 1, 6,
  438. roles=['compute'],
  439. cluster_id=self.cluster.id
  440. )
  441. self.node = self.cluster.nodes[0]
  442. objects.Cluster.set_network_template(
  443. self.cluster,
  444. net_template
  445. )
  446. objects.Node.update_attributes(
  447. self.node, {'hugepages': {
  448. 'nova': {'value': {'2048': 0}},
  449. 'dpdk': {'value': 1},
  450. }})
  451. objects.NIC.update(self.node.nic_interfaces[0],
  452. {'interface_properties':
  453. {
  454. 'dpdk': {'enabled': True,
  455. 'available': True},
  456. }})
  457. self.assertRaisesRegexp(
  458. errors.InvalidData,
  459. 'Hugepages for Nova are not configured',
  460. task.CheckBeforeDeploymentTask._check_dpdk_properties,
  461. self.task,
  462. )
  463. def test_check_public_networks(self):
  464. cluster = self.cluster
  465. self.env.create_nodes(
  466. 2, api=True, roles=['controller'], cluster_id=cluster.id)
  467. self.env.create_nodes(
  468. 2, api=True, roles=['compute'], cluster_id=cluster.id)
  469. # we have 3 controllers now
  470. self.assertEqual(
  471. sum('controller' in n.all_roles for n in self.env.nodes),
  472. 3
  473. )
  474. attrs = cluster.attributes.editable
  475. self.assertEqual(
  476. attrs['public_network_assignment']['assign_to_all_nodes']['value'],
  477. False
  478. )
  479. self.assertFalse(
  480. objects.Cluster.should_assign_public_to_all_nodes(cluster))
  481. resp = self.env.neutron_networks_get(cluster.id)
  482. nets = resp.json_body
  483. # not enough IPs for 3 nodes and 2 VIPs
  484. self.find_net_by_name(nets, 'public')['ip_ranges'] = \
  485. [["172.16.0.2", "172.16.0.5"]]
  486. resp = self.env.neutron_networks_put(cluster.id, nets)
  487. self.assertEqual(resp.status_code, 200)
  488. self.assertRaises(
  489. errors.NetworkCheckError,
  490. task.CheckBeforeDeploymentTask._check_public_network,
  491. self.task)
  492. # enough IPs for 3 nodes and 2 VIPs
  493. self.find_net_by_name(nets, 'public')['ip_ranges'] = \
  494. [["172.16.0.2", "172.16.0.6"]]
  495. resp = self.env.neutron_networks_put(cluster.id, nets)
  496. self.assertEqual(resp.status_code, 200)
  497. self.assertNotRaises(
  498. errors.NetworkCheckError,
  499. task.CheckBeforeDeploymentTask._check_public_network,
  500. self.task)
  501. attrs['public_network_assignment']['assign_to_all_nodes']['value'] = \
  502. True
  503. resp = self.app.patch(
  504. reverse(
  505. 'ClusterAttributesHandler',
  506. kwargs={'cluster_id': cluster.id}),
  507. params=jsonutils.dumps({'editable': attrs}),
  508. headers=self.default_headers
  509. )
  510. self.assertEqual(200, resp.status_code)
  511. self.assertTrue(
  512. objects.Cluster.should_assign_public_to_all_nodes(cluster))
  513. self.assertRaises(
  514. errors.NetworkCheckError,
  515. task.CheckBeforeDeploymentTask._check_public_network,
  516. self.task)
  517. class TestDeployTask(BaseTestCase):
  518. def create_deploy_tasks(self):
  519. cluster = self.env.create()
  520. deploy_task = Task(name=consts.TASK_NAMES.deploy,
  521. cluster_id=cluster.id,
  522. status=consts.TASK_STATUSES.pending)
  523. self.db.add(deploy_task)
  524. self.db.flush()
  525. provision_task = Task(name=consts.TASK_NAMES.provision,
  526. status=consts.TASK_STATUSES.pending,
  527. parent_id=deploy_task.id, cluster_id=cluster.id)
  528. self.db.add(provision_task)
  529. deployment_task = Task(name=consts.TASK_NAMES.deployment,
  530. status=consts.TASK_STATUSES.pending,
  531. parent_id=deploy_task.id, cluster_id=cluster.id)
  532. self.db.add(deployment_task)
  533. self.db.flush()
  534. return deploy_task, provision_task, deployment_task
  535. def test_running_status_bubble_for_deploy_task(self):
  536. deploy_task, provision_task, deployment_task = \
  537. self.create_deploy_tasks()
  538. objects.Task.update(provision_task,
  539. {'status': consts.TASK_STATUSES.running})
  540. # Only deploy and provision tasks are running now
  541. self.assertEqual(consts.TASK_STATUSES.running, deploy_task.status)
  542. self.assertEqual(consts.TASK_STATUSES.running, provision_task.status)
  543. self.assertEqual(consts.TASK_STATUSES.pending, deployment_task.status)
  544. def test_error_status_bubble_for_deploy_task(self):
  545. deploy_task, provision_task, deployment_task = \
  546. self.create_deploy_tasks()
  547. objects.Task.update(provision_task,
  548. {'status': consts.TASK_STATUSES.error})
  549. # All tasks have error status
  550. self.assertEqual(consts.TASK_STATUSES.error, deploy_task.status)
  551. self.assertEqual(consts.TASK_STATUSES.error, provision_task.status)
  552. self.assertEqual(consts.TASK_STATUSES.error, deployment_task.status)
  553. def test_ready_status_bubble_for_deploy_task(self):
  554. deploy_task, provision_task, deployment_task = \
  555. self.create_deploy_tasks()
  556. objects.Task.update(provision_task,
  557. {'status': consts.TASK_STATUSES.ready})
  558. # Not all child bugs in ready state
  559. self.assertEqual(consts.TASK_STATUSES.running, deploy_task.status)
  560. self.assertEqual(consts.TASK_STATUSES.ready, provision_task.status)
  561. self.assertEqual(consts.TASK_STATUSES.pending, deployment_task.status)
  562. # All child bugs in ready state
  563. objects.Task.update(deployment_task,
  564. {'status': consts.TASK_STATUSES.ready})
  565. self.assertEqual(consts.TASK_STATUSES.ready, deploy_task.status)
  566. self.assertEqual(consts.TASK_STATUSES.ready, provision_task.status)
  567. self.assertEqual(consts.TASK_STATUSES.ready, deployment_task.status)