Browse Source

Add Ironic multitenancy support

This patch adds support to deploy Ironic with separate Neutron network
for provisioning baremetal instances.

  * Add NetworkDeploymentSerializer100 as Ironic multitenancy is supported
    from Newton, and we will backport this till stable/newton.
  * Update network scheme generation to create 'vlan' baremetal network,
    assign IPs to Ironic conductors from this network, make them
    accessible from baremetal servers.
  * Add new checkbox at 'Openstack Settings/Additional components' tab
    which allows to define if separate provisioning network should be used
    during deployment. This is a trigger to switch ironic deployment to
    multitenancy case. If not selected old behaviour is kept, 'flat'
    network is used. The checkbox is shown only when Ironic component is
    enabled.

Change-Id: I861a8b3b046202526d6a856c9f2dca2cfaddc887
Related-Bug: #1588380
Vasyl Saienko 2 years ago
parent
commit
9dabe06369

+ 3
- 1
nailgun/nailgun/consts.py View File

@@ -104,6 +104,7 @@ DEFAULT_BRIDGES_NAMES = Enum(
104 104
     'br-aux',
105 105
     'br-baremetal',
106 106
     'br-ironic',
107
+    'br-bm-phy',
107 108
     names=(
108 109
         'br_fw_admin',
109 110
         'br_storage',
@@ -115,7 +116,8 @@ DEFAULT_BRIDGES_NAMES = Enum(
115 116
         'br_mesh',
116 117
         'br_aux',
117 118
         'br_baremetal',
118
-        'br_ironic'
119
+        'br_ironic',
120
+        'br_bm_phy'
119 121
     )
120 122
 )
121 123
 

+ 147
- 22
nailgun/nailgun/extensions/network_manager/serializers/neutron_serializers.py View File

@@ -27,6 +27,7 @@ from nailgun.extensions.network_manager.serializers.base \
27 27
     import NetworkDeploymentSerializer
28 28
 
29 29
 from nailgun import consts
30
+from nailgun.consts import DEFAULT_BRIDGES_NAMES as DBN
30 31
 from nailgun.db import db
31 32
 from nailgun.db.sqlalchemy import models
32 33
 from nailgun.logger import logger
@@ -602,7 +603,7 @@ class NeutronNetworkDeploymentSerializer61(
602 603
                 (consts.NEUTRON_SEGMENT_TYPES.gre,
603 604
                  consts.NEUTRON_SEGMENT_TYPES.tun):
604 605
             transformations.append(
605
-                cls.add_bridge(consts.DEFAULT_BRIDGES_NAMES.br_mesh))
606
+                cls.add_bridge(DBN.br_mesh))
606 607
 
607 608
     @classmethod
608 609
     def add_bond_interface(cls, transformations, iface, nets_by_ifaces, nm):
@@ -792,14 +793,14 @@ class NeutronNetworkDeploymentSerializer61(
792 793
         """
793 794
 
794 795
         transformations.append(cls.add_bridge(
795
-            consts.DEFAULT_BRIDGES_NAMES.br_prv,
796
+            DBN.br_prv,
796 797
             provider=consts.NEUTRON_L23_PROVIDERS.ovs))
797 798
         if not prv_base_ep:
798
-            prv_base_ep = consts.DEFAULT_BRIDGES_NAMES.br_aux
799
+            prv_base_ep = DBN.br_aux
799 800
             transformations.append(cls.add_bridge(prv_base_ep))
800 801
 
801 802
         transformations.append(cls.add_patch(
802
-            bridges=[consts.DEFAULT_BRIDGES_NAMES.br_prv, prv_base_ep],
803
+            bridges=[DBN.br_prv, prv_base_ep],
803 804
             provider=consts.NEUTRON_L23_PROVIDERS.ovs,
804 805
             mtu=65000))
805 806
 
@@ -830,7 +831,7 @@ class NeutronNetworkDeploymentSerializer70(
830 831
     @classmethod
831 832
     def is_valid_non_default_bridge_name(cls, name):
832 833
         """Validate bridge name for non-default network."""
833
-        if name in consts.DEFAULT_BRIDGES_NAMES:
834
+        if name in DBN:
834 835
             return False
835 836
         return bool(cls.RE_BRIDGE_NAME.match(name))
836 837
 
@@ -1285,12 +1286,12 @@ class GenerateL23Mixin80(object):
1285 1286
     def generate_l2(cls, cluster):
1286 1287
         l2 = super(GenerateL23Mixin80, cls).generate_l2(cluster)
1287 1288
         l2["phys_nets"]["physnet1"] = {
1288
-            "bridge": consts.DEFAULT_BRIDGES_NAMES.br_floating,
1289
+            "bridge": DBN.br_floating,
1289 1290
             "vlan_range": None
1290 1291
         }
1291 1292
         if objects.Cluster.is_component_enabled(cluster, 'ironic'):
1292 1293
             l2["phys_nets"]["physnet-ironic"] = {
1293
-                "bridge": consts.DEFAULT_BRIDGES_NAMES.br_ironic,
1294
+                "bridge": DBN.br_ironic,
1294 1295
                 "vlan_range": None
1295 1296
             }
1296 1297
         return l2
@@ -1355,23 +1356,23 @@ class NeutronNetworkDeploymentSerializer80(
1355 1356
     def get_network_to_endpoint_mapping(cls, node):
1356 1357
         mapping = {
1357 1358
             consts.NETWORKS.fuelweb_admin:
1358
-                consts.DEFAULT_BRIDGES_NAMES.br_fw_admin,
1359
+                DBN.br_fw_admin,
1359 1360
             consts.NETWORKS.storage:
1360
-                consts.DEFAULT_BRIDGES_NAMES.br_storage,
1361
+                DBN.br_storage,
1361 1362
             consts.NETWORKS.management:
1362
-                consts.DEFAULT_BRIDGES_NAMES.br_mgmt}
1363
+                DBN.br_mgmt}
1363 1364
         # roles can be assigned to br-ex only in case it has a public IP
1364 1365
         if objects.Node.should_have_public_with_ip(node):
1365 1366
             mapping[consts.NETWORKS.public] = \
1366
-                consts.DEFAULT_BRIDGES_NAMES.br_ex
1367
+                DBN.br_ex
1367 1368
         if node.cluster.network_config.segmentation_type in \
1368 1369
                 (consts.NEUTRON_SEGMENT_TYPES.gre,
1369 1370
                  consts.NEUTRON_SEGMENT_TYPES.tun):
1370 1371
             mapping[consts.NETWORKS.private] = \
1371
-                consts.DEFAULT_BRIDGES_NAMES.br_mesh
1372
+                DBN.br_mesh
1372 1373
         if objects.Cluster.is_component_enabled(node.cluster, 'ironic'):
1373 1374
             mapping[consts.NETWORKS.baremetal] = \
1374
-                consts.DEFAULT_BRIDGES_NAMES.br_baremetal
1375
+                DBN.br_baremetal
1375 1376
         mapping.update(cls.get_node_non_default_bridge_mapping(node))
1376 1377
         return mapping
1377 1378
 
@@ -1383,12 +1384,12 @@ class NeutronNetworkDeploymentSerializer80(
1383 1384
                                                      is_public, prv_base_ep))
1384 1385
         if objects.Cluster.is_component_enabled(node.cluster, 'ironic'):
1385 1386
             transformations.insert(0, cls.add_bridge(
1386
-                consts.DEFAULT_BRIDGES_NAMES.br_baremetal))
1387
+                DBN.br_baremetal))
1387 1388
             transformations.append(cls.add_bridge(
1388
-                consts.DEFAULT_BRIDGES_NAMES.br_ironic, provider='ovs'))
1389
+                DBN.br_ironic, provider='ovs'))
1389 1390
             transformations.append(cls.add_patch(
1390
-                bridges=[consts.DEFAULT_BRIDGES_NAMES.br_ironic,
1391
-                         consts.DEFAULT_BRIDGES_NAMES.br_baremetal],
1391
+                bridges=[DBN.br_ironic,
1392
+                         DBN.br_baremetal],
1392 1393
                 provider='ovs'))
1393 1394
         return transformations
1394 1395
 
@@ -1489,9 +1490,9 @@ class DPDKSerializerMixin90(object):
1489 1490
         vendor_specific = {'datapath_type': 'netdev'}
1490 1491
         if node.cluster.network_config.segmentation_type == \
1491 1492
                 consts.NEUTRON_SEGMENT_TYPES.vlan:
1492
-            br_name = consts.DEFAULT_BRIDGES_NAMES.br_prv
1493
+            br_name = DBN.br_prv
1493 1494
         else:
1494
-            br_name = consts.DEFAULT_BRIDGES_NAMES.br_mesh
1495
+            br_name = DBN.br_mesh
1495 1496
             vlan_id = objects.NetworkGroup.get_node_network_by_name(
1496 1497
                 node, 'private').vlan_start
1497 1498
             if vlan_id:
@@ -1653,18 +1654,142 @@ class NeutronNetworkTemplateSerializer90(
1653 1654
     pass
1654 1655
 
1655 1656
 
1656
-class NeutronNetworkTemplateSerializer110(
1657
+class NeutronNetworkTemplateSerializer100(
1657 1658
     NeutronNetworkTemplateSerializer90
1658 1659
 ):
1659 1660
     pass
1660 1661
 
1661 1662
 
1662
-class NeutronNetworkDeploymentSerializer110(
1663
+class NeutronNetworkDeploymentSerializer100(
1663 1664
     NeutronNetworkDeploymentSerializer90
1664 1665
 ):
1666
+
1667
+    @classmethod
1668
+    def _is_ironic_multitenancy_enabled(cls, cluster):
1669
+        """Check if ironic multitenancy is enabled."""
1670
+        return bool(
1671
+            utils.get_in(
1672
+                cluster.attributes.editable,
1673
+                'ironic_settings',
1674
+                'ironic_provision_network',
1675
+                'value'
1676
+            )
1677
+        )
1678
+
1679
+    @classmethod
1680
+    def _generate_baremetal_network(cls, cluster):
1681
+        ng = objects.NetworkGroup.get_from_node_group_by_name(
1682
+            objects.Cluster.get_default_group(cluster).id, 'baremetal')
1683
+
1684
+        network_type = 'flat'
1685
+        segment_id = None
1686
+        shared = True
1687
+        if cls._is_ironic_multitenancy_enabled(cluster):
1688
+            network_type = 'vlan'
1689
+            segment_id = ng.vlan_start
1690
+            shared = False
1691
+        return {
1692
+            "L3": {
1693
+                "subnet": ng.cidr,
1694
+                "nameservers": cluster.network_config.dns_nameservers,
1695
+                "gateway": cluster.network_config.baremetal_gateway,
1696
+                "floating": utils.join_range(
1697
+                    cluster.network_config.baremetal_range),
1698
+                "enable_dhcp": True
1699
+            },
1700
+            "L2": {
1701
+                "network_type": network_type,
1702
+                "segment_id": segment_id,
1703
+                "router_ext": False,
1704
+                "physnet": "physnet-ironic"
1705
+            },
1706
+            "tenant": objects.Cluster.get_creds(
1707
+                cluster)['tenant']['value'],
1708
+            "shared": shared
1709
+        }
1710
+
1711
+    @classmethod
1712
+    def generate_l2(cls, cluster):
1713
+        l2 = super(NeutronNetworkDeploymentSerializer100,
1714
+                   cls).generate_l2(cluster)
1715
+
1716
+        if (objects.Cluster.is_component_enabled(cluster, 'ironic') and
1717
+                cls._is_ironic_multitenancy_enabled(cluster)):
1718
+            ng = objects.NetworkGroup.get_from_node_group_by_name(
1719
+                objects.Cluster.get_default_group(cluster).id, 'baremetal')
1720
+            vlan_range = "{0}:{0}".format(ng.vlan_start)
1721
+            l2["phys_nets"]["physnet-ironic"] = {
1722
+                "bridge": DBN.br_ironic,
1723
+                "vlan_range": vlan_range
1724
+            }
1725
+        return l2
1726
+
1727
+    @classmethod
1728
+    def generate_transformations(cls, node, nm, nets_by_ifaces, is_public,
1729
+                                 prv_base_ep):
1730
+        transformations = (
1731
+            super(NeutronNetworkDeploymentSerializer100, cls)
1732
+            .generate_transformations(
1733
+                node, nm, nets_by_ifaces, is_public, prv_base_ep))
1734
+
1735
+        if (objects.Cluster.is_component_enabled(node.cluster, 'ironic') and
1736
+                cls._is_ironic_multitenancy_enabled(node.cluster)):
1737
+            transformations.insert(0, {'action': 'add-br',
1738
+                                       'name': DBN.br_bm_phy})
1739
+            netgroup = nm.get_network_by_netname('baremetal',
1740
+                                                 node.network_data)
1741
+            br_bm_phy_sub = '{0}.{1}'.format(DBN.br_bm_phy, netgroup['vlan'])
1742
+            bm_phy_configured = False
1743
+            for t in transformations:
1744
+                action = t.get('action')
1745
+                # Each transformation can be matched with the only one
1746
+                # condition at a time.
1747
+                if (action == 'add-patch' and
1748
+                        t.get('bridges') == [DBN.br_ironic,
1749
+                                             DBN.br_baremetal]):
1750
+                    t['bridges'] = [DBN.br_ironic,
1751
+                                    DBN.br_bm_phy]
1752
+                elif (action == 'add-port' and
1753
+                        t.get('name') == netgroup['dev']):
1754
+                    transformations.append(
1755
+                        cls.add_patch(bridges=[DBN.br_bm_phy,
1756
+                                      t.get('bridge')]))
1757
+                    bm_phy_configured = True
1758
+                elif (action == 'add-port' and
1759
+                        t.get('bridge') == DBN.br_baremetal):
1760
+                    t['name'] = br_bm_phy_sub
1761
+            # This is possible when only baremetal network is assigned to
1762
+            # interface. Add physical interface to br-bm-phy in this case.
1763
+            if not bm_phy_configured:
1764
+                transformations.append(cls.add_port(netgroup['dev'],
1765
+                                       DBN.br_bm_phy))
1766
+
1767
+        return transformations
1768
+
1769
+    @classmethod
1770
+    def generate_network_scheme(cls, node, networks):
1771
+        attrs = super(NeutronNetworkDeploymentSerializer100,
1772
+                      cls).generate_network_scheme(node, networks)
1773
+
1774
+        if (objects.Cluster.is_component_enabled(node.cluster, 'ironic') and
1775
+                cls._is_ironic_multitenancy_enabled(node.cluster)):
1776
+            attrs['endpoints'][DBN.br_ironic] = {'IP': 'none'}
1777
+
1778
+        return attrs
1779
+
1780
+
1781
+class NeutronNetworkTemplateSerializer110(
1782
+    NeutronNetworkTemplateSerializer100
1783
+):
1784
+    pass
1785
+
1786
+
1787
+class NeutronNetworkDeploymentSerializer110(
1788
+    NeutronNetworkDeploymentSerializer100,
1789
+):
1665 1790
     @classmethod
1666 1791
     def generate_transformations_by_segmentation_type(
1667
-            cls, node, nm, transformations, prv_base_ep, nets_by_ifaces
1792
+        cls, node, nm, transformations, prv_base_ep, nets_by_ifaces
1668 1793
     ):
1669 1794
         (super(NeutronNetworkDeploymentSerializer110, cls)
1670 1795
             .generate_transformations_by_segmentation_type(

+ 14
- 0
nailgun/nailgun/fixtures/openstack.yaml View File

@@ -948,6 +948,20 @@
948 948
             description: "Name for Mongo replication set"
949 949
             weight: 30
950 950
             type: "text"
951
+        ironic_settings:
952
+          metadata:
953
+            label: "Ironic Settings"
954
+            weight: 40
955
+            group: "openstack_services"
956
+            restrictions:
957
+              - condition: "settings:additional_components.ironic.value == false"
958
+                action: "hide"
959
+          ironic_provision_network:
960
+            value: false
961
+            label: "Use separate provisioning network"
962
+            description: "When selected Ironic instance will be provisioned in separate network."
963
+            weight: 10
964
+            type: "checkbox"
951 965
         additional_components:
952 966
           metadata:
953 967
             label: "Additional Components"

+ 12
- 1
nailgun/nailgun/orchestrator/deployment_serializers.py View File

@@ -809,7 +809,17 @@ class DeploymentLCMSerializer(DeploymentHASerializer90):
809 809
         return serialized_node
810 810
 
811 811
 
812
-class DeploymentLCMSerializer110(DeploymentLCMSerializer):
812
+class DeploymentLCMSerializer100(DeploymentLCMSerializer):
813
+
814
+    @classmethod
815
+    def get_net_provider_serializer(cls, cluster):
816
+        if cluster.network_config.configuration_template:
817
+            return neutron_serializers.NeutronNetworkTemplateSerializer100
818
+        else:
819
+            return neutron_serializers.NeutronNetworkDeploymentSerializer100
820
+
821
+
822
+class DeploymentLCMSerializer110(DeploymentLCMSerializer100):
813 823
 
814 824
     @classmethod
815 825
     def get_net_provider_serializer(cls, cluster):
@@ -897,6 +907,7 @@ def serialize_for_lcm(cluster, nodes,
897 907
                       ignore_customized=False, skip_extensions=False):
898 908
     serializers_map = {
899 909
         'default': DeploymentLCMSerializer,
910
+        '10.0': DeploymentLCMSerializer100,
900 911
         '11.0': DeploymentLCMSerializer110,
901 912
     }
902 913
 

+ 3
- 0
nailgun/nailgun/statistics/fuel_statistics/installation_info.py View File

@@ -157,6 +157,9 @@ class InstallationInfo(object):
157 157
         WhiteListRule(('murano_settings',
158 158
                        'murano_glance_artifacts_plugin', 'value'),
159 159
                       'murano_glance_artifacts_plugin', None),
160
+        WhiteListRule(('ironic_settings',
161
+                       'ironic_provision_network', 'value'),
162
+                      'ironic_provision_network', None),
160 163
 
161 164
         WhiteListRule(('workloads_collector', 'enabled', 'value'),
162 165
                       'workloads_collector_enabled', None),

+ 239
- 0
nailgun/nailgun/test/integration/test_orchestrator_serializer_100.py View File

@@ -0,0 +1,239 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+#    Copyright 2016 Mirantis, Inc.
4
+#
5
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
6
+#    not use this file except in compliance with the License. You may obtain
7
+#    a copy of the License at
8
+#
9
+#         http://www.apache.org/licenses/LICENSE-2.0
10
+#
11
+#    Unless required by applicable law or agreed to in writing, software
12
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+#    License for the specific language governing permissions and limitations
15
+#    under the License.
16
+
17
+from nailgun import consts
18
+from nailgun import objects
19
+
20
+from nailgun.orchestrator import deployment_serializers
21
+from nailgun.orchestrator.deployment_serializers import \
22
+    deployment_info_to_legacy
23
+from nailgun.test.integration.test_orchestrator_serializer import \
24
+    BaseDeploymentSerializer
25
+from nailgun.test.integration import test_orchestrator_serializer_90
26
+
27
+
28
+from nailgun.extensions.network_manager.serializers.neutron_serializers \
29
+    import NeutronNetworkDeploymentSerializer100
30
+from nailgun.extensions.network_manager.serializers.neutron_serializers \
31
+    import NeutronNetworkTemplateSerializer100
32
+
33
+
34
+class TestSerializer100Mixin(object):
35
+    env_version = 'newton-10.0'
36
+    task_deploy = True
37
+
38
+    @classmethod
39
+    def create_serializer(cls, cluster):
40
+        return deployment_serializers.DeploymentLCMSerializer100()
41
+
42
+    @classmethod
43
+    def _get_serializer(cluster):
44
+        return deployment_serializers.DeploymentLCMSerializer100()
45
+
46
+    @staticmethod
47
+    def _get_plugins_names(plugins):
48
+        """Plugins names for LCM serializers
49
+
50
+        Single out <name> since plugin data may contain
51
+        <scripts>, <repositories>, <whatever> as well.
52
+
53
+        :param nodes: array of plugins data
54
+        :returns: singled out names of plugins
55
+        """
56
+        return [plugin['name'] for plugin in plugins]
57
+
58
+    def _setup_cluster_with_ironic(self, ironic_provision_network,
59
+                                   separate_interface=False):
60
+        self.env._set_additional_component(self.cluster, 'ironic', True)
61
+        if ironic_provision_network:
62
+            objects.Cluster.patch_attributes(
63
+                self.cluster,
64
+                {'editable': {
65
+                    'ironic_settings': {
66
+                        'ironic_provision_network': {
67
+                            'value': True}}}})
68
+        node = self.env.create_nodes_w_interfaces_count(
69
+            1, 4, cluster_id=self.cluster.id,
70
+            roles=['controller', 'ironic'])[0]
71
+
72
+        if separate_interface:
73
+            nic_1 = node.nic_interfaces[0]
74
+            nic_4 = node.nic_interfaces[3]
75
+            nets_1 = nic_1.assigned_networks_list
76
+            nets_4 = nic_4.assigned_networks_list
77
+            for i, net in enumerate(nets_1):
78
+                if net['name'] == 'baremetal':
79
+                    nets_4.append(nets_1.pop(i))
80
+                    break
81
+            objects.NIC.assign_networks(nic_1, nets_1)
82
+            objects.NIC.assign_networks(nic_4, nets_4)
83
+        objects.Cluster.prepare_for_deployment(self.cluster)
84
+
85
+
86
+class TestSerializeInterfaceDriversData100(
87
+    TestSerializer100Mixin,
88
+    test_orchestrator_serializer_90.TestSerializeInterfaceDriversData90
89
+):
90
+    pass
91
+
92
+
93
+class TestDeploymentTasksSerialization100(
94
+    TestSerializer100Mixin,
95
+    test_orchestrator_serializer_90.TestDeploymentTasksSerialization90
96
+):
97
+    pass
98
+
99
+
100
+class TestNetworkTemplateSerializer100(
101
+    TestSerializer100Mixin,
102
+    test_orchestrator_serializer_90.TestNetworkTemplateSerializer90
103
+):
104
+    pass
105
+
106
+
107
+class TestNetworkDeploymentSerializer100(
108
+    TestSerializer100Mixin,
109
+    BaseDeploymentSerializer,
110
+):
111
+
112
+    legacy_serializer = NeutronNetworkDeploymentSerializer100
113
+    template_serializer = NeutronNetworkTemplateSerializer100
114
+
115
+    def setUp(self, *args):
116
+        super(TestNetworkDeploymentSerializer100, self).setUp()
117
+        self.cluster = self.env.create(
118
+            release_kwargs={'version': self.env_version},
119
+            cluster_kwargs={
120
+                'mode': consts.CLUSTER_MODES.ha_compact,
121
+                'net_provider': consts.CLUSTER_NET_PROVIDERS.neutron,
122
+                'net_segment_type': consts.NEUTRON_SEGMENT_TYPES.vlan})
123
+        self.serializer = self.create_serializer(self.cluster)
124
+
125
+    def test_baremetal_neutron_attrs_flat(self):
126
+        self._setup_cluster_with_ironic(ironic_provision_network=False)
127
+        serialized_for_astute = self.serializer.serialize(
128
+            self.cluster, self.cluster.nodes)
129
+        serialized_for_astute = deployment_info_to_legacy(
130
+            serialized_for_astute)
131
+        for node in serialized_for_astute:
132
+            expected_network = {
133
+                "network_type": "flat",
134
+                "segment_id": None,
135
+                "router_ext": False,
136
+                "physnet": "physnet-ironic"
137
+            }
138
+            self.assertEqual(expected_network, node['quantum_settings']
139
+                             ['predefined_networks']['baremetal']['L2'])
140
+            self.assertIn("physnet-ironic",
141
+                          node['quantum_settings']['L2']['phys_nets'])
142
+            self.assertEqual(consts.DEFAULT_BRIDGES_NAMES.br_ironic,
143
+                             (node['quantum_settings']['L2']['phys_nets']
144
+                              ["physnet-ironic"]["bridge"]))
145
+            self.assertEqual(None, (node['quantum_settings']['L2']['phys_nets']
146
+                                    ["physnet-ironic"]["vlan_range"]))
147
+
148
+    def test_baremetal_neutron_attrs_vlan(self):
149
+        self._setup_cluster_with_ironic(ironic_provision_network=True)
150
+        serialized_for_astute = self.serializer.serialize(
151
+            self.cluster, self.cluster.nodes)
152
+        serialized_for_astute = deployment_info_to_legacy(
153
+            serialized_for_astute)
154
+        for node in serialized_for_astute:
155
+            expected_network = {
156
+                "network_type": "vlan",
157
+                "segment_id": 104,
158
+                "router_ext": False,
159
+                "physnet": "physnet-ironic"
160
+            }
161
+            self.assertEqual(expected_network, node['quantum_settings']
162
+                             ['predefined_networks']['baremetal']['L2'])
163
+            self.assertIn("physnet-ironic",
164
+                          node['quantum_settings']['L2']['phys_nets'])
165
+            self.assertEqual(consts.DEFAULT_BRIDGES_NAMES.br_ironic,
166
+                             (node['quantum_settings']['L2']['phys_nets']
167
+                              ["physnet-ironic"]["bridge"]))
168
+            self.assertEqual('104:104',
169
+                             (node['quantum_settings']['L2']['phys_nets']
170
+                              ["physnet-ironic"]["vlan_range"]))
171
+
172
+    def test_baremetal_transformations_flat(self):
173
+        self._setup_cluster_with_ironic(ironic_provision_network=False)
174
+        serialized_for_astute = self.serializer.serialize(
175
+            self.cluster, self.cluster.nodes)
176
+        serialized_for_astute = deployment_info_to_legacy(
177
+            serialized_for_astute)
178
+        net_tr = serialized_for_astute[0]['network_scheme']['transformations']
179
+        expected_actions = [
180
+            {'action': 'add-br', 'name': 'br-baremetal'},
181
+            {'action': 'add-port', 'bridge': 'br-baremetal',
182
+             'name': 'eth0.104'},
183
+            {'action': 'add-br', 'name': 'br-ironic', 'provider': 'ovs'},
184
+            {'action': 'add-patch', 'bridges': ['br-ironic', 'br-baremetal'],
185
+             'provider': 'ovs'}]
186
+
187
+        for element in expected_actions:
188
+            self.assertIn(element, net_tr)
189
+
190
+    def test_baremetal_transformations_vlan(self):
191
+        self._setup_cluster_with_ironic(ironic_provision_network=True)
192
+        serialized_for_astute = self.serializer.serialize(
193
+            self.cluster, self.cluster.nodes)
194
+        serialized_for_astute = deployment_info_to_legacy(
195
+            serialized_for_astute)
196
+        net_tr = serialized_for_astute[0]['network_scheme']['transformations']
197
+        expected_actions = [
198
+            {'action': 'add-br', 'name': 'br-bm-phy'},
199
+            {'action': 'add-br', 'name': 'br-baremetal'},
200
+            {'action': 'add-port', 'bridge': 'br-baremetal',
201
+             'name': 'br-bm-phy.104'},
202
+            {'action': 'add-br', 'name': 'br-ironic', 'provider': 'ovs'},
203
+            {'action': 'add-patch', 'bridges': ['br-ironic', 'br-bm-phy'],
204
+             'provider': 'ovs'},
205
+            {'action': 'add-patch', 'bridges': ['br-bm-phy', 'br-fw-admin']}]
206
+
207
+        not_expected = [
208
+            {'action': 'add-port', 'bridge': 'br-bm-phy', 'name': u'eth0'}]
209
+
210
+        for element in expected_actions:
211
+            self.assertIn(element, net_tr)
212
+        for elemnet in not_expected:
213
+            self.assertNotIn(elemnet, net_tr)
214
+
215
+    def test_baremetal_transformations_vlan_baremetal_on_separate_nic(self):
216
+        self._setup_cluster_with_ironic(ironic_provision_network=True,
217
+                                        separate_interface=True)
218
+        serialized_for_astute = self.serializer.serialize(
219
+            self.cluster, self.cluster.nodes)
220
+        serialized_for_astute = deployment_info_to_legacy(
221
+            serialized_for_astute)
222
+        net_tr = serialized_for_astute[0]['network_scheme']['transformations']
223
+        expected_actions = [
224
+            {'action': 'add-br', 'name': 'br-bm-phy'},
225
+            {'action': 'add-br', 'name': 'br-baremetal'},
226
+            {'action': 'add-port', 'bridge': 'br-baremetal',
227
+             'name': 'br-bm-phy.104'},
228
+            {'action': 'add-br', 'name': 'br-ironic', 'provider': 'ovs'},
229
+            {'action': 'add-patch', 'bridges': ['br-ironic', 'br-bm-phy'],
230
+             'provider': 'ovs'},
231
+            {'action': 'add-port', 'bridge': 'br-bm-phy', 'name': u'eth3'}]
232
+
233
+        not_expected = [
234
+            {'action': 'add-patch', 'bridges': ['br-bm-phy', 'br-fw-admin']}]
235
+
236
+        for element in expected_actions:
237
+            self.assertIn(element, net_tr)
238
+        for elemnet in not_expected:
239
+            self.assertNotIn(elemnet, net_tr)

+ 4
- 11
nailgun/nailgun/test/integration/test_orchestrator_serializer_110.py View File

@@ -16,7 +16,7 @@
16 16
 
17 17
 from nailgun import consts
18 18
 from nailgun.orchestrator import deployment_serializers
19
-from nailgun.test.integration import test_orchestrator_serializer_90
19
+from nailgun.test.integration import test_orchestrator_serializer_100
20 20
 
21 21
 
22 22
 class TestSerializer110Mixin(object):
@@ -45,22 +45,15 @@ class TestSerializer110Mixin(object):
45 45
         return [plugin['name'] for plugin in plugins]
46 46
 
47 47
 
48
-class TestDeploymentAttributesSerialization110(
48
+class TestNetworkDeploymentSerializer110(
49 49
     TestSerializer110Mixin,
50
-    test_orchestrator_serializer_90.TestDeploymentAttributesSerialization90
51
-):
52
-    pass
53
-
54
-
55
-class TestDeploymentLCMSerialization110(
56
-    TestSerializer110Mixin,
57
-    test_orchestrator_serializer_90.TestDeploymentLCMSerialization90
50
+    test_orchestrator_serializer_100.TestNetworkDeploymentSerializer100
58 51
 ):
59 52
     pass
60 53
 
61 54
 
62 55
 class TestSerializeInterfaceDriversData110(
63 56
     TestSerializer110Mixin,
64
-    test_orchestrator_serializer_90.TestSerializeInterfaceDriversData90
57
+    test_orchestrator_serializer_100.TestSerializeInterfaceDriversData100
65 58
 ):
66 59
     pass

Loading…
Cancel
Save