Browse Source

Add test_sriov_instance_connectivity

+Add corresponding test
+Add _create_port
+Add _cleanup_ports
+Add sriov deployment tag if computes with SR-IOV enabled interface
are present and unit-tests for ostf-adapter
+Add sriov_enabled physnets to cluster config

Change-Id: I487c0dc0f4756b893af5d5c59ea85ba0d47faa5c
Closes-Bug: #1566906
Implements: blueprint test-sriov-support
tags/9.0.1
Volodymyr Shypyguzov 3 years ago
parent
commit
dee7b92c2e

+ 15
- 4
fuel_health/config.py View File

@@ -719,8 +719,8 @@ class NailgunConfig(object):
719 719
         compute_nodes = filter(lambda node: 'compute' in node['roles'],
720 720
                                data)
721 721
         online_computes = filter(
722
-            lambda node: 'compute' in node['roles']
723
-            and node['online'] is True, data)
722
+            lambda node: 'compute' in node['roles'] and
723
+                         node['online'] is True, data)
724 724
         online_computes_ips = []
725 725
         for node in online_computes:
726 726
             online_computes_ips.append(node['ip'])
@@ -730,14 +730,25 @@ class NailgunConfig(object):
730 730
         for node in compute_nodes:
731 731
             compute_ips.append(node['ip'])
732 732
         LOG.info("COMPUTES IPS %s" % compute_ips)
733
+        sriov_physnets = []
734
+        compute_ids = [node['id'] for node in online_computes]
735
+        for compute_id in compute_ids:
736
+            api_url = '/api/nodes/{}/interfaces'.format(compute_id)
737
+            ifaces_resp = self.req_session.get(
738
+                self.nailgun_url + api_url).json()
739
+            for iface in ifaces_resp:
740
+                if iface['interface_properties']['sriov']['enabled']:
741
+                    sriov_physnets.append(
742
+                        iface['interface_properties']['sriov']['physnet'])
743
+        self.compute.sriov_physnets = sriov_physnets
733 744
         self.compute.compute_nodes = compute_ips
734 745
         ceph_nodes = filter(lambda node: 'ceph-osd' in node['roles'],
735 746
                             data)
736 747
         self.compute.ceph_nodes = ceph_nodes
737 748
 
738 749
         online_ironic = filter(
739
-            lambda node: 'ironic' in node['roles']
740
-            and node['online'] is True, data)
750
+            lambda node: 'ironic' in node['roles'] and
751
+                         node['online'] is True, data)
741 752
         self.ironic.online_conductors = []
742 753
         for node in online_ironic:
743 754
             self.ironic.online_conductors.append(node['ip'])

+ 11
- 0
fuel_health/neutronmanager.py View File

@@ -31,6 +31,7 @@ class NeutronBaseTest(fuel_health.nmanager.NovaNetworkScenarioTest):
31 31
         cls.networks = []
32 32
         cls.floating_ips = []
33 33
         cls.security_groups = {}
34
+        cls.ports = []
34 35
 
35 36
     def setUp(self):
36 37
         super(NeutronBaseTest, self).setUp()
@@ -172,8 +173,18 @@ class NeutronBaseTest(fuel_health.nmanager.NovaNetworkScenarioTest):
172 173
             cls.error_msg.append(exc)
173 174
             LOG.debug(traceback.format_exc())
174 175
 
176
+    @classmethod
177
+    def _cleanup_ports(cls):
178
+        for port in cls.ports:
179
+            try:
180
+                cls.neutron_client.delete_port(port['port']['id'])
181
+            except Exception as exc:
182
+                cls.error_msg.append(exc)
183
+                LOG.debug(traceback.format_exc())
184
+
175 185
     @classmethod
176 186
     def tearDownClass(cls):
177 187
         super(NeutronBaseTest, cls)
178 188
         cls._clean_floating_ips()
179 189
         cls._clear_networks()
190
+        cls._cleanup_ports()

+ 30
- 9
fuel_health/nmanager.py View File

@@ -569,6 +569,7 @@ class NovaNetworkScenarioTest(OfficialClientTest):
569 569
             cls.error_msg = []
570 570
             cls.flavors = []
571 571
             cls.images = []
572
+            cls.ports = []
572 573
             cls.private_net = cls.config.network.private_net
573 574
 
574 575
     def setUp(self):
@@ -654,6 +655,22 @@ class NovaNetworkScenarioTest(OfficialClientTest):
654 655
                                           "Network creation failed")
655 656
         return networks
656 657
 
658
+    def _create_port(self, net_id, vnic_type, label='ost1_test-port-'):
659
+        n_label = rand_name(label)
660
+        port_data = {
661
+            'name': n_label,
662
+            'binding:vnic_type': vnic_type,
663
+            'network_id': net_id,
664
+        }
665
+        port = self.neutron_client.create_port({'port': port_data})
666
+        self.set_resource(n_label, port)
667
+        self.ports.append(port)
668
+        LOG.debug(port)
669
+        self.verify_response_body_content(port['port']['name'],
670
+                                          n_label,
671
+                                          "Port creation failed")
672
+        return port
673
+
657 674
     @classmethod
658 675
     def _clear_networks(cls):
659 676
         try:
@@ -680,7 +697,8 @@ class NovaNetworkScenarioTest(OfficialClientTest):
680 697
 
681 698
     def _create_server(self, client, name, security_groups=None,
682 699
                        flavor_id=None, net_id=None, img_name=None,
683
-                       data_file=None, az_name=None):
700
+                       data_file=None, az_name=None, port=None):
701
+        create_kwargs = {}
684 702
 
685 703
         if img_name:
686 704
             base_image_id = self.get_image_from_name(img_name=img_name)
@@ -702,6 +720,7 @@ class NovaNetworkScenarioTest(OfficialClientTest):
702 720
             security_groups = [self._create_security_group(
703 721
                 self.compute_client).name]
704 722
         if 'neutron' in self.config.network.network_provider:
723
+            create_kwargs['nics'] = []
705 724
             if net_id:
706 725
                 network = [net_id]
707 726
             else:
@@ -709,15 +728,17 @@ class NovaNetworkScenarioTest(OfficialClientTest):
709 728
                            self.compute_client.networks.list()
710 729
                            if net.label == self.private_net]
711 730
 
712
-            if network:
713
-                create_kwargs = {'nics': [{'net-id': network[0]}],
714
-                                 'security_groups': security_groups}
731
+            if port:
732
+                create_kwargs['nics'].append({'port-id': port['port']['id']})
715 733
             else:
716
-                self.fail("Default private network '{0}' isn't present. "
717
-                          "Please verify it is properly created.".
718
-                          format(self.private_net))
719
-        else:
720
-            create_kwargs = {'security_groups': security_groups}
734
+                if network:
735
+                    create_kwargs['nics'].append({'net-id': network[0]})
736
+                else:
737
+                    self.fail("Default private network '{0}' isn't present. "
738
+                              "Please verify it is properly created.".
739
+                              format(self.private_net))
740
+
741
+        create_kwargs['security_groups'] = security_groups
721 742
 
722 743
         server = client.servers.create(name, base_image_id,
723 744
                                        flavor_id, files=data_file,

+ 96
- 0
fuel_health/tests/smoke/test_neutron_actions.py View File

@@ -144,3 +144,99 @@ class TestNeutron(neutronmanager.NeutronBaseTest):
144 144
                     "Subnet deletion", subnet)
145 145
         self.verify(20, self._remove_network, 16,
146 146
                     "Network can not be deleted", "Network deletion", network)
147
+
148
+    def test_check_sriov_instance_connectivity(self):
149
+            """Check network connectivity from SRIOV instance via floating IP
150
+            Target component: Neutron
151
+
152
+            Scenario:
153
+                1. Create a new security group (if it doesn't exist yet).
154
+                2. Create SR-IOV port
155
+                3. Create an instance using new security group and SR-IOV port.
156
+                4. Create new floating IP
157
+                5. Assign created floating IP to the instance.
158
+                6. Check connectivity to the floating IP using ping command.
159
+                7. Check that public IP 8.8.8.8 can be pinged from instance.
160
+                8. Disassociate server floating ip.
161
+                9. Delete floating ip
162
+                10. Delete server.
163
+                11. Delete SR-IOV port
164
+            Duration: 300 s.
165
+
166
+            Deployment tags: sriov
167
+            """
168
+            if 'physnet2' not in self.config.compute.sriov_physnets:
169
+                self.skipTest('physnet2 is not configured for any interface')
170
+            self.check_image_exists()
171
+            if not self.security_groups:
172
+                self.security_groups[self.tenant_id] = self.verify(
173
+                    25, self._create_security_group, 1,
174
+                    "Security group can not be created.",
175
+                    'security group creation',
176
+                    self.compute_client)
177
+
178
+            name = rand_name('ost1_test-server-sriov-')
179
+            security_groups = [self.security_groups[self.tenant_id].name]
180
+
181
+            network = [net.id for net in
182
+                       self.compute_client.networks.list()
183
+                       if net.label == self.private_net]
184
+
185
+            port = self.verify(
186
+                20,
187
+                self._create_port,
188
+                2,
189
+                "SRIOV port can not be created.",
190
+                'SRIOV port creation',
191
+                net_id=network[0], vnic_type='direct')
192
+
193
+            server = self.verify(250, self._create_server, 3,
194
+                                 "Server can not be created.",
195
+                                 "server creation",
196
+                                 self.compute_client, name, security_groups,
197
+                                 port=port, net_id=network[0])
198
+
199
+            floating_ip = self.verify(
200
+                20,
201
+                self._create_floating_ip,
202
+                4,
203
+                "Floating IP can not be created.",
204
+                'floating IP creation')
205
+
206
+            self.verify(20, self._assign_floating_ip_to_instance,
207
+                        5, "Floating IP can not be assigned.",
208
+                        'floating IP assignment',
209
+                        self.compute_client, server, floating_ip)
210
+
211
+            self.floating_ips.append(floating_ip)
212
+
213
+            ip_address = floating_ip.ip
214
+            LOG.info('is address is  {0}'.format(ip_address))
215
+            LOG.debug(ip_address)
216
+
217
+            self.verify(600, self._check_vm_connectivity, 6,
218
+                        "VM connectivity doesn`t function properly.",
219
+                        'VM connectivity checking', ip_address,
220
+                        30, (5, 10))
221
+
222
+            self.verify(600, self._check_connectivity_from_vm,
223
+                        7, ("Connectivity to 8.8.8.8 from the VM doesn`t "
224
+                            "function properly."),
225
+                        'public connectivity checking from VM', ip_address,
226
+                        30, (5, 10))
227
+
228
+            self.verify(20, self.compute_client.servers.remove_floating_ip,
229
+                        8, "Floating IP cannot be removed.",
230
+                        "removing floating IP", server, floating_ip)
231
+
232
+            self.verify(20, self.compute_client.floating_ips.delete,
233
+                        9, "Floating IP cannot be deleted.",
234
+                        "floating IP deletion", floating_ip)
235
+
236
+            self.verify(30, self._delete_server, 10,
237
+                        "Server can not be deleted. ",
238
+                        "server deletion", server)
239
+
240
+            self.verify(30, self.neutron_client.delete_port, 11,
241
+                        "Port can not be deleted. ",
242
+                        "port deletion", port['port']['id'])

+ 14
- 0
fuel_plugin/ostf_adapter/mixins.py View File

@@ -160,7 +160,21 @@ def _get_cluster_attrs(cluster_id, token=None):
160 160
     enable_without_ceph = filter(lambda node: 'ceph-osd' in node['roles'],
161 161
                                  nodes_response)
162 162
 
163
+    sriov_compute_ids = []
164
+    compute_ids = [node['id'] for node in nodes_response
165
+                   if "compute" in node['roles']]
166
+    for compute_id in compute_ids:
167
+        ifaces_url = URL.format(
168
+            cfg.CONF.adapter.nailgun_host, cfg.CONF.adapter.nailgun_port,
169
+            'api/nodes/{id}/interfaces'.format(id=compute_id))
170
+        ifaces_resp = REQ_SES.get(ifaces_url).json()
171
+        for iface in ifaces_resp:
172
+            if iface['interface_properties']['sriov']['enabled']:
173
+                sriov_compute_ids.append(compute_id)
174
+
163 175
     deployment_tags = set()
176
+    if sriov_compute_ids:
177
+        deployment_tags.add('sriov')
164 178
     if not enable_without_ceph:
165 179
         deployment_tags.add('enable_without_ceph')
166 180
 

+ 41
- 1
fuel_plugin/testing/tests/base.py View File

@@ -147,7 +147,47 @@ CLUSTERS = {
147 147
                 'common': {}
148 148
             }
149 149
         }
150
-    }
150
+    },
151
+    7: {
152
+        'cluster_meta': {
153
+            'release_id': 7,
154
+            'mode': 'ha'
155
+        },
156
+        'release_data': {
157
+            'operating_system': 'rhel',
158
+            'version': '2015.2-1.0',
159
+        },
160
+        'cluster_node': [
161
+            {
162
+                "hostname": "node-1",
163
+                'id': "1",
164
+                'roles': "compute"
165
+            },
166
+        ],
167
+        'node_interfaces': [
168
+            {
169
+                'interface_properties': {
170
+                    'sriov': {
171
+                        'enabled': 'true'
172
+                    }
173
+                }
174
+
175
+            }
176
+        ],
177
+        'cluster_attributes': {
178
+            'editable': {
179
+                'additional_components': {
180
+                    'murano': {
181
+                        'value': True
182
+                    },
183
+                    'sahara': {
184
+                        'value': False
185
+                    }
186
+                },
187
+                'common': {}
188
+            }
189
+        }
190
+    },
151 191
 }
152 192
 
153 193
 

+ 28
- 0
fuel_plugin/testing/tests/unit/test_support_utilities.py View File

@@ -49,3 +49,31 @@ class TestDeplTagsGetter(base.BaseUnitTest):
49 49
             res = mixins._get_cluster_attrs(expected['cluster_id'])
50 50
 
51 51
         self.assertEqual(res, expected['attrs'])
52
+
53
+    def test_sriov_deployment_tag(self):
54
+        expected = {
55
+            'cluster_id': 7,
56
+            'attrs': {
57
+                'deployment_tags': set(
58
+                    ['ha', 'rhel', 'additional_components',
59
+                     'murano', 'nova_network', 'public_on_all_nodes',
60
+                     'enable_without_ceph', 'sriov']),
61
+                'release_version': '2015.2-1.0'
62
+            }
63
+        }
64
+
65
+        with requests_mock.Mocker() as m:
66
+            cluster = base.CLUSTERS[expected['cluster_id']]
67
+            m.register_uri('GET', '/api/clusters/7',
68
+                           json=cluster['cluster_meta'])
69
+            m.register_uri('GET', '/api/clusters/7/attributes',
70
+                           json=cluster['cluster_attributes'])
71
+            m.register_uri('GET', '/api/releases/7',
72
+                           json=cluster['release_data'])
73
+            m.register_uri('GET', '/api/nodes?cluster_id=7',
74
+                           json=cluster['cluster_node'])
75
+            m.register_uri('GET', '/api/nodes/1/interfaces',
76
+                           json=cluster['node_interfaces'])
77
+            res = mixins._get_cluster_attrs(expected['cluster_id'])
78
+
79
+        self.assertEqual(res, expected['attrs'])

Loading…
Cancel
Save