Merge "Adds protocol options for test_cross_tenant_traffic"
This commit is contained in:
commit
df5935be35
|
@ -156,3 +156,53 @@ class RemoteClient(remote_client.RemoteClient):
|
||||||
cmd_why = 'sudo ls -lR /dev'
|
cmd_why = 'sudo ls -lR /dev'
|
||||||
LOG.info("Contents of /dev: %s", self.exec_command(cmd_why))
|
LOG.info("Contents of /dev: %s", self.exec_command(cmd_why))
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
def nc_listen_host(self, port=80, protocol='tcp'):
|
||||||
|
"""Creates persistent nc server listening on the given TCP / UDP port
|
||||||
|
|
||||||
|
:port: the port to start listening on.
|
||||||
|
:protocol: the protocol used by the server. TCP by default.
|
||||||
|
"""
|
||||||
|
udp = '-u' if protocol.lower() == 'udp' else ''
|
||||||
|
cmd = "sudo nc %(udp)s -p %(port)s -lk -e echo foolish &" % {
|
||||||
|
'udp': udp, 'port': port}
|
||||||
|
return self.exec_command(cmd)
|
||||||
|
|
||||||
|
def nc_host(self, host, port=80, protocol='tcp', expected_response=None):
|
||||||
|
"""Check connectivity to TCP / UDP port at host via nc
|
||||||
|
|
||||||
|
:host: an IP against which the connectivity will be tested.
|
||||||
|
:port: the port to check connectivity against.
|
||||||
|
:protocol: the protocol used by nc to send packets. TCP by default.
|
||||||
|
:expected_response: string representing the expected response
|
||||||
|
from server.
|
||||||
|
:raises SSHExecCommandFailed: if an expected response is given and it
|
||||||
|
does not match the actual server response.
|
||||||
|
"""
|
||||||
|
udp = '-u' if protocol.lower() == 'udp' else ''
|
||||||
|
cmd = 'echo "bar" | nc -w 1 %(udp)s %(host)s %(port)s' % {
|
||||||
|
'udp': udp, 'host': host, 'port': port}
|
||||||
|
response = self.exec_command(cmd)
|
||||||
|
|
||||||
|
# sending an UDP packet will always succeed. we need to check
|
||||||
|
# the response.
|
||||||
|
if (expected_response is not None and
|
||||||
|
expected_response != response.strip()):
|
||||||
|
raise tempest.lib.exceptions.SSHExecCommandFailed(
|
||||||
|
command=cmd, exit_status=0, stdout=response, stderr='')
|
||||||
|
return response
|
||||||
|
|
||||||
|
def icmp_check(self, host, nic=None):
|
||||||
|
"""Wrapper for icmp connectivity checks"""
|
||||||
|
return self.ping_host(host, nic=nic)
|
||||||
|
|
||||||
|
def udp_check(self, host, **kwargs):
|
||||||
|
"""Wrapper for udp connectivity checks."""
|
||||||
|
kwargs.pop('nic', None)
|
||||||
|
return self.nc_host(host, protocol='udp', expected_response='foolish',
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
def tcp_check(self, host, **kwargs):
|
||||||
|
"""Wrapper for tcp connectivity checks."""
|
||||||
|
kwargs.pop('nic', None)
|
||||||
|
return self.nc_host(host, **kwargs)
|
||||||
|
|
|
@ -1052,7 +1052,12 @@ ScenarioGroup = [
|
||||||
choices=["udhcpc", "dhclient", ""],
|
choices=["udhcpc", "dhclient", ""],
|
||||||
help='DHCP client used by images to renew DCHP lease. '
|
help='DHCP client used by images to renew DCHP lease. '
|
||||||
'If left empty, update operation will be skipped. '
|
'If left empty, update operation will be skipped. '
|
||||||
'Supported clients: "udhcpc", "dhclient"')
|
'Supported clients: "udhcpc", "dhclient"'),
|
||||||
|
cfg.StrOpt('protocol',
|
||||||
|
default='icmp',
|
||||||
|
choices=('icmp', 'tcp', 'udp'),
|
||||||
|
help='The protocol used in security groups tests to check '
|
||||||
|
'connectivity.'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -979,24 +979,33 @@ class NetworkScenarioTest(ScenarioTest):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def check_remote_connectivity(self, source, dest, should_succeed=True,
|
def check_remote_connectivity(self, source, dest, should_succeed=True,
|
||||||
nic=None):
|
nic=None, protocol='icmp'):
|
||||||
"""assert ping server via source ssh connection
|
"""check server connectivity via source ssh connection
|
||||||
|
|
||||||
:param source: RemoteClient: an ssh connection from which to ping
|
:param source: RemoteClient: an ssh connection from which to execute
|
||||||
:param dest: an IP to ping against
|
the check
|
||||||
:param should_succeed: boolean: should ping succeed or not
|
:param dest: an IP to check connectivity against
|
||||||
:param nic: specific network interface to ping from
|
:param should_succeed: boolean should connection succeed or not
|
||||||
|
:param nic: specific network interface to test connectivity from
|
||||||
|
:param protocol: the protocol used to test connectivity with.
|
||||||
|
:returns: True, if the connection succeeded and it was expected to
|
||||||
|
succeed. False otherwise.
|
||||||
"""
|
"""
|
||||||
def ping_remote():
|
method_name = '%s_check' % protocol
|
||||||
|
connectivity_checker = getattr(source, method_name)
|
||||||
|
|
||||||
|
def connect_remote():
|
||||||
try:
|
try:
|
||||||
source.ping_host(dest, nic=nic)
|
connectivity_checker(dest, nic=nic)
|
||||||
except lib_exc.SSHExecCommandFailed:
|
except lib_exc.SSHExecCommandFailed:
|
||||||
LOG.warning('Failed to ping IP: %s via a ssh connection '
|
LOG.warning('Failed to check %(protocol)s connectivity for '
|
||||||
'from: %s.', dest, source.ssh_client.host)
|
'IP %(dest)s via a ssh connection from: %(src)s.',
|
||||||
|
dict(protocol=protocol, dest=dest,
|
||||||
|
src=source.ssh_client.host))
|
||||||
return not should_succeed
|
return not should_succeed
|
||||||
return should_succeed
|
return should_succeed
|
||||||
|
|
||||||
result = test_utils.call_until_true(ping_remote,
|
result = test_utils.call_until_true(connect_remote,
|
||||||
CONF.validation.ping_timeout, 1)
|
CONF.validation.ping_timeout, 1)
|
||||||
if result:
|
if result:
|
||||||
return
|
return
|
||||||
|
|
|
@ -395,24 +395,22 @@ class TestSecurityGroupsBasicOps(manager.NetworkScenarioTest):
|
||||||
self.check_remote_connectivity(source=access_point_ssh,
|
self.check_remote_connectivity(source=access_point_ssh,
|
||||||
dest=self._get_server_ip(server))
|
dest=self._get_server_ip(server))
|
||||||
|
|
||||||
def _test_cross_tenant_block(self, source_tenant, dest_tenant):
|
def _test_cross_tenant_block(self, source_tenant, dest_tenant, ruleset):
|
||||||
# if public router isn't defined, then dest_tenant access is via
|
# if public router isn't defined, then dest_tenant access is via
|
||||||
# floating-ip
|
# floating-ip
|
||||||
|
protocol = ruleset['protocol']
|
||||||
access_point_ssh = self._connect_to_access_point(source_tenant)
|
access_point_ssh = self._connect_to_access_point(source_tenant)
|
||||||
ip = self._get_server_ip(dest_tenant.access_point,
|
ip = self._get_server_ip(dest_tenant.access_point,
|
||||||
floating=self.floating_ip_access)
|
floating=self.floating_ip_access)
|
||||||
self.check_remote_connectivity(source=access_point_ssh, dest=ip,
|
self.check_remote_connectivity(source=access_point_ssh, dest=ip,
|
||||||
should_succeed=False)
|
should_succeed=False, protocol=protocol)
|
||||||
|
|
||||||
def _test_cross_tenant_allow(self, source_tenant, dest_tenant):
|
def _test_cross_tenant_allow(self, source_tenant, dest_tenant, ruleset):
|
||||||
"""check for each direction:
|
"""check for each direction:
|
||||||
|
|
||||||
creating rule for tenant incoming traffic enables only 1way traffic
|
creating rule for tenant incoming traffic enables only 1way traffic
|
||||||
"""
|
"""
|
||||||
ruleset = dict(
|
protocol = ruleset['protocol']
|
||||||
protocol='icmp',
|
|
||||||
direction='ingress'
|
|
||||||
)
|
|
||||||
sec_group_rules_client = (
|
sec_group_rules_client = (
|
||||||
dest_tenant.manager.security_group_rules_client)
|
dest_tenant.manager.security_group_rules_client)
|
||||||
self._create_security_group_rule(
|
self._create_security_group_rule(
|
||||||
|
@ -423,10 +421,10 @@ class TestSecurityGroupsBasicOps(manager.NetworkScenarioTest):
|
||||||
access_point_ssh = self._connect_to_access_point(source_tenant)
|
access_point_ssh = self._connect_to_access_point(source_tenant)
|
||||||
ip = self._get_server_ip(dest_tenant.access_point,
|
ip = self._get_server_ip(dest_tenant.access_point,
|
||||||
floating=self.floating_ip_access)
|
floating=self.floating_ip_access)
|
||||||
self.check_remote_connectivity(access_point_ssh, ip)
|
self.check_remote_connectivity(access_point_ssh, ip, protocol=protocol)
|
||||||
|
|
||||||
# test that reverse traffic is still blocked
|
# test that reverse traffic is still blocked
|
||||||
self._test_cross_tenant_block(dest_tenant, source_tenant)
|
self._test_cross_tenant_block(dest_tenant, source_tenant, ruleset)
|
||||||
|
|
||||||
# allow reverse traffic and check
|
# allow reverse traffic and check
|
||||||
sec_group_rules_client = (
|
sec_group_rules_client = (
|
||||||
|
@ -440,7 +438,8 @@ class TestSecurityGroupsBasicOps(manager.NetworkScenarioTest):
|
||||||
access_point_ssh_2 = self._connect_to_access_point(dest_tenant)
|
access_point_ssh_2 = self._connect_to_access_point(dest_tenant)
|
||||||
ip = self._get_server_ip(source_tenant.access_point,
|
ip = self._get_server_ip(source_tenant.access_point,
|
||||||
floating=self.floating_ip_access)
|
floating=self.floating_ip_access)
|
||||||
self.check_remote_connectivity(access_point_ssh_2, ip)
|
self.check_remote_connectivity(access_point_ssh_2, ip,
|
||||||
|
protocol=protocol)
|
||||||
|
|
||||||
def _verify_mac_addr(self, tenant):
|
def _verify_mac_addr(self, tenant):
|
||||||
"""Verify that VM has the same ip, mac as listed in port"""
|
"""Verify that VM has the same ip, mac as listed in port"""
|
||||||
|
@ -470,6 +469,17 @@ class TestSecurityGroupsBasicOps(manager.NetworkScenarioTest):
|
||||||
self._log_console_output(
|
self._log_console_output(
|
||||||
servers=[tenant.access_point], client=client)
|
servers=[tenant.access_point], client=client)
|
||||||
|
|
||||||
|
def _create_protocol_ruleset(self, protocol, port=80):
|
||||||
|
if protocol == 'icmp':
|
||||||
|
ruleset = dict(protocol='icmp',
|
||||||
|
direction='ingress')
|
||||||
|
else:
|
||||||
|
ruleset = dict(protocol=protocol,
|
||||||
|
port_range_min=port,
|
||||||
|
port_range_max=port,
|
||||||
|
direction='ingress')
|
||||||
|
return ruleset
|
||||||
|
|
||||||
@decorators.idempotent_id('e79f879e-debb-440c-a7e4-efeda05b6848')
|
@decorators.idempotent_id('e79f879e-debb-440c-a7e4-efeda05b6848')
|
||||||
@utils.services('compute', 'network')
|
@utils.services('compute', 'network')
|
||||||
def test_cross_tenant_traffic(self):
|
def test_cross_tenant_traffic(self):
|
||||||
|
@ -484,8 +494,18 @@ class TestSecurityGroupsBasicOps(manager.NetworkScenarioTest):
|
||||||
# cross tenant check
|
# cross tenant check
|
||||||
source_tenant = self.primary_tenant
|
source_tenant = self.primary_tenant
|
||||||
dest_tenant = self.alt_tenant
|
dest_tenant = self.alt_tenant
|
||||||
self._test_cross_tenant_block(source_tenant, dest_tenant)
|
|
||||||
self._test_cross_tenant_allow(source_tenant, dest_tenant)
|
protocol = CONF.scenario.protocol
|
||||||
|
LOG.debug("Testing cross tenant traffic for %s protocol",
|
||||||
|
protocol)
|
||||||
|
if protocol in ['udp', 'tcp']:
|
||||||
|
for tenant in [source_tenant, dest_tenant]:
|
||||||
|
access_point = self._connect_to_access_point(tenant)
|
||||||
|
access_point.nc_listen_host(protocol=protocol)
|
||||||
|
|
||||||
|
ruleset = self._create_protocol_ruleset(protocol)
|
||||||
|
self._test_cross_tenant_block(source_tenant, dest_tenant, ruleset)
|
||||||
|
self._test_cross_tenant_allow(source_tenant, dest_tenant, ruleset)
|
||||||
except Exception:
|
except Exception:
|
||||||
self._log_console_output_for_all_tenants()
|
self._log_console_output_for_all_tenants()
|
||||||
raise
|
raise
|
||||||
|
|
Loading…
Reference in New Issue