diff --git a/nailgun/nailgun/extensions/network_manager/managers/neutron.py b/nailgun/nailgun/extensions/network_manager/managers/neutron.py index 3ff8742cc1..0484b8fc57 100644 --- a/nailgun/nailgun/extensions/network_manager/managers/neutron.py +++ b/nailgun/nailgun/extensions/network_manager/managers/neutron.py @@ -34,7 +34,7 @@ from nailgun.extensions.network_manager.manager import NetworkManager from nailgun import objects from nailgun.extensions.network_manager.serializers.neutron_serializers \ - import NeutronNetworkTemplateSerializer70 + import NeutronNetworkTemplateSerializer110 class NeutronManager(NetworkManager): @@ -363,7 +363,7 @@ class NeutronManager70( except ValueError: vlan = None - return (iface, vlan) + return iface, vlan @classmethod def get_interfaces_from_template(cls, node): @@ -372,15 +372,37 @@ class NeutronManager70( Returns a list of bare interfaces and bonds. """ transformations = \ - NeutronNetworkTemplateSerializer70.generate_transformations(node) + NeutronNetworkTemplateSerializer110.generate_transformations(node) interfaces = {} for tx in transformations: if tx['action'] == 'add-port': - key = tx.get('bridge', tx['name']) + name = tx['name'] + key = tx.get('bridge', name) + + iface_type = consts.NETWORK_INTERFACE_TYPES.ether + + if tx.get('provider') == consts.NEUTRON_L23_PROVIDERS.ovs: + iface_name = name + vlan = tx.get('vlan_id') + else: + iface_name, vlan = cls._split_iface_name(name) + + if vlan is not None: + # We can't resolve bond type in case of adding port + # on the bond. Ether type can be set only if NIC with + # iface_name present in the DB + nic = objects.NIC.get_nic_by_name(node, iface_name) + if nic is None: + # We can't detect if vlan configured on the non + # existent NIC. In this case iface will have type + # BOND. Should be fixed in + # https://bugs.launchpad.net/fuel/+bug/1664286 + iface_type = consts.NETWORK_INTERFACE_TYPES.bond + interfaces[key] = { - 'name': tx['name'], - 'type': consts.NETWORK_INTERFACE_TYPES.ether + 'name': name, + 'type': iface_type } if tx['action'] == 'add-bond': @@ -489,8 +511,8 @@ class NeutronManager70( if nic is None: raise errors.NetworkTemplateCannotBeApplied( "Networks cannot be assigned as interface with name " - "{0} does not exist for node {1}" - .format(iface, objects.Node.get_slave_name(node)) + "{0} does not exist for node {1}".format( + iface, objects.Node.get_slave_name(node)) ) node_ifaces[iface]['id'] = nic.id diff --git a/nailgun/nailgun/extensions/network_manager/tests/test_network_manager.py b/nailgun/nailgun/extensions/network_manager/tests/test_network_manager.py index 4ac9e73fd7..47f4bc3bc1 100644 --- a/nailgun/nailgun/extensions/network_manager/tests/test_network_manager.py +++ b/nailgun/nailgun/extensions/network_manager/tests/test_network_manager.py @@ -44,6 +44,8 @@ from nailgun.extensions.network_manager.managers.neutron import \ NeutronManager70 from nailgun.extensions.network_manager.managers.neutron import \ NeutronManager80 +from nailgun.extensions.network_manager.managers.neutron import \ + NeutronManager90 from nailgun.extensions.network_manager.managers.nova_network import \ NovaNetworkManager from nailgun.extensions.network_manager.managers.nova_network import \ @@ -1698,70 +1700,51 @@ class TestTemplateManager70(BaseIntegrationTest): def test_get_interfaces_from_template(self): expected_interfaces = { 'br-aux': { - 'interface_properties': {}, - 'name': 'eth3.103', - 'offloading_modes': [], + 'name': 'eth2.103', 'type': 'ether' }, 'br-ex': { - 'interface_properties': {}, 'name': 'eth1', - 'offloading_modes': [], 'type': 'ether' }, 'br-fw-admin': { - 'interface_properties': {}, 'name': 'eth0', - 'offloading_modes': [], 'type': 'ether' }, 'br-keystone': { - 'interface_properties': {}, 'name': 'eth4.202', - 'offloading_modes': [], 'type': 'ether' }, 'br-mgmt': { 'bond_properties': {'mode': u'active-backup'}, 'name': u'lnxbond0', - 'offloading_modes': [], 'slaves': [{'name': u'eth3'}, {'name': u'eth4'}], 'type': 'bond' }, 'br-mongo': { - 'interface_properties': {}, 'name': u'eth4.201', - 'offloading_modes': [], 'type': 'ether' }, 'br-storage': { - 'interface_properties': {}, 'name': 'eth1.102', - 'offloading_modes': [], 'type': 'ether' }, 'eth2': { - 'interface_properties': {}, 'name': 'eth2', - 'offloading_modes': [], 'type': 'ether' }, 'eth3.101': { - 'interface_properties': {}, 'name': u'eth3.101', - 'offloading_modes': [], 'type': 'ether' }, 'eth4.101': { - 'interface_properties': {}, 'name': u'eth4.101', - 'offloading_modes': [], 'type': 'ether' } } interfaces = self.nm.get_interfaces_from_template(self.env.nodes[0]) - self.assertItemsEqual(interfaces, expected_interfaces) + self.assertEqual(expected_interfaces, interfaces) def test_reassign_networks_based_on_template(self): expected_mapping = { @@ -1947,3 +1930,59 @@ class TestNeutronManager80(BaseIntegrationTest): template['templates_for_node_role']['test_role'].remove('private') self.assertFalse(self.net_manager.dpdk_enabled_for_node(node)) + + +class TestTemplateManager90(BaseIntegrationTest): + + def setUp(self): + super(TestTemplateManager90, self).setUp() + self.cluster = self.env.create( + release_kwargs={'version': '1111-9.0'}, + cluster_kwargs={ + 'api': True, + 'net_provider': consts.CLUSTER_NET_PROVIDERS.neutron, + } + ) + self.cluster = objects.Cluster.get_by_uid(self.cluster['id']) + self.nm = objects.Cluster.get_network_manager(self.cluster) + self.net_templates = self.env.read_fixtures(['network_template_90']) + + def test_get_network_manager(self): + self.assertIs(self.nm, NeutronManager90) + + def test_get_interfaces_from_template(self): + nodes = self.env.create_nodes_w_interfaces_count( + 1, + if_count=15, + cluster_id=self.cluster.id, + status=consts.NODE_STATUSES.ready, + roles=["controller"], + iface_name_prefix='eno{0}' + ) + objects.Cluster.set_network_template( + self.cluster, + self.net_templates[3] + ) + + interfaces = self.nm.get_interfaces_from_template(nodes[0]) + + expected_interfaces = { + 'br-fw-admin': {'type': 'ether', 'name': 'eno3'}, + 'bond0': { + 'bond_properties': { + 'lacp_rate': 'fast', + 'mode': '802.3ad', + 'xmit_hash_policy': 'layer3+4' + }, + 'type': 'bond', + 'name': 'bond0', + 'slaves': [{'name': 'eno1'}, {'name': 'eno2'}]}, + 'br-prv': {'type': 'bond', 'name': 'bond0.342'}, + 'br-storage': {'type': 'bond', 'name': 'bond0.344'}, + 'br-mgmt': {'type': 'bond', 'name': 'bond0.346'}, + 'br-ex': {'type': 'bond', 'name': 'bond0.345'}, + 'br0': {'type': 'bond', 'name': 'port-with-tag-111'}, + 'br1': {'type': 'bond', 'name': 'eno3333.222'}, + 'br2': {'type': 'ether', 'name': 'eno3333'} + } + self.assertEqual(expected_interfaces, interfaces) diff --git a/nailgun/nailgun/extensions/network_manager/tests/test_network_template_handler.py b/nailgun/nailgun/extensions/network_manager/tests/test_network_template_handler.py index 8152b817dc..992fd78014 100644 --- a/nailgun/nailgun/extensions/network_manager/tests/test_network_template_handler.py +++ b/nailgun/nailgun/extensions/network_manager/tests/test_network_template_handler.py @@ -58,6 +58,42 @@ class TestHandlers(BaseIntegrationTest): self.assertEqual(200, resp.status_code) self.assertEqual(template, resp.json_body) + def test_network_template_add_node(self): + cluster = self.env.create( + release_kwargs={'version': '1111-9.0'}, + cluster_kwargs={ + 'api': False, + 'net_provider': consts.CLUSTER_NET_PROVIDERS.neutron + } + ) + + self.env.create_nodes_w_interfaces_count( + 5, + if_count=15, + cluster_id=cluster.id, + status=consts.NODE_STATUSES.ready, + roles=["controller"], + iface_name_prefix='eno{0}' + ) + + template = self.env.read_fixtures(['network_template_90'])[3] + template.pop('pk') # PK is not needed + + resp = self.app.put( + reverse( + 'TemplateNetworkConfigurationHandler', + kwargs={'cluster_id': cluster.id}, + ), + jsonutils.dumps(template), + headers=self.default_headers + ) + self.assertEqual(200, resp.status_code) + self.assertEquals(template, resp.json_body) + + resp = self.get_template(cluster.id) + self.assertEqual(200, resp.status_code) + self.assertEqual(template, resp.json_body) + def test_network_template_upload_on_multi_group_cluster(self): cluster = self.env.create_cluster( api=False, @@ -174,3 +210,38 @@ class TestHandlers(BaseIntegrationTest): # error (403 in this case) db().commit() self.check_put_delete_template(cluster, status not in allowed) + + def test_network_template_upload_90(self): + cluster = self.env.create( + release_kwargs={'version': '1111-9.0'}, + cluster_kwargs={ + 'api': True, + 'net_provider': consts.CLUSTER_NET_PROVIDERS.neutron, + } + ) + self.env.create_nodes_w_interfaces_count( + 1, + if_count=15, + cluster_id=cluster.id, + status=consts.NODE_STATUSES.ready, + roles=["controller"], + iface_name_prefix='eno{0}' + ) + + template = self.env.read_fixtures(['network_template_90'])[3] + template.pop('pk') # PK is not needed + + resp = self.app.put( + reverse( + 'TemplateNetworkConfigurationHandler', + kwargs={'cluster_id': cluster.id}, + ), + jsonutils.dumps(template), + headers=self.default_headers + ) + self.assertEqual(200, resp.status_code) + self.assertEquals(template, resp.json_body) + + resp = self.get_template(cluster.id) + self.assertEqual(200, resp.status_code) + self.assertEqual(template, resp.json_body) diff --git a/nailgun/nailgun/fixtures/network_template_90.json b/nailgun/nailgun/fixtures/network_template_90.json index 2cf46ad4b0..ceafdc5c5a 100644 --- a/nailgun/nailgun/fixtures/network_template_90.json +++ b/nailgun/nailgun/fixtures/network_template_90.json @@ -891,4 +891,410 @@ } } } +}, + +{ + "pk": 4, + "adv_net_template": { + "default": { + "network_assignments": { + "management": { + "ep": "br-mgmt" + }, + "ceph_cluster": { + "ep": "br-cluster" + }, + "storage": { + "ep": "br-storage" + }, + "public": { + "ep": "br-ex" + }, + "private": { + "ep": "br-prv" + }, + "fuelweb_admin": { + "ep": "br-fw-admin" + } + }, + "templates_for_node_role": { + "ceph-osd": [ + "common", + "storage", + "ceph_cluster" + ], + "compute": [ + "common", + "public", + "private", + "storage" + ], + "mongo": [ + "common" + ], + "kafka": [ + "common", + "public" + ], + "elasticsearch_kibana": [ + "common", + "public", + "private", + "storage" + ], + "base-os": [ + "common" + ], + "controller": [ + "common", + "public", + "private", + "storage" + ], + "influxdb_grafana": [ + "common", + "public", + "private", + "storage" + ], + "infrastructure_alerting": [ + "common", + "public", + "private", + "storage" + ], + "ceph-mon": [ + "common", + "storage", + "ceph_cluster" + ], + "standalone-rabbitmq": [ + "common", + "public" + ] + }, + "network_scheme": { + "ceph_cluster": { + "endpoints": [ + "br-cluster" + ], + "transformations": [ + { + "action": "add-br", + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "name": "br-cluster", + "mtu": 9000 + }, + { + "action": "add-port", + "bridge": "br-cluster", + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "name": "bond0.343", + "mtu": 9000 + } + ], + "roles": { + "ceph/replication": "br-cluster" + } + }, + "storage": { + "endpoints": [ + "br-storage" + ], + "transformations": [ + { + "action": "add-br", + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "name": "br-storage", + "mtu": 9000 + }, + { + "action": "add-port", + "bridge": "br-storage", + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "name": "bond0.344", + "mtu": 9000 + } + ], + "roles": { + "ceph/radosgw": "br-storage", + "rados_gw_plublic_vip": "br-storage", + "storage": "br-storage", + "cinder/iscsi": "br-storage", + "ceph/public": "br-storage" + } + }, + "public": { + "endpoints": [ + "br-ex" + ], + "transformations": [ + { + "action": "add-br", + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "name": "br-ex", + "mtu": 9000 + }, + { + "action": "add-br", + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "mtu": 9000, + "name": "br-floating", + "provider": "ovs" + }, + { + "action": "add-patch", + "bridges": [ + "br-floating", + "br-ex" + ], + "mtu": 9000, + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "provider": "ovs" + }, + { + "action": "add-port", + "bridge": "br-ex", + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "name": "bond0.345", + "mtu": 9000 + } + ], + "roles": { + "ex": "br-ex", + "neutron/floating": "br-floating", + "public/vip": "br-ex" + } + }, + "private": { + "endpoints": [ + "br-prv" + ], + "transformations": [ + { + "action": "add-br", + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "name": "br-prv", + "mtu": 9000 + }, + { + "action": "add-port", + "bridge": "br-prv", + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "name": "bond0.342", + "mtu": 9000 + } + ], + "roles": { + "neutron/private": "None", + "neutron/mesh": "br-prv" + } + }, + "common": { + "endpoints": [ + "br-fw-admin", + "br-mgmt" + ], + "transformations": [ + { + "action": "add-br", + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "name": "br-fw-admin", + "mtu": 9000 + }, + { + "action": "add-br", + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "name": "br-mgmt", + "mtu": 9000 + }, + { + "action": "add-port", + "bridge": "br-fw-admin", + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "name": "<%if2%>", + "mtu": 9000 + }, + { + "action": "add-port", + "bridge": "br1", + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "name": "<%if3%>.222", + "mtu": 9000 + }, + { + "action": "add-port", + "bridge": "br2", + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "name": "<%if3%>", + "mtu": 9000 + }, + { + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "bond_properties": { + "lacp_rate": "fast", + "mode": "802.3ad", + "xmit_hash_policy": "layer3+4" + }, + "name": "bond0", + "interface_properties": { + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "mtu": 9000 + }, + "action": "add-bond", + "interfaces": [ + "<%if0%>", + "<%if1%>" + ], + "mtu": 9000 + }, + { + "action": "add-port", + "bridge": "br-mgmt", + "ethtool": { + "offload": { + "large-receive-offload": false, + "generic-receive-offload": false + } + }, + "name": "bond0.346", + "mtu": 9000 + }, + { + "action": "add-port", + "name": "port-with-tag-111", + "bridge": "br0", + "vlan_id": 111, + "provider": "ovs" + } + ], + "roles": { + "keystone/api": "br-mgmt", + "neutron/api": "br-mgmt", + "mgmt/database": "br-mgmt", + "sahara/api": "br-mgmt", + "admin/pxe": "br-fw-admin", + "kibana": "br-mgmt", + "mgmt/corosync": "br-mgmt", + "mongo/db": "br-mgmt", + "ceilometer/api": "br-mgmt", + "glance/api": "br-mgmt", + "nova/migration": "br-mgmt", + "rados_gw_management_vip": "br-mgmt", + "mgmt/vip": "br-mgmt", + "fw-admin": "br-fw-admin", + "mgmt/messaging": "br-mgmt", + "management": "br-mgmt", + "swift/api": "br-mgmt", + "heat/api": "br-mgmt", + "mgmt/memcache": "br-mgmt", + "mgmt/api": "br-mgmt", + "murano/api": "br-mgmt", + "infrastructure_alerting_ui": "br-mgmt", + "grafana": "br-mgmt", + "influxdb_vip": "br-mgmt", + "nova/api": "br-mgmt", + "elasticsearch": "br-mgmt", + "horizon": "br-mgmt", + "infrastructure_alerting": "br-mgmt", + "cinder/api": "br-mgmt", + "swift/replication": "br-mgmt" + } + } + }, + "nic_mapping": { + "default": { + "if0": "eno1", + "if1": "eno2", + "if2": "eno3", + "if3": "eno3333" + } + } + } + } }] diff --git a/nailgun/nailgun/test/base.py b/nailgun/nailgun/test/base.py index 65dc76abfb..ceacc50c5b 100644 --- a/nailgun/nailgun/test/base.py +++ b/nailgun/nailgun/test/base.py @@ -457,11 +457,12 @@ class EnvironmentManager(object): Default random MAC is generated for each interface """ nodes = [] + prefix_tpl = kwargs.get('iface_name_prefix', 'eth{0}') for i in range(nodes_count): meta = self.default_metadata() if_list = [ { - "name": "eth{0}".format(i), + "name": prefix_tpl.format(i), "mac": self.generate_random_mac(), } for i in range(if_count)]