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_orchestrator_serializer.py 109KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752
  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 copy
  16. from operator import attrgetter
  17. from operator import itemgetter
  18. from random import randint
  19. import re
  20. import six
  21. from six.moves import range
  22. import mock
  23. from netaddr import IPAddress
  24. from netaddr import IPNetwork
  25. from netaddr import IPRange
  26. from oslo_serialization import jsonutils
  27. import yaml
  28. from nailgun import consts
  29. from nailgun.db.sqlalchemy.models import Cluster
  30. from nailgun.db.sqlalchemy.models import NetworkGroup
  31. from nailgun.db.sqlalchemy.models import Node
  32. from nailgun.orchestrator.deployment_serializers import \
  33. deployment_info_to_legacy
  34. from nailgun.orchestrator.deployment_serializers import\
  35. DeploymentHASerializer
  36. from nailgun.orchestrator.deployment_serializers import\
  37. DeploymentHASerializer50
  38. from nailgun.orchestrator.deployment_serializers import\
  39. DeploymentHASerializer51
  40. from nailgun.orchestrator.deployment_serializers import\
  41. DeploymentHASerializer61
  42. from nailgun.orchestrator.deployment_serializers import\
  43. DeploymentMultinodeSerializer
  44. from nailgun.orchestrator.deployment_serializers import\
  45. DeploymentMultinodeSerializer50
  46. from nailgun.orchestrator.deployment_serializers import\
  47. DeploymentMultinodeSerializer61
  48. from nailgun.orchestrator.deployment_serializers import\
  49. get_serializer_for_cluster
  50. from nailgun.orchestrator.orchestrator_graph import AstuteGraph
  51. from nailgun.db.sqlalchemy import models
  52. from nailgun import objects
  53. from nailgun.settings import settings
  54. from nailgun.test import base
  55. from nailgun.utils import reverse
  56. class BaseSerializerTest(base.BaseIntegrationTest):
  57. @classmethod
  58. def create_serializer(cls, cluster):
  59. return get_serializer_for_cluster(cluster)(AstuteGraph(cluster))
  60. class OrchestratorSerializerTestBase(BaseSerializerTest):
  61. """Class contains helpers."""
  62. def setUp(self):
  63. super(OrchestratorSerializerTestBase, self).setUp()
  64. self.cluster_mock = mock.MagicMock()
  65. self.cluster_mock.id = 0
  66. self.cluster_mock.deployment_tasks = []
  67. self.cluster_mock.release.deployment_tasks = []
  68. self.common_attrs = mock.MagicMock()
  69. def filter_by_role(self, nodes, role):
  70. return filter(lambda node: role in node['role'], nodes)
  71. def filter_by_uid(self, nodes, uid):
  72. return filter(lambda node: node['uid'] == uid, nodes)
  73. def assert_nodes_with_role(self, nodes, role, count):
  74. self.assertEqual(len(self.filter_by_role(nodes, role)), count)
  75. def get_controllers(self, cluster_id):
  76. return self.db.query(Node).\
  77. filter_by(cluster_id=cluster_id,
  78. pending_deletion=False).\
  79. filter(Node.roles.any('controller')).\
  80. order_by(Node.id)
  81. def add_default_params(self, nodes):
  82. """Adds necessary default parameters to nodes
  83. :param nodes: list of dicts
  84. """
  85. for pos, node in enumerate(nodes, start=1):
  86. node['uid'] = str(pos)
  87. @property
  88. def serializer(self):
  89. self.cluster_mock.release.environment_version = '5.0'
  90. return DeploymentHASerializer(AstuteGraph(self.cluster_mock))
  91. def serialize(self, cluster):
  92. objects.Cluster.prepare_for_deployment(cluster)
  93. return self.serializer.serialize(cluster, cluster.nodes)
  94. def move_network(self, node_id, net_name, from_if, to_if):
  95. resp = self.app.get(
  96. reverse("NodeNICsHandler",
  97. kwargs={"node_id": node_id}),
  98. headers=self.default_headers)
  99. self.assertEqual(resp.status_code, 200)
  100. data = resp.json_body
  101. net_from = None
  102. for nic in data:
  103. if nic['name'] == from_if:
  104. net_from = [n for n in nic['assigned_networks']
  105. if n['name'] == net_name]
  106. if net_from:
  107. nic['assigned_networks'] = \
  108. [n for n in nic['assigned_networks']
  109. if n != net_from[0]]
  110. self.assertIsNotNone(net_from)
  111. for nic in data:
  112. if nic['name'] == to_if:
  113. nic['assigned_networks'].append(net_from[0])
  114. resp = self.env.node_nics_put(node_id, data)
  115. self.assertEqual(resp.status_code, 200)
  116. def check_ep_format(self, endpoint_list):
  117. for ep in endpoint_list.values():
  118. if ep.get('IP'):
  119. self.assertTrue(
  120. ep['IP'] == 'none' or isinstance(ep['IP'], list))
  121. class TestReplacedDeploymentInfoSerialization(OrchestratorSerializerTestBase):
  122. env_version = '1111-6.0'
  123. def setUp(self):
  124. super(TestReplacedDeploymentInfoSerialization, self).setUp()
  125. self.cluster = self.env.create(
  126. release_kwargs={'version': self.env_version},
  127. cluster_kwargs={'api': False})
  128. objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
  129. def test_replaced_tasks_is_not_preserved(self):
  130. node = self.env.create_node(
  131. api=False,
  132. cluster_id=self.cluster.id,
  133. pending_addition=True,
  134. roles=['controller'])
  135. node.replaced_deployment_info = [
  136. {'role': 'controller', 'priority': 'XXX', 'tasks': [], 'uid': '1'}]
  137. self.db.flush()
  138. objects.Cluster.prepare_for_deployment(
  139. self.cluster, self.cluster.nodes
  140. )
  141. serialized_data = self.serializer.serialize(self.cluster, [node])
  142. # verify that task list is not empty
  143. self.assertTrue(serialized_data['nodes'][0]['tasks'])
  144. # verify that priority is preserved
  145. self.assertEqual(serialized_data['nodes'][0]['priority'], 'XXX')
  146. # TODO(awoodward): multinode deprecation: probably has duplicates
  147. class TestNovaOrchestratorSerializer(OrchestratorSerializerTestBase):
  148. env_version = '1111-6.0'
  149. def setUp(self):
  150. super(TestNovaOrchestratorSerializer, self).setUp()
  151. self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
  152. objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
  153. def create_env(self, mode, network_manager='FlatDHCPManager'):
  154. node_args = [
  155. {'roles': ['controller', 'cinder'], 'pending_addition': True},
  156. {'roles': ['compute', 'cinder'], 'pending_addition': True},
  157. {'roles': ['compute'], 'pending_addition': True},
  158. {'roles': ['mongo'], 'pending_addition': True},
  159. {'roles': [], 'pending_roles': ['cinder'],
  160. 'pending_addition': True}]
  161. cluster = self.env.create(
  162. release_kwargs={'version': self.env_version},
  163. cluster_kwargs={
  164. 'mode': mode,
  165. 'net_manager': network_manager,
  166. 'net_provider': consts.CLUSTER_NET_PROVIDERS.nova_network},
  167. nodes_kwargs=node_args)
  168. cluster_db = self.db.query(Cluster).get(cluster['id'])
  169. objects.Cluster.prepare_for_deployment(cluster_db)
  170. self.db.flush()
  171. return cluster_db
  172. def assert_roles_flattened(self, nodes):
  173. self.assertEqual(len(nodes), 7)
  174. self.assert_nodes_with_role(nodes, 'controller', 1)
  175. self.assert_nodes_with_role(nodes, 'compute', 2)
  176. self.assert_nodes_with_role(nodes, 'cinder', 3)
  177. self.assert_nodes_with_role(nodes, 'mongo', 1)
  178. def test_serialize_nodes(self):
  179. serialized_nodes = self.serializer.serialize_nodes(self.cluster.nodes)
  180. self.assert_roles_flattened(serialized_nodes)
  181. # Each not should be same as result of
  182. # serialize_node function
  183. for serialized_node in serialized_nodes:
  184. node_db = self.db.query(Node).get(int(serialized_node['uid']))
  185. expected_node = self.serializer.serialize_node(
  186. node_db, serialized_node['role']
  187. )
  188. self.assertEqual(serialized_node, expected_node)
  189. def test_serialize_node(self):
  190. node = self.env.create_node(
  191. api=True, cluster_id=self.cluster.id, pending_addition=True)
  192. objects.Cluster.prepare_for_deployment(self.cluster)
  193. self.db.flush()
  194. node_db = self.db.query(Node).get(node['id'])
  195. serialized_data = self.serializer.serialize_node(
  196. node_db, 'controller'
  197. )
  198. self.assertEqual(serialized_data['role'], 'controller')
  199. self.assertEqual(serialized_data['uid'], str(node_db.id))
  200. self.assertEqual(serialized_data['status'], node_db.status)
  201. self.assertEqual(serialized_data['online'], node_db.online)
  202. self.assertEqual(serialized_data['fqdn'],
  203. '%s.%s' % (node_db.hostname, settings.DNS_DOMAIN))
  204. def test_serialize_node_vms_conf(self):
  205. node = self.env.create_node(
  206. api=True, cluster_id=self.cluster.id, pending_addition=True)
  207. objects.Cluster.prepare_for_deployment(self.cluster)
  208. self.db.flush()
  209. node_db = self.db.query(Node).get(node['id'])
  210. vms_conf = [{'id': 1, 'cluster_id': self.cluster.id}]
  211. node_db.vms_conf = vms_conf
  212. serialized_data = self.serializer.serialize_node(
  213. node_db, 'controller'
  214. )
  215. self.assertEqual(serialized_data['vms_conf'], vms_conf)
  216. def test_node_list(self):
  217. node_list = self.serializer.get_common_attrs(self.cluster)['nodes']
  218. # Check right nodes count with right roles
  219. self.assert_roles_flattened(node_list)
  220. # Check common attrs
  221. for node in node_list:
  222. node_db = self.db.query(Node).get(int(node['uid']))
  223. self.assertEqual(node['public_netmask'], '255.255.255.0')
  224. self.assertEqual(node['internal_netmask'], '255.255.255.0')
  225. self.assertEqual(node['storage_netmask'], '255.255.255.0')
  226. self.assertEqual(node['uid'], str(node_db.id))
  227. self.assertEqual(node['name'], '%s' % node_db.hostname)
  228. self.assertEqual(node['fqdn'], '%s.%s' %
  229. (node_db.hostname, settings.DNS_DOMAIN))
  230. # Check uncommon attrs
  231. # Convert ids to int to have correct order in the set
  232. node_uids = sorted(set([int(n['uid']) for n in node_list]))
  233. man_ip = [str(ip) for ip in IPRange('192.168.0.1', '192.168.0.5')]
  234. pub_ip = [str(ip) for ip in IPRange('172.16.0.2', '172.16.0.6')]
  235. sto_ip = [str(ip) for ip in IPRange('192.168.1.1', '192.168.1.5')]
  236. expected_list = [
  237. {'roles': ['controller', 'cinder']},
  238. {'roles': ['compute', 'cinder']},
  239. {'roles': ['compute']},
  240. {'roles': ['mongo']},
  241. {'roles': ['cinder']}]
  242. for i in range(len(expected_list)):
  243. expected_list[i]['attrs'] = {'uid': str(node_uids[i])}
  244. used_man_ip = []
  245. used_pub_ip = []
  246. used_sto_ip = []
  247. for expected in expected_list:
  248. attrs = expected['attrs']
  249. ref_node = self.filter_by_uid(node_list, attrs['uid'])[0]
  250. self.assertTrue(ref_node['internal_address'] in man_ip)
  251. self.assertTrue(ref_node['public_address'] in pub_ip)
  252. self.assertTrue(ref_node['storage_address'] in sto_ip)
  253. self.assertFalse(ref_node['internal_address'] in used_man_ip)
  254. self.assertFalse(ref_node['public_address'] in used_pub_ip)
  255. self.assertFalse(ref_node['storage_address'] in used_sto_ip)
  256. used_man_ip.append(ref_node['internal_address'])
  257. used_pub_ip.append(ref_node['public_address'])
  258. used_sto_ip.append(ref_node['storage_address'])
  259. for role in expected['roles']:
  260. nodes = self.filter_by_role(node_list, role)
  261. node = self.filter_by_uid(nodes, attrs['uid'])[0]
  262. self.assertEqual(node['public_address'],
  263. ref_node['public_address'])
  264. self.assertEqual(node['storage_address'],
  265. ref_node['storage_address'])
  266. self.assertEqual(node['internal_address'],
  267. ref_node['internal_address'])
  268. def test_flatdhcp_manager(self):
  269. facts = self.serializer.serialize(self.cluster, self.cluster.nodes)
  270. common = facts['common']
  271. self.assertEqual(
  272. common['novanetwork_parameters']['network_manager'],
  273. 'FlatDHCPManager')
  274. self.assertEqual(
  275. common['novanetwork_parameters']['num_networks'], 1)
  276. self.assertEqual(
  277. common['novanetwork_parameters']['network_size'], 65536)
  278. def test_vlan_manager(self):
  279. data = {'networking_parameters': {'net_manager': 'VlanManager'}}
  280. url = reverse('NovaNetworkConfigurationHandler',
  281. kwargs={'cluster_id': self.cluster.id})
  282. self.app.put(url, jsonutils.dumps(data),
  283. headers=self.default_headers,
  284. expect_errors=False)
  285. facts = self.serializer.serialize(self.cluster, self.cluster.nodes)
  286. common = facts['common']
  287. facts = facts['nodes']
  288. for fact in facts:
  289. self.assertEqual(fact['vlan_interface'], 'eth0')
  290. self.assertEqual(fact['fixed_interface'], 'eth0')
  291. self.assertEqual(
  292. common['novanetwork_parameters']['network_manager'],
  293. 'VlanManager')
  294. self.assertEqual(
  295. common['novanetwork_parameters']['num_networks'], 1)
  296. self.assertEqual(
  297. common['novanetwork_parameters']['vlan_start'], 103)
  298. self.assertEqual(
  299. common['novanetwork_parameters']['network_size'], 256)
  300. def test_floating_ranges_generation(self):
  301. # Set ip ranges for floating ips
  302. ranges = [['172.16.0.2', '172.16.0.4'],
  303. ['172.16.0.3', '172.16.0.5'],
  304. ['172.16.0.10', '172.16.0.12']]
  305. self.cluster.network_config.floating_ranges = ranges
  306. self.db.commit()
  307. facts = self.serializer.serialize(self.cluster, self.cluster.nodes)
  308. facts = deployment_info_to_legacy(facts)
  309. for fact in facts:
  310. self.assertEqual(
  311. fact['floating_network_range'],
  312. ['172.16.0.2-172.16.0.4',
  313. '172.16.0.3-172.16.0.5',
  314. '172.16.0.10-172.16.0.12'])
  315. def test_configure_interfaces_untagged_network(self):
  316. for network in self.db.query(NetworkGroup).all():
  317. network.vlan_start = None
  318. self.cluster.network_config.fixed_networks_vlan_start = None
  319. self.db.commit()
  320. node_db = sorted(self.cluster.nodes, key=lambda n: n.id)[0]
  321. from nailgun.extensions.network_manager.serializers.nova_serializers \
  322. import NovaNetworkDeploymentSerializer
  323. interfaces = NovaNetworkDeploymentSerializer.\
  324. configure_interfaces(node_db)
  325. expected_interfaces = {
  326. 'lo': {
  327. 'interface': 'lo',
  328. 'ipaddr': ['127.0.0.1/8']
  329. },
  330. 'eth1': {
  331. 'interface': 'eth1',
  332. 'ipaddr': ['172.16.0.2/24'],
  333. 'gateway': '172.16.0.1',
  334. 'default_gateway': True
  335. },
  336. 'eth0': {
  337. 'interface': 'eth0',
  338. 'ipaddr': ['192.168.0.1/24',
  339. '192.168.1.1/24',
  340. '10.20.0.129/24'],
  341. }
  342. }
  343. self.datadiff(expected_interfaces, interfaces, ignore_keys=['ipaddr'])
  344. def test_set_deployment_priorities(self):
  345. nodes = [
  346. {'role': 'mongo'},
  347. {'role': 'mongo'},
  348. {'role': 'primary-mongo'},
  349. {'role': 'controller'},
  350. {'role': 'ceph-osd'}
  351. ]
  352. self.add_default_params(nodes)
  353. self.cluster_mock.release.environment_version = '5.0'
  354. serializer = DeploymentMultinodeSerializer(
  355. AstuteGraph(self.cluster_mock))
  356. serializer.set_deployment_priorities(nodes)
  357. expected_priorities = [
  358. {'role': 'mongo', 'priority': 100},
  359. {'role': 'mongo', 'priority': 200},
  360. {'role': 'primary-mongo', 'priority': 300},
  361. {'role': 'controller', 'priority': 400},
  362. {'role': 'ceph-osd', 'priority': 500}
  363. ]
  364. self.add_default_params(expected_priorities)
  365. self.assertEqual(expected_priorities, nodes)
  366. def test_set_critital_node(self):
  367. self.cluster_mock.release.environment_version = '5.0'
  368. serializer = DeploymentMultinodeSerializer(
  369. AstuteGraph(self.cluster_mock))
  370. serialized_nodes = serializer.serialize_nodes(self.cluster.nodes)
  371. # primary-contoller is not critical for MultiNode serializer
  372. expected_ciritial_roles = [
  373. {'fail_if_error': False, 'role': 'cinder'},
  374. {'fail_if_error': False, 'role': 'primary-controller'},
  375. {'fail_if_error': False, 'role': 'cinder'},
  376. {'fail_if_error': False, 'role': 'compute'},
  377. {'fail_if_error': False, 'role': 'compute'},
  378. {'fail_if_error': True, 'role': 'primary-mongo'},
  379. {'fail_if_error': False, 'role': 'cinder'}
  380. ]
  381. self.assertItemsEqual(
  382. expected_ciritial_roles,
  383. [
  384. {'role': n['role'], 'fail_if_error': n['fail_if_error']}
  385. for n in serialized_nodes
  386. ]
  387. )
  388. class TestNovaNetworkOrchestratorSerializer61(OrchestratorSerializerTestBase):
  389. env_version = '2014.2-6.1'
  390. def create_env(self, manager, nodes_count=3, ctrl_count=1, nic_count=2):
  391. cluster = self.env.create(
  392. release_kwargs={'version': self.env_version},
  393. cluster_kwargs={
  394. 'mode': consts.CLUSTER_MODES.ha_compact,
  395. 'net_provider': consts.CLUSTER_NET_PROVIDERS.nova_network})
  396. data = {'networking_parameters': {'net_manager': manager}}
  397. self.env.nova_networks_put(cluster['id'], data)
  398. self.env.create_nodes_w_interfaces_count(
  399. nodes_count=ctrl_count,
  400. if_count=nic_count,
  401. roles=['controller', 'cinder'],
  402. pending_addition=True,
  403. cluster_id=cluster['id'])
  404. self.env.create_nodes_w_interfaces_count(
  405. nodes_count=nodes_count - ctrl_count,
  406. if_count=nic_count,
  407. roles=['compute'],
  408. pending_addition=True,
  409. cluster_id=cluster['id'])
  410. cluster_db = self.db.query(Cluster).get(cluster['id'])
  411. objects.Cluster.prepare_for_deployment(cluster_db)
  412. objects.Cluster.set_primary_tags(cluster_db, cluster_db.nodes)
  413. self.db.flush()
  414. return cluster_db
  415. def test_flat_dhcp_schema(self):
  416. cluster = self.create_env(
  417. manager=consts.NOVA_NET_MANAGERS.FlatDHCPManager
  418. )
  419. serializer = self.create_serializer(cluster)
  420. facts = serializer.serialize(cluster, cluster.nodes)['nodes']
  421. for node in facts:
  422. scheme = node['network_scheme']
  423. self.assertEqual(
  424. set(scheme.keys()),
  425. set(['version', 'provider', 'interfaces',
  426. 'endpoints', 'roles', 'transformations'])
  427. )
  428. self.assertEqual(scheme['version'], '1.1')
  429. self.assertEqual(scheme['provider'], 'lnx')
  430. self.assertEqual(
  431. set(scheme['interfaces'].keys()),
  432. set(['eth0', 'eth1'])
  433. )
  434. self.assertEqual(
  435. set(scheme['endpoints'].keys()),
  436. set(['br-storage', 'br-mgmt', 'br-fw-admin', 'br-ex',
  437. 'eth0.103'])
  438. )
  439. self.check_ep_format(scheme['endpoints'])
  440. self.assertEqual(
  441. scheme['roles'],
  442. {'storage': 'br-storage',
  443. 'management': 'br-mgmt',
  444. 'fw-admin': 'br-fw-admin',
  445. 'ex': 'br-ex',
  446. 'novanetwork/fixed': 'eth0.103'}
  447. )
  448. self.assertEqual(
  449. scheme['transformations'],
  450. [
  451. {'action': 'add-br',
  452. 'name': 'br-fw-admin'},
  453. {'action': 'add-br',
  454. 'name': 'br-storage'},
  455. {'action': 'add-br',
  456. 'name': 'br-mgmt'},
  457. {'action': 'add-br',
  458. 'name': 'br-ex'},
  459. {'action': 'add-port',
  460. 'bridge': 'br-fw-admin',
  461. 'name': 'eth0'},
  462. {'action': 'add-port',
  463. 'bridge': 'br-storage',
  464. 'name': 'eth0.102'},
  465. {'action': 'add-port',
  466. 'bridge': 'br-mgmt',
  467. 'name': 'eth0.101'},
  468. {'action': 'add-port',
  469. 'bridge': 'br-ex',
  470. 'name': 'eth1'},
  471. {'action': 'add-port',
  472. 'name': 'eth0.103'},
  473. ]
  474. )
  475. def test_vlan_schema(self):
  476. cluster = self.create_env(
  477. manager=consts.NOVA_NET_MANAGERS.VlanManager
  478. )
  479. serializer = self.create_serializer(cluster)
  480. facts = serializer.serialize(cluster, cluster.nodes)['nodes']
  481. for node in facts:
  482. scheme = node['network_scheme']
  483. self.assertEqual(
  484. set(scheme.keys()),
  485. set(['version', 'provider', 'interfaces',
  486. 'endpoints', 'roles', 'transformations'])
  487. )
  488. self.assertEqual(scheme['version'], '1.1')
  489. self.assertEqual(scheme['provider'], 'lnx')
  490. self.assertEqual(
  491. set(scheme['interfaces'].keys()),
  492. set(['eth0', 'eth1'])
  493. )
  494. self.assertEqual(
  495. set(scheme['endpoints'].keys()),
  496. set(['br-storage', 'br-mgmt', 'br-fw-admin', 'br-ex',
  497. 'eth0'])
  498. )
  499. self.check_ep_format(scheme['endpoints'])
  500. self.assertEqual(
  501. scheme['roles'],
  502. {'storage': 'br-storage',
  503. 'management': 'br-mgmt',
  504. 'fw-admin': 'br-fw-admin',
  505. 'ex': 'br-ex',
  506. 'novanetwork/vlan': 'eth0'}
  507. )
  508. self.assertEqual(
  509. scheme['transformations'],
  510. [
  511. {'action': 'add-br',
  512. 'name': 'br-fw-admin'},
  513. {'action': 'add-br',
  514. 'name': 'br-storage'},
  515. {'action': 'add-br',
  516. 'name': 'br-mgmt'},
  517. {'action': 'add-br',
  518. 'name': 'br-ex'},
  519. {'action': 'add-port',
  520. 'bridge': 'br-fw-admin',
  521. 'name': 'eth0'},
  522. {'action': 'add-port',
  523. 'bridge': 'br-storage',
  524. 'name': 'eth0.102'},
  525. {'action': 'add-port',
  526. 'bridge': 'br-mgmt',
  527. 'name': 'eth0.101'},
  528. {'action': 'add-port',
  529. 'bridge': 'br-ex',
  530. 'name': 'eth1'},
  531. ]
  532. )
  533. def test_flat_dhcp_with_bonds(self):
  534. cluster = self.create_env(
  535. manager=consts.NOVA_NET_MANAGERS.FlatDHCPManager,
  536. ctrl_count=3,
  537. nic_count=3
  538. )
  539. for node in cluster.nodes:
  540. self.move_network(node.id, 'management', 'eth0', 'eth1')
  541. self.env.make_bond_via_api(
  542. 'lnx_bond', '', ['eth1', 'eth2'], node.id,
  543. attrs={
  544. 'type__': {'value': consts.BOND_TYPES.linux},
  545. 'mode': {
  546. 'value': {'value': consts.BOND_MODES.balance_rr}}})
  547. serializer = self.create_serializer(cluster)
  548. facts = serializer.serialize(cluster, cluster.nodes)['nodes']
  549. for node in facts:
  550. self.assertEqual(
  551. node['network_scheme']['transformations'],
  552. [
  553. {'action': 'add-br',
  554. 'name': 'br-fw-admin'},
  555. {'action': 'add-br',
  556. 'name': 'br-storage'},
  557. {'action': 'add-br',
  558. 'name': 'br-mgmt'},
  559. {'action': 'add-br',
  560. 'name': 'br-ex'},
  561. {'action': 'add-port',
  562. 'bridge': 'br-fw-admin',
  563. 'name': 'eth0'},
  564. {'action': 'add-port',
  565. 'bridge': 'br-storage',
  566. 'name': 'eth0.102'},
  567. {'action': 'add-bond',
  568. 'bridge': 'br-ex',
  569. 'name': 'lnx_bond',
  570. 'interfaces': ['eth1', 'eth2'],
  571. 'bond_properties': {'mode': 'balance-rr'},
  572. 'interface_properties': {}},
  573. {'action': 'add-port',
  574. 'bridge': 'br-mgmt',
  575. 'name': 'lnx_bond.101'},
  576. {'action': 'add-port',
  577. 'name': 'eth0.103'},
  578. ]
  579. )
  580. def test_vlan_with_bonds(self):
  581. cluster = self.create_env(
  582. manager=consts.NOVA_NET_MANAGERS.VlanManager,
  583. ctrl_count=3,
  584. nic_count=3
  585. )
  586. for node in cluster.nodes:
  587. self.move_network(node.id, 'management', 'eth0', 'eth1')
  588. self.move_network(node.id, 'fixed', 'eth0', 'eth1')
  589. self.env.make_bond_via_api(
  590. 'lnx_bond', '', ['eth1', 'eth2'], node.id,
  591. attrs={
  592. 'type__': {'value': consts.BOND_TYPES.linux},
  593. 'mode': {
  594. 'value': {'value': consts.BOND_MODES.balance_rr}}})
  595. serializer = self.create_serializer(cluster)
  596. facts = serializer.serialize(cluster, cluster.nodes)['nodes']
  597. for node in facts:
  598. self.assertEqual(
  599. node['network_scheme']['roles'],
  600. {'storage': 'br-storage',
  601. 'management': 'br-mgmt',
  602. 'fw-admin': 'br-fw-admin',
  603. 'ex': 'br-ex',
  604. 'novanetwork/vlan': 'lnx_bond'}
  605. )
  606. self.assertEqual(
  607. node['network_scheme']['transformations'],
  608. [
  609. {'action': 'add-br',
  610. 'name': 'br-fw-admin'},
  611. {'action': 'add-br',
  612. 'name': 'br-storage'},
  613. {'action': 'add-br',
  614. 'name': 'br-mgmt'},
  615. {'action': 'add-br',
  616. 'name': 'br-ex'},
  617. {'action': 'add-port',
  618. 'bridge': 'br-fw-admin',
  619. 'name': 'eth0'},
  620. {'action': 'add-port',
  621. 'bridge': 'br-storage',
  622. 'name': 'eth0.102'},
  623. {'action': 'add-bond',
  624. 'bridge': 'br-ex',
  625. 'name': 'lnx_bond',
  626. 'interfaces': ['eth1', 'eth2'],
  627. 'bond_properties': {'mode': 'balance-rr'},
  628. 'interface_properties': {}},
  629. {'action': 'add-port',
  630. 'bridge': 'br-mgmt',
  631. 'name': 'lnx_bond.101'},
  632. ]
  633. )
  634. class TestNeutronOrchestratorSerializer61(OrchestratorSerializerTestBase):
  635. env_version = '2014.2-6.1'
  636. def create_env(self, segment_type, nodes_count=3, ctrl_count=1,
  637. nic_count=2):
  638. cluster = self.env.create(
  639. release_kwargs={'version': self.env_version},
  640. cluster_kwargs={
  641. 'mode': consts.CLUSTER_MODES.ha_compact,
  642. 'net_provider': 'neutron',
  643. 'net_segment_type': segment_type}
  644. )
  645. self.env.create_nodes_w_interfaces_count(
  646. nodes_count=ctrl_count,
  647. if_count=nic_count,
  648. roles=['controller', 'cinder'],
  649. pending_addition=True,
  650. cluster_id=cluster['id'])
  651. self.env.create_nodes_w_interfaces_count(
  652. nodes_count=nodes_count - ctrl_count,
  653. if_count=nic_count,
  654. roles=['compute'],
  655. pending_addition=True,
  656. cluster_id=cluster['id'])
  657. cluster_db = self.db.query(Cluster).get(cluster['id'])
  658. objects.Cluster.prepare_for_deployment(cluster_db)
  659. objects.Cluster.set_primary_tags(cluster_db, cluster_db.nodes)
  660. self.db.flush()
  661. return cluster_db
  662. def add_nics_properties(self, cluster):
  663. nodes_list = []
  664. for node in cluster.nodes:
  665. resp = self.app.get(
  666. reverse('NodeNICsHandler', kwargs={'node_id': node.id}),
  667. headers=self.default_headers
  668. )
  669. self.assertEquals(200, resp.status_code)
  670. interfaces = jsonutils.loads(resp.body)
  671. for iface in interfaces:
  672. if iface['name'] == 'eth0':
  673. iface['attributes']['mtu']['value']['value'] = 1500
  674. iface['attributes']['offloading'][
  675. 'disable']['value'] = True
  676. nodes_list.append({'id': node.id, 'interfaces': interfaces})
  677. resp_put = self.app.put(
  678. reverse('NodeCollectionNICsHandler'),
  679. jsonutils.dumps(nodes_list),
  680. headers=self.default_headers
  681. )
  682. self.assertEqual(resp_put.status_code, 200)
  683. def check_gateways(self, node, scheme, is_public):
  684. nm = objects.Cluster.get_network_manager(node.cluster)
  685. ep = scheme['endpoints']
  686. if is_public:
  687. gw = nm.get_network_by_netname(
  688. 'public', nm.get_node_networks(node))['gateway']
  689. self.assertEqual(ep['br-ex']['gateway'], gw)
  690. else:
  691. gw = nm.get_default_gateway(node.id)
  692. self.assertEqual(ep['br-fw-admin']['gateway'], gw)
  693. def check_vlan_schema(self, facts, transformations):
  694. for node in facts:
  695. node_db = objects.Node.get_by_uid(node['uid'])
  696. is_public = objects.Node.should_have_public(node_db)
  697. scheme = node['network_scheme']
  698. self.assertEqual(
  699. set(scheme.keys()),
  700. set(['version', 'provider', 'interfaces',
  701. 'endpoints', 'roles', 'transformations'])
  702. )
  703. self.assertEqual(scheme['version'], '1.1')
  704. self.assertEqual(scheme['provider'], 'lnx')
  705. self.assertEqual(
  706. scheme['interfaces'],
  707. {'eth0': {'mtu': 1500,
  708. 'vendor_specific': {
  709. 'disable_offloading': True}},
  710. 'eth1': {}}
  711. )
  712. br_set = set(['br-storage', 'br-mgmt', 'br-fw-admin', 'br-prv'])
  713. role_dict = {'storage': 'br-storage',
  714. 'management': 'br-mgmt',
  715. 'fw-admin': 'br-fw-admin',
  716. 'neutron/private': 'br-prv'}
  717. if is_public:
  718. br_set.update(['br-ex', 'br-floating'])
  719. role_dict.update({'ex': 'br-ex',
  720. 'neutron/floating': 'br-floating'})
  721. self.assertEqual(
  722. set(scheme['endpoints'].keys()),
  723. br_set
  724. )
  725. self.check_ep_format(scheme['endpoints'])
  726. self.check_gateways(node_db, scheme, is_public)
  727. self.assertEqual(
  728. scheme['roles'],
  729. role_dict
  730. )
  731. transformations_ = transformations
  732. if not is_public:
  733. # exclude all 'br-ex' and 'br-floating' objects
  734. transformations_ = [
  735. t for t in transformations if all([
  736. t.get('name') not in ('br-ex', 'br-floating'),
  737. t.get('bridge') not in ('br-ex', 'br-floating'),
  738. 'br-ex' not in t.get('bridges', []),
  739. 'br-floating' not in t.get('bridges', []),
  740. ])]
  741. self.assertEqual(
  742. scheme['transformations'],
  743. transformations_
  744. )
  745. def test_vlan_schema(self):
  746. cluster = self.create_env(segment_type='vlan')
  747. self.add_nics_properties(cluster)
  748. serializer = self.create_serializer(cluster)
  749. facts = serializer.serialize(cluster, cluster.nodes)['nodes']
  750. self.check_vlan_schema(facts, [
  751. {'action': 'add-br',
  752. 'name': 'br-fw-admin'},
  753. {'action': 'add-br',
  754. 'name': 'br-mgmt'},
  755. {'action': 'add-br',
  756. 'name': 'br-storage'},
  757. {'action': 'add-br',
  758. 'name': 'br-ex'},
  759. {'action': 'add-br',
  760. 'name': 'br-floating',
  761. 'provider': 'ovs'},
  762. {'action': 'add-patch',
  763. 'mtu': 65000,
  764. 'bridges': ['br-floating', 'br-ex'],
  765. 'provider': 'ovs'},
  766. {'action': 'add-br',
  767. 'name': 'br-prv',
  768. 'provider': 'ovs'},
  769. {'action': 'add-patch',
  770. 'mtu': 65000,
  771. 'bridges': ['br-prv', 'br-fw-admin'],
  772. 'provider': 'ovs'},
  773. {'action': 'add-port',
  774. 'bridge': 'br-fw-admin',
  775. 'name': 'eth0'},
  776. {'action': 'add-port',
  777. 'bridge': 'br-storage',
  778. 'name': 'eth0.102'},
  779. {'action': 'add-port',
  780. 'bridge': 'br-mgmt',
  781. 'name': 'eth0.101'},
  782. {'action': 'add-port',
  783. 'bridge': 'br-ex',
  784. 'name': 'eth1'},
  785. ])
  786. def test_vlan_schema_with_br_aux(self):
  787. cluster = self.create_env(segment_type='vlan')
  788. self.add_nics_properties(cluster)
  789. # move all networks to first interface and assign private network
  790. # to second one
  791. for node in cluster.nodes:
  792. interfaces = node.interfaces
  793. interfaces[0].assigned_networks_list.extend(
  794. interfaces[1].assigned_networks_list)
  795. private_net = next((
  796. net for net in interfaces[0].assigned_networks_list
  797. if net.name == 'private'))
  798. interfaces[0].assigned_networks_list.remove(private_net)
  799. interfaces[1].assigned_networks_list = [private_net]
  800. self.db.flush()
  801. serializer = self.create_serializer(cluster)
  802. facts = serializer.serialize(cluster, cluster.nodes)['nodes']
  803. self.check_vlan_schema(facts, [
  804. {'action': 'add-br',
  805. 'name': 'br-fw-admin'},
  806. {'action': 'add-br',
  807. 'name': 'br-mgmt'},
  808. {'action': 'add-br',
  809. 'name': 'br-storage'},
  810. {'action': 'add-br',
  811. 'name': 'br-ex'},
  812. {'action': 'add-br',
  813. 'name': 'br-floating',
  814. 'provider': 'ovs'},
  815. {'action': 'add-patch',
  816. 'mtu': 65000,
  817. 'bridges': ['br-floating', 'br-ex'],
  818. 'provider': 'ovs'},
  819. {'action': 'add-br',
  820. 'name': 'br-prv',
  821. 'provider': 'ovs'},
  822. {'action': 'add-br',
  823. 'name': 'br-aux'},
  824. {'action': 'add-patch',
  825. 'mtu': 65000,
  826. 'bridges': ['br-prv', 'br-aux'],
  827. 'provider': 'ovs'},
  828. {'action': 'add-port',
  829. 'bridge': 'br-fw-admin',
  830. 'name': 'eth0'},
  831. {'action': 'add-port',
  832. 'bridge': 'br-ex',
  833. 'name': 'eth0'},
  834. {'action': 'add-port',
  835. 'bridge': 'br-storage',
  836. 'name': 'eth0.102'},
  837. {'action': 'add-port',
  838. 'bridge': 'br-mgmt',
  839. 'name': 'eth0.101'},
  840. {'action': 'add-port',
  841. 'bridge': 'br-aux',
  842. 'name': 'eth1'},
  843. ])
  844. def test_vlan_with_bond(self):
  845. cluster = self.create_env(segment_type='vlan', ctrl_count=3,
  846. nic_count=3)
  847. for node in cluster.nodes:
  848. self.move_network(node.id, 'storage', 'eth0', 'eth1')
  849. self.env.make_bond_via_api(
  850. 'lnx_bond', '', ['eth1', 'eth2'], node.id,
  851. attrs={
  852. 'type__': {'value': consts.BOND_TYPES.linux},
  853. 'mtu': {'value': {'value': 9000}},
  854. 'mode': {'value': {'value': consts.BOND_MODES.balance_rr}}
  855. }
  856. )
  857. serializer = self.create_serializer(cluster)
  858. facts = serializer.serialize(cluster, cluster.nodes)['nodes']
  859. for node in facts:
  860. transformations = [
  861. {'action': 'add-br',
  862. 'name': 'br-fw-admin'},
  863. {'action': 'add-br',
  864. 'name': 'br-mgmt'},
  865. {'action': 'add-br',
  866. 'name': 'br-storage'},
  867. {'action': 'add-br',
  868. 'name': 'br-ex'},
  869. {'action': 'add-br',
  870. 'name': 'br-floating',
  871. 'provider': 'ovs'},
  872. {'action': 'add-patch',
  873. 'mtu': 65000,
  874. 'bridges': ['br-floating', 'br-ex'],
  875. 'provider': 'ovs'},
  876. {'action': 'add-br',
  877. 'name': 'br-prv',
  878. 'provider': 'ovs'},
  879. {'action': 'add-patch',
  880. 'mtu': 65000,
  881. 'bridges': ['br-prv', 'br-fw-admin'],
  882. 'provider': 'ovs'},
  883. {'action': 'add-port',
  884. 'bridge': 'br-fw-admin',
  885. 'name': 'eth0'},
  886. {'action': 'add-port',
  887. 'bridge': 'br-mgmt',
  888. 'name': 'eth0.101'},
  889. {'action': 'add-bond',
  890. 'bridge': 'br-ex',
  891. 'name': 'lnx_bond',
  892. 'mtu': 9000,
  893. 'interfaces': ['eth1', 'eth2'],
  894. 'bond_properties': {'mode': 'balance-rr'},
  895. 'interface_properties': {'mtu': 9000}},
  896. {'action': 'add-port',
  897. 'bridge': 'br-storage',
  898. 'name': 'lnx_bond.102'},
  899. ]
  900. self.assertEqual(
  901. node['network_scheme']['transformations'],
  902. transformations
  903. )
  904. def test_gre_schema(self):
  905. cluster = self.create_env(segment_type='gre')
  906. self.add_nics_properties(cluster)
  907. serializer = self.create_serializer(cluster)
  908. facts = serializer.serialize(cluster, cluster.nodes)['nodes']
  909. for node in facts:
  910. node_db = objects.Node.get_by_uid(node['uid'])
  911. is_public = objects.Node.should_have_public(node_db)
  912. scheme = node['network_scheme']
  913. self.assertEqual(
  914. set(scheme.keys()),
  915. set(['version', 'provider', 'interfaces',
  916. 'endpoints', 'roles', 'transformations'])
  917. )
  918. self.assertEqual(scheme['version'], '1.1')
  919. self.assertEqual(scheme['provider'], 'lnx')
  920. self.assertEqual(
  921. scheme['interfaces'],
  922. {'eth0': {'mtu': 1500,
  923. 'vendor_specific': {
  924. 'disable_offloading': True}},
  925. 'eth1': {}}
  926. )
  927. br_set = set(['br-storage', 'br-mgmt', 'br-fw-admin', 'br-mesh'])
  928. role_dict = {'storage': 'br-storage',
  929. 'management': 'br-mgmt',
  930. 'fw-admin': 'br-fw-admin',
  931. 'neutron/mesh': 'br-mesh'}
  932. if is_public:
  933. br_set.update(['br-ex', 'br-floating'])
  934. role_dict.update({'ex': 'br-ex',
  935. 'neutron/floating': 'br-floating'})
  936. self.assertEqual(
  937. set(scheme['endpoints'].keys()),
  938. br_set
  939. )
  940. self.check_ep_format(scheme['endpoints'])
  941. self.check_gateways(node_db, scheme, is_public)
  942. self.assertEqual(
  943. scheme['roles'],
  944. role_dict
  945. )
  946. transformations = [
  947. {'action': 'add-br',
  948. 'name': 'br-fw-admin'},
  949. {'action': 'add-br',
  950. 'name': 'br-mgmt'},
  951. {'action': 'add-br',
  952. 'name': 'br-storage'},
  953. {'action': 'add-br',
  954. 'name': 'br-ex'},
  955. {'action': 'add-br',
  956. 'name': 'br-floating',
  957. 'provider': 'ovs'},
  958. {'action': 'add-patch',
  959. 'mtu': 65000,
  960. 'bridges': ['br-floating', 'br-ex'],
  961. 'provider': 'ovs'},
  962. {'action': 'add-br',
  963. 'name': 'br-mesh'},
  964. {'action': 'add-port',
  965. 'bridge': 'br-fw-admin',
  966. 'name': 'eth0'},
  967. {'action': 'add-port',
  968. 'bridge': 'br-storage',
  969. 'name': 'eth0.102'},
  970. {'action': 'add-port',
  971. 'bridge': 'br-mgmt',
  972. 'name': 'eth0.101'},
  973. {'action': 'add-port',
  974. 'bridge': 'br-mesh',
  975. 'name': 'eth0.103'},
  976. {'action': 'add-port',
  977. 'bridge': 'br-ex',
  978. 'name': 'eth1'},
  979. ]
  980. if not is_public:
  981. # exclude all 'br-ex' and 'br-floating' objects
  982. transformations = transformations[:3] + transformations[6:-1]
  983. self.assertEqual(
  984. scheme['transformations'],
  985. transformations
  986. )
  987. def test_gre_with_bond(self):
  988. cluster = self.create_env(segment_type='gre', ctrl_count=3,
  989. nic_count=3)
  990. for node in cluster.nodes:
  991. self.move_network(node.id, 'storage', 'eth0', 'eth1')
  992. self.env.make_bond_via_api(
  993. 'lnx_bond', '', ['eth1', 'eth2'], node.id,
  994. attrs={
  995. 'mtu': {
  996. 'value': {
  997. 'value': 9000}},
  998. 'mode': {
  999. 'value': {
  1000. 'value': consts.BOND_MODES.l_802_3ad}},
  1001. 'xmit_hash_policy': {
  1002. 'value': {
  1003. 'value': consts.BOND_XMIT_HASH_POLICY.layer2}},
  1004. 'lacp_rate': {
  1005. 'value': {
  1006. 'value': consts.BOND_LACP_RATES.slow}},
  1007. 'type__': {
  1008. 'value': consts.BOND_TYPES.linux}
  1009. }
  1010. )
  1011. serializer = self.create_serializer(cluster)
  1012. facts = serializer.serialize(cluster, cluster.nodes)['nodes']
  1013. for node in facts:
  1014. transformations = [
  1015. {'action': 'add-br',
  1016. 'name': 'br-fw-admin'},
  1017. {'action': 'add-br',
  1018. 'name': 'br-mgmt'},
  1019. {'action': 'add-br',
  1020. 'name': 'br-storage'},
  1021. {'action': 'add-br',
  1022. 'name': 'br-ex'},
  1023. {'action': 'add-br',
  1024. 'name': 'br-floating',
  1025. 'provider': 'ovs'},
  1026. {'action': 'add-patch',
  1027. 'mtu': 65000,
  1028. 'bridges': ['br-floating', 'br-ex'],
  1029. 'provider': 'ovs'},
  1030. {'action': 'add-br',
  1031. 'name': 'br-mesh'},
  1032. {'action': 'add-port',
  1033. 'bridge': 'br-fw-admin',
  1034. 'name': 'eth0'},
  1035. {'action': 'add-port',
  1036. 'bridge': 'br-mgmt',
  1037. 'name': 'eth0.101'},
  1038. {'action': 'add-port', 'bridge': 'br-mesh', 'name':
  1039. 'eth0.103'},
  1040. {'action': 'add-bond',
  1041. 'bridge': 'br-ex',
  1042. 'name': 'lnx_bond',
  1043. 'mtu': 9000,
  1044. 'interfaces': ['eth1', 'eth2'],
  1045. 'bond_properties': {'mode': '802.3ad',
  1046. 'xmit_hash_policy': 'layer2',
  1047. 'lacp_rate': 'slow'},
  1048. 'interface_properties': {'mtu': 9000}},
  1049. {'action': 'add-port',
  1050. 'bridge': 'br-storage',
  1051. 'name': 'lnx_bond.102'},
  1052. ]
  1053. self.assertEqual(
  1054. node['network_scheme']['transformations'],
  1055. transformations
  1056. )
  1057. @mock.patch('nailgun.task.task.rpc.cast')
  1058. def test_gre_with_multi_groups(self, mocked_rpc):
  1059. cluster = self.create_env(segment_type='gre', ctrl_count=3)
  1060. resp = self.env.create_node_group()
  1061. group_id = resp.json_body['id']
  1062. nets = self.env.neutron_networks_get(cluster.id).json_body
  1063. nets_w_gw = {'management': '199.99.20.0/24',
  1064. 'storage': '199.98.20.0/24',
  1065. 'fuelweb_admin': '199.97.20.0/24',
  1066. 'private': '199.95.20.0/24',
  1067. 'public': '199.96.20.0/24'}
  1068. for net in nets['networks']:
  1069. if net['name'] in nets_w_gw.keys():
  1070. if net['group_id'] == group_id:
  1071. net['cidr'] = nets_w_gw[net['name']]
  1072. if net['meta']['notation'] == 'ip_ranges':
  1073. net['ip_ranges'] = [[
  1074. str(IPAddress(IPNetwork(net['cidr']).first + 2)),
  1075. str(IPAddress(IPNetwork(net['cidr']).first + 126)),
  1076. ]]
  1077. if not net['meta']['use_gateway']:
  1078. # IP ranges for networks in default nodegroup must
  1079. # be updated as well to exclude gateway address.
  1080. # Do not use first address to avoid clashing
  1081. # with floating range.
  1082. net['ip_ranges'] = [[
  1083. str(IPAddress(IPNetwork(net['cidr']).first + 2)),
  1084. str(IPAddress(IPNetwork(net['cidr']).first + 254)),
  1085. ]]
  1086. net['meta']['use_gateway'] = True
  1087. net['gateway'] = str(
  1088. IPAddress(IPNetwork(net['cidr']).first + 1))
  1089. resp = self.env.neutron_networks_put(cluster.id, nets)
  1090. self.assertEqual(resp.status_code, 200)
  1091. self.assertEqual(mocked_rpc.call_count, 1)
  1092. self.env.create_nodes_w_interfaces_count(
  1093. nodes_count=3,
  1094. if_count=2,
  1095. roles=['compute'],
  1096. pending_addition=True,
  1097. cluster_id=cluster.id,
  1098. group_id=group_id)
  1099. objects.Cluster.prepare_for_deployment(cluster)
  1100. serializer = self.create_serializer(cluster)
  1101. facts = serializer.serialize(cluster, cluster.nodes)['nodes']
  1102. for node in facts:
  1103. node_db = objects.Node.get_by_uid(node['uid'])
  1104. is_public = objects.Node.should_have_public(node_db)
  1105. endpoints = node['network_scheme']['endpoints']
  1106. br_set = set(['br-storage', 'br-mgmt', 'br-fw-admin', 'br-mesh'])
  1107. if is_public:
  1108. br_set.add('br-ex')
  1109. # floating network won't have routes
  1110. self.assertEqual(endpoints['br-floating'], {'IP': 'none'})
  1111. endpoints.pop('br-floating')
  1112. self.assertEqual(
  1113. set(endpoints.keys()),
  1114. br_set
  1115. )
  1116. for name, descr in six.iteritems(endpoints):
  1117. self.assertTrue(set(['IP', 'routes']) <= set(descr.keys()))
  1118. self.assertEqual(len(descr['routes']), 1)
  1119. for route in descr['routes']:
  1120. self.assertEqual(set(['net', 'via']), set(route.keys()))
  1121. class TestNovaOrchestratorHASerializer(OrchestratorSerializerTestBase):
  1122. env_version = '1111-5.0'
  1123. def setUp(self):
  1124. super(TestNovaOrchestratorHASerializer, self).setUp()
  1125. self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
  1126. objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
  1127. def create_env(self, mode):
  1128. cluster = self.env.create(
  1129. release_kwargs={'version': self.env_version},
  1130. cluster_kwargs={
  1131. 'mode': mode,
  1132. 'net_provider': consts.CLUSTER_NET_PROVIDERS.nova_network},
  1133. nodes_kwargs=[
  1134. {'roles': ['controller'], 'pending_addition': True},
  1135. {'roles': ['controller'], 'pending_addition': True},
  1136. {'roles': ['controller', 'cinder'], 'pending_addition': True},
  1137. {'roles': ['compute', 'cinder'], 'pending_addition': True},
  1138. {'roles': ['compute'], 'pending_addition': True},
  1139. {'roles': ['mongo'], 'pending_addition': True},
  1140. {'roles': ['cinder'], 'pending_addition': True}])
  1141. cluster_db = self.db.query(Cluster).get(cluster['id'])
  1142. objects.Cluster.prepare_for_deployment(cluster_db)
  1143. return cluster_db
  1144. @property
  1145. def serializer(self):
  1146. self.cluster_mock.release.environment_version = '5.0'
  1147. return DeploymentHASerializer(AstuteGraph(self.cluster_mock))
  1148. def test_set_deployment_priorities(self):
  1149. nodes = [
  1150. {'role': 'mongo'},
  1151. {'role': 'primary-mongo'},
  1152. {'role': 'primary-controller'},
  1153. {'role': 'controller'},
  1154. {'role': 'controller'},
  1155. {'role': 'ceph-osd'}
  1156. ]
  1157. self.add_default_params(nodes)
  1158. self.serializer.set_deployment_priorities(nodes)
  1159. expected_priorities = [
  1160. {'role': 'mongo', 'priority': 100},
  1161. {'role': 'primary-mongo', 'priority': 200},
  1162. {'role': 'primary-controller', 'priority': 300},
  1163. {'role': 'controller', 'priority': 400},
  1164. {'role': 'controller', 'priority': 500},
  1165. {'role': 'ceph-osd', 'priority': 600},
  1166. ]
  1167. self.add_default_params(expected_priorities)
  1168. self.assertEqual(expected_priorities, nodes)
  1169. def test_set_deployment_priorities_many_cntrls(self):
  1170. nodes = [
  1171. {'role': 'mongo'},
  1172. {'role': 'primary-mongo'},
  1173. {'role': 'primary-controller'},
  1174. {'role': 'controller'},
  1175. {'role': 'controller'},
  1176. {'role': 'controller'},
  1177. {'role': 'controller'},
  1178. {'role': 'controller'},
  1179. {'role': 'controller'},
  1180. {'role': 'controller'},
  1181. {'role': 'controller'},
  1182. {'role': 'ceph-osd'}
  1183. ]
  1184. self.add_default_params(nodes)
  1185. self.serializer.set_deployment_priorities(nodes)
  1186. expected_priorities = [
  1187. {'role': 'mongo', 'priority': 100},
  1188. {'role': 'primary-mongo', 'priority': 200},
  1189. {'role': 'primary-controller', 'priority': 300},
  1190. {'role': 'controller', 'priority': 400},
  1191. {'role': 'controller', 'priority': 500},
  1192. {'role': 'controller', 'priority': 600},
  1193. {'role': 'controller', 'priority': 700},
  1194. {'role': 'controller', 'priority': 800},
  1195. {'role': 'controller', 'priority': 900},
  1196. {'role': 'controller', 'priority': 1000},
  1197. {'role': 'controller', 'priority': 1100},
  1198. {'role': 'ceph-osd', 'priority': 1200}
  1199. ]
  1200. self.add_default_params(expected_priorities)
  1201. self.assertEqual(expected_priorities, nodes)
  1202. def test_set_critital_node(self):
  1203. serialized_nodes = self.serializer.serialize_nodes(self.cluster.nodes)
  1204. expected_ciritial_roles = [
  1205. {'fail_if_error': True, 'role': 'primary-controller'},
  1206. {'fail_if_error': True, 'role': 'controller'},
  1207. {'fail_if_error': False, 'role': 'cinder'},
  1208. {'fail_if_error': True, 'role': 'controller'},
  1209. {'fail_if_error': False, 'role': 'cinder'},
  1210. {'fail_if_error': False, 'role': 'compute'},
  1211. {'fail_if_error': False, 'role': 'compute'},
  1212. {'fail_if_error': True, 'role': 'primary-mongo'},
  1213. {'fail_if_error': False, 'role': 'cinder'}
  1214. ]
  1215. self.assertItemsEqual(
  1216. expected_ciritial_roles,
  1217. [
  1218. {'role': n['role'], 'fail_if_error': n['fail_if_error']}
  1219. for n in serialized_nodes
  1220. ]
  1221. )
  1222. def test_set_primary_controller_priority_not_depend_on_nodes_order(self):
  1223. controllers = filter(lambda n: 'controller' in n.roles, self.env.nodes)
  1224. expected_primary_controller = sorted(
  1225. controllers, key=attrgetter('id'))[0]
  1226. reverse_sorted_controllers = sorted(
  1227. controllers, key=attrgetter('id'), reverse=True)
  1228. result_nodes = self.serializer.serialize(
  1229. self.cluster, reverse_sorted_controllers)['nodes']
  1230. high_priority = sorted(result_nodes, key=itemgetter('priority'))[0]
  1231. self.assertEqual(high_priority['role'], 'primary-controller')
  1232. self.assertEqual(
  1233. int(high_priority['uid']),
  1234. expected_primary_controller.id)
  1235. def test_node_list(self):
  1236. serialized_nodes = self.serializer.node_list(self.cluster.nodes)
  1237. for node in serialized_nodes:
  1238. # Each node has swift_zone
  1239. self.assertEqual(node['swift_zone'], node['uid'])
  1240. def test_get_common_attrs(self):
  1241. attrs = self.serializer.get_common_attrs(self.cluster)
  1242. # vips
  1243. self.assertEqual(attrs['management_vip'], '192.168.0.8')
  1244. self.assertEqual(attrs['public_vip'], '172.16.0.9')
  1245. # last_contrller
  1246. controllers = self.get_controllers(self.cluster.id)
  1247. self.assertEqual(attrs['last_controller'],
  1248. 'node-%d' % controllers[-1].id)
  1249. # primary_controller
  1250. controllers = self.filter_by_role(attrs['nodes'], 'primary-controller')
  1251. self.assertEqual(controllers[0]['role'], 'primary-controller')
  1252. # primary_mongo
  1253. mongo_nodes = self.filter_by_role(attrs['nodes'], 'primary-mongo')
  1254. self.assertEqual(mongo_nodes[-1]['role'], 'primary-mongo')
  1255. # mountpoints and mp attrs
  1256. self.assertEqual(
  1257. attrs['mp'],
  1258. [{'point': '1', 'weight': '1'},
  1259. {'point': '2', 'weight': '2'}])
  1260. class TestNovaOrchestratorHASerializer51(TestNovaOrchestratorHASerializer):
  1261. env_version = '1111-5.1'
  1262. @property
  1263. def serializer(self):
  1264. self.cluster_mock.release.environment_version = '5.1'
  1265. return DeploymentHASerializer51(AstuteGraph(self.cluster_mock))
  1266. def test_set_deployment_priorities(self):
  1267. nodes = [
  1268. {'role': 'mongo'},
  1269. {'role': 'primary-mongo'},
  1270. {'role': 'primary-controller'},
  1271. {'role': 'controller'},
  1272. {'role': 'controller'},
  1273. {'role': 'ceph-osd'}
  1274. ]
  1275. self.add_default_params(nodes)
  1276. self.serializer.set_deployment_priorities(nodes)
  1277. expected_priorities = [
  1278. {'role': 'mongo', 'priority': 100},
  1279. {'role': 'primary-mongo', 'priority': 200},
  1280. {'role': 'primary-controller', 'priority': 300},
  1281. {'role': 'controller', 'priority': 400},
  1282. {'role': 'controller', 'priority': 400},
  1283. {'role': 'ceph-osd', 'priority': 500},
  1284. ]
  1285. self.add_default_params(expected_priorities)
  1286. self.assertEqual(expected_priorities, nodes)
  1287. def test_set_deployment_priorities_many_cntrls(self):
  1288. nodes = [
  1289. {'role': 'mongo'},
  1290. {'role': 'primary-mongo'},
  1291. {'role': 'primary-controller'},
  1292. {'role': 'controller'},
  1293. {'role': 'controller'},
  1294. {'role': 'controller'},
  1295. {'role': 'controller'},
  1296. {'role': 'controller'},
  1297. {'role': 'controller'},
  1298. {'role': 'controller'},
  1299. {'role': 'controller'},
  1300. {'role': 'ceph-osd'}
  1301. ]
  1302. self.add_default_params(nodes)
  1303. self.serializer.set_deployment_priorities(nodes)
  1304. expected_priorities = [
  1305. {'role': 'mongo', 'priority': 100},
  1306. {'role': 'primary-mongo', 'priority': 200},
  1307. {'role': 'primary-controller', 'priority': 300},
  1308. {'role': 'controller', 'priority': 400},
  1309. {'role': 'controller', 'priority': 400},
  1310. {'role': 'controller', 'priority': 400},
  1311. {'role': 'controller', 'priority': 400},
  1312. {'role': 'controller', 'priority': 400},
  1313. {'role': 'controller', 'priority': 400},
  1314. {'role': 'controller', 'priority': 500},
  1315. {'role': 'controller', 'priority': 500},
  1316. {'role': 'ceph-osd', 'priority': 600}
  1317. ]
  1318. self.add_default_params(expected_priorities)
  1319. self.assertEqual(expected_priorities, nodes)
  1320. # TODO(awoodward): multinode deprecation: probably has duplicates
  1321. class TestNeutronOrchestratorSerializer(OrchestratorSerializerTestBase):
  1322. new_env_release_version = '1111-6.0'
  1323. def setUp(self):
  1324. super(TestNeutronOrchestratorSerializer, self).setUp()
  1325. self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
  1326. objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
  1327. def create_env(self, mode, segment_type='vlan'):
  1328. release_kwargs = {}
  1329. if self.new_env_release_version:
  1330. release_kwargs['version'] = self.new_env_release_version
  1331. # unique name is required as some tests create releases with
  1332. # the same version
  1333. release_kwargs['name'] = \
  1334. self.new_env_release_version + segment_type
  1335. cluster = self.env.create(
  1336. release_kwargs=release_kwargs,
  1337. cluster_kwargs={
  1338. 'mode': mode,
  1339. 'net_provider': 'neutron',
  1340. 'net_segment_type': segment_type
  1341. },
  1342. nodes_kwargs=[
  1343. {'roles': ['controller', 'cinder'], 'pending_addition': True},
  1344. {'roles': ['compute', 'cinder'], 'pending_addition': True},
  1345. {'roles': ['compute'], 'pending_addition': True},
  1346. {'roles': [], 'pending_roles': ['cinder'],
  1347. 'pending_addition': True}])
  1348. cluster_db = self.db.query(Cluster).get(cluster['id'])
  1349. objects.Cluster.prepare_for_deployment(cluster_db)
  1350. return cluster_db
  1351. def serialize_env_w_version(self, version):
  1352. self.new_env_release_version = version
  1353. cluster = self.create_env(mode=consts.CLUSTER_MODES.ha_compact)
  1354. serializer = self.create_serializer(cluster)
  1355. return serializer.serialize(cluster, cluster.nodes)
  1356. def assert_roles_flattened(self, nodes):
  1357. self.assertEqual(len(nodes), 6)
  1358. self.assert_nodes_with_role(nodes, 'controller', 1)
  1359. self.assert_nodes_with_role(nodes, 'compute', 2)
  1360. self.assert_nodes_with_role(nodes, 'cinder', 3)
  1361. def set_assign_public_to_all_nodes(self, cluster_db, value):
  1362. attrs = copy.deepcopy(cluster_db.attributes.editable)
  1363. attrs['public_network_assignment']['assign_to_all_nodes']['value'] = \
  1364. value
  1365. resp = self.app.patch(
  1366. reverse(
  1367. 'ClusterAttributesHandler',
  1368. kwargs={'cluster_id': cluster_db.id}),
  1369. params=jsonutils.dumps({'editable': attrs}),
  1370. headers=self.default_headers
  1371. )
  1372. self.assertEqual(200, resp.status_code)
  1373. self.assertEqual(
  1374. attrs['public_network_assignment']['assign_to_all_nodes']['value'],
  1375. value
  1376. )
  1377. def test_serialize_nodes(self):
  1378. serialized_nodes = self.serializer.serialize_nodes(self.cluster.nodes)
  1379. self.assert_roles_flattened(serialized_nodes)
  1380. # Each not should be same as result of
  1381. # serialize_node function
  1382. for serialized_node in serialized_nodes:
  1383. node_db = self.db.query(Node).get(int(serialized_node['uid']))
  1384. expected_node = self.serializer.serialize_node(
  1385. node_db, serialized_node['role']
  1386. )
  1387. self.assertEqual(serialized_node, expected_node)
  1388. def test_neutron_vlan_ids_tag_present_on_6_0_env(self):
  1389. serialized = self.serialize_env_w_version('2014.2-6.0')
  1390. for node in serialized['nodes']:
  1391. for item in node['network_scheme']['transformations']:
  1392. if 'tags' in item:
  1393. self.assertEqual(item['tags'], item['vlan_ids'])
  1394. def check_5x_60_neutron_attrs(self, version):
  1395. common_attrs = self.serialize_env_w_version(version)['common']
  1396. self.assertEqual(
  1397. {
  1398. "network_type": "local",
  1399. "segment_id": None,
  1400. "router_ext": True,
  1401. "physnet": None
  1402. },
  1403. common_attrs['quantum_settings']['predefined_networks'][
  1404. 'admin_floating_net']['L2']
  1405. )
  1406. self.assertFalse(
  1407. 'physnet1' in common_attrs['quantum_settings']['L2']['phys_nets']
  1408. )
  1409. def test_serialize_neutron_attrs_on_6_0_env(self):
  1410. self.check_5x_60_neutron_attrs("2014.2-6.0")
  1411. def test_serialize_neutron_attrs_on_5_1_env(self):
  1412. self.check_5x_60_neutron_attrs("2014.1.1-5.1")
  1413. def check_50x_neutron_attrs(self, version):
  1414. common_attrs = self.serialize_env_w_version(version)['common']
  1415. self.assertEqual(
  1416. {
  1417. "network_type": "flat",
  1418. "segment_id": None,
  1419. "router_ext": True,
  1420. "physnet": "physnet1"
  1421. },
  1422. common_attrs['quantum_settings']['predefined_networks'][
  1423. 'admin_floating_net']['L2']
  1424. )
  1425. self.assertEqual(
  1426. {
  1427. "bridge": "br-ex",
  1428. "vlan_range": None
  1429. },
  1430. common_attrs['quantum_settings']['L2']['phys_nets']['physnet1']
  1431. )
  1432. def test_serialize_neutron_attrs_on_5_0_2_env(self):
  1433. self.check_50x_neutron_attrs("2014.1.1-5.0.2")
  1434. def test_serialize_neutron_attrs_on_5_0_1_env(self):
  1435. self.check_50x_neutron_attrs("2014.1.1-5.0.1")
  1436. def test_serialize_neutron_attrs_on_5_0_env(self):
  1437. self.check_50x_neutron_attrs("2014.1")
  1438. def test_serialize_node(self):
  1439. node = self.env.create_node(
  1440. api=True, cluster_id=self.cluster.id, pending_addition=True)
  1441. objects.Cluster.prepare_for_deployment(self.cluster)
  1442. node_db = self.db.query(Node).get(node['id'])
  1443. serialized_data = self.serializer.serialize_node(
  1444. node_db, 'controller'
  1445. )
  1446. self.assertEqual(serialized_data['role'], 'controller')
  1447. self.assertEqual(serialized_data['uid'], str(node_db.id))
  1448. self.assertEqual(serialized_data['status'], node_db.status)
  1449. self.assertEqual(serialized_data['online'], node_db.online)
  1450. self.assertEqual(serialized_data['fqdn'],
  1451. '%s.%s' % (node_db.hostname, settings.DNS_DOMAIN))
  1452. def test_node_list(self):
  1453. assign_public_options = (False, True)
  1454. for assign in assign_public_options:
  1455. self.set_assign_public_to_all_nodes(self.cluster, assign)
  1456. # Clear IPs
  1457. for ip in self.db.query(models.IPAddr):
  1458. self.db.delete(ip)
  1459. self.db.flush()
  1460. objects.Cluster.prepare_for_deployment(self.cluster)
  1461. node_list = self.serializer.get_common_attrs(self.cluster)['nodes']
  1462. roles_w_public_count = 0
  1463. # Check right nodes count with right roles
  1464. self.assert_roles_flattened(node_list)
  1465. # Check common attrs
  1466. for node in node_list:
  1467. node_db = self.db.query(Node).get(int(node['uid']))
  1468. is_public = objects.Node.should_have_public(node_db)
  1469. if is_public:
  1470. self.assertEqual(node['public_netmask'], '255.255.255.0')
  1471. roles_w_public_count += 1
  1472. else:
  1473. self.assertFalse('public_netmask' in node)
  1474. self.assertEqual(node['internal_netmask'], '255.255.255.0')
  1475. self.assertEqual(node['storage_netmask'], '255.255.255.0')
  1476. self.assertEqual(node['uid'], str(node_db.id))
  1477. self.assertEqual(node['name'], '%s' % node_db.hostname)
  1478. self.assertEqual(
  1479. node['fqdn'],
  1480. '%s.%s' % (node_db.hostname, settings.DNS_DOMAIN))
  1481. # We have 6 roles on 4 nodes summarily.
  1482. # Only 1 node w 2 roles (controller+cinder) will have public
  1483. # when 'assign_to_all_nodes' option is switched off
  1484. self.assertEqual(roles_w_public_count, 6 if assign else 2)
  1485. # Check uncommon attrs
  1486. node_uids = sorted(set([int(n['uid']) for n in node_list]))
  1487. man_ip = [str(ip) for ip in IPRange('192.168.0.1', '192.168.0.4')]
  1488. pub_ip = [str(ip) for ip in IPRange('172.16.0.2', '172.16.0.5')]
  1489. sto_ip = [str(ip) for ip in IPRange('192.168.1.1', '192.168.1.4')]
  1490. expected_list = [
  1491. {'roles': ['controller', 'cinder']},
  1492. {'roles': ['compute', 'cinder']},
  1493. {'roles': ['compute']},
  1494. {'roles': ['cinder']}]
  1495. for i in range(len(expected_list)):
  1496. expected_list[i]['attrs'] = {'uid': str(node_uids[i])}
  1497. if assign:
  1498. expected_list[i]['attrs']['public_address'] = pub_ip[i]
  1499. if not assign:
  1500. expected_list[0]['attrs']['public_address'] = pub_ip[0]
  1501. # Check if ips are unique for node and
  1502. # they are the same for all nodes roles
  1503. used_man_ip, used_pub_ip, used_sto_ip = [], [], []
  1504. for expected in expected_list:
  1505. attrs = expected['attrs']
  1506. ref_node = self.filter_by_uid(node_list, attrs['uid'])[0]
  1507. is_public = objects.Node.should_have_public(
  1508. objects.Node.get_by_mac_or_uid(node_uid=attrs['uid']))
  1509. self.assertTrue(ref_node['internal_address'] in man_ip)
  1510. self.assertTrue(ref_node['storage_address'] in sto_ip)
  1511. self.assertFalse(ref_node['internal_address'] in used_man_ip)
  1512. self.assertFalse(ref_node['storage_address'] in used_sto_ip)
  1513. used_man_ip.append(ref_node['internal_address'])
  1514. used_sto_ip.append(ref_node['storage_address'])
  1515. # Check if pubclic ip field exists
  1516. if is_public:
  1517. self.assertTrue(ref_node['public_address'] in pub_ip)
  1518. self.assertFalse(ref_node['public_address'] in used_pub_ip)
  1519. used_pub_ip.append(ref_node['public_address'])
  1520. for role in expected['roles']:
  1521. nodes = self.filter_by_role(node_list, role)
  1522. node = self.filter_by_uid(nodes, attrs['uid'])[0]
  1523. if is_public:
  1524. self.assertEqual(node['public_address'],
  1525. ref_node['public_address'])
  1526. else:
  1527. self.assertFalse('public_address' in node)
  1528. self.assertEqual(node['storage_address'],
  1529. ref_node['storage_address'])
  1530. self.assertEqual(node['internal_address'],
  1531. ref_node['internal_address'])
  1532. def test_public_serialization_for_different_roles(self):
  1533. assign_public_options = (False, True)
  1534. for assign in assign_public_options:
  1535. self.set_assign_public_to_all_nodes(self.cluster, assign)
  1536. objects.Cluster.prepare_for_deployment(self.cluster)
  1537. serialized = self.serializer.serialize(self.cluster,
  1538. self.cluster.nodes)
  1539. for node_attrs in serialized['common']['nodes']:
  1540. is_public_for_role = objects.Node.should_have_public(
  1541. objects.Node.get_by_mac_or_uid(
  1542. node_uid=int(node_attrs['uid'])))
  1543. self.assertEqual('public_address' in node_attrs,
  1544. is_public_for_role)
  1545. self.assertEqual('public_netmask' in node_attrs,
  1546. is_public_for_role)
  1547. need_public_nodes_count = set()
  1548. for node in serialized['nodes']:
  1549. node_db = self.db.query(Node).get(int(node['uid']))
  1550. is_public = objects.Node.should_have_public(node_db)
  1551. if is_public:
  1552. need_public_nodes_count.add(int(node['uid']))
  1553. net_man = objects.Cluster.get_network_manager(node_db.cluster)
  1554. self.assertEqual(
  1555. net_man.get_ip_by_network_name(
  1556. node_db, 'public') is not None,
  1557. is_public
  1558. )
  1559. self.assertEqual(
  1560. {
  1561. 'action': 'add-br',
  1562. 'name': 'br-ex'
  1563. } in node['network_scheme']['transformations'],
  1564. is_public
  1565. )
  1566. self.assertEqual(
  1567. {
  1568. 'action': 'add-patch',
  1569. 'bridges': ['br-eth1', 'br-ex'],
  1570. 'trunks': [0]
  1571. } in node['network_scheme']['transformations'],
  1572. is_public
  1573. )
  1574. self.assertEqual(
  1575. 'ex' in node['network_scheme']['roles'],
  1576. is_public
  1577. )
  1578. self.assertEqual(
  1579. 'br-ex' in node['network_scheme']['endpoints'],
  1580. is_public
  1581. )
  1582. self.assertEqual(len(need_public_nodes_count), 4 if assign else 1)
  1583. def test_neutron_l3_gateway(self):
  1584. cluster = self.create_env(consts.CLUSTER_MODES.ha_compact, 'gre')
  1585. test_gateway = "192.168.111.255"
  1586. public_ng = self.db.query(NetworkGroup).filter(
  1587. NetworkGroup.name == 'public'
  1588. ).filter(
  1589. NetworkGroup.group_id ==
  1590. objects.Cluster.get_default_group(cluster).id
  1591. ).first()
  1592. public_ng.gateway = test_gateway
  1593. self.db.add(public_ng)
  1594. self.db.commit()
  1595. serialized = self.serializer.serialize(cluster, cluster.nodes)
  1596. common_attrs = serialized['common']
  1597. pd_nets = common_attrs["quantum_settings"]["predefined_networks"]
  1598. self.assertEqual(
  1599. pd_nets["admin_floating_net"]["L3"]["gateway"],
  1600. test_gateway
  1601. )
  1602. @mock.patch('nailgun.rpc.cast')
  1603. def test_neutron_l3_floating_w_multiple_node_groups(self, _):
  1604. self.new_env_release_version = '1111-8.0'
  1605. ng2_networks = {
  1606. 'public': {'cidr': '199.10.0.0/24',
  1607. 'ip_ranges': [['199.10.0.5', '199.10.0.55']],
  1608. 'gateway': '199.10.0.1'},
  1609. 'management': {'cidr': '199.10.1.0/24',
  1610. 'gateway': '199.10.1.1'},
  1611. 'storage': {'cidr': '199.10.2.0/24',
  1612. 'gateway': '199.10.2.1'},
  1613. 'fuelweb_admin': {'cidr': '199.11.0.0/24',
  1614. 'ip_ranges': [['199.11.0.5', '199.11.0.55']],
  1615. 'gateway': '199.11.0.1'}
  1616. }
  1617. cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
  1618. ng2 = self.env.create_node_group(api=False, cluster_id=cluster.id)
  1619. netw_ids = [net.id for net in ng2.networks]
  1620. netconfig = self.env.neutron_networks_get(cluster.id).json_body
  1621. for network in netconfig['networks']:
  1622. if network['id'] in netw_ids and network['name'] in ng2_networks:
  1623. for pkey, pval in six.iteritems(ng2_networks[network['name']]):
  1624. network[pkey] = pval
  1625. network['meta']['use_gateway'] = True
  1626. elif network['meta']['notation'] and not network['gateway']:
  1627. cidr = IPNetwork(network['cidr'])
  1628. network['gateway'] = six.text_type(IPAddress(cidr.first))
  1629. network['meta']['use_gateway'] = True
  1630. netconfig['networking_parameters']['floating_ranges'] = \
  1631. [['199.10.0.77', '199.10.0.177']]
  1632. resp = self.env.neutron_networks_put(cluster.id, netconfig)
  1633. self.assertEqual(resp.status_code, 200)
  1634. objects.Cluster.prepare_for_deployment(cluster)
  1635. serialized = self.serializer.serialize(cluster, cluster.nodes)
  1636. common_attrs = serialized['common']
  1637. pd_nets = common_attrs["quantum_settings"]["predefined_networks"]
  1638. self.assertEqual(
  1639. pd_nets["admin_floating_net"]["L3"]["subnet"],
  1640. ng2_networks['public']['cidr']
  1641. )
  1642. self.assertEqual(
  1643. pd_nets["admin_floating_net"]["L3"]["gateway"],
  1644. ng2_networks['public']['gateway']
  1645. )
  1646. self.assertEqual(
  1647. pd_nets["admin_floating_net"]["L3"]["floating"],
  1648. '199.10.0.77:199.10.0.177'
  1649. )
  1650. def test_gre_segmentation(self):
  1651. cluster = self.create_env(consts.CLUSTER_MODES.ha_compact, 'gre')
  1652. serialized = self.serializer.serialize(cluster, cluster.nodes)
  1653. common_attrs = serialized['common']
  1654. self.assertEqual(
  1655. common_attrs['quantum_settings']['L2']['segmentation_type'], 'gre')
  1656. for fact in serialized['nodes']:
  1657. self.assertEqual(
  1658. 'br-prv' in fact['network_scheme']['endpoints'], False)
  1659. self.assertEqual(
  1660. 'private' in (fact['network_scheme']['roles']), False)
  1661. def test_tun_segmentation(self):
  1662. self.new_env_release_version = 'liberty-8.0'
  1663. cluster = self.create_env(consts.CLUSTER_MODES.ha_compact, 'tun')
  1664. serialized = self.serializer.serialize(cluster, cluster.nodes)
  1665. common_attrs = serialized['common']
  1666. facts = serialized['nodes']
  1667. self.assertEqual(
  1668. common_attrs['quantum_settings']['L2']['segmentation_type'], 'tun')
  1669. for fact in facts:
  1670. self.assertNotIn(
  1671. 'br-prv', fact['network_scheme']['endpoints'])
  1672. self.assertNotIn(
  1673. 'private', fact['network_scheme']['roles'])
  1674. def test_gw_added_but_default_gw_is_ex_or_admin(self):
  1675. cluster = self.cluster
  1676. networks = objects.Cluster.get_default_group(cluster).networks
  1677. for net in networks:
  1678. if net.name in ('storage', 'management'):
  1679. net.gateway = str(IPNetwork(net["cidr"]).cidr[1])
  1680. self.db.flush()
  1681. objects.Cluster.prepare_for_deployment(cluster)
  1682. serializer = self.create_serializer(cluster)
  1683. facts = serializer.serialize(cluster, cluster.nodes)['nodes']
  1684. for fact in facts:
  1685. ep = fact['network_scheme']['endpoints']
  1686. if 'br-ex' in ep:
  1687. self.assertNotIn('default_gateway', ep['br-fw-admin'])
  1688. self.assertIn('gateway', ep['br-ex'])
  1689. self.assertIn('default_gateway', ep['br-ex'])
  1690. self.assertTrue(ep['br-ex']['default_gateway'])
  1691. else:
  1692. self.assertIn('gateway', ep['br-fw-admin'])
  1693. self.assertIn('default_gateway', ep['br-fw-admin'])
  1694. self.assertTrue(ep['br-fw-admin']['default_gateway'])
  1695. self.assertIn('gateway', ep['br-storage'])
  1696. self.assertIn('gateway', ep['br-mgmt'])
  1697. class TestVlanSplinters(OrchestratorSerializerTestBase):
  1698. env_version = '1111-6.0'
  1699. @property
  1700. def vlan_splinters_meta(self):
  1701. meta = """
  1702. vlan_splinters:
  1703. metadata:
  1704. toggleable: true
  1705. enabled: false
  1706. label: "VLAN Splinters"
  1707. weight: 50
  1708. restrictions:
  1709. - condition: "cluster:net_provider != 'neutron'"
  1710. action: "hide"
  1711. vswitch:
  1712. value: "disabled"
  1713. label: "Open VSwitch VLAN Splinters feature"
  1714. weight: 55
  1715. type: "radio"
  1716. values:
  1717. - data: "soft"
  1718. label: "Enable OVS VLAN splinters soft trunks workaround"
  1719. description: "Configure OVS to use VLAN splinters workaround
  1720. with soft trunk detection. This may resolve issues that
  1721. might be encountered when using VLAN tags with OVS and
  1722. Neutron on Kernels <3.3 (CentOS)"
  1723. - data: "hard"
  1724. label: "Enable OVS VLAN splinters hard trunks workaround"
  1725. description: "Configure OVS to use VLAN splinters workaround
  1726. with hard trunk allocation. Offers similar effect as soft
  1727. trunks workaround, but forces each trunk to be predefined.
  1728. This may work better than soft trunks especially if you
  1729. still see network problems using soft trunks"
  1730. - data: "kernel_lt"
  1731. label: "EXPERIMENTAL: Use Fedora longterm kernel"
  1732. description: "Install the Fedora 3.10 longterm kernel instead
  1733. of the default 2.6.32 kernel. This should remove any need
  1734. for VLAN Splinters workarounds as the 3.10 kernel has better
  1735. support for OVS VLANs. This kernel may not work with all
  1736. hardware platforms, use caution."
  1737. """
  1738. return yaml.load(meta)
  1739. def _create_cluster_for_vlan_splinters(self, segment_type='gre'):
  1740. meta = {
  1741. 'interfaces': [
  1742. {'name': 'eth0', 'mac': self.env.generate_random_mac()},
  1743. {'name': 'eth1', 'mac': self.env.generate_random_mac()},
  1744. {'name': 'eth2', 'mac': self.env.generate_random_mac()},
  1745. {'name': 'eth3', 'mac': self.env.generate_random_mac()},
  1746. {'name': 'eth4', 'mac': self.env.generate_random_mac()}
  1747. ]
  1748. }
  1749. cluster = self.env.create(
  1750. release_kwargs={'version': self.env_version},
  1751. cluster_kwargs={
  1752. 'net_provider': 'neutron',
  1753. 'net_segment_type': segment_type,
  1754. 'editable_attributes': self.vlan_splinters_meta
  1755. },
  1756. nodes_kwargs=[
  1757. {'roles': ['controller'], 'pending_addition': True,
  1758. 'meta': meta}
  1759. ]
  1760. )
  1761. cluster_db = self.db.query(Cluster).get(cluster['id'])
  1762. objects.Cluster.prepare_for_deployment(cluster_db)
  1763. return cluster_db
  1764. def test_vlan_splinters_disabled(self):
  1765. cluster = self._create_cluster_for_vlan_splinters()
  1766. cluster_id = cluster.id
  1767. editable_attrs = copy.deepcopy(cluster.attributes.editable)
  1768. # Remove 'vlan_splinters' attribute and check results.
  1769. editable_attrs.pop('vlan_splinters', None)
  1770. cluster.attributes.editable = editable_attrs
  1771. self.db.commit()
  1772. cluster = self.db.query(Cluster).get(cluster_id)
  1773. self.assertNotIn('vlan_splinters', editable_attrs)
  1774. node = self.serializer.serialize(cluster, cluster.nodes)['nodes'][0]
  1775. interfaces = node['network_scheme']['interfaces']
  1776. for iface_attrs in interfaces.itervalues():
  1777. self.assertIn('L2', iface_attrs)
  1778. L2_attrs = iface_attrs['L2']
  1779. self.assertIn('vlan_splinters', L2_attrs)
  1780. self.assertEqual(L2_attrs['vlan_splinters'], 'off')
  1781. self.assertNotIn('trunks', L2_attrs)
  1782. # Set 'vlan_splinters' to 'some_text' and check results.
  1783. editable_attrs = copy.deepcopy(cluster.attributes.editable)
  1784. editable_attrs['vlan_splinters'] = {'vswitch': {'value': 'some_text'}}
  1785. editable_attrs['vlan_splinters']['metadata'] = {'enabled': True}
  1786. cluster.attributes.editable = editable_attrs
  1787. self.db.commit()
  1788. cluster = self.db.query(Cluster).get(cluster_id)
  1789. editable_attrs = copy.deepcopy(cluster.attributes.editable)
  1790. self.assertEqual(editable_attrs['vlan_splinters']['vswitch']['value'],
  1791. 'some_text')
  1792. node = self.serializer.serialize(cluster, cluster.nodes)['nodes'][0]
  1793. interfaces = node['network_scheme']['interfaces']
  1794. for iface_attrs in interfaces.itervalues():
  1795. self.assertIn('L2', iface_attrs)
  1796. L2_attrs = iface_attrs['L2']
  1797. self.assertNotIn('vlan_splinters', L2_attrs)
  1798. self.assertNotIn('trunks', L2_attrs)
  1799. # Set 'vlan_splinters' to 'disabled' and check results.
  1800. editable_attrs['vlan_splinters']['metadata']['enabled'] = False
  1801. cluster.attributes.editable = editable_attrs
  1802. self.db.commit()
  1803. cluster = self.db.query(Cluster).get(cluster_id)
  1804. editable_attrs = cluster.attributes.editable
  1805. self.assertEqual(
  1806. editable_attrs['vlan_splinters']['metadata']['enabled'],
  1807. False
  1808. )
  1809. node = self.serializer.serialize(cluster, cluster.nodes)['nodes'][0]
  1810. interfaces = node['network_scheme']['interfaces']
  1811. for iface_attrs in interfaces.itervalues():
  1812. self.assertIn('L2', iface_attrs)
  1813. L2_attrs = iface_attrs['L2']
  1814. self.assertIn('vlan_splinters', L2_attrs)
  1815. self.assertEqual(L2_attrs['vlan_splinters'], 'off')
  1816. self.assertNotIn('trunks', L2_attrs)
  1817. def test_kernel_lt_vlan_splinters(self):
  1818. cluster = self._create_cluster_for_vlan_splinters()
  1819. cluster_id = cluster.id
  1820. editable_attrs = copy.deepcopy(cluster.attributes.editable)
  1821. # value of kernel-ml should end up with vlan_splinters = off
  1822. editable_attrs['vlan_splinters']['metadata']['enabled'] = True
  1823. editable_attrs['vlan_splinters']['vswitch']['value'] = 'kernel_lt'
  1824. cluster.attributes.editable = editable_attrs
  1825. self.db.commit()
  1826. cluster = self.db.query(Cluster).get(cluster_id)
  1827. editable_attrs = cluster.attributes.editable
  1828. self.assertEqual(editable_attrs['vlan_splinters']['vswitch']['value'],
  1829. 'kernel_lt')
  1830. node = self.serializer.serialize(cluster, cluster.nodes)['nodes'][0]
  1831. interfaces = node['network_scheme']['interfaces']
  1832. for iface_attrs in interfaces.itervalues():
  1833. self.assertIn('L2', iface_attrs)
  1834. L2_attrs = iface_attrs['L2']
  1835. self.assertIn('vlan_splinters', L2_attrs)
  1836. self.assertEqual(L2_attrs['vlan_splinters'], 'off')
  1837. self.assertNotIn('trunks', L2_attrs)
  1838. def test_hard_vlan_splinters_in_gre(self):
  1839. cluster = self._create_cluster_for_vlan_splinters('gre')
  1840. editable_attrs = copy.deepcopy(cluster.attributes.editable)
  1841. editable_attrs['vlan_splinters']['metadata']['enabled'] = True
  1842. editable_attrs['vlan_splinters']['vswitch']['value'] = 'hard'
  1843. cluster.attributes.editable = editable_attrs
  1844. self.db.commit()
  1845. vlan_set = set(
  1846. [ng.vlan_start for ng in cluster.network_groups if ng.vlan_start]
  1847. )
  1848. node = self.serializer.serialize(cluster, cluster.nodes)['nodes'][0]
  1849. interfaces = node['network_scheme']['interfaces']
  1850. for iface_attrs in interfaces.itervalues():
  1851. self.assertIn('L2', iface_attrs)
  1852. L2_attrs = iface_attrs['L2']
  1853. self.assertIn('vlan_splinters', L2_attrs)
  1854. self.assertEqual(L2_attrs['vlan_splinters'], 'auto')
  1855. self.assertIn('trunks', L2_attrs)
  1856. self.assertIn(0, L2_attrs['trunks'])
  1857. for n in L2_attrs['trunks']:
  1858. if n:
  1859. vlan_set.remove(n)
  1860. self.assertEqual(len(vlan_set), 0)
  1861. def test_hard_vlan_splinters_in_vlan(self):
  1862. cluster = self._create_cluster_for_vlan_splinters('vlan')
  1863. editable_attrs = copy.deepcopy(cluster.attributes.editable)
  1864. editable_attrs['vlan_splinters']['metadata']['enabled'] = True
  1865. editable_attrs['vlan_splinters']['vswitch']['value'] = 'hard'
  1866. cluster.attributes.editable = editable_attrs
  1867. self.db.commit()
  1868. vlan_set = set(
  1869. [ng.vlan_start for ng in cluster.network_groups if ng.vlan_start]
  1870. )
  1871. private_vlan_range = cluster.network_config["vlan_range"]
  1872. vlan_set.update(range(*private_vlan_range))
  1873. vlan_set.add(private_vlan_range[1])
  1874. node = self.serializer.serialize(cluster, cluster.nodes)['nodes'][0]
  1875. interfaces = node['network_scheme']['interfaces']
  1876. for iface_attrs in interfaces.itervalues():
  1877. self.assertIn('L2', iface_attrs)
  1878. L2_attrs = iface_attrs['L2']
  1879. self.assertIn('vlan_splinters', L2_attrs)
  1880. self.assertEqual(L2_attrs['vlan_splinters'], 'auto')
  1881. self.assertIn('trunks', L2_attrs)
  1882. self.assertIn(0, L2_attrs['trunks'])
  1883. for n in L2_attrs['trunks']:
  1884. if n:
  1885. vlan_set.remove(n)
  1886. self.assertEqual(len(vlan_set), 0)
  1887. def test_soft_vlan_splinters_in_vlan(self):
  1888. cluster = self._create_cluster_for_vlan_splinters('vlan')
  1889. editable_attrs = copy.deepcopy(cluster.attributes.editable)
  1890. editable_attrs['vlan_splinters']['metadata']['enabled'] = True
  1891. editable_attrs['vlan_splinters']['vswitch']['value'] = 'soft'
  1892. cluster.attributes.editable = editable_attrs
  1893. self.db.commit()
  1894. node = self.serializer.serialize(cluster, cluster.nodes)['nodes'][0]
  1895. interfaces = node['network_scheme']['interfaces']
  1896. for iface_attrs in interfaces.itervalues():
  1897. self.assertIn('L2', iface_attrs)
  1898. L2_attrs = iface_attrs['L2']
  1899. self.assertIn('vlan_splinters', L2_attrs)
  1900. self.assertEqual(L2_attrs['vlan_splinters'], 'auto')
  1901. self.assertIn('trunks', L2_attrs)
  1902. self.assertEqual(L2_attrs['trunks'], [0])
  1903. class TestNeutronOrchestratorHASerializer(OrchestratorSerializerTestBase):
  1904. env_version = '1111-5.0'
  1905. def setUp(self):
  1906. super(TestNeutronOrchestratorHASerializer, self).setUp()
  1907. self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
  1908. objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
  1909. def create_env(self, mode):
  1910. cluster = self.env.create(
  1911. api=True,
  1912. release_kwargs={'version': self.env_version},
  1913. cluster_kwargs={
  1914. 'mode': mode,
  1915. 'net_provider': 'neutron',
  1916. 'net_segment_type': 'vlan'
  1917. },
  1918. nodes_kwargs=[
  1919. {'roles': ['controller'], 'pending_addition': True},
  1920. {'roles': ['controller'], 'pending_addition': True},
  1921. {'roles': ['controller', 'cinder'], 'pending_addition': True},
  1922. {'roles': ['compute', 'cinder'], 'pending_addition': True},
  1923. {'roles': ['compute'], 'pending_addition': True},
  1924. {'roles': ['cinder'], 'pending_addition': True}
  1925. ]
  1926. )
  1927. cluster_db = self.db.query(Cluster).get(cluster['id'])
  1928. objects.Cluster.prepare_for_deployment(cluster_db)
  1929. return cluster_db
  1930. @property
  1931. def serializer(self):
  1932. self.cluster_mock.release.environment_version = '5.0'
  1933. return DeploymentHASerializer(AstuteGraph(self.cluster_mock))
  1934. def test_node_list(self):
  1935. serialized_nodes = self.serializer.node_list(self.cluster.nodes)
  1936. for node in serialized_nodes:
  1937. # Each node has swift_zone
  1938. self.assertEqual(node['swift_zone'], node['uid'])
  1939. def test_get_common_attrs(self):
  1940. attrs = self.serializer.get_common_attrs(self.cluster)
  1941. # vips
  1942. self.assertEqual(attrs['management_vip'], '192.168.0.7')
  1943. self.assertTrue(
  1944. re.compile('172.16.0.[1-9]').match(attrs['public_vip']))
  1945. # last_contrller
  1946. controllers = self.get_controllers(self.cluster.id)
  1947. self.assertEqual(attrs['last_controller'],
  1948. 'node-%d' % controllers[-1].id)
  1949. # primary_controller
  1950. controllers = self.filter_by_role(attrs['nodes'], 'primary-controller')
  1951. self.assertEqual(controllers[0]['role'], 'primary-controller')
  1952. # mountpoints and mp attrs
  1953. self.assertEqual(
  1954. attrs['mp'],
  1955. [{'point': '1', 'weight': '1'},
  1956. {'point': '2', 'weight': '2'}])
  1957. class TestNeutronOrchestratorSerializerBonds(OrchestratorSerializerTestBase):
  1958. env_version = '1111-6.0'
  1959. def create_release(self):
  1960. self.release_id = self.env.create_release(version=self.env_version).id
  1961. def create_env(self, nodes_count=2, nic_count=3, segment_type='vlan'):
  1962. cluster = self.env.create_cluster(
  1963. net_provider='neutron',
  1964. net_segment_type=segment_type,
  1965. release_id=self.release_id)
  1966. self.env.create_nodes_w_interfaces_count(
  1967. nodes_count=1,
  1968. if_count=nic_count,
  1969. roles=['controller', 'cinder'],
  1970. pending_addition=True,
  1971. cluster_id=cluster['id'])
  1972. self.env.create_nodes_w_interfaces_count(
  1973. nodes_count=nodes_count - 1,
  1974. if_count=nic_count,
  1975. roles=['compute'],
  1976. pending_addition=True,
  1977. cluster_id=cluster['id'])
  1978. cluster_db = self.db.query(Cluster).get(cluster['id'])
  1979. return cluster_db
  1980. def check_add_bond_msg_lacp(self, msg):
  1981. expected = {
  1982. 'action': 'add-bond',
  1983. 'bridge': 'br-ovsbond0',
  1984. 'interfaces': ['eth1', 'eth2'],
  1985. 'name': 'ovsbond0',
  1986. 'properties': ['lacp=active', 'bond_mode=balance-tcp']
  1987. }
  1988. self.datadiff(msg, expected, compare_sorted=True)
  1989. def check_add_bond_msg_non_lacp(self, msg, mode):
  1990. expected = {
  1991. 'action': 'add-bond',
  1992. 'bridge': 'br-ovsbond0',
  1993. 'interfaces': ['eth2', 'eth1'],
  1994. 'name': 'ovsbond0',
  1995. 'properties': ['bond_mode={0}'.format(mode)]
  1996. }
  1997. self.datadiff(msg, expected, compare_sorted=True)
  1998. def check_bond_with_mode(self, mode, bond_type):
  1999. cluster = self.create_env()
  2000. for node in cluster.nodes:
  2001. self.env.make_bond_via_api(
  2002. 'ovsbond0', mode, ['eth1', 'eth2'], node.id,
  2003. attrs={'type__': {'value': bond_type}})
  2004. facts = self.serialize(cluster)
  2005. for node in facts['nodes']:
  2006. transforms = node['network_scheme']['transformations']
  2007. bonds = filter(lambda t: t['action'] == 'add-bond',
  2008. transforms)
  2009. self.assertEqual(len(bonds), 1)
  2010. if mode == consts.BOND_MODES.lacp_balance_tcp:
  2011. self.check_add_bond_msg_lacp(bonds[0])
  2012. else:
  2013. self.check_add_bond_msg_non_lacp(bonds[0], mode)
  2014. def test_bonds_serialization(self):
  2015. self.create_release()
  2016. from nailgun.extensions.network_manager.validators.network \
  2017. import NetAssignmentValidator
  2018. ovs_modes = NetAssignmentValidator.get_allowed_modes_for_bond_type(
  2019. consts.BOND_TYPES.ovs)
  2020. for mode in consts.BOND_MODES:
  2021. if mode in ovs_modes:
  2022. bond_type = consts.BOND_TYPES.ovs
  2023. else:
  2024. bond_type = consts.BOND_TYPES.linux
  2025. self.check_bond_with_mode(mode, bond_type)
  2026. class TestCephOsdImageOrchestratorSerialize(OrchestratorSerializerTestBase):
  2027. env_version = '1111-6.0'
  2028. def setUp(self):
  2029. super(TestCephOsdImageOrchestratorSerialize, self).setUp()
  2030. cluster = self.env.create(
  2031. release_kwargs={
  2032. 'version': self.env_version,
  2033. 'modes': [consts.CLUSTER_MODES.ha_compact,
  2034. consts.CLUSTER_MODES.multinode]},
  2035. cluster_kwargs={
  2036. 'mode': consts.CLUSTER_MODES.multinode},
  2037. nodes_kwargs=[
  2038. {'roles': ['controller', 'ceph-osd']}])
  2039. self.app.patch(
  2040. reverse(
  2041. 'ClusterAttributesHandler',
  2042. kwargs={'cluster_id': cluster['id']}),
  2043. params=jsonutils.dumps({
  2044. 'editable': {'storage': {'images_ceph': {'value': True}}}}),
  2045. headers=self.default_headers)
  2046. self.cluster = self.db.query(Cluster).get(cluster['id'])
  2047. class TestMongoNodesSerialization(OrchestratorSerializerTestBase):
  2048. env_version = '1111-5.0'
  2049. def create_env(self):
  2050. cluster = self.env.create(
  2051. release_kwargs={'version': self.env_version},
  2052. cluster_kwargs={
  2053. 'mode': consts.CLUSTER_MODES.ha_compact,
  2054. 'network_manager': 'FlatDHCPManager'
  2055. },
  2056. nodes_kwargs=[
  2057. {'roles': ['mongo'], 'pending_addition': True},
  2058. {'roles': ['mongo'], 'pending_addition': True},
  2059. {'roles': ['mongo'], 'pending_addition': True}
  2060. ]
  2061. )
  2062. cluster = self.db.query(Cluster).get(cluster['id'])
  2063. objects.Cluster.prepare_for_deployment(cluster)
  2064. return cluster
  2065. @property
  2066. def serializer_ha(self):
  2067. self.cluster_mock.release.environment_version = '5.0'
  2068. return DeploymentHASerializer(AstuteGraph(self.cluster_mock))
  2069. @property
  2070. def serializer_mn(self):
  2071. self.cluster_mock.release.environment_version = '5.0'
  2072. return DeploymentMultinodeSerializer(AstuteGraph(self.cluster_mock))
  2073. def test_mongo_roles_equals_in_defferent_modes(self):
  2074. cluster = self.create_env()
  2075. ha_nodes = self.serializer_ha.serialize_nodes(cluster.nodes)
  2076. mn_nodes = self.serializer_mn.serialize_nodes(cluster.nodes)
  2077. self.assertEqual(mn_nodes, ha_nodes)
  2078. class TestNSXOrchestratorSerializer(OrchestratorSerializerTestBase):
  2079. env_version = '1111-6.0'
  2080. def setUp(self):
  2081. super(TestNSXOrchestratorSerializer, self).setUp()
  2082. self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
  2083. def create_env(self, mode, segment_type='gre'):
  2084. cluster = self.env.create(
  2085. release_kwargs={'version': self.env_version},
  2086. cluster_kwargs={
  2087. 'mode': mode,
  2088. 'net_provider': 'neutron',
  2089. 'net_segment_type': segment_type
  2090. },
  2091. nodes_kwargs=[
  2092. {'roles': ['controller'], 'pending_addition': True},
  2093. {'roles': ['compute'], 'pending_addition': True},
  2094. ]
  2095. )
  2096. cluster_db = self.db.query(Cluster).get(cluster['id'])
  2097. editable_attrs = copy.deepcopy(cluster_db.attributes.editable)
  2098. nsx_attrs = editable_attrs.setdefault('nsx_plugin', {})
  2099. nsx_attrs.setdefault('metadata', {})['enabled'] = True
  2100. cluster_db.attributes.editable = editable_attrs
  2101. self.db.commit()
  2102. cluster_db = self.db.query(Cluster).get(cluster['id'])
  2103. objects.Cluster.prepare_for_deployment(cluster_db)
  2104. return cluster_db
  2105. def test_serialize_node(self):
  2106. serialized_data = self.serializer.serialize(self.cluster,
  2107. self.cluster.nodes)
  2108. q_settings = serialized_data['common']['quantum_settings']
  2109. self.assertIn('L2', q_settings)
  2110. self.assertIn('provider', q_settings['L2'])
  2111. self.assertEqual(q_settings['L2']['provider'], 'nsx')
  2112. l3_settings = q_settings['L3']
  2113. self.assertIn('dhcp_agent', l3_settings)
  2114. self.assertIn('enable_isolated_metadata', l3_settings['dhcp_agent'])
  2115. self.assertEqual(l3_settings['dhcp_agent']['enable_isolated_metadata'],
  2116. True)
  2117. self.assertIn('enable_metadata_network', l3_settings['dhcp_agent'])
  2118. self.assertEqual(l3_settings['dhcp_agent']['enable_metadata_network'],
  2119. True)
  2120. class BaseDeploymentSerializer(BaseSerializerTest):
  2121. node_name = 'node name'
  2122. # Needs to be set in childs
  2123. serializer = None
  2124. env_version = '2014.2-6.1'
  2125. def setUp(self):
  2126. super(BaseDeploymentSerializer, self).setUp()
  2127. self.common_attrs = mock.MagicMock()
  2128. def create_env(self, mode):
  2129. if mode == consts.CLUSTER_MODES.multinode:
  2130. available_modes = [consts.CLUSTER_MODES.ha_compact,
  2131. consts.CLUSTER_MODES.multinode]
  2132. else:
  2133. available_modes = [consts.CLUSTER_MODES.ha_compact, ]
  2134. return self.env.create(
  2135. release_kwargs={
  2136. 'version': self.env_version,
  2137. 'modes': available_modes,
  2138. },
  2139. cluster_kwargs={
  2140. 'mode': mode,
  2141. 'net_provider': 'neutron',
  2142. 'net_segment_type': 'gre'},
  2143. nodes_kwargs=[
  2144. {'roles': ['controller'],
  2145. 'pending_addition': True,
  2146. 'name': self.node_name,
  2147. }
  2148. ])
  2149. def check_serialize_node(self):
  2150. self.assertEqual(
  2151. self.serializer.serialize_node(
  2152. self.env.nodes[0], 'role'
  2153. )['user_node_name'],
  2154. self.node_name)
  2155. def check_serialize_node_for_node_list(self):
  2156. self.assertEqual(
  2157. self.serializer.serialize_node_for_node_list(
  2158. self.env.nodes[0], 'role')['user_node_name'],
  2159. self.node_name)
  2160. def check_no_murano_data(self):
  2161. glance_properties = self.serializer.generate_test_vm_image_data(
  2162. self.env.nodes[0])['test_vm_image']['glance_properties']
  2163. self.assertNotIn('murano_image_info', glance_properties)
  2164. def check_murano_data(self):
  2165. glance_properties = self.serializer.generate_test_vm_image_data(
  2166. self.env.nodes[0])['test_vm_image']['glance_properties']
  2167. self.assertIn('murano_image_info', glance_properties)
  2168. @staticmethod
  2169. def _get_serializer(cluster):
  2170. serializer_type = get_serializer_for_cluster(cluster)
  2171. return serializer_type(AstuteGraph(cluster))
  2172. @staticmethod
  2173. def _get_nodes_count_in_astute_info(nodes):
  2174. """Count number of node in deployment info for non-LCM serializers
  2175. As we are running 7.0 tests against 9.0 environments where
  2176. LCM serializer is used we should consider difference in a number
  2177. of elements in deployment info.
  2178. In case of non-LCM serializer we have separate item in deployment
  2179. info for each node-role relationship.
  2180. :param nodes: array of cluster nodes
  2181. :returns: expected number of elements in deployment info
  2182. """
  2183. return len([role for n in nodes for role in n.roles])
  2184. @staticmethod
  2185. def _handle_facts(facts):
  2186. """Handle deployment facts for non-LCM serializers
  2187. This method was introduced to be overloaded for classes where LCM
  2188. serialization engine is used and 'master' node info should be
  2189. filtered.
  2190. :param facts: deployment info produced by non-LCM serializer
  2191. :returns: deployment info as it is
  2192. """
  2193. return facts
  2194. @staticmethod
  2195. def _get_plugins_names(plugins):
  2196. """Plugins names for non-LCM serializers
  2197. Plugins data in case of legacy serializers consist
  2198. of plugins names only.
  2199. Could be overloaded by LCM serializers.
  2200. :param plugins: array of plugins names
  2201. :returns: plugins names as it is
  2202. """
  2203. return plugins
  2204. class TestDeploymentMultinodeSerializer61(BaseDeploymentSerializer):
  2205. def setUp(self):
  2206. super(TestDeploymentMultinodeSerializer61, self).setUp()
  2207. self.cluster = self.create_env(consts.CLUSTER_MODES.multinode)
  2208. objects.Cluster.prepare_for_deployment(self.env.clusters[-1])
  2209. self.serializer = DeploymentMultinodeSerializer61(self.cluster)
  2210. def test_serialize_node(self):
  2211. self.check_serialize_node()
  2212. def test_serialize_node_for_node_list(self):
  2213. self.check_serialize_node_for_node_list()
  2214. def test_glance_properties(self):
  2215. self.check_no_murano_data()
  2216. class TestDeploymentAttributesSerialization61(BaseDeploymentSerializer):
  2217. def setUp(self):
  2218. super(TestDeploymentAttributesSerialization61, self).setUp()
  2219. self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
  2220. objects.Cluster.prepare_for_deployment(self.env.clusters[-1])
  2221. self.serializer = DeploymentHASerializer61(self.cluster)
  2222. @mock.patch('nailgun.objects.MasterNodeSettings.must_send_stats',
  2223. return_value=False)
  2224. def test_serialize_workloads_collector_user_opted_out(self, _):
  2225. oswl_user = self.serializer.get_common_attrs(
  2226. self.cluster
  2227. )['workloads_collector']
  2228. self.assertEqual(set(oswl_user.keys()),
  2229. set(['username',
  2230. 'enabled',
  2231. 'password',
  2232. 'metadata',
  2233. 'tenant',
  2234. 'create_user']))
  2235. self.assertEqual(oswl_user['username'], 'fuel_stats_user')
  2236. self.assertEqual(oswl_user['enabled'], True)
  2237. self.assertEqual(len(oswl_user['password']), 24)
  2238. self.assertEqual(oswl_user['tenant'], 'services')
  2239. self.assertEqual(oswl_user['create_user'], False)
  2240. @mock.patch('nailgun.objects.MasterNodeSettings.must_send_stats',
  2241. return_value=True)
  2242. def test_serialize_workloads_collector_user_opted_in(self, _):
  2243. oswl_user = self.serializer.get_common_attrs(
  2244. self.cluster
  2245. )['workloads_collector']
  2246. self.assertEqual(set(oswl_user.keys()),
  2247. set(['username',
  2248. 'enabled',
  2249. 'password',
  2250. 'metadata',
  2251. 'tenant',
  2252. 'create_user']))
  2253. self.assertEqual(oswl_user['username'], 'fuel_stats_user')
  2254. self.assertEqual(oswl_user['enabled'], True)
  2255. self.assertEqual(len(oswl_user['password']), 24)
  2256. self.assertEqual(oswl_user['tenant'], 'services')
  2257. self.assertEqual(oswl_user['create_user'], True)
  2258. class TestDeploymentHASerializer61(BaseDeploymentSerializer):
  2259. def setUp(self):
  2260. super(TestDeploymentHASerializer61, self).setUp()
  2261. self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
  2262. objects.Cluster.prepare_for_deployment(self.env.clusters[-1])
  2263. self.serializer = DeploymentHASerializer61(self.cluster)
  2264. def check_generate_test_vm_image_data(self):
  2265. kvm_img_name = 'TestVM'
  2266. kvm_img_disk_format = 'qcow2'
  2267. kvm_img_path = '/opt/vm/cirros-x86_64-disk.img'
  2268. self.assertEqual(
  2269. len(self.serializer.generate_test_vm_image_data(
  2270. self.env.nodes[0])['test_vm_image']), 2)
  2271. self.assertEqual(
  2272. self.serializer.generate_test_vm_image_data(
  2273. self.env.nodes[0])['test_vm_image'][1]['img_name'],
  2274. kvm_img_name)
  2275. self.assertEqual(
  2276. self.serializer.generate_test_vm_image_data(
  2277. self.env.nodes[0])['test_vm_image'][1]['disk_format'],
  2278. kvm_img_disk_format)
  2279. self.assertEqual(
  2280. self.serializer.generate_test_vm_image_data(
  2281. self.env.nodes[0])['test_vm_image'][1]['img_path'],
  2282. kvm_img_path)
  2283. def test_serialize_node(self):
  2284. self.check_serialize_node()
  2285. def test_serialize_node_for_node_list(self):
  2286. self.check_serialize_node_for_node_list()
  2287. def test_glance_properties(self):
  2288. self.check_no_murano_data()
  2289. class TestSerializeInterfaceDriversData(base.BaseIntegrationTest):
  2290. env_version = '2014.2-6.1'
  2291. def setUp(self):
  2292. super(TestSerializeInterfaceDriversData, self).setUp()
  2293. self.common_attrs = mock.MagicMock()
  2294. def _create_cluster_for_interfaces(self, driver_mapping={},
  2295. bus_mapping={},
  2296. segment_type='gre'):
  2297. meta = {
  2298. 'interfaces': [
  2299. {'name': 'eth0', 'mac': self.env.generate_random_mac(),
  2300. 'driver': driver_mapping.get('eth0', 'igb'),
  2301. 'bus_info': bus_mapping.get('eth0', '0000:05:00.0')},
  2302. {'name': 'eth1', 'mac': self.env.generate_random_mac(),
  2303. 'driver': driver_mapping.get('eth1', 'mlx4_en'),
  2304. 'bus_info': bus_mapping.get('eth1', '0000:06:00.0')}
  2305. ]
  2306. }
  2307. cluster = self.env.create(
  2308. release_kwargs={'version': self.env_version},
  2309. cluster_kwargs={
  2310. 'net_provider': 'neutron',
  2311. 'net_segment_type': segment_type
  2312. },
  2313. nodes_kwargs=[
  2314. {'roles': ['controller'], 'pending_addition': True,
  2315. 'meta': meta}
  2316. ]
  2317. )
  2318. self.serializer = DeploymentHASerializer61(cluster)
  2319. cluster_db = self.db.query(Cluster).get(cluster['id'])
  2320. objects.Cluster.prepare_for_deployment(cluster_db)
  2321. return cluster_db
  2322. def test_interface_driver_bus_info(self):
  2323. driver_mapping = {'eth0': 'igb',
  2324. 'eth1': 'eth_ipoib'}
  2325. bus_mapping = {'eth0': '0000:01:00.0',
  2326. 'eth1': 'ib1'}
  2327. cluster = \
  2328. self._create_cluster_for_interfaces(driver_mapping, bus_mapping)
  2329. self.db.commit()
  2330. cluster_db = self.db.query(Cluster).get(cluster['id'])
  2331. node = self.serializer.serialize_node(
  2332. cluster_db.nodes[0], 'controller'
  2333. )
  2334. interfaces = node['network_scheme']['interfaces']
  2335. for iface, iface_attrs in interfaces.items():
  2336. self.assertIn('vendor_specific', iface_attrs)
  2337. self.assertIn('driver', iface_attrs['vendor_specific'])
  2338. self.assertEqual(iface_attrs['vendor_specific']['driver'],
  2339. driver_mapping[iface])
  2340. self.assertIn('bus_info', iface_attrs['vendor_specific'])
  2341. self.assertEqual(iface_attrs['vendor_specific']['bus_info'],
  2342. bus_mapping[iface])
  2343. def test_interface_mapping(self):
  2344. cluster = self._create_cluster_for_interfaces(segment_type='vlan')
  2345. network_group = self.db().query(NetworkGroup)
  2346. public_vlan = randint(0, 4095)
  2347. storage_vlan = randint(0, 4095)
  2348. management_vlan = randint(0, 4095)
  2349. private_vlan_range = [randint(0, 4095), randint(0, 4095)]
  2350. vlan_mapping = {'ex': public_vlan,
  2351. 'storage': storage_vlan,
  2352. 'management': management_vlan,
  2353. 'neutron/private': "%s:%s" % (private_vlan_range[0],
  2354. private_vlan_range[1])}
  2355. cluster.network_config["vlan_range"] = private_vlan_range
  2356. network_group.filter_by(name="storage").update(
  2357. {"vlan_start": storage_vlan}, synchronize_session="fetch")
  2358. network_group.filter_by(name="management").update(
  2359. {"vlan_start": management_vlan}, synchronize_session="fetch")
  2360. network_group.filter_by(name="public").update(
  2361. {"vlan_start": public_vlan}, synchronize_session="fetch")
  2362. self.db.commit()
  2363. cluster_db = self.db.query(Cluster).get(cluster['id'])
  2364. node = self.serializer.serialize_node(
  2365. cluster_db.nodes[0], 'controller'
  2366. )
  2367. endpoints = node['network_scheme']['endpoints']
  2368. net_roles = node['network_scheme']['roles']
  2369. for net_role, bridge in net_roles.items():
  2370. ep_dict = endpoints[bridge]
  2371. if net_role in vlan_mapping.keys():
  2372. self.assertIn('vendor_specific', ep_dict.keys())
  2373. self.assertIn('phy_interfaces',
  2374. ep_dict['vendor_specific'].keys())
  2375. self.assertIn('vlans', ep_dict['vendor_specific'].keys())
  2376. self.assertEqual(ep_dict['vendor_specific']['vlans'],
  2377. vlan_mapping[net_role])
  2378. class TestDeploymentHASerializer50(BaseDeploymentSerializer):
  2379. env_version = '1111-5.0'
  2380. def setUp(self):
  2381. super(TestDeploymentHASerializer50, self).setUp()
  2382. self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
  2383. objects.Cluster.prepare_for_deployment(self.env.clusters[-1])
  2384. self.serializer = DeploymentHASerializer50(self.cluster)
  2385. def test_glance_properties(self):
  2386. self.check_murano_data()
  2387. class TestDeploymentMultinodeSerializer50(BaseDeploymentSerializer):
  2388. env_version = '1111-5.0'
  2389. def setUp(self):
  2390. super(TestDeploymentMultinodeSerializer50, self).setUp()
  2391. self.cluster = self.create_env(consts.CLUSTER_MODES.multinode)
  2392. objects.Cluster.prepare_for_deployment(self.env.clusters[-1])
  2393. self.serializer = DeploymentMultinodeSerializer50(self.cluster)
  2394. def test_glance_properties(self):
  2395. self.check_murano_data()
  2396. class TestDeploymentGraphlessSerializers(OrchestratorSerializerTestBase):
  2397. env_version = '1111-5.0'
  2398. def setUp(self):
  2399. super(TestDeploymentGraphlessSerializers, self).setUp()
  2400. self.cluster = self.env.create(
  2401. release_kwargs={'version': self.env_version},
  2402. cluster_kwargs={'api': False},
  2403. nodes_kwargs=[
  2404. {'roles': ['controller', 'cinder'], 'pending_addition': True},
  2405. {'roles': ['compute', 'cinder'], 'pending_addition': True},
  2406. {'roles': ['compute'], 'pending_addition': True},
  2407. {'roles': [], 'pending_roles': ['cinder'],
  2408. 'pending_addition': True}]
  2409. )
  2410. objects.Cluster.set_primary_tags(self.cluster, self.cluster.nodes)
  2411. @property
  2412. def serializer(self):
  2413. self.cluster_mock.release.environment_version = '5.0'
  2414. return DeploymentMultinodeSerializer(None)
  2415. def test_serialize_cluster(self):
  2416. serialized_data = self.serialize(self.cluster)
  2417. self.assertGreater(len(serialized_data), 0)
  2418. self.assertNotIn('tasks', serialized_data['nodes'][0])
  2419. self.assertGreater(len(serialized_data['common']['nodes']), 0)