blob: 89b31a7e08c947ff11158bd15d3675469fc31542 [file] [log] [blame]
Itzik Brown1ef813a2016-06-06 12:56:21 +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.
15import errno
16import socket
17import time
18
19from oslo_log import log as logging
20from tempest.lib.common import ssh
21from tempest.lib import exceptions
22from tempest import test
23
24from neutron.common import utils
25from neutron.tests.tempest import config
26from neutron.tests.tempest.scenario import base
27from neutron.tests.tempest.scenario import constants
28from neutron.tests.tempest.scenario import exceptions as sc_exceptions
29
30CONF = config.CONF
31LOG = logging.getLogger(__name__)
32
33
34def _try_connect(host_ip, port):
35 try:
36 client_socket = socket.socket(socket.AF_INET,
37 socket.SOCK_STREAM)
38 client_socket.connect((host_ip, port))
39 client_socket.setblocking(0)
40 return client_socket
41 except socket.error as serr:
42 if serr.errno == errno.ECONNREFUSED:
43 raise sc_exceptions.SocketConnectionRefused(host=host_ip,
44 port=port)
45 else:
46 raise
47
48
49def _connect_socket(host, port):
50 """Try to initiate a connection to a host using an ip address
51 and a port.
52
53 Trying couple of times until a timeout is reached in case the listening
54 host is not ready yet.
55 """
56
57 start = time.time()
58 while True:
59 try:
60 return _try_connect(host, port)
61 except sc_exceptions.SocketConnectionRefused:
62 if time.time() - start > constants.SOCKET_CONNECT_TIMEOUT:
63 raise sc_exceptions.ConnectionTimeoutException(host=host,
64 port=port)
65
66
67class QoSTest(base.BaseTempestTestCase):
68 credentials = ['primary', 'admin']
69 force_tenant_isolation = False
70
71 BUFFER_SIZE = 1024 * 1024
72 TOLERANCE_FACTOR = 1.5
73 BS = 512
74 COUNT = BUFFER_SIZE / BS
75 FILE_SIZE = BS * COUNT
76 LIMIT_BYTES_SEC = (constants.LIMIT_KILO_BITS_PER_SECOND * 1024
77 * TOLERANCE_FACTOR / 8.0)
78 FILE_PATH = "/tmp/img"
79
YAMAMOTO Takashica174642016-07-15 15:01:31 +090080 @classmethod
81 @test.requires_ext(extension="qos", service="network")
82 def resource_setup(cls):
83 super(QoSTest, cls).resource_setup()
84
Itzik Brown1ef813a2016-06-06 12:56:21 +000085 def _create_file_for_bw_tests(self, ssh_client):
86 cmd = ("(dd if=/dev/zero bs=%(bs)d count=%(count)d of=%(file_path)s) "
87 % {'bs': QoSTest.BS, 'count': QoSTest.COUNT,
88 'file_path': QoSTest.FILE_PATH})
89 ssh_client.exec_command(cmd)
90 cmd = "stat -c %%s %s" % QoSTest.FILE_PATH
91 filesize = ssh_client.exec_command(cmd)
92 if int(filesize.strip()) != QoSTest.FILE_SIZE:
93 raise sc_exceptions.FileCreationFailedException(
94 file=QoSTest.FILE_PATH)
95
96 def _check_bw(self, ssh_client, host, port):
97 total_bytes_read = 0
98 cycle_start_time = time.time()
99 cycle_data_read = 0
100
101 cmd = "killall -q nc"
102 try:
103 ssh_client.exec_command(cmd)
104 except exceptions.SSHExecCommandFailed:
105 pass
106 cmd = ("(nc -ll -p %(port)d < %(file_path)s > /dev/null &)" % {
107 'port': port, 'file_path': QoSTest.FILE_PATH})
108 ssh_client.exec_command(cmd)
109 client_socket = _connect_socket(host, port)
110
111 while total_bytes_read < QoSTest.FILE_SIZE:
112 try:
113 data = client_socket.recv(QoSTest.BUFFER_SIZE)
114 except socket.error as e:
115 if e.args[0] in [errno.EAGAIN, errno.EWOULDBLOCK]:
116 continue
117 else:
118 raise
119 total_bytes_read += len(data)
120 cycle_data_read += len(data)
121 time_elapsed = time.time() - cycle_start_time
122 should_check = (time_elapsed >= 5 or
123 total_bytes_read == QoSTest.FILE_SIZE)
124 if should_check:
125 LOG.debug("time_elapsed = %(time_elapsed)d,"
126 "total_bytes_read = %(bytes_read)d,"
127 "cycle_data_read = %(cycle_data)d",
128 {"time_elapsed": time_elapsed,
129 "bytes_read": total_bytes_read,
130 "cycle_data": cycle_data_read})
131
132 if cycle_data_read / time_elapsed > QoSTest.LIMIT_BYTES_SEC:
133 # Limit reached
134 return False
135 else:
136 cycle_start_time = time.time()
137 cycle_data_read = 0
138 return True
139
140 @test.idempotent_id('1f7ed39b-428f-410a-bd2b-db9f465680df')
141 def test_qos(self):
142 """This is a basic test that check that a QoS policy with
143
144 a bandwidth limit rule is applied correctly by sending
145 a file from the instance to the test node.
146 Then calculating the bandwidth every ~1 sec by the number of bits
147 received / elapsed time.
148 """
149
150 NC_PORT = 1234
151
152 self.setup_network_and_server()
153 self.check_connectivity(self.fip['floating_ip_address'],
154 CONF.validation.image_ssh_user,
155 self.keypair['private_key'])
156 rulesets = [{'protocol': 'tcp',
157 'direction': 'ingress',
158 'port_range_min': NC_PORT,
159 'port_range_max': NC_PORT,
160 'remote_ip_prefix': '0.0.0.0/0'}]
161 self.create_secgroup_rules(rulesets)
162 ssh_client = ssh.Client(self.fip['floating_ip_address'],
163 CONF.validation.image_ssh_user,
164 pkey=self.keypair['private_key'])
165 policy = self.admin_manager.network_client.create_qos_policy(
166 name='test-policy',
167 description='test-qos-policy',
168 shared=True)
169 policy_id = policy['policy']['id']
170 self.admin_manager.network_client.create_bandwidth_limit_rule(
171 policy_id, max_kbps=constants.LIMIT_KILO_BITS_PER_SECOND,
172 max_burst_kbps=constants.LIMIT_KILO_BITS_PER_SECOND)
173 port = self.client.list_ports(network_id=self.network['id'],
174 device_id=self.server[
175 'server']['id'])['ports'][0]
176 self.admin_manager.network_client.update_port(port['id'],
177 qos_policy_id=policy_id)
178 self._create_file_for_bw_tests(ssh_client)
179 utils.wait_until_true(lambda: self._check_bw(
180 ssh_client,
181 self.fip['floating_ip_address'],
182 port=NC_PORT),
183 timeout=120,
184 sleep=1)