blob: ac18ab5e8fcc9e131b77581ad7b87494d5616d61 [file] [log] [blame]
Itzik Browne67ebb52016-05-15 05:34:41 +00001# Copyright 2016 Red Hat, Inc.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
Itzik Browne67ebb52016-05-15 05:34:41 +000015
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090016import netaddr
Alex Stafeyevc4d9c352016-12-12 04:13:33 -050017from oslo_log import log
18
Itzik Browne67ebb52016-05-15 05:34:41 +000019from tempest.common import waiters
Itzik Browne67ebb52016-05-15 05:34:41 +000020from tempest.lib.common.utils import data_utils
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090021from tempest.lib.common.utils import test_utils
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -050022from tempest.lib import exceptions as lib_exc
Itzik Browne67ebb52016-05-15 05:34:41 +000023
24from neutron.tests.tempest.api import base as base_api
Jakub Libosvar7c58cb22017-05-03 09:00:14 +000025from neutron.tests.tempest.common import ssh
Itzik Browne67ebb52016-05-15 05:34:41 +000026from neutron.tests.tempest import config
27from neutron.tests.tempest.scenario import constants
28
29CONF = config.CONF
Itzik Browne67ebb52016-05-15 05:34:41 +000030
Alex Stafeyevc4d9c352016-12-12 04:13:33 -050031LOG = log.getLogger(__name__)
32
Itzik Browne67ebb52016-05-15 05:34:41 +000033
34class BaseTempestTestCase(base_api.BaseNetworkTest):
35 @classmethod
36 def resource_setup(cls):
37 super(BaseTempestTestCase, cls).resource_setup()
38
Itzik Browne67ebb52016-05-15 05:34:41 +000039 cls.keypairs = []
40
41 @classmethod
42 def resource_cleanup(cls):
Itzik Browne67ebb52016-05-15 05:34:41 +000043 for keypair in cls.keypairs:
rajat294495c042017-06-28 15:37:16 +053044 cls.os_primary.keypairs_client.delete_keypair(
Itzik Browne67ebb52016-05-15 05:34:41 +000045 keypair_name=keypair['name'])
46
47 super(BaseTempestTestCase, cls).resource_cleanup()
48
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +000049 def create_server(self, flavor_ref, image_ref, key_name, networks,
Itzik Brownbac51dc2016-10-31 12:25:04 +000050 name=None, security_groups=None):
51 """Create a server using tempest lib
52 All the parameters are the ones used in Compute API
53
54 Args:
55 flavor_ref(str): The flavor of the server to be provisioned.
56 image_ref(str): The image of the server to be provisioned.
57 key_name(str): SSH key to to be used to connect to the
58 provisioned server.
59 networks(list): List of dictionaries where each represent
60 an interface to be attached to the server. For network
61 it should be {'uuid': network_uuid} and for port it should
62 be {'port': port_uuid}
63 name(str): Name of the server to be provisioned.
64 security_groups(list): List of dictionaries where
65 the keys is 'name' and the value is the name of
66 the security group. If it's not passed the default
67 security group will be used.
68 """
69
Itzik Browne67ebb52016-05-15 05:34:41 +000070 name = name or data_utils.rand_name('server-test')
Itzik Brownbac51dc2016-10-31 12:25:04 +000071 if not security_groups:
72 security_groups = [{'name': 'default'}]
73
Brian Haleyf86ac2e2017-06-21 10:43:50 -040074 server = self.os_primary.servers_client.create_server(
Itzik Brownbac51dc2016-10-31 12:25:04 +000075 name=name,
76 flavorRef=flavor_ref,
Itzik Browne67ebb52016-05-15 05:34:41 +000077 imageRef=image_ref,
78 key_name=key_name,
Itzik Brownbac51dc2016-10-31 12:25:04 +000079 networks=networks,
80 security_groups=security_groups)
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +000081
82 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
83 waiters.wait_for_server_termination,
Brian Haleyf86ac2e2017-06-21 10:43:50 -040084 self.os_primary.servers_client, server['server']['id'])
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +000085 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Brian Haleyf86ac2e2017-06-21 10:43:50 -040086 self.os_primary.servers_client.delete_server,
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +000087 server['server']['id'])
Itzik Browne67ebb52016-05-15 05:34:41 +000088 return server
89
90 @classmethod
91 def create_keypair(cls, client=None):
rajat294495c042017-06-28 15:37:16 +053092 client = client or cls.os_primary.keypairs_client
Itzik Browne67ebb52016-05-15 05:34:41 +000093 name = data_utils.rand_name('keypair-test')
94 body = client.create_keypair(name=name)
95 cls.keypairs.append(body['keypair'])
96 return body['keypair']
97
98 @classmethod
Itzik Brown1ef813a2016-06-06 12:56:21 +000099 def create_secgroup_rules(cls, rule_list, secgroup_id=None):
rajat294495c042017-06-28 15:37:16 +0530100 client = cls.os_primary.network_client
Itzik Browne67ebb52016-05-15 05:34:41 +0000101 if not secgroup_id:
102 sgs = client.list_security_groups()['security_groups']
103 for sg in sgs:
104 if sg['name'] == constants.DEFAULT_SECURITY_GROUP:
105 secgroup_id = sg['id']
106 break
107
Itzik Brown1ef813a2016-06-06 12:56:21 +0000108 for rule in rule_list:
109 direction = rule.pop('direction')
110 client.create_security_group_rule(
111 direction=direction,
112 security_group_id=secgroup_id,
113 **rule)
114
115 @classmethod
116 def create_loginable_secgroup_rule(cls, secgroup_id=None):
117 """This rule is intended to permit inbound ssh
118
119 Allowing ssh traffic traffic from all sources, so no group_id is
120 provided.
121 Setting a group_id would only permit traffic from ports
122 belonging to the same security group.
123 """
124
125 rule_list = [{'protocol': 'tcp',
126 'direction': 'ingress',
127 'port_range_min': 22,
128 'port_range_max': 22,
129 'remote_ip_prefix': '0.0.0.0/0'}]
130 cls.create_secgroup_rules(rule_list, secgroup_id=secgroup_id)
Itzik Browne67ebb52016-05-15 05:34:41 +0000131
132 @classmethod
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900133 def create_pingable_secgroup_rule(cls, secgroup_id=None):
134 """This rule is intended to permit inbound ping
135 """
136
137 rule_list = [{'protocol': 'icmp',
138 'direction': 'ingress',
139 'port_range_min': 8, # type
140 'port_range_max': 0, # code
141 'remote_ip_prefix': '0.0.0.0/0'}]
142 cls.create_secgroup_rules(rule_list, secgroup_id=secgroup_id)
143
144 @classmethod
Genadi Chereshnyac0411e92016-07-11 16:59:42 +0300145 def create_router_by_client(cls, is_admin=False, **kwargs):
146 kwargs.update({'router_name': data_utils.rand_name('router'),
147 'admin_state_up': True,
148 'external_network_id': CONF.network.public_network_id})
149 if not is_admin:
150 router = cls.create_router(**kwargs)
151 else:
152 router = cls.create_admin_router(**kwargs)
Alex Stafeyevc4d9c352016-12-12 04:13:33 -0500153 LOG.debug("Created router %s", router['name'])
Itzik Browne67ebb52016-05-15 05:34:41 +0000154 cls.routers.append(router)
155 return router
156
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000157 def create_and_associate_floatingip(self, port_id):
Brian Haleyf86ac2e2017-06-21 10:43:50 -0400158 fip = self.os_primary.network_client.create_floatingip(
Itzik Browne67ebb52016-05-15 05:34:41 +0000159 CONF.network.public_network_id,
160 port_id=port_id)['floatingip']
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000161 self.floating_ips.append(fip)
Itzik Browne67ebb52016-05-15 05:34:41 +0000162 return fip
163
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000164 def setup_network_and_server(self, router=None, **kwargs):
Genadi Chereshnyac0411e92016-07-11 16:59:42 +0300165 """Create network resources and a server.
Itzik Brownbac51dc2016-10-31 12:25:04 +0000166
167 Creating a network, subnet, router, keypair, security group
168 and a server.
169 """
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000170 self.network = self.create_network()
171 LOG.debug("Created network %s", self.network['name'])
172 self.subnet = self.create_subnet(self.network)
173 LOG.debug("Created subnet %s", self.subnet['id'])
Itzik Brown1ef813a2016-06-06 12:56:21 +0000174
Brian Haleyf86ac2e2017-06-21 10:43:50 -0400175 secgroup = self.os_primary.network_client.create_security_group(
Itzik Brownbac51dc2016-10-31 12:25:04 +0000176 name=data_utils.rand_name('secgroup-'))
Alex Stafeyevc4d9c352016-12-12 04:13:33 -0500177 LOG.debug("Created security group %s",
178 secgroup['security_group']['name'])
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000179 self.security_groups.append(secgroup['security_group'])
Genadi Chereshnyac0411e92016-07-11 16:59:42 +0300180 if not router:
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000181 router = self.create_router_by_client(**kwargs)
182 self.create_router_interface(router['id'], self.subnet['id'])
183 self.keypair = self.create_keypair()
184 self.create_loginable_secgroup_rule(
Itzik Brownbac51dc2016-10-31 12:25:04 +0000185 secgroup_id=secgroup['security_group']['id'])
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000186 self.server = self.create_server(
Itzik Brown1ef813a2016-06-06 12:56:21 +0000187 flavor_ref=CONF.compute.flavor_ref,
188 image_ref=CONF.compute.image_ref,
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000189 key_name=self.keypair['name'],
190 networks=[{'uuid': self.network['id']}],
Itzik Brownbac51dc2016-10-31 12:25:04 +0000191 security_groups=[{'name': secgroup['security_group']['name']}])
Brian Haleyf86ac2e2017-06-21 10:43:50 -0400192 waiters.wait_for_server_status(self.os_primary.servers_client,
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000193 self.server['server']['id'],
Itzik Brown1ef813a2016-06-06 12:56:21 +0000194 constants.SERVER_STATUS_ACTIVE)
Jakub Libosvar1345d9d2017-06-09 13:59:05 +0000195 self.port = self.client.list_ports(network_id=self.network['id'],
196 device_id=self.server[
197 'server']['id'])['ports'][0]
198 self.fip = self.create_and_associate_floatingip(self.port['id'])
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500199
200 def check_connectivity(self, host, ssh_user, ssh_key, servers=None):
201 ssh_client = ssh.Client(host, ssh_user, pkey=ssh_key)
202 try:
203 ssh_client.test_connection_auth()
204 except lib_exc.SSHTimeout as ssh_e:
205 LOG.debug(ssh_e)
206 self._log_console_output(servers)
207 raise
208
209 def _log_console_output(self, servers=None):
210 if not CONF.compute_feature_enabled.console_output:
211 LOG.debug('Console output not supported, cannot log')
212 return
213 if not servers:
Brian Haleyf86ac2e2017-06-21 10:43:50 -0400214 servers = self.os_primary.servers_client.list_servers()
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500215 servers = servers['servers']
216 for server in servers:
217 try:
218 console_output = (
Brian Haleyf86ac2e2017-06-21 10:43:50 -0400219 self.os_primary.servers_client.get_console_output(
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500220 server['id'])['output'])
221 LOG.debug('Console output for %s\nbody=\n%s',
222 server['id'], console_output)
223 except lib_exc.NotFound:
224 LOG.debug("Server %s disappeared(deleted) while looking "
225 "for the console log", server['id'])
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900226
227 def _check_remote_connectivity(self, source, dest, should_succeed=True,
228 nic=None):
229 """check ping server via source ssh connection
230
231 :param source: RemoteClient: an ssh connection from which to ping
232 :param dest: and IP to ping against
233 :param should_succeed: boolean should ping succeed or not
234 :param nic: specific network interface to ping from
235 :returns: boolean -- should_succeed == ping
236 :returns: ping is false if ping failed
237 """
238 def ping_host(source, host, count=CONF.validation.ping_count,
239 size=CONF.validation.ping_size, nic=None):
240 addr = netaddr.IPAddress(host)
241 cmd = 'ping6' if addr.version == 6 else 'ping'
242 if nic:
243 cmd = 'sudo {cmd} -I {nic}'.format(cmd=cmd, nic=nic)
244 cmd += ' -c{0} -w{0} -s{1} {2}'.format(count, size, host)
245 return source.exec_command(cmd)
246
247 def ping_remote():
248 try:
249 result = ping_host(source, dest, nic=nic)
250
251 except lib_exc.SSHExecCommandFailed:
252 LOG.warning('Failed to ping IP: %s via a ssh connection '
253 'from: %s.', dest, source.host)
254 return not should_succeed
255 LOG.debug('ping result: %s', result)
256 # Assert that the return traffic was from the correct
257 # source address.
258 from_source = 'from %s' % dest
259 self.assertIn(from_source, result)
260 return should_succeed
261
262 return test_utils.call_until_true(ping_remote,
263 CONF.validation.ping_timeout,
264 1)
265
266 def check_remote_connectivity(self, source, dest, should_succeed=True,
267 nic=None):
268 self.assertTrue(self._check_remote_connectivity(
269 source, dest, should_succeed, nic))