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_migration_fuel_9_2.py 35KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943
  1. # Copyright 2016 Mirantis, Inc.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  4. # not use this file except in compliance with the License. You may obtain
  5. # a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. # License for the specific language governing permissions and limitations
  13. # under the License.
  14. import copy
  15. import datetime
  16. import alembic
  17. from oslo_serialization import jsonutils
  18. import six
  19. import sqlalchemy as sa
  20. from nailgun.db import db
  21. from nailgun.db import dropdb
  22. from nailgun.db.migration import ALEMBIC_CONFIG
  23. from nailgun.test import base
  24. from nailgun.utils import is_feature_supported
  25. from nailgun.utils import migration
  26. _prepare_revision = 'f2314e5d63c9'
  27. _test_revision = '3763c404ca48'
  28. VMWARE_ATTRIBUTES_METADATA = {
  29. 'editable': {
  30. 'metadata': [
  31. {
  32. 'name': 'availability_zones',
  33. 'fields': []
  34. },
  35. {
  36. 'name': 'glance',
  37. 'fields': []
  38. },
  39. ],
  40. 'value': {
  41. 'availability_zones': [{}, {}],
  42. 'glance': {},
  43. }
  44. }
  45. }
  46. ATTRIBUTES_METADATA = {
  47. 'editable': {
  48. 'common': {}
  49. }
  50. }
  51. SECURITY_GROUPS = {
  52. 'value': 'iptables_hybrid',
  53. 'values': [
  54. {
  55. 'data': 'openvswitch',
  56. 'label': 'Open vSwitch Firewall Driver',
  57. 'description': 'Choose this driver for OVS based security groups '
  58. 'implementation. NOTE: Open vSwitch Firewall '
  59. 'Driver requires kernel version >= 4.3 '
  60. 'for non-dpdk case.'
  61. },
  62. {
  63. 'data': 'iptables_hybrid',
  64. 'label': 'Iptables-based Firewall Driver'
  65. ' (No firewall for DPDK case)',
  66. 'description': 'Choose this driver for iptables/linux bridge '
  67. 'based security groups implementation.'
  68. }
  69. ],
  70. 'group': 'security',
  71. 'weight': 20,
  72. 'type': 'radio',
  73. }
  74. DEFAULT_NIC_ATTRIBUTES = {
  75. 'offloading': {
  76. 'disable': {'type': 'checkbox', 'value': False,
  77. 'weight': 10, 'label': 'Disable Offloading'},
  78. 'modes': {'value': {}, 'type': 'offloading_modes', 'weight': 20,
  79. 'label': 'Offloading Modes'},
  80. 'metadata': {'weight': 10, 'label': 'Offloading'}
  81. },
  82. 'mtu': {
  83. 'value': {'type': 'number', 'value': None, 'weight': 10,
  84. 'label': 'Use Custom MTU', 'nullable': True,
  85. 'min': 42, 'max': 65536},
  86. 'metadata': {'weight': 20, 'label': 'MTU'}
  87. },
  88. 'sriov': {
  89. 'numvfs': {'min': 1, 'type': 'number', 'value': None, 'nullable': True,
  90. 'weight': 20, 'label': 'Custom Number of Virtual Functions',
  91. 'restrictions': ['nic_attributes:sriov.enabled.value == "'
  92. 'false"']
  93. },
  94. 'enabled': {'type': 'checkbox', 'value': False,
  95. 'weight': 10, 'label': 'Enable SR-IOV',
  96. 'description': 'Single-root I/O Virtualization (SR-IOV) '
  97. 'is a specification that, when implemented '
  98. 'by a physical PCIe device, enables it to '
  99. 'appear as multiple separate PCIe devices. '
  100. 'This enables multiple virtualized guests '
  101. 'to share direct access to the physical '
  102. 'device, offering improved performance '
  103. 'over an equivalent virtual device.',
  104. 'restrictions': [{'settings:common.libvirt_type.value != '
  105. '\'kvm\'': '"Only KVM hypervisor works '
  106. 'with SR-IOV"'}]},
  107. 'physnet': {'type': 'text', 'value': '', 'weight': 30,
  108. 'label': 'Physical Network Name',
  109. 'regex': {
  110. 'source': '^[A-Za-z0-9 _]*[A-Za-z0-9][A-Za-z0-9 _]*$',
  111. 'error': 'Invalid physical network name'
  112. },
  113. 'restrictions': [
  114. 'nic_attributes:sriov.enabled.value == false',
  115. {'condition': "nic_attributes:sriov.physnet.value "
  116. "!= 'physnet2'",
  117. 'message': 'Only "physnet2" will be configured by '
  118. 'Fuel in Neutron. Configuration of other '
  119. 'physical networks is up to Operator or '
  120. 'plugin. Fuel will just configure '
  121. 'appropriate pci_passthrough_whitelist '
  122. 'option in nova.conf for such interface '
  123. 'and physical networks.',
  124. 'action': 'none'
  125. }
  126. ]},
  127. 'metadata': {'weight': 30, 'label': 'SR-IOV'}
  128. },
  129. 'dpdk': {
  130. 'enabled': {'type': 'checkbox', 'value': False,
  131. 'weight': 10, 'label': 'Enable DPDK',
  132. 'description': 'The Data Plane Development Kit (DPDK) '
  133. 'provides high-performance packet '
  134. 'processing libraries and user space '
  135. 'drivers.',
  136. 'restrictions': [
  137. {'settings:common.libvirt_type.value != \'kvm\'':
  138. 'Only KVM hypervisor works with DPDK'}
  139. ]},
  140. 'metadata': {
  141. 'weight': 40, 'label': 'DPDK',
  142. 'restrictions': [{
  143. 'condition': "not ('experimental' in version:feature_groups)",
  144. 'action': "hide"
  145. }]
  146. }
  147. }
  148. }
  149. DEFAULT_BOND_ATTRIBUTES = {
  150. 'lacp_rate': {
  151. 'value': {'type': 'select', 'weight': 10, 'value': '',
  152. 'label': 'Lacp rate'},
  153. 'metadata': {'weight': 60, 'label': 'Lacp rate'}
  154. },
  155. 'xmit_hash_policy': {
  156. 'value': {'type': 'select', 'weight': 10, 'value': '',
  157. 'label': 'Xmit hash policy'},
  158. 'metadata': {'weight': 70, 'label': 'Xmit hash policy'}
  159. },
  160. 'offloading': {
  161. 'disable': {'type': 'checkbox', 'weight': 10, 'value': False,
  162. 'label': 'Disable Offloading'},
  163. 'modes': {'weight': 20, 'type': 'offloading_modes',
  164. 'value': {}, 'label': 'Offloading Modes'},
  165. 'metadata': {'weight': 20, 'label': 'Offloading'}
  166. },
  167. 'mtu': {
  168. 'value': {'type': 'number', 'weight': 10, 'value': None,
  169. 'label': 'Use Custom MTU', 'nullable': True,
  170. 'min': 42, 'max': 65536},
  171. 'metadata': {'weight': 30, 'label': 'MTU'}
  172. },
  173. 'lacp': {
  174. 'value': {'type': 'select', 'weight': 10, 'value': '',
  175. 'label': 'Lacp'},
  176. 'metadata': {'weight': 50, 'label': 'Lacp'}
  177. },
  178. 'mode': {
  179. 'value': {'type': 'select', 'weight': 10, 'value': '',
  180. 'label': 'Mode'},
  181. 'metadata': {'weight': 10, 'label': 'Mode'}
  182. },
  183. 'type__': {'type': 'hidden', 'value': None},
  184. 'dpdk': {
  185. 'enabled': {'type': 'checkbox', 'value': False,
  186. 'weight': 10, 'label': 'Enable DPDK',
  187. 'description': 'The Data Plane Development Kit (DPDK) '
  188. 'provides high-performance packet '
  189. 'processing libraries and user space '
  190. 'drivers.',
  191. 'restrictions': [
  192. {'settings:common.libvirt_type.value != \'kvm\'':
  193. 'Only KVM hypervisor works with DPDK'}
  194. ]},
  195. 'metadata': {
  196. 'weight': 40, 'label': 'DPDK',
  197. 'restrictions': [{
  198. 'condition': "not ('experimental' in version:feature_groups)",
  199. 'action': "hide"
  200. }]
  201. }
  202. }
  203. }
  204. NODE_NIC_PROPERTIES = {
  205. 'mtu': 'test_mtu',
  206. 'disable_offloading': 'test_disable_offloading',
  207. 'sriov': {
  208. 'available': 'test_sriov_available',
  209. 'sriov_numvfs': 'test_sriov_sriov_numvfs',
  210. 'enabled': 'test_sriov_enabled',
  211. 'pci_id': 'test_sriov_pci_id',
  212. 'sriov_totalvfs': 'test_sriov_totalvfs',
  213. 'physnet': 'test_sriov_physnet'
  214. },
  215. 'dpdk': {
  216. 'available': 'test_dpdk_available',
  217. 'enabled': 'test_dpdk_enabled',
  218. },
  219. 'pci_id': 'test_pci_id',
  220. 'numa_node': 12345
  221. }
  222. NODE_OFFLOADING_MODES = [
  223. {
  224. 'state': True,
  225. 'name': 'tx-checksumming',
  226. 'sub': [{
  227. 'state': True,
  228. 'name': 'tx-checksum-sctp',
  229. 'sub': []
  230. }, {
  231. 'state': False,
  232. 'name': 'tx-checksum-ipv6',
  233. 'sub': []
  234. }]
  235. }, {
  236. 'state': None,
  237. 'name': 'rx-checksumming',
  238. 'sub': []
  239. }, {
  240. 'state': None,
  241. 'name': 'rx-vlan-offload',
  242. 'sub': []
  243. }
  244. ]
  245. # version of Fuel when security group switch was added
  246. RELEASE_VERSION = '9.0'
  247. # version of Fuel when tags was introduced
  248. FUEL_TAGS_SUPPORT = '9.0'
  249. NEW_ROLES_META = {
  250. 'controller': {
  251. 'tags': [
  252. 'controller',
  253. 'rabbitmq',
  254. 'database',
  255. 'keystone',
  256. 'neutron'
  257. ]
  258. }
  259. }
  260. NEW_TAGS_LIST = [
  261. 'rabbitmq',
  262. 'database',
  263. 'keystone',
  264. 'neutron'
  265. ]
  266. def setup_module():
  267. dropdb()
  268. alembic.command.upgrade(ALEMBIC_CONFIG, _prepare_revision)
  269. prepare()
  270. alembic.command.upgrade(ALEMBIC_CONFIG, _test_revision)
  271. def prepare():
  272. meta = base.reflect_db_metadata()
  273. for release_name, env_version, cluster_name, uuid, mac in zip(
  274. ('release_1', 'release_2'),
  275. ('liberty-8.0', 'mitaka-9.0'),
  276. ('cluster_1', 'cluster_2'),
  277. ('fcd49872-3917-4a18-98f9-3f5acfe3fde',
  278. 'fcd49872-3917-4a18-98f9-3f5acfe3fdd'),
  279. ('bb:aa:aa:aa:aa:aa', 'bb:aa:aa:aa:aa:cc')
  280. ):
  281. release = {
  282. 'name': release_name,
  283. 'version': env_version,
  284. 'operating_system': 'ubuntu',
  285. 'state': 'available',
  286. 'networks_metadata': '{}',
  287. 'attributes_metadata': jsonutils.dumps(ATTRIBUTES_METADATA),
  288. 'deployment_tasks': '{}',
  289. 'roles': jsonutils.dumps([
  290. 'controller',
  291. 'compute',
  292. 'virt',
  293. 'compute-vmware',
  294. 'ironic',
  295. 'cinder',
  296. 'cinder-block-device',
  297. 'cinder-vmware',
  298. 'ceph-osd',
  299. 'mongo',
  300. 'base-os',
  301. ]),
  302. 'roles_metadata': jsonutils.dumps({
  303. 'controller': {
  304. 'name': 'Controller',
  305. },
  306. 'compute': {
  307. 'name': 'Compute',
  308. },
  309. 'virt': {
  310. 'name': 'Virtual',
  311. },
  312. 'compute-vmware': {
  313. 'name': 'Compute VMware',
  314. },
  315. 'ironic': {
  316. 'name': 'Ironic',
  317. },
  318. 'cinder': {
  319. 'name': 'Cinder',
  320. },
  321. 'cinder-block-device': {
  322. 'name': 'Cinder Block Device',
  323. },
  324. 'cinder-vmware': {
  325. 'name': 'Cinder Proxy to VMware Datastore',
  326. },
  327. 'ceph-osd': {
  328. 'name': 'Ceph OSD',
  329. },
  330. 'mongo': {
  331. 'name': 'Telemetry - MongoDB',
  332. },
  333. 'base-os': {
  334. 'name': 'Operating System',
  335. }
  336. }),
  337. 'is_deployable': True,
  338. 'vmware_attributes_metadata':
  339. jsonutils.dumps(VMWARE_ATTRIBUTES_METADATA)
  340. }
  341. result = db.execute(meta.tables['releases'].insert(), [release])
  342. release_id = result.inserted_primary_key[0]
  343. result = db.execute(
  344. meta.tables['clusters'].insert(),
  345. [{
  346. 'name': cluster_name,
  347. 'release_id': release_id,
  348. 'mode': 'ha_compact',
  349. 'status': 'new',
  350. 'net_provider': 'neutron',
  351. 'grouping': 'roles',
  352. 'fuel_version': '9.0',
  353. 'deployment_tasks': '{}'
  354. }])
  355. cluster_id = result.inserted_primary_key[0]
  356. editable = ATTRIBUTES_METADATA.get('editable', {})
  357. db.execute(
  358. meta.tables['attributes'].insert(),
  359. [{
  360. 'cluster_id': cluster_id,
  361. 'editable': jsonutils.dumps(editable)
  362. }]
  363. )
  364. db.execute(
  365. meta.tables['nodes'].insert(),
  366. [{
  367. 'uuid': uuid,
  368. 'cluster_id': cluster_id,
  369. 'group_id': None,
  370. 'status': 'ready',
  371. 'roles': ['controller', 'ceph-osd'],
  372. 'primary_roles': ['controller'],
  373. 'meta': jsonutils.dumps({
  374. 'interfaces': [{
  375. 'mac': '00:00:00:00:00:01'
  376. }]
  377. }),
  378. 'mac': mac,
  379. 'timestamp': datetime.datetime.utcnow(),
  380. }]
  381. )
  382. node_interface_properties = copy.deepcopy(NODE_NIC_PROPERTIES)
  383. node_interface_properties['dpdk'].pop('available')
  384. result = db.execute(
  385. meta.tables['nodes'].insert(),
  386. [{
  387. 'uuid': 'fcd49872-3917-4a18-98f9-3f5acfe3fdec',
  388. 'cluster_id': cluster_id,
  389. 'group_id': None,
  390. 'status': 'ready',
  391. 'roles': ['controller', 'ceph-osd'],
  392. 'meta': jsonutils.dumps({
  393. 'interfaces': [
  394. {
  395. 'name': 'test_nic_empty_attributes',
  396. 'mac': '00:00:00:00:00:01',
  397. 'interface_properties': {}
  398. },
  399. {
  400. 'name': 'test_nic_attributes',
  401. 'mac': '00:00:00:00:00:02',
  402. 'interface_properties': node_interface_properties,
  403. 'offloading_modes': NODE_OFFLOADING_MODES
  404. },
  405. {
  406. 'name': 'test_nic_attributes_2',
  407. 'mac': '00:00:00:00:00:03',
  408. 'interface_properties': node_interface_properties,
  409. 'offloading_modes': [
  410. {
  411. 'state': True,
  412. 'name': 'tx-checksumming',
  413. 'sub': [{
  414. 'state': False,
  415. 'name': 'tx-checksum-sctp',
  416. 'sub': []
  417. }]
  418. }, {
  419. 'state': True,
  420. 'name': 'rx-checksumming',
  421. 'sub': []
  422. }, {
  423. 'state': False,
  424. 'name': 'rx-vlan-offload',
  425. 'sub': []
  426. }
  427. ]
  428. }
  429. ]
  430. }),
  431. 'mac': 'bb:bb:aa:aa:aa:aa',
  432. 'timestamp': datetime.datetime.utcnow(),
  433. 'hostname': 'test_node'
  434. }]
  435. )
  436. node_id = result.inserted_primary_key[0]
  437. db.execute(
  438. meta.tables['node_bond_interfaces'].insert(),
  439. [{
  440. 'node_id': node_id,
  441. 'name': 'test_bond_interface',
  442. 'mode': 'active-backup',
  443. 'bond_properties': jsonutils.dumps(
  444. {'test_property': 'test_value'})
  445. }]
  446. )
  447. bond = db.execute(
  448. meta.tables['node_bond_interfaces'].insert(),
  449. [{
  450. 'node_id': node_id,
  451. 'name': 'test_bond_interface_attributes',
  452. 'mode': '802.3ad',
  453. 'bond_properties': jsonutils.dumps(
  454. {'lacp_rate': 'slow', 'type__': 'linux',
  455. 'mode': '802.3ad', 'xmit_hash_policy': 'layer2'}),
  456. 'interface_properties': jsonutils.dumps(
  457. {'mtu': 2000, 'disable_offloading': False,
  458. 'dpdk': {'available': True, 'enabled': True}})
  459. }]
  460. )
  461. bond_id = bond.inserted_primary_key[0]
  462. db.execute(
  463. meta.tables['node_nic_interfaces'].insert(),
  464. [{
  465. 'node_id': node_id,
  466. 'name': 'test_nic_empty_attributes',
  467. 'mac': '00:00:00:00:00:01',
  468. 'interface_properties': "{}",
  469. 'offloading_modes': "[]"
  470. }]
  471. )
  472. changed_offloading_modes = copy.deepcopy(NODE_OFFLOADING_MODES)
  473. changed_offloading_modes[0]['state'] = False
  474. db.execute(
  475. meta.tables['node_nic_interfaces'].insert(),
  476. [{
  477. 'node_id': node_id,
  478. 'parent_id': bond_id,
  479. 'name': 'test_nic_attributes',
  480. 'mac': '00:00:00:00:00:02',
  481. 'interface_properties': jsonutils.dumps(NODE_NIC_PROPERTIES),
  482. 'offloading_modes': jsonutils.dumps(changed_offloading_modes)
  483. }]
  484. )
  485. db.execute(
  486. meta.tables['node_nic_interfaces'].insert(),
  487. [{
  488. 'node_id': node_id,
  489. 'parent_id': bond_id,
  490. 'name': 'test_nic_attributes_2',
  491. 'mac': '00:00:00:00:00:03',
  492. 'interface_properties': jsonutils.dumps(NODE_NIC_PROPERTIES),
  493. 'offloading_modes': jsonutils.dumps([
  494. {
  495. 'state': True,
  496. 'name': 'tx-checksumming',
  497. 'sub': [{
  498. 'state': True,
  499. 'name': 'tx-checksum-sctp',
  500. 'sub': []
  501. }]
  502. }, {
  503. 'state': True,
  504. 'name': 'rx-checksumming',
  505. 'sub': []
  506. }, {
  507. 'state': False,
  508. 'name': 'rx-vlan-offload',
  509. 'sub': []
  510. }
  511. ])
  512. }]
  513. )
  514. db.execute(
  515. meta.tables['plugins'].insert(),
  516. [{
  517. 'name': 'test_tags',
  518. 'title': 'Test tags plugin',
  519. 'version': '2.0.0',
  520. 'description': 'Test plugin A for Fuel',
  521. 'homepage': 'http://fuel_plugins.test_plugin.com',
  522. 'package_version': '5.0.0',
  523. 'groups': jsonutils.dumps(['tgroup']),
  524. 'authors': jsonutils.dumps(['tauthor']),
  525. 'licenses': jsonutils.dumps(['tlicense']),
  526. 'releases': jsonutils.dumps([
  527. {'repository_path': 'repositories/ubuntu'}
  528. ]),
  529. 'deployment_tasks': jsonutils.dumps([]),
  530. 'fuel_version': jsonutils.dumps(['9.2']),
  531. 'network_roles_metadata': jsonutils.dumps([]),
  532. 'roles_metadata': jsonutils.dumps({
  533. 'plugin-tags-controller': {
  534. 'name': 'Plugin Tags Controller',
  535. },
  536. }),
  537. }]
  538. )
  539. db.commit()
  540. class TestReleasesUpdate(base.BaseAlembicMigrationTest):
  541. def test_vmware_attributes_metadata_update(self):
  542. result = db.execute(sa.select([
  543. self.meta.tables['releases']])).first()
  544. attrs = jsonutils.loads(result['vmware_attributes_metadata'])
  545. fields = attrs['editable']['metadata'][0]['fields']
  546. self.assertItemsEqual(['vcenter_security_disabled'],
  547. [f['name'] for f in fields])
  548. fields = attrs['editable']['metadata'][1]['fields']
  549. self.assertItemsEqual(['vcenter_security_disabled'],
  550. [f['name'] for f in fields])
  551. self.assertEqual(
  552. attrs['editable']['value'],
  553. {
  554. 'availability_zones':
  555. [
  556. {
  557. 'vcenter_security_disabled': True,
  558. },
  559. {
  560. 'vcenter_security_disabled': True,
  561. }
  562. ],
  563. 'glance':
  564. {
  565. 'vcenter_security_disabled': True,
  566. }
  567. })
  568. class TestAttributesUpdate(base.BaseAlembicMigrationTest):
  569. def test_release_attributes_update(self):
  570. releases = self.meta.tables['releases']
  571. results = db.execute(
  572. sa.select([releases.c.attributes_metadata],
  573. releases.c.id.in_(
  574. self.get_release_ids(RELEASE_VERSION))))
  575. for attrs in results:
  576. attrs = jsonutils.loads(attrs[0])
  577. common = attrs.setdefault('editable', {}).setdefault('common', {})
  578. self.assertEqual(common.get('security_groups'), SECURITY_GROUPS)
  579. def test_release_attributes_no_update(self):
  580. releases = self.meta.tables['releases']
  581. results = db.execute(
  582. sa.select([releases.c.attributes_metadata],
  583. releases.c.id.in_(
  584. self.get_release_ids(RELEASE_VERSION,
  585. available=False))))
  586. for attrs in results:
  587. attrs = jsonutils.loads(attrs[0])
  588. common = attrs.setdefault('editable', {}).setdefault('common', {})
  589. self.assertEqual(common.get('security_groups'), None)
  590. def test_cluster_attributes_update(self):
  591. clusters_attributes = self.meta.tables['attributes']
  592. clusters = self.meta.tables['clusters']
  593. releases_list = self.get_release_ids(RELEASE_VERSION)
  594. results = db.execute(
  595. sa.select([clusters_attributes.c.editable],
  596. clusters.c.release_id.in_(releases_list)
  597. ).select_from(sa.join(clusters, clusters_attributes,
  598. clusters.c.id ==
  599. clusters_attributes.c.cluster_id)))
  600. for editable in results:
  601. editable = jsonutils.loads(editable[0])
  602. common = editable.setdefault('common', {})
  603. self.assertEqual(common.get('security_groups'), SECURITY_GROUPS)
  604. def test_cluster_attributes_no_update(self):
  605. clusters_attributes = self.meta.tables['attributes']
  606. clusters = self.meta.tables['clusters']
  607. releases_list = self.get_release_ids(RELEASE_VERSION, available=False)
  608. results = db.execute(
  609. sa.select([clusters_attributes.c.editable],
  610. clusters.c.release_id.in_(releases_list)
  611. ).select_from(sa.join(clusters, clusters_attributes,
  612. clusters.c.id ==
  613. clusters_attributes.c.cluster_id)))
  614. for editable in results:
  615. editable = jsonutils.loads(editable[0])
  616. common = editable.setdefault('common', {})
  617. self.assertEqual(common.get('security_groups'), None)
  618. def test_upgrade_release_with_nic_attributes(self):
  619. releases_table = self.meta.tables['releases']
  620. result = db.execute(
  621. sa.select([releases_table.c.nic_attributes,
  622. releases_table.c.bond_attributes],
  623. releases_table.c.id.in_(
  624. self.get_release_ids(RELEASE_VERSION)))
  625. ).fetchone()
  626. self.assertEqual(DEFAULT_NIC_ATTRIBUTES,
  627. jsonutils.loads(result['nic_attributes']))
  628. self.assertEqual(DEFAULT_BOND_ATTRIBUTES,
  629. jsonutils.loads(result['bond_attributes']))
  630. def get_release_ids(self, start_version, available=True):
  631. """Get release ids
  632. :param start_version: String in version format "n.n"
  633. for comparing
  634. :param available: boolean value
  635. :return: * list of release ids since start_version
  636. if available parameter is True
  637. * list of release ids before start_version
  638. if available parameter is False
  639. """
  640. releases = self.meta.tables['releases']
  641. results = db.execute(
  642. sa.select([releases.c.id,
  643. releases.c.version]))
  644. release_ids = []
  645. for release_id, release_version in results:
  646. if (available ==
  647. migration.is_security_groups_available(release_version,
  648. start_version)):
  649. release_ids.append(release_id)
  650. return release_ids
  651. class TestTags(base.BaseAlembicMigrationTest):
  652. def test_primary_tags_migration(self):
  653. nodes = self.meta.tables['nodes']
  654. query = sa.select([nodes.c.primary_tags]).where(
  655. nodes.c.uuid == 'fcd49872-3917-4a18-98f9-3f5acfe3fde')
  656. primary_tags = db.execute(query).fetchone()[0]
  657. self.assertItemsEqual(primary_tags, ['controller'])
  658. def test_tags_releases_meta_migration(self):
  659. releases = self.meta.tables['releases']
  660. query = sa.select([releases.c.roles_metadata,
  661. releases.c.tags_metadata])
  662. for roles_meta, tags_meta in db.execute(query):
  663. tags_meta = jsonutils.loads(tags_meta)
  664. for role_name, role_meta in six.iteritems(
  665. jsonutils.loads(roles_meta)):
  666. self.assertEqual(
  667. tags_meta[role_name].get('has_primary', False),
  668. role_meta.get('has_primary', False)
  669. )
  670. self.assertIn('tags', role_meta)
  671. def test_tags_plugins_meta_migration(self):
  672. plugins = self.meta.tables['plugins']
  673. query = sa.select([plugins.c.roles_metadata,
  674. plugins.c.tags_metadata])
  675. for roles_meta, tags_meta in db.execute(query):
  676. tags_meta = jsonutils.loads(tags_meta)
  677. for role_name, role_meta in six.iteritems(
  678. jsonutils.loads(roles_meta)):
  679. self.assertEqual(
  680. tags_meta[role_name].get('has_primary', False),
  681. role_meta.get('has_primary', False)
  682. )
  683. self.assertIn('tags', role_meta)
  684. def test_tags_migration_for_supported_releases(self):
  685. releases = self.meta.tables['releases']
  686. query = sa.select([releases.c.version,
  687. releases.c.roles_metadata,
  688. releases.c.tags_metadata])
  689. for version, roles_meta, tags_meta in db.execute(query):
  690. if not is_feature_supported(version, FUEL_TAGS_SUPPORT):
  691. continue
  692. roles_meta = jsonutils.loads(roles_meta)
  693. for role_name, role_meta in six.iteritems(NEW_ROLES_META):
  694. self.assertItemsEqual(
  695. roles_meta[role_name]['tags'],
  696. role_meta['tags']
  697. )
  698. tags_meta = jsonutils.loads(tags_meta)
  699. missing_tags = set(NEW_TAGS_LIST) - set(tags_meta)
  700. self.assertEqual(len(missing_tags), 0)
  701. def test_tags_migration_for_not_supported_releases(self):
  702. releases = self.meta.tables['releases']
  703. query = sa.select([releases.c.version,
  704. releases.c.roles_metadata,
  705. releases.c.tags_metadata])
  706. for version, roles_meta, tags_meta in db.execute(query):
  707. if is_feature_supported(version, FUEL_TAGS_SUPPORT):
  708. continue
  709. roles_meta = jsonutils.loads(roles_meta)
  710. for role_name, role_meta in six.iteritems(NEW_ROLES_META):
  711. common_tags = (set(role_meta['tags']) &
  712. set(roles_meta[role_name]['tags']))
  713. # common tag 'controller' for backward compatibility
  714. self.assertEqual(len(common_tags), 1)
  715. tags_meta = jsonutils.loads(tags_meta)
  716. wrong_tags = set(NEW_TAGS_LIST) - set(tags_meta)
  717. self.assertNotEqual(len(wrong_tags), 0)
  718. class TestNodeNICAndBondAttributesMigration(base.BaseAlembicMigrationTest):
  719. def test_upgrade_node_nic_attributes_with_empty_properties(self):
  720. interfaces_table = self.meta.tables['node_nic_interfaces']
  721. result = db.execute(
  722. sa.select([interfaces_table.c.meta,
  723. interfaces_table.c.attributes]).
  724. where(interfaces_table.c.name == 'test_nic_empty_attributes')
  725. ).fetchone()
  726. self.assertEqual(jsonutils.loads(result['meta']),
  727. {'offloading_modes': [],
  728. 'sriov': {'available': False,
  729. 'pci_id': '', 'totalvfs': 0},
  730. 'dpdk': {'available': False},
  731. 'pci_id': '',
  732. 'numa_node': None})
  733. expected_nic_attributes = copy.deepcopy(DEFAULT_NIC_ATTRIBUTES)
  734. expected_nic_attributes['sriov']['enabled']['value'] = False
  735. expected_nic_attributes['sriov']['physnet']['value'] = 'physnet2'
  736. expected_nic_attributes['dpdk']['enabled']['value'] = False
  737. self.assertEqual(jsonutils.loads(result['attributes']),
  738. expected_nic_attributes)
  739. def test_upgrade_node_nic_attributes(self):
  740. interfaces_table = self.meta.tables['node_nic_interfaces']
  741. result = db.execute(
  742. sa.select([interfaces_table.c.meta,
  743. interfaces_table.c.attributes]).
  744. where(interfaces_table.c.name == 'test_nic_attributes')
  745. ).fetchone()
  746. self.assertEqual(
  747. jsonutils.loads(result['meta']),
  748. {
  749. 'offloading_modes': NODE_OFFLOADING_MODES,
  750. 'sriov': {'available': 'test_sriov_available',
  751. 'pci_id': 'test_sriov_pci_id',
  752. 'totalvfs': 'test_sriov_totalvfs'},
  753. 'dpdk': {'available': 'test_dpdk_available'},
  754. 'pci_id': 'test_pci_id',
  755. 'numa_node': 12345
  756. }
  757. )
  758. expected_nic_attributes = copy.deepcopy(DEFAULT_NIC_ATTRIBUTES)
  759. expected_nic_attributes['mtu']['value']['value'] = \
  760. NODE_NIC_PROPERTIES['mtu']
  761. expected_nic_attributes['sriov']['enabled']['value'] = \
  762. NODE_NIC_PROPERTIES['sriov']['enabled']
  763. expected_nic_attributes['sriov']['numvfs']['value'] = \
  764. NODE_NIC_PROPERTIES['sriov']['sriov_numvfs']
  765. expected_nic_attributes['sriov']['physnet']['value'] = \
  766. NODE_NIC_PROPERTIES['sriov']['physnet']
  767. expected_nic_attributes['dpdk']['enabled']['value'] = \
  768. NODE_NIC_PROPERTIES['dpdk']['enabled']
  769. expected_nic_attributes['offloading']['disable']['value'] = \
  770. NODE_NIC_PROPERTIES['disable_offloading']
  771. expected_nic_attributes['offloading']['modes']['value'] = {
  772. 'tx-checksumming': False, 'tx-checksum-sctp': True,
  773. 'tx-checksum-ipv6': False, 'rx-checksumming': None,
  774. 'rx-vlan-offload': None
  775. }
  776. self.assertEqual(jsonutils.loads(result['attributes']),
  777. expected_nic_attributes)
  778. # TODO(apopovych): uncomment after removing redundant data
  779. # self.assertNotIn('offloading_modes', interfaces_table.c)
  780. # self.assertNotIn('interface_properties', interfaces_table.c)
  781. def test_upgrade_node_nic_attributes_only_for_cluster_node(self):
  782. interfaces_table = self.meta.tables['node_nic_interfaces']
  783. nodes_table = self.meta.tables['nodes']
  784. result = db.execute(
  785. sa.select([nodes_table.c.cluster_id, interfaces_table.c.attributes,
  786. interfaces_table.c.meta])
  787. .select_from(interfaces_table.join(
  788. nodes_table, interfaces_table.c.node_id == nodes_table.c.id))
  789. )
  790. for cluster_id, attributes, meta in result:
  791. self.assertTrue(bool(jsonutils.loads(meta)))
  792. self.assertEqual(bool(jsonutils.loads(attributes)),
  793. bool(cluster_id))
  794. def test_upgrade_node_bond_attributes_all_defaults(self):
  795. bonds_table = self.meta.tables['node_bond_interfaces']
  796. result = db.execute(
  797. sa.select([bonds_table.c.attributes]).
  798. where(bonds_table.c.name == 'test_bond_interface')
  799. ).fetchone()
  800. expected_attributes = copy.deepcopy(DEFAULT_BOND_ATTRIBUTES)
  801. expected_attributes['mode']['value']['value'] = 'active-backup'
  802. self.assertEqual(jsonutils.loads(result['attributes']),
  803. expected_attributes)
  804. def test_upgrade_node_bond_attributes(self):
  805. bonds_table = self.meta.tables['node_bond_interfaces']
  806. result = db.execute(
  807. sa.select([bonds_table.c.attributes]).
  808. where(bonds_table.c.name == 'test_bond_interface_attributes')
  809. ).fetchone()
  810. expected_attributes = copy.deepcopy(DEFAULT_BOND_ATTRIBUTES)
  811. expected_attributes['mtu']['value']['value'] = 2000
  812. expected_attributes['lacp_rate']['value']['value'] = 'slow'
  813. expected_attributes['xmit_hash_policy']['value']['value'] = 'layer2'
  814. expected_attributes['offloading']['disable']['value'] = False
  815. expected_attributes['dpdk']['enabled']['value'] = True
  816. expected_attributes['type__']['value'] = 'linux'
  817. expected_attributes['mode']['value']['value'] = '802.3ad'
  818. expected_attributes['offloading']['modes']['value'] = {
  819. 'tx-checksumming': False, 'tx-checksum-sctp': True,
  820. 'rx-checksumming': None, 'rx-vlan-offload': False}
  821. self.assertEqual(jsonutils.loads(result['attributes']),
  822. expected_attributes)
  823. # TODO(apopovych): uncomment after removing redundant data
  824. # self.assertNotIn('offloading_modes', bonds_table.c)
  825. # self.assertNotIn('interface_properties', bonds_table.c)
  826. # self.assertNotIn('bond_properties', bonds_table.c)
  827. class TestTransactionsNames(base.BaseAlembicMigrationTest):
  828. def test_field_reset_environment_exist(self):
  829. db.execute(
  830. self.meta.tables['tasks'].insert(),
  831. [
  832. {
  833. 'uuid': 'fake_task_uuid_0',
  834. 'name': 'reset_environment',
  835. 'status': 'pending'
  836. }
  837. ]
  838. )
  839. def test_field_reset_nodes_exist(self):
  840. db.execute(
  841. self.meta.tables['tasks'].insert(),
  842. [
  843. {
  844. 'uuid': 'fake_task_uuid_0',
  845. 'name': 'reset_nodes',
  846. 'status': 'pending'
  847. }
  848. ]
  849. )
  850. def test_field_remove_keys_exist(self):
  851. db.execute(
  852. self.meta.tables['tasks'].insert(),
  853. [
  854. {
  855. 'uuid': 'fake_task_uuid_0',
  856. 'name': 'remove_keys',
  857. 'status': 'pending'
  858. }
  859. ]
  860. )
  861. def test_field_remove_ironic_bootstrap_exist(self):
  862. db.execute(
  863. self.meta.tables['tasks'].insert(),
  864. [
  865. {
  866. 'uuid': 'fake_task_uuid_0',
  867. 'name': 'remove_ironic_bootstrap',
  868. 'status': 'pending'
  869. }
  870. ]
  871. )