Roman Safronov 8741bffcfa Add test_qos.py tests
Moved almost all tests from the downstream test_qos.py except
test_qos_user_policies that was intended for non-RBAC environments.
The test can be handled later in another patch, if needed.

Added window_size parameter for tweaking iperf functionality.

Updated test uuids in order to distinguish between d/s tests.

Changed node to ubuntu (nested-virt-ubuntu-jammy) in order to
overcome node_failure zuul issues with centos-9-stream.

Change-Id: Ieda4ed56a0c69b97ac0c0584faad8be8dc5006ca
2024-03-19 02:29:30 +02:00

138 lines
5.1 KiB
Python

# Copyright 2019 Red Hat, Inc.
# All Rights Reserved.
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import time
import fixtures
from oslo_log import log
from scapy.all import ICMP
from scapy.all import rdpcap
from tempest import config
from tempest.lib import exceptions
from whitebox_neutron_tempest_plugin.common import utils
CONF = config.CONF
LOG = log.getLogger(__name__)
class TcpdumpCapture(fixtures.Fixture):
capture_files = None
processes = None
def __init__(self, client, interfaces, filter_str=''):
self.client = client
self.interfaces = [ifc.strip() for ifc in interfaces.split(',')]
self.filter_str = filter_str
self.timeout = CONF.whitebox_neutron_plugin_options.capture_timeout
def _setUp(self):
self.start()
def start(self):
if not self.capture_files:
# mktemp needs to be executed with sudo - otherwise the later
# tcpdump command (run with sudo) fails because the created temp
# file cannot be written
# This happens in RHEL9 because fs.protected_regular is enabled
self.capture_files = []
self.processes = []
for interface in self.interfaces:
process = self.client.open_session()
capture_file = self.client.exec_command('sudo mktemp').rstrip()
cmd = 'sudo timeout {} tcpdump -s0 -Uni {} {} -w {}'.format(
self.timeout, interface, self.filter_str,
capture_file)
self.capture_files.append(capture_file)
LOG.debug('Executing command: {}'.format(cmd))
process.exec_command(cmd)
self.processes.append(process)
self.addCleanup(self.cleanup)
def stop(self):
for process in (self.processes or []):
process.close()
self.processes = None
def cleanup(self):
self.stop()
if self.capture_files:
if utils.host_responds_to_ping(self.client.host):
self.client.exec_command(
'sudo rm -f ' + ' '.join(self.capture_files))
self.capture_files = None
def is_empty(self):
try:
pcap = rdpcap(self._open_capture_file())
except Exception as e:
LOG.debug('Error reading pcap file: ', str(e))
return True
for record in pcap:
return False
return True
def get_next_hop_mtu(self):
pcap = rdpcap(self._open_capture_file())
for record in pcap:
if 'IP' in record and 'ICMP' in record:
icmp = record[ICMP]
# ICMP type 3 = Destionation Unreachable
if icmp.type == 3:
return repr(icmp.nexthopmtu)
return None
def _open_capture_file(self):
if not self.capture_files:
raise ValueError('No capture files available')
elif len(self.capture_files) == 1:
merged_cap_file = self.capture_files[0]
else:
cap_file_candidates = []
print_pcap_file_cmd = 'sudo tcpdump -r {} | wc -l'
for cap_file in self.capture_files:
if 0 < int(self.client.exec_command(
print_pcap_file_cmd.format(cap_file)).rstrip()):
# cap files that are not empty
cap_file_candidates.append(cap_file)
if not cap_file_candidates:
# they are all empty
merged_cap_file = self.capture_files[0]
elif 1 == len(cap_file_candidates):
merged_cap_file = cap_file_candidates[0]
else:
merged_cap_file = self.client.exec_command(
'sudo mktemp').rstrip()
n_retries = 5
for i in range(n_retries):
try:
self.client.exec_command(
'sudo tcpslice -w {} {}'.format(
merged_cap_file,
' '.join(cap_file_candidates)))
except exceptions.SSHExecCommandFailed as exc:
if i == (n_retries - 1):
raise exc
LOG.warn('tcpslice command failed - retrying...')
time.sleep(5)
else:
break
ssh_channel = self.client.open_session()
ssh_channel.exec_command('sudo cat ' + merged_cap_file)
self.addCleanup(ssh_channel.close)
return ssh_channel.makefile()