blob: c78ff69c8ec990ddb31af66f68cb0343ddc41974 [file] [log] [blame]
Bence Romsics61589652020-09-04 14:49:58 +02001# Copyright 2020 Ericsson Software Technology
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
15import collections
16
17from neutron_lib import constants as nlib_const
18from oslo_log import log as logging
19from tempest.lib.common.utils import data_utils
20from tempest.lib import decorators
21import testtools
22
23from neutron_tempest_plugin.common import ssh
24from neutron_tempest_plugin import config
25from neutron_tempest_plugin.scenario import base
26
27LOG = logging.getLogger(__name__)
28CONF = config.CONF
29
30Server = collections.namedtuple(
31 'Server', ['floating_ip', 'server', 'ssh_client'])
32
33
34class MetadataTest(base.BaseTempestTestCase):
35
36 """Test metadata access over IPv6 tenant subnet.
37
38 Please note that there is metadata over IPv4 test coverage in tempest:
39
40 tempest.scenario.test_server_basic_ops\
41 .TestServerBasicOps.test_server_basic_ops
42 """
43
44 credentials = ['primary', 'admin']
45 force_tenant_isolation = False
46
47 @classmethod
48 def resource_setup(cls):
49 super(MetadataTest, cls).resource_setup()
50 cls.rand_name = data_utils.rand_name(
51 cls.__name__.rsplit('.', 1)[-1])
52 cls.network = cls.create_network(name=cls.rand_name)
53 cls.subnet_v4 = cls.create_subnet(
54 network=cls.network, name=cls.rand_name)
55 cls.subnet_v6 = cls.create_subnet(
56 network=cls.network, name=cls.rand_name, ip_version=6)
57 cls.router = cls.create_router_by_client()
58 cls.create_router_interface(cls.router['id'], cls.subnet_v4['id'])
59 cls.create_router_interface(cls.router['id'], cls.subnet_v6['id'])
60 cls.keypair = cls.create_keypair(name=cls.rand_name)
61 cls.security_group = cls.create_security_group(name=cls.rand_name)
62 cls.create_loginable_secgroup_rule(cls.security_group['id'])
63
64 def _create_server_with_network(self, network, use_advanced_image=False):
65 port = self._create_server_port(network=network)
66 floating_ip = self.create_floatingip(port=port)
67 ssh_client = self._create_ssh_client(
68 floating_ip=floating_ip, use_advanced_image=use_advanced_image)
69 server = self._create_server(port=port,
70 use_advanced_image=use_advanced_image)
71 return Server(
72 floating_ip=floating_ip, server=server, ssh_client=ssh_client)
73
74 def _create_server_port(self, network=None, **params):
75 network = network or self.network
76 return self.create_port(network=network, name=self.rand_name,
77 security_groups=[self.security_group['id']],
78 **params)
79
80 def _create_server(self, port, use_advanced_image=False, **params):
81 if use_advanced_image:
82 flavor_ref = CONF.neutron_plugin_options.advanced_image_flavor_ref
83 image_ref = CONF.neutron_plugin_options.advanced_image_ref
84 else:
85 flavor_ref = CONF.compute.flavor_ref
86 image_ref = CONF.compute.image_ref
87 return self.create_server(flavor_ref=flavor_ref,
88 image_ref=image_ref,
89 key_name=self.keypair['name'],
90 networks=[{'port': port['id']}],
91 **params)['server']
92
93 def _create_ssh_client(self, floating_ip, use_advanced_image=False):
94 if use_advanced_image:
95 username = CONF.neutron_plugin_options.advanced_image_ssh_user
96 else:
97 username = CONF.validation.image_ssh_user
98 return ssh.Client(host=floating_ip['floating_ip_address'],
99 username=username,
100 pkey=self.keypair['private_key'])
101
102 def _assert_has_ssh_connectivity(self, ssh_client):
103 ssh_client.exec_command('true')
104
105 def _get_primary_interface(self, ssh_client):
106 out = ssh_client.exec_command(
107 "ip -6 -br address show scope link up | head -1 | cut -d ' ' -f1")
108 interface = out.strip()
109 if not interface:
110 self.fail(
111 'Could not find a single interface '
112 'with an IPv6 link-local address.')
113 return interface
114
115 @testtools.skipUnless(
116 (CONF.neutron_plugin_options.ipv6_metadata and
117 (CONF.neutron_plugin_options.advanced_image_ref or
118 CONF.neutron_plugin_options.default_image_is_advanced)),
119 'Advanced image and neutron_plugin_options.ipv6_metadata=True '
120 'is required to run this test.')
121 @decorators.idempotent_id('e680949a-f1cc-11ea-b49a-cba39bbbe5ad')
122 def test_metadata_routed(self):
123 use_advanced_image = (
124 not CONF.neutron_plugin_options.default_image_is_advanced)
125
126 vm = self._create_server_with_network(
127 self.network, use_advanced_image=use_advanced_image)
128 self.wait_for_server_active(server=vm.server)
129 self._assert_has_ssh_connectivity(vm.ssh_client)
130 interface = self._get_primary_interface(vm.ssh_client)
131
132 out = vm.ssh_client.exec_command(
133 'curl http://[%(address)s%%25%(interface)s]/' % {
134 'address': nlib_const.METADATA_V6_IP,
135 'interface': interface})
136 self.assertIn('latest', out)
137
138 out = vm.ssh_client.exec_command(
139 'curl http://[%(address)s%%25%(interface)s]/openstack/' % {
140 'address': nlib_const.METADATA_V6_IP,
141 'interface': interface})
142 self.assertIn('latest', out)