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_node_assignment_handler.py 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  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 yaml
  16. from oslo_serialization import jsonutils
  17. from nailgun.db.sqlalchemy.models import NodeBondInterface
  18. from nailgun import consts
  19. from nailgun.test.base import BaseIntegrationTest
  20. from nailgun.utils import reverse
  21. class TestAssignmentHandlers(BaseIntegrationTest):
  22. def _assign_roles(self, assignment_data, expect_errors=False):
  23. return self.app.post(
  24. reverse(
  25. 'NodeAssignmentHandler',
  26. kwargs={'cluster_id': self.cluster.id}
  27. ),
  28. jsonutils.dumps(assignment_data),
  29. headers=self.default_headers,
  30. expect_errors=expect_errors
  31. )
  32. def test_assignment(self):
  33. self.cluster = self.env.create(
  34. cluster_kwargs={"api": True},
  35. nodes_kwargs=[
  36. {
  37. "cluster_id": None,
  38. "api": True
  39. }
  40. ]
  41. )
  42. node = self.env.nodes[0]
  43. assignment_data = [
  44. {
  45. "id": node.id,
  46. "roles": ['controller']
  47. }
  48. ]
  49. resp = self._assign_roles(assignment_data)
  50. self.assertEqual(200, resp.status_code)
  51. self.assertEqual(None, resp.json_body)
  52. self.assertEqual(node.cluster, self.cluster)
  53. self.datadiff(
  54. node.pending_roles,
  55. assignment_data[0]["roles"]
  56. )
  57. # NOTE(el): Role can be reassigned after initial assigment
  58. resp = self._assign_roles(assignment_data, True)
  59. self.assertEqual(200, resp.status_code)
  60. def test_unassignment(self):
  61. cluster = self.env.create(
  62. cluster_kwargs={"api": True},
  63. nodes_kwargs=[{}]
  64. )
  65. node = self.env.nodes[0]
  66. # correct unassignment
  67. resp = self.app.post(
  68. reverse(
  69. 'NodeUnassignmentHandler',
  70. kwargs={'cluster_id': cluster['id']}
  71. ),
  72. jsonutils.dumps([{'id': node.id}]),
  73. headers=self.default_headers
  74. )
  75. self.assertEqual(200, resp.status_code)
  76. self.assertEqual(None, resp.json_body)
  77. self.assertEqual(node.cluster, None)
  78. self.assertEqual(node.pending_roles, [])
  79. self.assertEqual(node.pending_addition, False)
  80. # Test with invalid node ids
  81. for node_id in (0, node.id + 50):
  82. resp = self.app.post(
  83. reverse(
  84. 'NodeUnassignmentHandler',
  85. kwargs={'cluster_id': cluster['id']}
  86. ),
  87. jsonutils.dumps([{'id': node_id}]),
  88. headers=self.default_headers,
  89. expect_errors=True
  90. )
  91. self.assertEqual(400, resp.status_code)
  92. # Test with invalid cluster id
  93. resp = self.app.post(
  94. reverse(
  95. 'NodeUnassignmentHandler',
  96. kwargs={'cluster_id': cluster['id'] + 5}
  97. ),
  98. jsonutils.dumps([{'id': node.id}]),
  99. headers=self.default_headers,
  100. expect_errors=True
  101. )
  102. self.assertEqual(resp.status_code, 404)
  103. # Test with wrong cluster id
  104. self.env.create(
  105. cluster_kwargs={"api": True},
  106. nodes_kwargs=[{}]
  107. )
  108. resp = self.app.post(
  109. reverse(
  110. 'NodeUnassignmentHandler',
  111. kwargs={'cluster_id': cluster['id']}
  112. ),
  113. jsonutils.dumps([{'id': self.env.clusters[1].nodes[0].id}]),
  114. headers=self.default_headers,
  115. expect_errors=True
  116. )
  117. self.assertEqual(resp.status_code, 400)
  118. def test_unassignment_after_deploy(self):
  119. cluster = self.env.create(
  120. nodes_kwargs=[{}]
  121. )
  122. node = self.env.nodes[0]
  123. node.status = 'error'
  124. self.db.commit()
  125. resp = self.app.post(
  126. reverse(
  127. 'NodeUnassignmentHandler',
  128. kwargs={'cluster_id': cluster['id']}
  129. ),
  130. jsonutils.dumps([{'id': node.id}]),
  131. headers=self.default_headers
  132. )
  133. self.assertEqual(resp.status_code, 200)
  134. self.assertEqual(node.pending_deletion, True)
  135. def test_assigment_with_invalid_cluster(self):
  136. node = self.env.create_node(api=False)
  137. resp = self.app.post(
  138. reverse(
  139. 'NodeAssignmentHandler',
  140. kwargs={'cluster_id': '9999'}
  141. ),
  142. jsonutils.dumps([{
  143. 'id': node.id,
  144. 'roles': ['controller']
  145. }]),
  146. headers=self.default_headers,
  147. expect_errors=True
  148. )
  149. self.assertEquals(404, resp.status_code)
  150. def test_assign_conflicting_roles(self):
  151. self.cluster = self.env.create(
  152. cluster_kwargs={"api": True},
  153. nodes_kwargs=[
  154. {
  155. "cluster_id": None,
  156. "api": True
  157. }
  158. ]
  159. )
  160. node = self.env.nodes[0]
  161. assignment_data = [
  162. {
  163. "id": node.id,
  164. "roles": ['controller', 'compute']
  165. }
  166. ]
  167. resp = self._assign_roles(assignment_data, True)
  168. self.assertEquals(400, resp.status_code)
  169. def test_assign_conflicting_all_role(self):
  170. ROLE = yaml.safe_load("""
  171. name: test_role
  172. meta:
  173. name: "Some plugin role"
  174. description: "Some description"
  175. conflicts: "*"
  176. tags: []
  177. volumes_roles_mapping:
  178. - id: os
  179. allocate_size: all
  180. """)
  181. release = self.env.create_release()
  182. resp = self.env.create_role('releases', release.id, ROLE)
  183. self.cluster = self.env.create(
  184. cluster_kwargs={
  185. "api": True,
  186. "release_id": release.id
  187. },
  188. nodes_kwargs=[
  189. {
  190. "cluster_id": None,
  191. "api": True
  192. }
  193. ]
  194. )
  195. node = self.env.nodes[0]
  196. assignment_data = [
  197. {
  198. "id": node.id,
  199. "roles": ['controller', 'test_role']
  200. }
  201. ]
  202. resp = self._assign_roles(assignment_data, True)
  203. self.assertEquals(400, resp.status_code, resp.body)
  204. assignment_data[0]["roles"] = ['test_role']
  205. resp = self._assign_roles(assignment_data)
  206. self.assertEquals(200, resp.status_code, resp.body)
  207. def test_add_node_with_cluster_network_template(self):
  208. net_template = {
  209. "adv_net_template": {
  210. "default": {
  211. "network_assignments": {
  212. "management": {
  213. "ep": "br-mgmt"
  214. },
  215. "storage": {
  216. "ep": "br-storage"
  217. },
  218. "public": {
  219. "ep": "br-ex"
  220. },
  221. "private": {
  222. "ep": "br-prv"
  223. },
  224. "fuelweb_admin": {
  225. "ep": "br-fw-admin"
  226. }
  227. },
  228. "templates_for_node_role": {
  229. "controller": [
  230. "common"
  231. ]
  232. },
  233. "nic_mapping": {
  234. "default": {
  235. "if4": "eth3",
  236. "if1": "eth0",
  237. "if2": "eth1",
  238. "if3": "eth2"
  239. }
  240. },
  241. "network_scheme": {
  242. "common": {
  243. "endpoints": [
  244. "br-mgmt"
  245. ],
  246. "transformations": [
  247. {
  248. "action": "add-br",
  249. "name": "br-mgmt"
  250. },
  251. {
  252. "action": "add-port",
  253. "bridge": "br-mgmt",
  254. "name": "<% if2 %>"
  255. }
  256. ],
  257. "roles": {
  258. "management": "br-mgmt"
  259. }
  260. }
  261. }
  262. }
  263. }
  264. }
  265. cluster = self.env.create_cluster(
  266. api=False,
  267. net_provider=consts.CLUSTER_NET_PROVIDERS.neutron
  268. )
  269. cluster.release.version = '1111-7.0'
  270. cluster.network_config.configuration_template = net_template
  271. node = self.env.create_node()
  272. assignment_data = [
  273. {
  274. "id": node.id,
  275. "roles": ['controller']
  276. }
  277. ]
  278. self.app.post(
  279. reverse(
  280. 'NodeAssignmentHandler',
  281. kwargs={'cluster_id': cluster.id}
  282. ),
  283. jsonutils.dumps(assignment_data),
  284. headers=self.default_headers
  285. )
  286. net_scheme = node.network_template['templates']['common']
  287. self.assertNotEqual({}, node.network_template)
  288. self.assertEquals(['br-mgmt'], net_scheme['endpoints'])
  289. self.assertEquals({'management': 'br-mgmt'}, net_scheme['roles'])
  290. # The order of transformations matters
  291. self.assertIn('add-br', net_scheme['transformations'][0].values())
  292. self.assertIn('add-port', net_scheme['transformations'][1].values())
  293. self.assertEquals('eth1', net_scheme['transformations'][1]['name'])
  294. class TestClusterStateUnassignment(BaseIntegrationTest):
  295. def test_delete_bond_and_networks_state_on_unassignment(self):
  296. """Test verifies that
  297. 1. bond configuration will be deleted
  298. 2. network unassigned from node interfaces
  299. when node unnasigned from cluster
  300. """
  301. cluster = self.env.create(
  302. nodes_kwargs=[{}]
  303. )
  304. node = self.env.nodes[0]
  305. node.bond_interfaces.append(
  306. NodeBondInterface(name='ovs-bond0',
  307. slaves=node.nic_interfaces))
  308. self.db.flush()
  309. resp = self.app.post(
  310. reverse(
  311. 'NodeUnassignmentHandler',
  312. kwargs={'cluster_id': cluster['id']}
  313. ),
  314. jsonutils.dumps([{'id': node.id}]),
  315. headers=self.default_headers
  316. )
  317. self.assertEqual(resp.status_code, 200)
  318. self.assertEqual(node.bond_interfaces, [])
  319. for interface in node.interfaces:
  320. self.assertEqual(interface.assigned_networks_list, [])