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_objects.py 80KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2014 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 copy
  16. import datetime
  17. import hashlib
  18. import mock
  19. from itertools import cycle
  20. from itertools import ifilter
  21. from nailgun.db import db
  22. from nailgun.db.sqlalchemy import models
  23. import uuid
  24. from sqlalchemy import inspect as sqlalchemy_inspect
  25. from sqlalchemy.orm import Query
  26. import jsonschema
  27. from oslo_serialization import jsonutils
  28. import six
  29. from six.moves import range
  30. from nailgun.api.v1.validators.json_schema import action_log
  31. from nailgun.test.base import BaseIntegrationTest
  32. from nailgun.test.base import BaseTestCase
  33. from nailgun.utils import reverse
  34. from nailgun import errors
  35. from nailgun import consts
  36. from nailgun import plugins
  37. from nailgun.db.sqlalchemy.models import NodeGroup
  38. from nailgun.db.sqlalchemy.models import Task
  39. from nailgun.extensions.network_manager.manager import NetworkManager
  40. from nailgun.extensions.network_manager.managers import neutron
  41. from nailgun.extensions.network_manager.managers import nova_network
  42. from nailgun import objects
  43. from nailgun.plugins.manager import PluginManager
  44. from nailgun.settings import settings
  45. from nailgun.test import base
  46. from nailgun.utils import dict_merge
  47. class TestObjects(BaseIntegrationTest):
  48. def test_filter_by(self):
  49. names = cycle('ABCD')
  50. os = cycle([consts.RELEASE_OS.centos, consts.RELEASE_OS.ubuntu])
  51. for i in range(12):
  52. self.env.create_release(
  53. name=names.next(),
  54. operating_system=os.next()
  55. )
  56. # filtering query - returns query
  57. query_filtered = objects.ReleaseCollection.filter_by(
  58. objects.ReleaseCollection.all(),
  59. name="A",
  60. operating_system=consts.RELEASE_OS.centos
  61. )
  62. self.assertIsInstance(query_filtered, Query)
  63. self.assertEqual(
  64. objects.ReleaseCollection.count(query_filtered),
  65. 3
  66. )
  67. for r in query_filtered:
  68. self.assertEqual(r.name, "A")
  69. self.assertEqual(r.operating_system, consts.RELEASE_OS.centos)
  70. # filtering iterable - returns ifilter
  71. iterable_filtered = objects.ReleaseCollection.filter_by(
  72. list(objects.ReleaseCollection.all()),
  73. name="A",
  74. operating_system=consts.RELEASE_OS.centos
  75. )
  76. self.assertIsInstance(iterable_filtered, ifilter)
  77. self.assertEqual(
  78. objects.ReleaseCollection.count(iterable_filtered),
  79. 3
  80. )
  81. for r in iterable_filtered:
  82. self.assertEqual(r.name, "A")
  83. self.assertEqual(r.operating_system, consts.RELEASE_OS.centos)
  84. iterable_filtered = objects.ReleaseCollection.filter_by(
  85. list(),
  86. name="A",
  87. )
  88. self.assertIsInstance(iterable_filtered, ifilter)
  89. self.assertEquals(0, len(list(iterable_filtered)))
  90. def test_filter_by_not(self):
  91. names = cycle('ABCDE')
  92. os = cycle([consts.RELEASE_OS.centos, consts.RELEASE_OS.ubuntu])
  93. # create releases: we'll have only two releases with both
  94. # name A and operating_system CentOS
  95. for i in range(12):
  96. self.env.create_release(
  97. name=names.next(),
  98. operating_system=os.next()
  99. )
  100. # filtering query - returns query
  101. query_filtered = objects.ReleaseCollection.filter_by_not(
  102. objects.ReleaseCollection.all(),
  103. name="A",
  104. operating_system=consts.RELEASE_OS.centos
  105. )
  106. self.assertIsInstance(query_filtered, Query)
  107. self.assertEqual(
  108. objects.ReleaseCollection.count(query_filtered),
  109. 10
  110. )
  111. for r in query_filtered:
  112. if r.name == "A":
  113. self.assertNotEqual(r.operating_system,
  114. consts.RELEASE_OS.centos)
  115. elif r.operating_system == consts.RELEASE_OS.centos:
  116. self.assertNotEqual(r.name, "A")
  117. # filtering iterable - returns ifilter
  118. iterable_filtered = objects.ReleaseCollection.filter_by_not(
  119. list(objects.ReleaseCollection.all()),
  120. name="A",
  121. operating_system=consts.RELEASE_OS.centos
  122. )
  123. self.assertIsInstance(iterable_filtered, ifilter)
  124. self.assertEqual(
  125. objects.ReleaseCollection.count(iterable_filtered),
  126. 10
  127. )
  128. for r in iterable_filtered:
  129. if r.name == "A":
  130. self.assertNotEqual(r.operating_system,
  131. consts.RELEASE_OS.centos)
  132. elif r.operating_system == consts.RELEASE_OS.centos:
  133. self.assertNotEqual(r.name, "A")
  134. def test_to_list_iterable_none(self):
  135. nodes_count = 3
  136. self.env.create_nodes(nodes_count)
  137. nodes_db = objects.NodeCollection.to_list()
  138. self.assertEqual(nodes_count, len(nodes_db))
  139. def test_to_list_iterable_empty(self):
  140. nodes_count = 3
  141. self.env.create_nodes(nodes_count)
  142. # check that nodes were created
  143. self.assertEqual(nodes_count, len(self.env.nodes))
  144. nodes_db = objects.NodeCollection.to_list([])
  145. self.assertEqual(0, len(nodes_db))
  146. class TestNodeObject(BaseIntegrationTest):
  147. @mock.patch('nailgun.objects.node.fire_callback_on_node_delete')
  148. def test_delete(self, callback_mock):
  149. cluster = self.env.create(
  150. cluster_kwargs={'api': False},
  151. nodes_kwargs=[{'role': 'controller'}])
  152. node_db = cluster.nodes[0]
  153. self.assertEqual(len(cluster.nodes), 1)
  154. objects.Node.delete(node_db)
  155. callback_mock.assert_called_once_with(node_db)
  156. self.db.refresh(cluster)
  157. self.assertEqual(len(cluster.nodes), 0)
  158. @mock.patch(
  159. 'nailgun.objects.node.'
  160. 'fire_callback_on_node_collection_delete')
  161. def test_delete_by_ids(self, callback_mock):
  162. cluster = self.env.create(
  163. cluster_kwargs={'api': False},
  164. nodes_kwargs=[{'role': 'controller'}] * 3)
  165. ids = [n.id for n in cluster.nodes]
  166. self.assertEqual(len(ids), 3)
  167. objects.NodeCollection.delete_by_ids(ids)
  168. callback_mock.assert_called_once_with(ids)
  169. self.db.refresh(cluster)
  170. self.assertEqual(len(cluster.nodes), 0)
  171. def test_update_cluster_assignment(self):
  172. cluster = self.env.create(
  173. cluster_kwargs={'api': False},
  174. nodes_kwargs=[{'role': 'controller'}] * 3)
  175. new_cluster = self.env.create_cluster(api=False)
  176. new_group = objects.Cluster.get_default_group(new_cluster)
  177. node = cluster.nodes[0]
  178. roles = node.roles
  179. objects.Node.update_cluster_assignment(node, new_cluster, [], roles)
  180. self.assertEqual(new_cluster.id, node.cluster_id)
  181. self.assertEqual(new_group.id, node.group_id)
  182. self.assertEqual([], node.roles)
  183. self.assertEqual([], node.primary_tags)
  184. self.assertItemsEqual(roles, node.pending_roles)
  185. self.assertEqual(node.attributes, cluster.release.node_attributes)
  186. def test_assign_group(self):
  187. cluster = self.env.create(
  188. cluster_kwargs={'api': False},
  189. nodes_kwargs=[{'role': 'controller'}] * 3)
  190. new_cluster = self.env.create_cluster(api=False)
  191. data = {
  192. 'name': 'custom',
  193. 'cluster_id': new_cluster.id
  194. }
  195. new_group = objects.NodeGroup.create(data)
  196. admin_group_id = db().query(
  197. models.NetworkGroup.id
  198. ).join(
  199. models.NetworkGroup.nodegroup
  200. ).filter(
  201. models.NodeGroup.cluster_id == new_group.cluster_id,
  202. models.NetworkGroup.name == consts.NETWORKS.fuelweb_admin
  203. ).first()
  204. admin_group = objects.NetworkGroup.get_by_uid(admin_group_id)
  205. admin_group.cidr = '10.20.0.0/24'
  206. node = cluster.nodes[0]
  207. roles = node.roles
  208. objects.Node.update_cluster_assignment(node, new_cluster, [], roles)
  209. self.assertEqual(new_group.id, node.group_id)
  210. def test_update_cluster_assignment_with_templates_80(self):
  211. cluster = self.env.create(
  212. cluster_kwargs={'api': False},
  213. nodes_kwargs=[{'role': 'controller'}] * 3)
  214. new_cluster = self.env.create(
  215. cluster_kwargs={'api': False},
  216. release_kwargs={'version': 'liberty-8.0'},
  217. )
  218. net_template = self.env.read_fixtures(['network_template_80'])[0]
  219. objects.Cluster.set_network_template(new_cluster, net_template)
  220. new_group = objects.Cluster.get_default_group(new_cluster)
  221. node = cluster.nodes[0]
  222. roles = node.roles
  223. objects.Node.update_cluster_assignment(node, new_cluster, [], roles)
  224. self.assertEqual(new_cluster.id, node.cluster_id)
  225. self.assertEqual(new_group.id, node.group_id)
  226. self.assertEqual([], node.roles)
  227. self.assertEqual([], node.primary_tags)
  228. self.assertItemsEqual(roles, node.pending_roles)
  229. self.assertIsNotNone(node.network_template)
  230. endpoints = node.network_template['templates']['common']['endpoints']
  231. self.assertEqual([u'br-mgmt', u'br-fw-admin'], endpoints)
  232. def test_adding_to_cluster_kernel_params_centos(self):
  233. self.env.create(
  234. release_kwargs={
  235. "operating_system": consts.RELEASE_OS.centos
  236. },
  237. cluster_kwargs={},
  238. nodes_kwargs=[
  239. {"role": "controller"}
  240. ]
  241. )
  242. node_db = self.env.nodes[0]
  243. self.assertEqual(
  244. objects.Node.get_kernel_params(node_db),
  245. (
  246. 'console=tty0 '
  247. 'biosdevname=0 '
  248. 'crashkernel=none '
  249. 'rootdelay=90 '
  250. 'nomodeset'
  251. )
  252. )
  253. def test_adding_to_cluster_kernel_params_ubuntu(self):
  254. self.env.create(
  255. release_kwargs={
  256. "operating_system": consts.RELEASE_OS.ubuntu,
  257. "attributes_metadata": {
  258. "editable": {
  259. "kernel_params": {
  260. "kernel": {
  261. "value": (
  262. "console=tty0 "
  263. "rootdelay=90 "
  264. "nomodeset"
  265. )
  266. }
  267. }
  268. }
  269. }
  270. },
  271. cluster_kwargs={},
  272. nodes_kwargs=[
  273. {"role": "controller"}
  274. ]
  275. )
  276. node_db = self.env.nodes[0]
  277. self.assertEqual(
  278. objects.Node.get_kernel_params(node_db),
  279. (
  280. 'console=tty0 '
  281. 'rootdelay=90 '
  282. 'nomodeset'
  283. )
  284. )
  285. def test_get_kernel_params_overwritten(self):
  286. """Test verifies that overwriten kernel params will be returned."""
  287. cluster = self.env.create(
  288. nodes_kwargs=[
  289. {"role": "controller"}
  290. ])
  291. additional_kernel_params = 'intel_iommu=true'
  292. default_kernel_params = objects.Cluster.get_default_kernel_params(
  293. cluster)
  294. kernel_params = '{0} {1}'.format(default_kernel_params,
  295. additional_kernel_params)
  296. self.env.nodes[0].kernel_params = kernel_params
  297. self.assertNotEqual(
  298. objects.Node.get_kernel_params(self.env.nodes[0]),
  299. default_kernel_params)
  300. self.assertEqual(
  301. objects.Node.get_kernel_params(self.env.nodes[0]),
  302. kernel_params)
  303. def test_get_kernel_params_w_old_release(self):
  304. cluster = self.env.create(
  305. release_kwargs={
  306. 'operating_system': consts.RELEASE_OS.ubuntu,
  307. 'version': '2015.1.0-8.0',
  308. },
  309. nodes_kwargs=[
  310. {"role": "compute"}
  311. ]
  312. )
  313. node = cluster.nodes[0]
  314. del node.meta['numa_topology']
  315. self.assertNotRaises(KeyError, objects.Node.get_kernel_params, node)
  316. def test_should_have_public_with_ip(self):
  317. nodes = [
  318. {'roles': ['controller', 'cinder'], 'pending_addition': True},
  319. {'roles': ['compute', 'cinder'], 'pending_addition': True},
  320. {'roles': ['compute'], 'pending_addition': True},
  321. {'roles': ['mongo'], 'pending_addition': True},
  322. {'roles': [], 'pending_roles': ['cinder'],
  323. 'pending_addition': True},
  324. {'roles': [], 'pending_roles': ['controller'],
  325. 'pending_addition': True}]
  326. cluster = self.env.create(
  327. cluster_kwargs={
  328. 'net_provider': consts.CLUSTER_NET_PROVIDERS.neutron,
  329. },
  330. nodes_kwargs=nodes)
  331. cluster.release.roles_metadata['mongo']['public_ip_required'] = True
  332. attrs = cluster.attributes.editable
  333. self.assertFalse(
  334. attrs['public_network_assignment']['assign_to_all_nodes']['value'])
  335. self.assertFalse(
  336. objects.Cluster.should_assign_public_to_all_nodes(cluster))
  337. nodes_w_public_count = sum(
  338. int(objects.Node.should_have_public_with_ip(node))
  339. for node in self.env.nodes)
  340. self.assertEqual(nodes_w_public_count, 3)
  341. attrs['public_network_assignment']['assign_to_all_nodes']['value'] = \
  342. True
  343. self.assertTrue(
  344. objects.Cluster.should_assign_public_to_all_nodes(cluster))
  345. nodes_w_public_count = sum(
  346. int(objects.Node.should_have_public_with_ip(node))
  347. for node in self.env.nodes)
  348. self.assertEqual(nodes_w_public_count, len(nodes))
  349. def test_should_have_public_with_ip_with_given_metadata(self):
  350. cluster = self.env.create(
  351. cluster_kwargs={
  352. 'net_provider': consts.CLUSTER_NET_PROVIDERS.neutron,
  353. },
  354. nodes_kwargs=[{}, {}])
  355. node = self.env.nodes[0]
  356. roles_metadata = objects.Cluster.get_roles(cluster)
  357. with mock.patch.object(objects.Cluster, 'get_roles') as get_roles_mock:
  358. get_roles_mock.return_value = roles_metadata
  359. objects.Node.should_have_public_with_ip(node)
  360. self.assertEqual(get_roles_mock.call_count, 1)
  361. with mock.patch.object(objects.Cluster, 'get_roles') as get_roles_mock:
  362. objects.Node.should_have_public_with_ip(node, roles_metadata)
  363. self.assertEqual(get_roles_mock.call_count, 0)
  364. def test_should_have_public(self):
  365. nodes = [
  366. {'roles': ['controller', 'cinder'], 'pending_addition': True},
  367. {'roles': ['compute', 'cinder'], 'pending_addition': True},
  368. {'roles': ['compute'], 'pending_addition': True},
  369. {'roles': ['mongo'], 'pending_addition': True},
  370. {'roles': [], 'pending_roles': ['cinder'],
  371. 'pending_addition': True},
  372. {'roles': [], 'pending_roles': ['controller'],
  373. 'pending_addition': True}]
  374. cluster = self.env.create(
  375. cluster_kwargs={
  376. 'net_provider': consts.CLUSTER_NET_PROVIDERS.neutron,
  377. },
  378. nodes_kwargs=nodes)
  379. attrs = copy.deepcopy(cluster.attributes.editable)
  380. attrs['neutron_advanced_configuration']['neutron_dvr']['value'] = True
  381. resp = self.app.patch(
  382. reverse(
  383. 'ClusterAttributesHandler',
  384. kwargs={'cluster_id': cluster.id}),
  385. params=jsonutils.dumps({'editable': attrs}),
  386. headers=self.default_headers
  387. )
  388. self.assertEqual(200, resp.status_code)
  389. self.assertTrue(
  390. objects.Cluster.neutron_dvr_enabled(cluster))
  391. self.assertFalse(
  392. objects.Cluster.should_assign_public_to_all_nodes(cluster))
  393. nodes_w_public_count = sum(
  394. int(objects.Node.should_have_public(node))
  395. for node in self.env.nodes)
  396. # only controllers and computes should have public for DVR
  397. self.assertEqual(4, nodes_w_public_count)
  398. nodes_w_public_ip_count = sum(
  399. int(objects.Node.should_have_public_with_ip(node))
  400. for node in self.env.nodes)
  401. # only controllers should have public with IP address for DVR
  402. self.assertEqual(2, nodes_w_public_ip_count)
  403. def test_removing_from_cluster(self):
  404. cluster = self.env.create(
  405. cluster_kwargs={},
  406. nodes_kwargs=[
  407. {"role": "controller"}
  408. ]
  409. )
  410. node_db = self.env.nodes[0]
  411. config = self.env.create_openstack_config(
  412. cluster_id=cluster['id'], node_id=node_db.id, configuration={})
  413. node2_db = self.env.create_node()
  414. objects.Node.remove_from_cluster(node_db)
  415. self.db().refresh(config)
  416. self.assertIsNone(node_db.cluster_id)
  417. self.assertEqual(node_db.roles, [])
  418. self.assertEqual(node_db.pending_roles, [])
  419. self.assertFalse(config.is_active)
  420. self.assertEqual(node_db.attributes, {})
  421. exclude_fields = [
  422. "group_id",
  423. "id",
  424. "hostname",
  425. "fqdn",
  426. "mac",
  427. "meta",
  428. "name",
  429. "agent_checksum",
  430. "uuid",
  431. "timestamp",
  432. "nic_interfaces",
  433. "attributes",
  434. ]
  435. fields = set(
  436. c.key for c in sqlalchemy_inspect(objects.Node.model).attrs
  437. ) - set(exclude_fields)
  438. for f in fields:
  439. self.assertEqual(
  440. getattr(node_db, f),
  441. getattr(node2_db, f)
  442. )
  443. def test_removing_from_cluster_idempotent(self):
  444. self.env.create(
  445. cluster_kwargs={},
  446. nodes_kwargs=[
  447. {"role": "controller"}
  448. ]
  449. )
  450. node_db = self.env.nodes[0]
  451. objects.Node.remove_from_cluster(node_db)
  452. try:
  453. objects.Node.remove_from_cluster(node_db)
  454. except Exception as exc:
  455. self.fail("Node removing is not idempotent: {0}!".format(exc))
  456. def test_update_by_agent(self):
  457. node_db = self.env.create_node()
  458. data = {
  459. "status": node_db.status,
  460. "meta": copy.deepcopy(node_db.meta),
  461. "mac": node_db.mac,
  462. }
  463. # test empty disks handling
  464. data["meta"]["disks"] = []
  465. objects.Node.update_by_agent(node_db, copy.deepcopy(data))
  466. self.assertNotEqual(node_db.meta["disks"], data["meta"]["disks"])
  467. # test status handling
  468. for status in (consts.NODE_STATUSES.provisioning,
  469. consts.NODE_STATUSES.error):
  470. node_db.status = status
  471. data["status"] = consts.NODE_STATUSES.discover
  472. objects.Node.update_by_agent(node_db, copy.deepcopy(data))
  473. self.assertEqual(node_db.status, status)
  474. def test_node_roles_to_pending_roles(self):
  475. self.env.create(
  476. cluster_kwargs={},
  477. nodes_kwargs=[
  478. {'role': 'controller'}
  479. ]
  480. )
  481. node_db = self.env.nodes[0]
  482. node = objects.Node.get_by_uid(node_db.id, fail_if_not_found=True)
  483. self.assertEquals(['controller'], node.roles)
  484. self.assertEquals([], node.pending_roles)
  485. # Checking roles moved
  486. objects.Node.move_roles_to_pending_roles(node)
  487. self.assertEquals([], node.roles)
  488. self.assertEquals(['controller'], node.pending_roles)
  489. # Checking second moving has no affect
  490. objects.Node.move_roles_to_pending_roles(node)
  491. self.assertEquals([], node.roles)
  492. self.assertEquals(['controller'], node.pending_roles)
  493. def test_objects_order_by(self):
  494. self.env.create(
  495. cluster_kwargs={},
  496. nodes_kwargs=[
  497. {'role': 'z'},
  498. {'role': 'a'},
  499. {'role': 'b'},
  500. {'role': 'controller'},
  501. {'role': 'controller'},
  502. {'role': 'controller'},
  503. {'role': 'controller'},
  504. {'role': 'controller'}
  505. ]
  506. )
  507. # Checking nothing to be sorted
  508. nodes = objects.NodeCollection.order_by(None, 'id')
  509. self.assertEquals(None, nodes)
  510. iterable = ['b', 'a']
  511. nodes = objects.NodeCollection.order_by(iterable, ())
  512. self.assertEquals(iterable, nodes)
  513. # Checking query ASC ordering applied
  514. q_nodes = objects.NodeCollection.filter_by(None)
  515. nodes = objects.NodeCollection.order_by(q_nodes, 'id').all()
  516. self.assertListEqual(nodes, sorted(nodes, key=lambda x: x.id))
  517. # Checking query DESC ordering applied
  518. q_nodes = objects.NodeCollection.filter_by(None)
  519. nodes = objects.NodeCollection.order_by(q_nodes, '-id').all()
  520. self.assertListEqual(
  521. nodes,
  522. sorted(nodes, key=lambda x: x.id, reverse=True)
  523. )
  524. # Checking iterable ASC ordering applied
  525. nodes = objects.NodeCollection.filter_by(None).all()
  526. ordered_nodes = objects.NodeCollection.order_by(nodes, 'role')
  527. self.assertListEqual(
  528. ordered_nodes,
  529. sorted(nodes, key=lambda x: x.role)
  530. )
  531. # Checking iterable DESC ordering applied
  532. nodes = objects.NodeCollection.filter_by(None).all()
  533. ordered_nodes = objects.NodeCollection.order_by(nodes, '-id')
  534. self.assertListEqual(
  535. ordered_nodes,
  536. sorted(nodes, key=lambda x: x.id, reverse=True)
  537. )
  538. # Checking order by number of fields
  539. nodes = objects.NodeCollection.filter_by(None).all()
  540. ordered_nodes = objects.NodeCollection.order_by(nodes, ('role', '-id'))
  541. self.assertListEqual(
  542. ordered_nodes,
  543. [self.env.nodes[i] for i in [1, 2, 7, 6, 5, 4, 3, 0]]
  544. )
  545. def test_eager_nodes_handlers(self):
  546. """Custom handler works and returns correct number of nodes."""
  547. nodes_count = 10
  548. self.env.create_nodes(nodes_count)
  549. nodes_db = objects.NodeCollection.eager_nodes_handlers(None)
  550. self.assertEqual(nodes_db.count(), nodes_count)
  551. def test_make_slave_name(self):
  552. node = self.env.create_node()
  553. node.hostname = 'test-name'
  554. self.assertEqual(
  555. 'test-name',
  556. objects.Node.get_slave_name(node))
  557. node.hostname = ''
  558. self.assertEqual(
  559. "node-{0}".format(node.id),
  560. objects.Node.get_slave_name(node))
  561. def test_reset_to_discover(self):
  562. self.env.create(
  563. nodes_kwargs=[
  564. {'role': 'controller'},
  565. {'role': 'controller'},
  566. ]
  567. )
  568. netmanager = objects.Cluster.get_network_manager()
  569. netmanager.assign_admin_ips(self.env.nodes)
  570. for node in self.env.nodes:
  571. networks = [ip.network_data.name for ip in node.ip_addrs]
  572. prev_roles = node.roles
  573. self.assertIn(consts.NETWORKS.fuelweb_admin, networks)
  574. objects.Node.reset_to_discover(node)
  575. self.db().flush()
  576. self.db().refresh(node)
  577. self.assertEqual(node.status, consts.NODE_STATUSES.discover)
  578. self.assertEqual(node.ip_addrs, [])
  579. self.assertEqual(node.pending_roles, prev_roles)
  580. def _assert_cluster_create_data(self, network_data):
  581. release = self.env.create_release(api=False)
  582. expected_data = {
  583. "name": "cluster-0",
  584. "mode": consts.CLUSTER_MODES.ha_compact,
  585. "release_id": release.id,
  586. }
  587. expected_data.update(network_data)
  588. cluster = self.env.create_cluster(api=False, **expected_data)
  589. create_data = objects.Cluster.get_create_data(cluster)
  590. self.assertEqual(expected_data, create_data)
  591. def test_cluster_get_create_data_neutron(self):
  592. network_data = {
  593. "net_provider": consts.CLUSTER_NET_PROVIDERS.neutron,
  594. "net_segment_type": consts.NEUTRON_SEGMENT_TYPES.vlan,
  595. "net_l23_provider": consts.NEUTRON_L23_PROVIDERS.ovs,
  596. }
  597. self._assert_cluster_create_data(network_data)
  598. def test_cluster_get_create_data_nova(self):
  599. network_data = {
  600. "net_provider": consts.CLUSTER_NET_PROVIDERS.nova_network,
  601. }
  602. self._assert_cluster_create_data(network_data)
  603. def test_apply_network_template(self):
  604. node = self.env.create_node()
  605. template = self.env.read_fixtures(['network_template_80'])[0]
  606. group_name = 'group-custom-1'
  607. with mock.patch('objects.NodeGroup.get_by_uid',
  608. return_value=NodeGroup(name=group_name)):
  609. objects.Node.apply_network_template(node, template)
  610. self.assertDictEqual(
  611. node.network_template['templates'],
  612. base.get_nodegroup_network_schema_template(
  613. template, group_name)
  614. )
  615. def test_update_w_error(self):
  616. self.env.create(
  617. nodes_kwargs=[
  618. {'roles': ['controller']},
  619. {'roles': ['compute', 'cinder']}
  620. ]
  621. )
  622. cluster_2 = self.env.create_cluster()
  623. node_0 = self.env.nodes[0]
  624. data = {
  625. 'cluster_id': cluster_2['id']
  626. }
  627. self.assertRaises(
  628. errors.CannotUpdate, objects.Node.update, node_0, data)
  629. def test_get_attributes(self):
  630. fake_attributes = {
  631. 'fake_attributes': {'fake_key_1': 'fake_value_1',
  632. 'fake_key_2': 'fake_value_2'}
  633. }
  634. fake_plugin_attributes = {
  635. 'plugin_a_section': {'plugin_attr_key': 'plugin_attr_val'}
  636. }
  637. node = self.env.create_node(attributes=fake_attributes)
  638. with mock.patch('nailgun.plugins.manager.PluginManager.'
  639. 'get_plugin_node_attributes',
  640. return_value=fake_plugin_attributes):
  641. fake_attributes.update(fake_plugin_attributes)
  642. self.assertDictEqual(fake_attributes,
  643. objects.Node.get_attributes(node))
  644. def test_update_attributes(self):
  645. node = self.env.create_node()
  646. node.attributes = {
  647. 'fake_attributes': {'fake_key_1': {'key': 'old_value'},
  648. 'fake_key_2': 'fake_value_2'}
  649. }
  650. objects.Node.update_attributes(
  651. node,
  652. {
  653. 'fake_attributes': {
  654. 'fake_key_1': {'key': 'new_value'}
  655. },
  656. 'plugin_a_section': {
  657. 'plugin_attr_key': {'value': 'new_attr_val'},
  658. 'metadata': {'class': 'plugin', 'node_plugin_id': 1}
  659. }
  660. }
  661. )
  662. expected_attributes = {
  663. 'fake_attributes': {'fake_key_1': {'key': 'new_value'},
  664. 'fake_key_2': 'fake_value_2'}
  665. }
  666. self.assertDictEqual(expected_attributes, node.attributes)
  667. def test_get_default_attributes(self):
  668. release_node_attributes = {'release_attr_a': 'release_attr_a_val'}
  669. cluster = self.env.create(
  670. release_kwargs={
  671. 'version': 'newton-10.0',
  672. 'operating_system': 'Ubuntu',
  673. 'node_attributes': release_node_attributes
  674. },
  675. nodes_kwargs=[
  676. {'role': 'controller'}
  677. ]
  678. )
  679. plugin_node_attributes = self.env.get_default_plugin_node_config()
  680. self.env.create_plugin(
  681. name='plugin_a',
  682. cluster=cluster,
  683. package_version='5.0.0',
  684. node_attributes_metadata=plugin_node_attributes)
  685. node = cluster.nodes[0]
  686. node.node_cluster_plugins[0].attributes = {}
  687. node.attributes = {}
  688. self.db.flush()
  689. default_attributes = objects.Node.get_default_attributes(node)
  690. expected_attributes = copy.deepcopy(plugin_node_attributes)
  691. expected_attributes.update(release_node_attributes)
  692. self.assertDictEqual(expected_attributes, default_attributes)
  693. class TestTaskObject(BaseIntegrationTest):
  694. def setUp(self):
  695. super(TestTaskObject, self).setUp()
  696. self.cluster = self.env.create(
  697. nodes_kwargs=[
  698. {'roles': ['controller']},
  699. {'roles': ['compute']},
  700. {'roles': ['cinder']}])
  701. def _node_should_be_error_with_type(self, node, error_type):
  702. self.assertEquals(node.status, consts.NODE_STATUSES.error)
  703. self.assertEquals(node.error_type, error_type)
  704. self.assertEquals(node.progress, 0)
  705. def _nodes_should_not_be_error(self, nodes):
  706. for node in nodes:
  707. self.assertEquals(node.status, consts.NODE_STATUSES.discover)
  708. def test_update_nodes_to_error_if_deployment_task_failed(self):
  709. self.cluster.nodes[0].status = consts.NODE_STATUSES.deploying
  710. self.cluster.nodes[0].progress = 12
  711. task = Task(name=consts.TASK_NAMES.deployment,
  712. cluster=self.cluster,
  713. status=consts.TASK_STATUSES.error)
  714. self.db.add(task)
  715. self.db.flush()
  716. objects.Task._update_cluster_data(task)
  717. self.db.flush()
  718. self.assertEquals(self.cluster.status, consts.CLUSTER_STATUSES.error)
  719. self.assertFalse(self.cluster.is_locked)
  720. self._node_should_be_error_with_type(self.cluster.nodes[0],
  721. consts.NODE_ERRORS.deploy)
  722. self._nodes_should_not_be_error(self.cluster.nodes[1:])
  723. def test_update_cluster_to_error_if_deploy_task_failed(self):
  724. task = Task(name=consts.TASK_NAMES.deploy,
  725. cluster=self.cluster,
  726. status=consts.TASK_STATUSES.error)
  727. self.db.add(task)
  728. self.db.flush()
  729. objects.Task._update_cluster_data(task)
  730. self.db.flush()
  731. self.assertEquals(self.cluster.status, consts.CLUSTER_STATUSES.error)
  732. self.assertFalse(self.cluster.is_locked)
  733. def test_update_nodes_to_error_if_provision_task_failed(self):
  734. self.cluster.nodes[0].status = consts.NODE_STATUSES.provisioning
  735. self.cluster.nodes[0].progress = 12
  736. task = Task(name=consts.TASK_NAMES.provision,
  737. cluster=self.cluster,
  738. status=consts.TASK_STATUSES.error)
  739. self.db.add(task)
  740. self.db.flush()
  741. objects.Task._update_cluster_data(task)
  742. self.db.flush()
  743. self.assertEquals(self.cluster.status, consts.CLUSTER_STATUSES.error)
  744. self.assertFalse(self.cluster.is_locked)
  745. self._node_should_be_error_with_type(self.cluster.nodes[0],
  746. consts.NODE_ERRORS.provision)
  747. self._nodes_should_not_be_error(self.cluster.nodes[1:])
  748. def test_update_cluster_to_operational(self):
  749. task = Task(name=consts.TASK_NAMES.deployment,
  750. cluster=self.cluster,
  751. status=consts.TASK_STATUSES.ready)
  752. self.db.add(task)
  753. self.db.flush()
  754. for node in self.env.nodes:
  755. node.status = consts.NODE_STATUSES.ready
  756. objects.Task._update_cluster_data(task)
  757. self.db.flush()
  758. self.assertEqual(self.cluster.status,
  759. consts.CLUSTER_STATUSES.operational)
  760. self.assertFalse(self.cluster.is_locked)
  761. self.assertTrue(
  762. self.cluster.attributes.generated['deployed_before']['value'])
  763. def test_update_vms_conf(self):
  764. kvm_node = self.cluster.nodes[0]
  765. kvm_node.roles = [consts.VIRTUAL_NODE_TYPES.virt]
  766. self.db.flush()
  767. kvm_node.vms_conf = [{'id': 1, 'cluster_id': self.cluster.id}]
  768. task = Task(name=consts.TASK_NAMES.spawn_vms,
  769. cluster=self.cluster,
  770. status=consts.TASK_STATUSES.ready)
  771. self.db.add(task)
  772. self.db.flush()
  773. objects.Task._update_cluster_data(task)
  774. self.db.flush()
  775. for node in self.cluster.nodes:
  776. if consts.VIRTUAL_NODE_TYPES.virt in node.roles:
  777. self.assertTrue(node.vms_conf[0].get('created'))
  778. else:
  779. self.assertNotEquals(node.status, consts.NODE_STATUSES.ready)
  780. def test_update_if_parent_task_is_ready_all_nodes_should_be_ready(self):
  781. for node in self.cluster.nodes:
  782. node.status = consts.NODE_STATUSES.ready
  783. node.progress = 100
  784. self.cluster.nodes[0].status = consts.NODE_STATUSES.deploying
  785. self.cluster.nodes[0].progress = 24
  786. task = Task(name=consts.TASK_NAMES.deployment,
  787. cluster=self.cluster,
  788. status=consts.TASK_STATUSES.ready)
  789. self.db.add(task)
  790. self.db.flush()
  791. objects.Task._update_cluster_data(task)
  792. self.db.flush()
  793. self.assertEquals(self.cluster.status,
  794. consts.CLUSTER_STATUSES.operational)
  795. self.assertFalse(self.cluster.is_locked)
  796. for node in self.cluster.nodes:
  797. self.assertEquals(node.status, consts.NODE_STATUSES.ready)
  798. self.assertEquals(node.progress, 100)
  799. def test_update_cluster_status_if_task_was_already_in_error_status(self):
  800. for node in self.cluster.nodes:
  801. node.status = consts.NODE_STATUSES.provisioning
  802. node.progress = 12
  803. task = Task(name=consts.TASK_NAMES.provision,
  804. cluster=self.cluster,
  805. status=consts.TASK_STATUSES.error)
  806. self.db.add(task)
  807. self.db.flush()
  808. data = {'status': consts.TASK_STATUSES.error, 'progress': 100}
  809. objects.Task.update(task, data)
  810. self.db.flush()
  811. self.assertEquals(self.cluster.status, consts.CLUSTER_STATUSES.error)
  812. self.assertFalse(self.cluster.is_locked)
  813. self.assertEquals(task.status, consts.TASK_STATUSES.error)
  814. for node in self.cluster.nodes:
  815. self.assertEquals(node.status, consts.NODE_STATUSES.error)
  816. self.assertEquals(node.progress, 0)
  817. def test_do_not_set_cluster_to_error_if_validation_failed(self):
  818. for task_name in [consts.TASK_NAMES.check_before_deployment,
  819. consts.TASK_NAMES.check_networks]:
  820. supertask = Task(
  821. name=consts.TASK_NAMES.deploy,
  822. cluster=self.cluster,
  823. status=consts.TASK_STATUSES.error)
  824. check_task = Task(
  825. name=task_name,
  826. cluster=self.cluster,
  827. status=consts.TASK_STATUSES.error)
  828. supertask.subtasks.append(check_task)
  829. self.db.add(check_task)
  830. self.db.flush()
  831. objects.Task._update_cluster_data(supertask)
  832. self.db.flush()
  833. self.assertEquals(self.cluster.status, consts.CLUSTER_STATUSES.new)
  834. self.assertFalse(self.cluster.is_locked)
  835. def test_get_task_by_uuid_returns_task(self):
  836. task = Task(name=consts.TASK_NAMES.deploy)
  837. self.db.add(task)
  838. self.db.flush()
  839. task_by_uuid = objects.Task.get_by_uuid(task.uuid)
  840. self.assertEquals(task.uuid, task_by_uuid.uuid)
  841. def test_get_task_by_uuid_raises_error(self):
  842. self.assertRaises(errors.ObjectNotFound,
  843. objects.Task.get_by_uuid,
  844. uuid='not_found_uuid',
  845. fail_if_not_found=True)
  846. def test_task_wrong_status_filtered(self):
  847. task = Task(name=consts.TASK_NAMES.deploy)
  848. self.db.add(task)
  849. self.db.flush()
  850. task_obj = objects.Task.get_by_uuid(task.uuid)
  851. self.assertEquals(consts.TASK_STATUSES.running, task_obj.status)
  852. # Checking correct status is set
  853. objects.Task.update(task, {'status': consts.TASK_STATUSES.ready})
  854. self.db.flush()
  855. task_obj = objects.Task.get_by_uuid(task.uuid)
  856. self.assertEquals(consts.TASK_STATUSES.ready, task_obj.status)
  857. # Checking wrong statuses are not set
  858. objects.Task.update(task, {'status': None})
  859. self.db.flush()
  860. task_obj = objects.Task.get_by_uuid(task.uuid)
  861. self.assertEquals(consts.TASK_STATUSES.ready, task_obj.status)
  862. objects.Task.update(task, {'status': 'xxx'})
  863. self.db.flush()
  864. task_obj = objects.Task.get_by_uuid(task.uuid)
  865. self.assertEquals(consts.TASK_STATUSES.ready, task_obj.status)
  866. class TestActionLogObject(BaseIntegrationTest):
  867. def _create_log_entry(self, object_data):
  868. object_data['actor_id'] = hashlib.sha256('actionlog_test').hexdigest()
  869. object_data['start_timestamp'] = datetime.datetime.now()
  870. object_data['end_timestamp'] = \
  871. object_data['start_timestamp'] + datetime.timedelta(hours=1)
  872. return objects.ActionLog.create(object_data)
  873. def test_validate_json_schema(self):
  874. object_data = {
  875. 'action_group': 'test_group',
  876. 'action_name': 'test_action_one',
  877. 'action_type': 'http_request',
  878. 'additional_info': {},
  879. 'is_sent': False,
  880. 'cluster_id': 1
  881. }
  882. al = self._create_log_entry(object_data)
  883. instance_to_validate = jsonutils.loads(objects.ActionLog.to_json(al))
  884. self.assertNotRaises(jsonschema.ValidationError, jsonschema.validate,
  885. instance_to_validate, action_log.schema)
  886. def test_validate_json_schema_failure(self):
  887. object_data = {
  888. 'id': 1,
  889. 'action_group': 'test_group',
  890. 'action_name': 'test_action_one',
  891. 'action_type': consts.ACTION_TYPES.http_request,
  892. 'additional_info': '', # validation should fail because of this
  893. 'is_sent': False,
  894. 'cluster_id': 1
  895. }
  896. self.assertRaises(jsonschema.ValidationError, jsonschema.validate,
  897. object_data, action_log.schema)
  898. self.assertRaises(ValueError, self._create_log_entry, object_data)
  899. def test_get_by_uuid_method(self):
  900. object_data = {
  901. 'id': 1,
  902. 'action_group': 'test_group',
  903. 'action_name': 'test_action',
  904. 'action_type': consts.ACTION_TYPES.nailgun_task,
  905. 'additional_info': {},
  906. 'is_sent': False,
  907. 'cluster_id': 1,
  908. 'task_uuid': str(uuid.uuid4())
  909. }
  910. al = self._create_log_entry(object_data)
  911. self.db.add(al)
  912. self.db.commit()
  913. al_db = objects.ActionLog.get_by_kwargs(
  914. task_uuid=object_data['task_uuid'])
  915. self.assertIsNotNone(al_db)
  916. self.db.delete(al)
  917. self.db.commit()
  918. def test_update_method(self):
  919. object_data = {
  920. 'id': 1,
  921. 'action_group': 'test_group',
  922. 'action_name': 'test_action',
  923. 'action_type': consts.ACTION_TYPES.nailgun_task,
  924. 'additional_info': {'already_present_data': None},
  925. 'is_sent': False,
  926. 'cluster_id': 1,
  927. 'task_uuid': str(uuid.uuid4())
  928. }
  929. al = self._create_log_entry(object_data)
  930. update_kwargs = {
  931. 'additional_info': {'new_data': []}
  932. }
  933. al = objects.ActionLog.update(al, update_kwargs)
  934. self.assertIn('new_data', six.iterkeys(al.additional_info))
  935. self.assertIn('already_present_data', six.iterkeys(al.additional_info))
  936. self.db.rollback()
  937. class TestClusterObject(BaseTestCase):
  938. def setUp(self):
  939. super(TestClusterObject, self).setUp()
  940. self.cluster = self.env.create(
  941. cluster_kwargs={'net_provider': 'neutron'},
  942. nodes_kwargs=[
  943. {'roles': ['controller']},
  944. {'roles': ['controller']},
  945. {'roles': ['compute']},
  946. {'roles': ['cinder']}])
  947. def _create_cluster_with_plugins(self, plugins_kw_list):
  948. cluster = self.env.create_cluster(api=False)
  949. for kw in plugins_kw_list:
  950. plugin = objects.Plugin.create(kw)
  951. cluster.plugins.append(plugin)
  952. objects.ClusterPlugin.set_attributes(cluster.id,
  953. plugin.id,
  954. enabled=True)
  955. return cluster
  956. def _get_network_role_metadata(self, **kwargs):
  957. network_role = {
  958. 'id': 'test_network_role',
  959. 'default_mapping': consts.NETWORKS.public,
  960. 'properties': {
  961. 'subnet': True,
  962. 'gateway': False,
  963. 'vip': [
  964. {'name': 'test_vip_a'}
  965. ]
  966. }
  967. }
  968. return dict_merge(network_role, kwargs)
  969. # FIXME(aroma): remove this test when stop action will be reworked for ha
  970. # cluster. To get more details, please, refer to [1]
  971. # [1]: https://bugs.launchpad.net/fuel/+bug/1529691
  972. def test_set_deployed_before_flag(self):
  973. # for new clusters that are created by Fuel of version >= 8.0
  974. # the flag is set to False by default
  975. self.assertFalse(
  976. self.cluster.attributes.generated['deployed_before']['value'])
  977. # check that the flags is set to true if was false
  978. objects.Cluster.set_deployed_before_flag(self.cluster, value=True)
  979. self.assertTrue(
  980. self.cluster.attributes.generated['deployed_before']['value'])
  981. # check that flag is set to false if was true
  982. objects.Cluster.set_deployed_before_flag(self.cluster, value=False)
  983. self.assertFalse(
  984. self.cluster.attributes.generated['deployed_before']['value'])
  985. # check that flag is not changed when same value is given
  986. objects.Cluster.set_deployed_before_flag(self.cluster, value=False)
  987. self.assertFalse(
  988. self.cluster.attributes.generated['deployed_before']['value'])
  989. # FIXME(aroma): remove this test when stop action will be reworked for ha
  990. # cluster. To get more details, please, refer to [1]
  991. # [1]: https://bugs.launchpad.net/fuel/+bug/1529691
  992. def test_set_deployed_before_flag_if_it_is_not_in_generated(self):
  993. # there will be no 'deployed_before' attribute present in
  994. # existing clusters' attributes after master node upgrade to Fuel of
  995. # versions >= 8.0 so it must be set in such case by the method under
  996. # the test
  997. def check_flag_set(value):
  998. del self.cluster.attributes.generated['deployed_before']
  999. objects.Cluster.set_deployed_before_flag(self.cluster, value)
  1000. self.assertEqual(
  1001. self.cluster.attributes.generated['deployed_before']['value'],
  1002. value
  1003. )
  1004. for value in (True, False):
  1005. check_flag_set(value)
  1006. def test_network_defaults(self):
  1007. cluster = objects.Cluster.get_by_uid(self.env.create(api=True)['id'])
  1008. self.assertEqual(
  1009. consts.CLUSTER_NET_PROVIDERS.neutron,
  1010. cluster.net_provider)
  1011. self.assertEqual(
  1012. consts.NEUTRON_SEGMENT_TYPES.vlan,
  1013. cluster.network_config.segmentation_type)
  1014. @mock.patch('nailgun.objects.cluster.fire_callback_on_cluster_delete')
  1015. @mock.patch(
  1016. 'nailgun.objects.cluster.'
  1017. 'fire_callback_on_node_collection_delete')
  1018. def test_delete(self, mock_node_coll_delete_cb, mock_cluster_delete_cb):
  1019. ids = [node.id for node in self.cluster.nodes]
  1020. objects.Cluster.delete(self.cluster)
  1021. mock_node_coll_delete_cb.assert_called_once_with(ids)
  1022. mock_cluster_delete_cb.assert_called_once_with(self.cluster)
  1023. self.assertEqual(self.db.query(objects.Node.model).count(), 0)
  1024. self.assertEqual(self.db.query(objects.Cluster.model).count(), 0)
  1025. def test_all_controllers(self):
  1026. self.assertEqual(len(objects.Cluster.get_nodes_by_role(
  1027. self.cluster, 'controller')), 2)
  1028. def test_put_delete_template_after_deployment(self):
  1029. allowed = [consts.CLUSTER_STATUSES.new,
  1030. consts.CLUSTER_STATUSES.stopped,
  1031. consts.CLUSTER_STATUSES.operational,
  1032. consts.CLUSTER_STATUSES.error,
  1033. consts.CLUSTER_STATUSES.partially_deployed]
  1034. for status in consts.CLUSTER_STATUSES:
  1035. self.cluster.status = status
  1036. self.db.flush()
  1037. self.assertEqual(
  1038. objects.Cluster.is_network_modification_locked(
  1039. self.cluster),
  1040. status not in allowed
  1041. )
  1042. def test_get_controller_group_id(self):
  1043. controllers = objects.Cluster.get_nodes_by_role(
  1044. self.cluster, 'controller')
  1045. group_id = objects.Cluster.get_controllers_group_id(
  1046. self.cluster)
  1047. self.assertEqual(controllers[0].group_id, group_id)
  1048. def test_get_node_group(self):
  1049. controller = objects.Cluster.get_nodes_by_role(
  1050. self.cluster, 'controller')[0]
  1051. compute = objects.Cluster.get_nodes_by_role(
  1052. self.cluster, 'compute')[0]
  1053. group_id = self.env.create_node_group().json_body['id']
  1054. compute.group_id = group_id
  1055. self.db.flush()
  1056. self.assertEqual(
  1057. group_id,
  1058. objects.Cluster.get_common_node_group(self.cluster,
  1059. ['compute']).id)
  1060. self.assertEqual(
  1061. controller.group_id,
  1062. objects.Cluster.get_common_node_group(self.cluster,
  1063. ['controller']).id)
  1064. def test_get_node_group_multiple_return_same_group(self):
  1065. group_id = self.env.create_node_group().json_body['id']
  1066. compute = objects.Cluster.get_nodes_by_role(self.cluster, 'compute')[0]
  1067. cinder = objects.Cluster.get_nodes_by_role(self.cluster, 'cinder')[0]
  1068. compute.group_id = group_id
  1069. cinder.group_id = group_id
  1070. self.db.flush()
  1071. self.assertEqual(
  1072. group_id,
  1073. objects.Cluster.get_common_node_group(
  1074. self.cluster, ['compute', 'cinder']).id)
  1075. def test_get_node_group_multiple_fail(self):
  1076. group_id = self.env.create_node_group().json_body['id']
  1077. controller = \
  1078. objects.Cluster.get_nodes_by_role(self.cluster, 'controller')[0]
  1079. cinder = objects.Cluster.get_nodes_by_role(self.cluster, 'cinder')[0]
  1080. controller.group_id = group_id
  1081. cinder.group_id = group_id
  1082. self.db.flush()
  1083. # since we have two controllers, and one of them is in another
  1084. # node group, the error will be raised
  1085. self.assertRaisesRegexp(
  1086. errors.CanNotFindCommonNodeGroup,
  1087. '^Node roles \[controller, cinder\] has more than one common '
  1088. 'node group$',
  1089. objects.Cluster.get_common_node_group,
  1090. self.cluster,
  1091. ['controller', 'cinder'])
  1092. def test_get_network_roles(self):
  1093. self.assertItemsEqual(
  1094. objects.Cluster.get_network_roles(self.cluster),
  1095. self.cluster.release.network_roles_metadata)
  1096. def test_get_deployment_tasks(self):
  1097. deployment_tasks = self.env.get_default_plugin_deployment_tasks()
  1098. plugin_metadata = self.env.get_default_plugin_metadata(
  1099. deployment_tasks=deployment_tasks
  1100. )
  1101. cluster = self._create_cluster_with_plugins([plugin_metadata])
  1102. cluster_deployment_tasks = \
  1103. objects.Cluster.get_deployment_tasks(cluster)
  1104. tasks_ids = [t['id'] for t in cluster_deployment_tasks]
  1105. depl_task_id = deployment_tasks[0]['id']
  1106. self.assertIn(depl_task_id, tasks_ids)
  1107. default_tasks_count = len(objects.Release.get_deployment_tasks(
  1108. cluster.release))
  1109. plugin_tasks_count = len(plugins.wrap_plugin(
  1110. cluster.plugins[0]).get_deployment_tasks())
  1111. self.assertEqual(
  1112. len(cluster_deployment_tasks),
  1113. default_tasks_count + plugin_tasks_count)
  1114. def test_get_deployment_tasks_overlapping_error(self):
  1115. deployment_tasks = self.env.get_default_plugin_deployment_tasks()
  1116. plugins_kw_list = [
  1117. self.env.get_default_plugin_metadata(
  1118. name=plugin_name,
  1119. deployment_tasks=deployment_tasks)
  1120. for plugin_name in ('test_plugin_first', 'test_plugin_second')
  1121. ]
  1122. cluster = self._create_cluster_with_plugins(plugins_kw_list)
  1123. expected_message = (
  1124. 'Plugin test_plugin_second-0.1.0 is overlapping with plugin '
  1125. 'test_plugin_first-0.1.0 by introducing the same '
  1126. 'deployment task with id role-name'
  1127. )
  1128. with self.assertRaisesRegexp(errors.AlreadyExists,
  1129. expected_message):
  1130. objects.Cluster.get_deployment_tasks(cluster)
  1131. def test_get_refreshable_tasks(self):
  1132. deployment_tasks = [
  1133. self.env.get_default_plugin_deployment_tasks(**{
  1134. 'id': 'refreshable_task_on_keystone',
  1135. consts.TASK_REFRESH_FIELD: ['keystone_config']
  1136. })[0],
  1137. self.env.get_default_plugin_deployment_tasks(**{
  1138. 'id': 'refreshable_task_on_nova',
  1139. consts.TASK_REFRESH_FIELD: ['nova_config']
  1140. })[0],
  1141. ]
  1142. plugin_metadata = self.env.get_default_plugin_metadata(
  1143. deployment_tasks=deployment_tasks
  1144. )
  1145. cluster = self._create_cluster_with_plugins([plugin_metadata])
  1146. refreshable_tasks = \
  1147. objects.Cluster.get_refreshable_tasks(cluster)
  1148. tasks_ids = [t['id'] for t in refreshable_tasks]
  1149. self.assertIn(deployment_tasks[1]['id'], tasks_ids)
  1150. self.assertIn(deployment_tasks[0]['id'], tasks_ids)
  1151. refreshable_tasks_on_nova = \
  1152. objects.Cluster.get_refreshable_tasks(
  1153. cluster, filter_by_configs=('nova_config',))
  1154. tasks_ids = [t['id'] for t in refreshable_tasks_on_nova]
  1155. self.assertIn(deployment_tasks[1]['id'], tasks_ids)
  1156. self.assertNotIn(deployment_tasks[0]['id'], tasks_ids)
  1157. def test_get_refreshable_tasks_w_custom_graph(self):
  1158. deployment_tasks = [
  1159. self.env.get_default_plugin_deployment_tasks(**{
  1160. 'id': 'refreshable_task_on_keystone',
  1161. consts.TASK_REFRESH_FIELD: ['keystone_config']
  1162. })[0]
  1163. ]
  1164. cluster = self.cluster
  1165. release_graph = objects.DeploymentGraph.get_for_model(cluster.release)
  1166. release_tasks = objects.DeploymentGraph.get_tasks(release_graph)
  1167. objects.DeploymentGraph.create_for_model(
  1168. {'tasks': release_tasks}, cluster.release, 'custom-graph')
  1169. objects.DeploymentGraph.create_for_model(
  1170. {'tasks': deployment_tasks}, cluster, 'custom-graph')
  1171. refreshable_tasks = objects.Cluster.get_refreshable_tasks(
  1172. cluster, None, 'custom-graph')
  1173. tasks_ids = [t['id'] for t in refreshable_tasks]
  1174. self.assertIn(deployment_tasks[0]['id'], tasks_ids)
  1175. def test_get_plugin_network_roles(self):
  1176. network_roles = [self._get_network_role_metadata()]
  1177. plugin_data = self.env.get_default_plugin_metadata(
  1178. network_roles_metadata=network_roles)
  1179. cluster = self._create_cluster_with_plugins([plugin_data])
  1180. self.assertItemsEqual(
  1181. objects.Cluster.get_network_roles(cluster),
  1182. cluster.release.network_roles_metadata + network_roles)
  1183. def test_get_plugin_network_roles_fail(self):
  1184. plugins_kw_list = [
  1185. self.env.get_default_plugin_metadata(
  1186. name='test_plugin_{0}'.format(idx),
  1187. network_roles_metadata=[
  1188. self._get_network_role_metadata(
  1189. properties={'gateway': bool(idx)}
  1190. )
  1191. ]
  1192. ) for idx in six.moves.range(2)
  1193. ]
  1194. cluster = self._create_cluster_with_plugins(plugins_kw_list)
  1195. self.assertRaises(
  1196. errors.NetworkRoleConflict,
  1197. objects.Cluster.get_network_roles, cluster)
  1198. def test_merge_network_roles(self):
  1199. network_roles = [self._get_network_role_metadata()]
  1200. plugins_kw_list = [
  1201. self.env.get_default_plugin_metadata(
  1202. name=plugin_name,
  1203. network_roles_metadata=network_roles)
  1204. for plugin_name in ('test_plugin_first', 'test_plugin_second')
  1205. ]
  1206. cluster = self._create_cluster_with_plugins(plugins_kw_list)
  1207. self.assertItemsEqual(
  1208. cluster.release.network_roles_metadata + network_roles,
  1209. objects.Cluster.get_network_roles(cluster)
  1210. )
  1211. def test_get_volumes_metadata_when_no_boot_rules_in_release(self):
  1212. expected_volumes_metadata = {
  1213. 'volumes_roles_mapping': {},
  1214. 'volumes': [],
  1215. 'rule_to_pick_boot_disk': []
  1216. }
  1217. cluster = self.env.create(release_kwargs={
  1218. 'volumes_metadata': {
  1219. 'volumes_roles_mapping': {},
  1220. 'volumes': []
  1221. }
  1222. })
  1223. volumes_metadata = objects.Cluster.get_volumes_metadata(
  1224. cluster)
  1225. self.assertEqual(
  1226. volumes_metadata, expected_volumes_metadata)
  1227. def test_get_volumes_metadata_when_plugins_are_enabled(self):
  1228. plugin_volumes_metadata = {
  1229. 'volumes_roles_mapping': {
  1230. 'test_plugin_1': [
  1231. {'allocate_size': 'min', 'id': 'test_plugin_1'}
  1232. ],
  1233. 'test_plugin_2': [
  1234. {'allocate_size': 'min', 'id': 'test_plugin_2'}
  1235. ],
  1236. },
  1237. 'volumes': [
  1238. {'id': 'test_plugin_1', 'type': 'vg'},
  1239. {'id': 'test_plugin_2', 'type': 'vg'}
  1240. ],
  1241. 'rule_to_pick_boot_disk': []
  1242. }
  1243. with mock.patch.object(
  1244. PluginManager, 'get_volumes_metadata') as plugin_volumes:
  1245. plugin_volumes.return_value = plugin_volumes_metadata
  1246. expected_volumes_metadata = copy.deepcopy(
  1247. self.env.releases[0].volumes_metadata)
  1248. expected_volumes_metadata['volumes_roles_mapping'].update(
  1249. plugin_volumes_metadata['volumes_roles_mapping'])
  1250. expected_volumes_metadata['volumes'].extend(
  1251. plugin_volumes_metadata['volumes'])
  1252. volumes_metadata = objects.Cluster.get_volumes_metadata(
  1253. self.cluster)
  1254. self.assertDictEqual(
  1255. volumes_metadata, expected_volumes_metadata)
  1256. def test_cluster_is_component_enabled(self):
  1257. self.assertFalse(objects.Cluster.is_component_enabled(self.cluster,
  1258. 'ironic'))
  1259. self.env._set_additional_component(self.cluster, 'ironic', True)
  1260. self.assertTrue(objects.Cluster.is_component_enabled(self.cluster,
  1261. 'ironic'))
  1262. def test_get_cluster_attributes_by_components(self):
  1263. release = self.env.create_release(
  1264. components_metadata=[{
  1265. 'name': 'hypervisor:libvirt:test',
  1266. 'bind': [['settings:common.libvirt_type.value', 'test'],
  1267. ['wrong_model:field.value', 'smth']]
  1268. }, {
  1269. 'name': 'additional_service:new',
  1270. 'bind': ['settings:additional_components.new.value']
  1271. }, {
  1272. 'name': 'network:some_net',
  1273. 'bind': [['cluster:net_provider', 'test_provider'],
  1274. 'settings:some_net.checkbox']
  1275. }]
  1276. )
  1277. selected_components = ['network:some_net', 'hypervisor:libvirt:test',
  1278. 'additional_service:new_plugin_service']
  1279. result_attrs = objects.Cluster.get_cluster_attributes_by_components(
  1280. selected_components, release.id)
  1281. self.assertDictEqual(
  1282. result_attrs,
  1283. {'editable': {u'some_net': {u'checkbox': True},
  1284. u'common': {u'libvirt_type': {u'value': u'test'}}},
  1285. 'cluster': {u'net_provider': u'test_provider'}}
  1286. )
  1287. def test_enable_settings_by_components(self):
  1288. components = [{
  1289. 'name': 'network:neutron:tun',
  1290. 'bind': [['cluster:net_provider', 'neutron'],
  1291. ['cluster:net_segment_type', 'tun']]
  1292. }, {
  1293. 'name': 'hypervisor:libvirt:kvm',
  1294. 'bind': [['settings:common.libvirt_type.value', 'kvm']]
  1295. }, {
  1296. 'name': 'additional_service:sahara',
  1297. 'bind': ['settings:additional_components.sahara.value']
  1298. }]
  1299. default_editable_attributes = {
  1300. 'common': {'libvirt_type': {'value': 'qemu'}},
  1301. 'additional_components': {'sahara': {'value': False}}
  1302. }
  1303. release = self.env.create_release(
  1304. version='2015.1-8.0',
  1305. operating_system=consts.RELEASE_OS.ubuntu,
  1306. modes=[consts.CLUSTER_MODES.ha_compact],
  1307. components_metadata=components)
  1308. self.env.create_plugin(
  1309. name='plugin_with_test_network_for_neutron',
  1310. package_version='4.0.0',
  1311. fuel_version=['8.0'],
  1312. components_metadata=self.env.get_default_components(
  1313. name='network:neutron:test_network',
  1314. bind=[['cluster:net_segment_type', 'tun']]))
  1315. tests_data = [{
  1316. 'selected_components': ['network:neutron:tun',
  1317. 'hypervisor:libvirt:kvm',
  1318. 'additional_service:sahara'],
  1319. 'expected_values': {
  1320. 'net_provider': consts.CLUSTER_NET_PROVIDERS.neutron,
  1321. 'segmentation_type': consts.NEUTRON_SEGMENT_TYPES.tun
  1322. }
  1323. }, {
  1324. 'selected_components': ['network:neutron:test_network',
  1325. 'hypervisor:libvirt:kvm',
  1326. 'additional_service:sahara'],
  1327. 'expected_values': {
  1328. 'net_provider': consts.CLUSTER_NET_PROVIDERS.neutron,
  1329. 'segmentation_type': consts.NEUTRON_SEGMENT_TYPES.tun
  1330. }
  1331. }]
  1332. for i, test_data in enumerate(tests_data):
  1333. with mock.patch('objects.Cluster.get_default_editable_attributes',
  1334. return_value=default_editable_attributes):
  1335. cluster = objects.Cluster.create({
  1336. 'name': 'test-{0}'.format(i),
  1337. 'release_id': release.id,
  1338. 'components': test_data.get('selected_components', [])
  1339. })
  1340. editable_attrs = cluster.attributes.editable
  1341. expected_values = test_data['expected_values']
  1342. self.assertEqual(cluster.net_provider,
  1343. expected_values['net_provider'])
  1344. if expected_values['segmentation_type']:
  1345. self.assertEqual(cluster.network_config.segmentation_type,
  1346. expected_values['segmentation_type'])
  1347. self.assertEqual(
  1348. editable_attrs[u'common'][u'libvirt_type'][u'value'], u'kvm')
  1349. self.assertTrue(
  1350. editable_attrs[u'additional_components'][u'sahara'][u'value'])
  1351. def test_cleanup_openstack_config(self):
  1352. cluster = self.env.create_cluster(
  1353. api=False, nodes=[self.env.nodes[0].id])
  1354. config = self.env.create_openstack_config(
  1355. cluster_id=cluster.id, node_id=self.env.nodes[0].id,
  1356. configuration={'key': 'value'})
  1357. self.assertTrue(config.is_active)
  1358. objects.Cluster.update(cluster, {'nodes': []})
  1359. self.db().refresh(config)
  1360. self.assertFalse(config.is_active)
  1361. def test_get_nodes_count_unmet_status(self):
  1362. # by default all nodes in discover state
  1363. remaining = objects.Cluster.get_nodes_count_unmet_status(
  1364. self.cluster, consts.NODE_STATUSES.discover
  1365. )
  1366. self.assertEqual(0, remaining)
  1367. remaining = objects.Cluster.get_nodes_count_unmet_status(
  1368. self.cluster, consts.NODE_STATUSES.ready
  1369. )
  1370. self.assertEqual(len(self.env.nodes), remaining)
  1371. self.env.nodes[0].status = consts.NODE_STATUSES.ready
  1372. remaining = objects.Cluster.get_nodes_count_unmet_status(
  1373. self.cluster, consts.NODE_STATUSES.ready
  1374. )
  1375. self.assertEqual(len(self.env.nodes) - 1, remaining)
  1376. def test_set_netgroups_ids(self):
  1377. cluster = self.env.create_cluster(api=False)
  1378. node = self.env.create_node(cluster_id=cluster.id)
  1379. self.env.network_manager.assign_ips(
  1380. cluster, [node], consts.NETWORKS.management
  1381. )
  1382. admin_ng_id = \
  1383. objects.NetworkGroup.get_admin_network_group(node).id
  1384. node_ng_ids = dict((ip.network, admin_ng_id) for ip in node.ip_addrs)
  1385. objects.Node.set_netgroups_ids(node, node_ng_ids)
  1386. for ip in node.ip_addrs:
  1387. self.assertEquals(admin_ng_id, ip.network)
  1388. def test_get_updated_editable_attributes_with_plugin(self):
  1389. cluster = self.env.create_cluster(api=False)
  1390. self.env.create_plugin(
  1391. name='test_plugin',
  1392. version='1.0.0',
  1393. package_version='4.0.0',
  1394. cluster=cluster,
  1395. attributes_metadata=self.env.get_default_plugin_env_config()
  1396. )
  1397. self.env.create_plugin(
  1398. name='test_plugin',
  1399. version='3.0.0',
  1400. package_version='4.0.0',
  1401. cluster=cluster,
  1402. attributes_metadata=self.env.get_default_plugin_env_config()
  1403. )
  1404. attributes = objects.Cluster.get_editable_attributes(cluster, True)
  1405. plugin_attrs = attributes['test_plugin']['metadata']['versions'][1]
  1406. plugin_attrs['plugin_name_text']['value'] = 'test_value_a'
  1407. updated_attributes = objects.Cluster.get_updated_editable_attributes(
  1408. cluster, {'editable': attributes})
  1409. self.assertEqual(
  1410. 'test_value_a',
  1411. updated_attributes['editable']['test_plugin']
  1412. ['plugin_name_text']['value'])
  1413. def test_get_attributes_with_plugin(self):
  1414. cluster = self.env.create_cluster(api=False)
  1415. self.env.create_plugin(
  1416. name='test_plugin',
  1417. version='1.0.0',
  1418. package_version='4.0.0',
  1419. cluster=cluster,
  1420. attributes_metadata=self.env.get_default_plugin_env_config(
  1421. value='{}')
  1422. )
  1423. attr = objects.Cluster.get_attributes(cluster, True)
  1424. plugin_attrs = attr.editable['test_plugin']['metadata']['versions'][0]
  1425. self.assertEqual('{}', plugin_attrs['plugin_name_text']['value'])
  1426. @mock.patch.object(objects.Cluster, 'get_editable_attributes')
  1427. def test_cluster_get_restrictions_models(self, m_get_attrs):
  1428. attrs = {'some': {'fake': 'attributes'}}
  1429. m_get_attrs.return_value = attrs
  1430. cluster = mock.Mock()
  1431. models = objects.Cluster.get_restrictions_models(cluster)
  1432. self.assertEqual(
  1433. {
  1434. 'settings': attrs,
  1435. 'cluster': cluster,
  1436. 'version': settings.VERSION,
  1437. 'networking_parameters': cluster.network_config
  1438. },
  1439. models
  1440. )
  1441. @mock.patch.object(objects.Cluster, 'get_editable_attributes')
  1442. def test_cluster_get_restrictions_models_with_attrs(self, m_get_attrs):
  1443. attrs = {'some': {'fake': 'attributes'}}
  1444. cluster = mock.Mock()
  1445. models = objects.Cluster.get_restrictions_models(cluster, attrs=attrs)
  1446. self.assertEqual(0, m_get_attrs.call_count)
  1447. self.assertEqual(
  1448. {
  1449. 'settings': attrs,
  1450. 'cluster': cluster,
  1451. 'version': settings.VERSION,
  1452. 'networking_parameters': cluster.network_config
  1453. },
  1454. models
  1455. )
  1456. class TestClusterObjectVirtRoles(BaseTestCase):
  1457. def setUp(self):
  1458. super(TestClusterObjectVirtRoles, self).setUp()
  1459. self.cluster = self.env.create(
  1460. nodes_kwargs=[
  1461. {'roles': ['virt']},
  1462. {'roles': ['virt']},
  1463. {'roles': ['controller']},
  1464. ]
  1465. )
  1466. self.env.nodes[0].vms_conf = [
  1467. {'id': 1, 'cpu': 1, 'mem': 2},
  1468. {'id': 2, 'cpu': 1, 'mem': 2},
  1469. ]
  1470. self.env.nodes[1].vms_conf = [
  1471. {'id': 1, 'cpu': 1, 'mem': 2},
  1472. {'id': 2, 'cpu': 1, 'mem': 2},
  1473. ]
  1474. def test_set_vms_created_state(self):
  1475. objects.Cluster.set_vms_created_state(self.cluster)
  1476. for node in self.env.nodes:
  1477. for conf in node.vms_conf:
  1478. self.assertTrue(conf['created'])
  1479. def test_reset_vms_created_state(self):
  1480. objects.Cluster.set_vms_created_state(self.cluster)
  1481. objects.Node.reset_vms_created_state(self.env.nodes[0])
  1482. for conf in self.env.nodes[0].vms_conf:
  1483. self.assertFalse(conf['created'])
  1484. for conf in self.env.nodes[1].vms_conf:
  1485. self.assertTrue(conf['created'])
  1486. class TestClusterObjectGetRoles(BaseTestCase):
  1487. def setUp(self):
  1488. super(TestClusterObjectGetRoles, self).setUp()
  1489. self.cluster = self.env.create(
  1490. release_kwargs={
  1491. 'roles_metadata': {
  1492. 'role_a': {
  1493. 'name': 'Role A', 'description': 'Role A is ...', },
  1494. 'role_b': {
  1495. 'name': 'Role B', 'description': 'Role B is ...', },
  1496. }
  1497. })
  1498. def create_plugin(self, roles_metadata):
  1499. plugin = objects.Plugin.create(self.env.get_default_plugin_metadata(
  1500. name=uuid.uuid4().get_hex(),
  1501. roles_metadata=roles_metadata,
  1502. ))
  1503. self.cluster.plugins.append(plugin)
  1504. objects.ClusterPlugin.set_attributes(self.cluster.id,
  1505. plugin.id,
  1506. enabled=True)
  1507. self.db.refresh(plugin)
  1508. return plugin
  1509. def test_no_plugins_no_additional_roles(self):
  1510. roles = objects.Cluster.get_roles(self.cluster)
  1511. self.assertItemsEqual(roles.keys(), ['role_a', 'role_b'])
  1512. def test_plugin_adds_new_roles(self):
  1513. self.create_plugin({
  1514. 'role_c': {
  1515. 'name': 'Role C', 'description': 'Role C is ...', },
  1516. })
  1517. roles = objects.Cluster.get_roles(self.cluster)
  1518. self.assertItemsEqual(roles.keys(), ['role_a', 'role_b', 'role_c'])
  1519. def test_plugin_role_conflict_with_core_roles(self):
  1520. plugin = self.create_plugin({
  1521. 'role_a': {
  1522. 'name': 'Role X', 'description': 'Role X is ...', },
  1523. })
  1524. expected_message = (
  1525. "Plugin \(ID={0}\) is unable to register "
  1526. "the following node roles: role_a"
  1527. .format(plugin.id)
  1528. )
  1529. with self.assertRaisesRegexp(errors.AlreadyExists,
  1530. expected_message):
  1531. objects.Cluster.get_roles(self.cluster)
  1532. def test_plugin_role_conflict_with_other_plugins(self):
  1533. self.create_plugin({
  1534. 'role_x': {
  1535. 'name': 'Role X', 'description': 'Role X is ...', },
  1536. })
  1537. plugin_in_conflict = self.create_plugin({
  1538. 'role_x': {
  1539. 'name': 'Role X', 'description': 'Role X is ...', },
  1540. })
  1541. expected_message = (
  1542. "Plugin \(ID={0}\) is unable to register "
  1543. "the following node roles: role_x"
  1544. .format(plugin_in_conflict.id)
  1545. )
  1546. with self.assertRaisesRegexp(errors.AlreadyExists,
  1547. expected_message):
  1548. objects.Cluster.get_roles(self.cluster)
  1549. def test_plugin_role_conflict_with_plugin_and_core(self):
  1550. self.create_plugin({
  1551. 'role_x': {
  1552. 'name': 'Role X', 'description': 'Role X is ...', },
  1553. })
  1554. plugin_in_conflict = self.create_plugin({
  1555. 'role_x': {
  1556. 'name': 'Role Y', 'description': 'Role Y is ...', },
  1557. 'role_a': {
  1558. 'name': 'Role A', 'description': 'Role A is ...', },
  1559. })
  1560. message_pattern = (
  1561. '^Plugin \(ID={0}\) is unable to register the following node '
  1562. 'roles: role_a, role_x'
  1563. .format(plugin_in_conflict.id))
  1564. with self.assertRaisesRegexp(errors.AlreadyExists, message_pattern):
  1565. objects.Cluster.get_roles(self.cluster)
  1566. class TestClusterObjectGetNetworkManager(BaseTestCase):
  1567. def setUp(self):
  1568. super(TestClusterObjectGetNetworkManager, self).setUp()
  1569. self.cluster = self.env.create(
  1570. cluster_kwargs={'net_provider': 'neutron'})
  1571. def test_get_default(self):
  1572. nm = objects.Cluster.get_network_manager()
  1573. self.assertIs(nm, NetworkManager)
  1574. def check_neutron_network_manager(
  1575. self, net_provider, version, expected_manager):
  1576. self.cluster.net_provider = net_provider
  1577. self.cluster.release.version = version
  1578. nm = objects.Cluster.get_network_manager(self.cluster)
  1579. self.assertIs(expected_manager, nm)
  1580. def test_raise_if_unknown(self):
  1581. self.cluster.net_provider = "invalid_data"
  1582. self.assertRaisesWithMessage(
  1583. Exception,
  1584. 'The network provider "invalid_data" is not supported.',
  1585. objects.Cluster.get_network_manager, self.cluster
  1586. )
  1587. def test_neutron_network_managers_by_version(self):
  1588. for version, manager_class in (
  1589. ('2014.2.2-6.0', neutron.NeutronManagerLegacy),
  1590. ('2014.2.2-6.1', neutron.NeutronManager61),
  1591. ('2015.6.7-7.0', neutron.NeutronManager70),
  1592. ('2016.1.1-8.0', neutron.NeutronManager80),
  1593. ('mitaka-9.0', neutron.NeutronManager90)
  1594. ):
  1595. self.check_neutron_network_manager(
  1596. consts.CLUSTER_NET_PROVIDERS.neutron,
  1597. version, manager_class
  1598. )
  1599. def test_nova_network_managers_by_version(self):
  1600. for version, manager_class in (
  1601. ('2014.2.2-6.0', nova_network.NovaNetworkManagerLegacy),
  1602. ('2014.2.2-6.1', nova_network.NovaNetworkManager61),
  1603. ('2015.6.7-7.0', nova_network.NovaNetworkManager70),
  1604. ):
  1605. self.check_neutron_network_manager(
  1606. consts.CLUSTER_NET_PROVIDERS.nova_network,
  1607. version, manager_class
  1608. )
  1609. def test_get_neutron_80(self):
  1610. self.cluster.release.version = '2014.2.2-8.0'
  1611. nm = objects.Cluster.get_network_manager(self.cluster)
  1612. self.assertEqual(nm, neutron.NeutronManager80)
  1613. class TestRelease(BaseTestCase):
  1614. def test_get_all_components(self):
  1615. release = self.env.create_release(
  1616. version='2015.1-8.0',
  1617. operating_system=consts.RELEASE_OS.ubuntu,
  1618. modes=[consts.CLUSTER_MODES.ha_compact],
  1619. components_metadata=self.env.get_default_components(
  1620. name='hypervisor:test_component_1'))
  1621. self.env.create_plugin(
  1622. name='plugin_with_components',
  1623. package_version='4.0.0',
  1624. fuel_version=['8.0'],
  1625. releases=[{
  1626. 'repository_path': 'repositories/ubuntu',
  1627. 'version': '2015.1-8.0',
  1628. 'os': 'ubuntu',
  1629. 'mode': ['ha'],
  1630. 'deployment_scripts_path': 'deployment_scripts/'}],
  1631. components_metadata=[dict(
  1632. name='storage:test_component_2',
  1633. label='Test storage',
  1634. incompatible=[{
  1635. 'name': 'hypervisor:test_component_1',
  1636. 'message': 'component_2 not compatible with component_1'}]
  1637. ), dict(
  1638. name='network:test_component_3',
  1639. label='Test network',
  1640. compatible=[{
  1641. 'name': 'storage:test_component_2'}])]
  1642. )
  1643. components = objects.Release.get_all_components(release)
  1644. self.assertItemsEqual(components, [{
  1645. 'name': 'hypervisor:test_component_1',
  1646. 'compatible': [
  1647. {'name': 'hypervisor:*'},
  1648. {'name': 'storage:object:block:swift'}],
  1649. 'incompatible': [
  1650. {'name': 'network:*'},
  1651. {'name': 'additional_service:*'},
  1652. {'name': 'storage:test_component_2',
  1653. 'message': 'Not compatible with Test storage'}]}, {
  1654. 'name': 'storage:test_component_2',
  1655. 'label': 'Test storage',
  1656. 'compatible': [
  1657. {'name': 'network:test_component_3'}],
  1658. 'incompatible': [
  1659. {'name': 'hypervisor:test_component_1',
  1660. 'message': 'component_2 not compatible with component_1'}]}, {
  1661. 'name': 'network:test_component_3',
  1662. 'label': 'Test network',
  1663. 'compatible': [
  1664. {'name': 'storage:test_component_2'}],
  1665. 'incompatible': [
  1666. {'name': 'hypervisor:test_component_1',
  1667. 'message': 'Not compatible with hypervisor:test_component_1'}]
  1668. }])
  1669. def test_contain_component(self):
  1670. components = [
  1671. {'name': 'test_component_type_1:test_component_1'},
  1672. {'name': 'test_component_type_2:*'}
  1673. ]
  1674. self.assertTrue(objects.Release._contain(
  1675. components, 'test_component_type_1:test_component_1'))
  1676. self.assertTrue(objects.Release._contain(
  1677. components, 'test_component_type_2:test_component_3'))
  1678. self.assertFalse(objects.Release._contain(
  1679. components, 'test_component_type_1:test_component_4'))
  1680. class TestOpenstackConfig(BaseTestCase):
  1681. def setUp(self):
  1682. super(TestOpenstackConfig, self).setUp()
  1683. self.cluster = self.env.create(
  1684. nodes_kwargs=[
  1685. {'role': 'controller', 'status': 'ready'},
  1686. {'role': 'compute', 'status': 'ready'},
  1687. {'role': 'cinder', 'status': 'ready'},
  1688. ])
  1689. self.nodes = self.env.nodes
  1690. def test_create(self):
  1691. config = objects.OpenstackConfig.create({
  1692. 'cluster_id': self.cluster.id,
  1693. 'configuration': {'key': 'value'},
  1694. })
  1695. self.assertEqual(config.cluster_id, self.cluster.id)
  1696. self.assertEqual(config.config_type,
  1697. consts.OPENSTACK_CONFIG_TYPES.cluster)
  1698. self.assertTrue(config.is_active)
  1699. config = objects.OpenstackConfig.create({
  1700. 'cluster_id': self.cluster.id,
  1701. 'node_id': self.nodes[0].id,
  1702. 'configuration': {'key': 'value'},
  1703. })
  1704. self.assertEqual(config.cluster_id, self.cluster.id)
  1705. self.assertEqual(config.node_id, self.nodes[0].id)
  1706. self.assertEqual(config.config_type,
  1707. consts.OPENSTACK_CONFIG_TYPES.node)
  1708. self.assertTrue(config.is_active)
  1709. config = objects.OpenstackConfig.create({
  1710. 'cluster_id': self.cluster.id,
  1711. 'node_role': 'cinder',
  1712. 'configuration': {'key': 'value'},
  1713. })
  1714. self.assertEqual(config.cluster_id, self.cluster.id)
  1715. self.assertEqual(config.node_role, 'cinder')
  1716. self.assertEqual(config.config_type,
  1717. consts.OPENSTACK_CONFIG_TYPES.role)
  1718. self.assertTrue(config.is_active)
  1719. def test_create_override(self):
  1720. config_1 = objects.OpenstackConfig.create({
  1721. 'cluster_id': self.cluster.id,
  1722. 'configuration': {'key': 'value'},
  1723. })
  1724. self.assertTrue(config_1.is_active)
  1725. config_2 = objects.OpenstackConfig.create({
  1726. 'cluster_id': self.cluster.id,
  1727. 'configuration': {'key': 'value'},
  1728. })
  1729. self.assertTrue(config_2.is_active)
  1730. self.assertFalse(config_1.is_active)
  1731. def test_disable(self):
  1732. config = objects.OpenstackConfig.create({
  1733. 'cluster_id': self.cluster.id,
  1734. 'configuration': {'key': 'value'},
  1735. })
  1736. objects.OpenstackConfig.disable(config)
  1737. self.assertFalse(config.is_active)
  1738. class TestOpenstackConfigCollection(BaseTestCase):
  1739. def setUp(self):
  1740. super(TestOpenstackConfigCollection, self).setUp()
  1741. self.cluster = self.env.create(
  1742. nodes_kwargs=[
  1743. {'role': 'controller', 'status': 'ready'},
  1744. {'role': 'compute', 'status': 'ready'},
  1745. {'role': 'cinder', 'status': 'ready'},
  1746. ])
  1747. self.nodes = self.env.nodes
  1748. def test_create(self):
  1749. configs = objects.OpenstackConfigCollection.create({
  1750. 'cluster_id': self.cluster.id,
  1751. 'configuration': {'key': 'value'},
  1752. })
  1753. self.assertEqual(len(configs), 1)
  1754. self.assertEqual(configs[0].cluster_id, self.cluster.id)
  1755. self.assertEqual(configs[0].config_type,
  1756. consts.OPENSTACK_CONFIG_TYPES.cluster)
  1757. self.assertIsNone(configs[0].node_id)
  1758. def test_create_by_role(self):
  1759. configs = objects.OpenstackConfigCollection.create({
  1760. 'cluster_id': self.cluster.id,
  1761. 'node_role': 'controller',
  1762. 'configuration': {'key': 'value'},
  1763. })
  1764. self.assertEqual(len(configs), 1)
  1765. self.assertEqual(configs[0].cluster_id, self.cluster.id)
  1766. self.assertEqual(configs[0].config_type,
  1767. consts.OPENSTACK_CONFIG_TYPES.role)
  1768. self.assertEqual(configs[0].node_role, 'controller')
  1769. self.assertIsNone(configs[0].node_id)
  1770. def test_create_singlenode(self):
  1771. configs = objects.OpenstackConfigCollection.create({
  1772. 'cluster_id': self.cluster.id,
  1773. 'node_ids': [self.nodes[0].id],
  1774. 'configuration': {'key': 'value'},
  1775. })
  1776. self.assertEqual(len(configs), 1)
  1777. self.assertEqual(configs[0].cluster_id, self.cluster.id)
  1778. self.assertEqual(configs[0].config_type,
  1779. consts.OPENSTACK_CONFIG_TYPES.node)
  1780. self.assertEqual(configs[0].node_id, self.nodes[0].id)
  1781. def test_create_multinode(self):
  1782. node_ids = [n.id for n in self.nodes]
  1783. configs = objects.OpenstackConfigCollection.create({
  1784. 'cluster_id': self.cluster.id,
  1785. 'node_ids': node_ids,
  1786. 'configuration': {'key': 'value'},
  1787. })
  1788. self.assertEqual(len(configs), len(self.nodes))
  1789. for config, node_id in six.moves.zip(configs, node_ids):
  1790. self.assertEqual(config.node_id, node_id)
  1791. self.assertEqual(configs[0].config_type,
  1792. consts.OPENSTACK_CONFIG_TYPES.node)
  1793. class TestNodeStatus(BaseTestCase):
  1794. def setUp(self):
  1795. super(TestNodeStatus, self).setUp()
  1796. self.node = self.env.create_node()
  1797. def test_in_progress_has_high_priority(self):
  1798. node = self.node
  1799. node.error_type = consts.NODE_ERRORS.deploy
  1800. node.status = consts.NODE_STATUSES.removing
  1801. self.assertEqual(
  1802. consts.NODE_STATUSES.removing, objects.Node.get_status(node)
  1803. )
  1804. node.status = consts.NODE_STATUSES.provisioning
  1805. self.assertEqual(
  1806. consts.NODE_STATUSES.provisioning, objects.Node.get_status(node)
  1807. )
  1808. node.status = consts.NODE_STATUSES.deploying
  1809. self.assertEqual(
  1810. consts.NODE_STATUSES.deploying, objects.Node.get_status(node)
  1811. )
  1812. node.status = consts.NODE_STATUSES.provisioned
  1813. node.progress = 1
  1814. self.assertEqual(
  1815. consts.NODE_STATUSES.deploying, objects.Node.get_status(node)
  1816. )
  1817. def test_in_pgogress_status(self):
  1818. node = self.node
  1819. node.progress = 1
  1820. node.status = consts.NODE_STATUSES.ready
  1821. node.pending_addition = True
  1822. self.assertEqual(
  1823. consts.NODE_STATUSES.provisioning, objects.Node.get_status(node)
  1824. )
  1825. node.pending_addition = False
  1826. node.pending_deletion = True
  1827. self.assertEqual(
  1828. consts.NODE_STATUSES.removing, objects.Node.get_status(node)
  1829. )
  1830. node.pending_deletion = False
  1831. self.assertEqual(
  1832. consts.NODE_STATUSES.deploying, objects.Node.get_status(node)
  1833. )
  1834. def test_error_state(self):
  1835. node = self.node
  1836. node.status = consts.NODE_STATUSES.error
  1837. node.error_type = consts.NODE_ERRORS.deploy
  1838. self.assertEqual(
  1839. consts.NODE_STATUSES.error, objects.Node.get_status(node)
  1840. )
  1841. class TestPlugin(BaseTestCase):
  1842. def test_name_unchangeable(self):
  1843. self.env.create_plugin(
  1844. name='name',
  1845. package_version='4.0.0',
  1846. fuel_version=['9.2']
  1847. )
  1848. plugin = objects.PluginCollection.all()[0]
  1849. self.assertRaises(errors.InvalidData, objects.Plugin.update,
  1850. plugin, {'name': 'new_name'})