Add test_add_remove_security_group_with_active_flow
Change-Id: I0e0a60f397f188aea547825739f1141d663fed50
This commit is contained in:
parent
8d17d7ca0a
commit
cc0c9950f3
|
@ -39,12 +39,10 @@ def contrail_2_networks(create_network, create_subnet):
|
|||
@pytest.fixture
|
||||
def contrail_2_servers_different_networks(
|
||||
request,
|
||||
cirros_image,
|
||||
flavor,
|
||||
security_group,
|
||||
sorted_hypervisors,
|
||||
contrail_2_networks,
|
||||
hypervisor_steps,
|
||||
server_steps):
|
||||
"""Function fixture to prepare environment with 2 servers.
|
||||
|
||||
|
@ -53,31 +51,49 @@ def contrail_2_servers_different_networks(
|
|||
|
||||
All created resources are to be deleted after test.
|
||||
|
||||
Can be parametrized with 'same_host'.
|
||||
Can be parametrized with dict.
|
||||
|
||||
Example:
|
||||
@pytest.mark.parametrize('neutron_2_servers_different_networks',
|
||||
['same_host'],
|
||||
@pytest.mark.parametrize('contrail_2_servers_different_networks',
|
||||
[dict(same_host=True)],
|
||||
indirect=True)
|
||||
def test_foo(neutron_2_servers_different_networks):
|
||||
def test_foo(contrail_2_servers_different_networks):
|
||||
# Instances will be created on the same compute
|
||||
"""
|
||||
|
||||
params = dict(
|
||||
same_host=False,
|
||||
ubuntu=False
|
||||
)
|
||||
hypervisors = sorted_hypervisors[:2]
|
||||
if getattr(request, 'param', None) == 'same_host':
|
||||
new_params = getattr(request, 'param', {})
|
||||
params.update(new_params)
|
||||
|
||||
if params['same_host']:
|
||||
hypervisors[1] = hypervisors[0]
|
||||
|
||||
if params['ubuntu']:
|
||||
image = request.getfixturevalue('ubuntu_image')
|
||||
keypair = request.getfixturevalue('keypair')
|
||||
username = stepler_config.UBUNTU_USERNAME
|
||||
password = None
|
||||
else:
|
||||
image = request.getfixturevalue('cirros_image')
|
||||
keypair = None
|
||||
username = stepler_config.CIRROS_USERNAME
|
||||
password = stepler_config.CIRROS_PASSWORD
|
||||
|
||||
servers = []
|
||||
|
||||
for hypervisor, network in zip(hypervisors, contrail_2_networks.networks):
|
||||
server = server_steps.create_servers(
|
||||
image=cirros_image,
|
||||
image=image,
|
||||
flavor=flavor,
|
||||
networks=[network],
|
||||
keypair=keypair,
|
||||
availability_zone='nova:{}'.format(hypervisor.service['host']),
|
||||
security_groups=[security_group],
|
||||
username=stepler_config.CIRROS_USERNAME,
|
||||
password=stepler_config.CIRROS_PASSWORD,
|
||||
username=username,
|
||||
password=password,
|
||||
check=False)[0]
|
||||
servers.append(server)
|
||||
|
||||
|
|
|
@ -10,8 +10,12 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import contextlib
|
||||
import time
|
||||
|
||||
from hamcrest import is_
|
||||
from stepler.third_party import ping
|
||||
from stepler.third_party import tcpdump
|
||||
from stepler.third_party import waiter
|
||||
|
||||
CONNECTED = 'CONNECTED'
|
||||
|
@ -77,16 +81,65 @@ def check_icmp_connection_status(ip, remote, must_available=True, timeout=0):
|
|||
return waiter.wait(predicate, timeout_seconds=timeout)
|
||||
|
||||
|
||||
def start_port_listener(server_ssh, port, udp=False, answer=CONNECTED):
|
||||
def start_port_listener(server_ssh,
|
||||
port,
|
||||
udp=False,
|
||||
answer=CONNECTED,
|
||||
socat=False):
|
||||
"""Start background netcat listener on remote server.
|
||||
|
||||
Note:
|
||||
Netcat call syntax is valid only for cirros.
|
||||
Netcat call syntax is valid only for cirros. For ubuntu use socat.
|
||||
"""
|
||||
if socat:
|
||||
if not server_ssh.execute('which socat').is_ok:
|
||||
raise RuntimeError('socat is not installed on remote server')
|
||||
proto = 'UDP4' if udp else 'TCP4'
|
||||
cmd = "socat {proto}-LISTEN:{port},fork EXEC:'echo {answer}'".format(
|
||||
proto=proto, port=port, answer=answer)
|
||||
else:
|
||||
proto = '-u' if udp else ''
|
||||
listener_cmd = 'nc {proto} -l -p {port} -e echo "{answer}"'.format(
|
||||
proto=proto, port=port, answer=answer)
|
||||
|
||||
cmd = "while true; do {}; done".format(listener_cmd)
|
||||
|
||||
server_ssh.background_call(cmd)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def calc_packets_count(os_faults_steps, nodes, iface, filters):
|
||||
"""CM to calc packages count on nodes' iface.
|
||||
|
||||
Returns dict: fqdn -> captured packets count.
|
||||
"""
|
||||
tcpdump_base_path = os_faults_steps.start_tcpdump(
|
||||
nodes, '-i {0} {1}'.format(iface, filters))
|
||||
result = {node.fqdn: 0 for node in nodes}
|
||||
yield result
|
||||
os_faults_steps.stop_tcpdump(nodes, tcpdump_base_path)
|
||||
|
||||
for fqdn, pcap in os_faults_steps.download_tcpdump_results(
|
||||
nodes, tcpdump_base_path).items():
|
||||
packets = list(tcpdump.read_pcap(pcap))
|
||||
result[fqdn] = len(packets)
|
||||
|
||||
|
||||
def start_iperf_pair(client_ssh, server_ssh, ip, port, udp=False, timeout=10):
|
||||
"""Start iperf client/server."""
|
||||
if not server_ssh.execute('which iperf').is_ok:
|
||||
raise RuntimeError('iperf is not installed on server')
|
||||
if not client_ssh.execute('which iperf').is_ok:
|
||||
raise RuntimeError('iperf is not installed on server')
|
||||
|
||||
proto = '-u' if udp else ''
|
||||
listener_cmd = 'nc {proto} -l -p {port} -e echo "{answer}"'.format(
|
||||
proto=proto, port=port, answer=answer)
|
||||
server_cmd = "iperf {proto} -s -p {port}"
|
||||
client_cmd = "iperf {proto} -c {ip} -p {port} -t {time}"
|
||||
|
||||
loop_cmd = "while true; do {}; done".format(listener_cmd)
|
||||
server_ssh.background_call(server_cmd.format(proto=proto, port=port))
|
||||
|
||||
server_ssh.background_call(loop_cmd)
|
||||
if not udp:
|
||||
time.sleep(10)
|
||||
|
||||
client_ssh.background_call(
|
||||
client_cmd.format(proto=proto, ip=ip, port=port, time=timeout))
|
||||
|
|
|
@ -11,14 +11,12 @@
|
|||
# under the License.
|
||||
|
||||
|
||||
def get_nodes_interfaces(os_faults_steps):
|
||||
"""Returns dict with all nodes interfaces names."""
|
||||
nodes = os_faults_steps.get_nodes()
|
||||
def get_nodes_interfaces(os_faults_steps, nodes=None):
|
||||
"""Return dict with all nodes interfaces names."""
|
||||
nodes = nodes or os_faults_steps.get_nodes()
|
||||
results = os_faults_steps.execute_cmd(nodes, "ip -o a | awk '{print $2}'")
|
||||
ifaces = {}
|
||||
for node_result in results:
|
||||
for node in nodes:
|
||||
if node.ip == node_result.host:
|
||||
break
|
||||
node = next(node for node in nodes if node.ip == node_result.host)
|
||||
ifaces[node.fqdn] = set(node_result.payload['stdout_lines'])
|
||||
return ifaces
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# 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.
|
||||
|
||||
from stepler import config as stepler_config
|
||||
|
||||
from vapor import settings
|
||||
from vapor.helpers import nodes_steps
|
||||
|
||||
|
||||
def get_server_port(server, port_steps):
|
||||
"""Return server's port."""
|
||||
return port_steps.get_port(
|
||||
device_owner=stepler_config.PORT_DEVICE_OWNER_SERVER,
|
||||
device_id=server.id)
|
||||
|
||||
|
||||
def get_server_node(server, os_faults_steps):
|
||||
"""Return server's compute node."""
|
||||
node_name = getattr(server, settings.SERVER_ATTR_HYPERVISOR_HOSTNAME)
|
||||
return os_faults_steps.get_node(fqdns=[node_name])
|
||||
|
||||
|
||||
def get_server_compute_iface(server, os_faults_steps, port_steps):
|
||||
"""Return node and tap interface name for server port."""
|
||||
port = get_server_port(server, port_steps)
|
||||
node = get_server_node(server, os_faults_steps)
|
||||
expected_name = 'tap{}'.format(port['id'])
|
||||
interfaces = nodes_steps.get_nodes_interfaces(os_faults_steps, node)
|
||||
return next(x for x in interfaces if expected_name.startswith(x))
|
|
@ -10,15 +10,26 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import time
|
||||
|
||||
import attrdict
|
||||
from hamcrest import assert_that, equal_to # noqa: H301
|
||||
from hamcrest import assert_that, equal_to, greater_than # noqa: H301
|
||||
from pycontrail import types
|
||||
import pytest
|
||||
from stepler import config as stepler_config
|
||||
from stepler.third_party import utils
|
||||
|
||||
from vapor.helpers import connectivity
|
||||
from vapor.helpers import policy
|
||||
from vapor import settings
|
||||
from vapor.helpers import connectivity, policy, nodes_steps
|
||||
|
||||
try:
|
||||
import contextlib2 as contextlib
|
||||
except ImportError:
|
||||
import contextlib
|
||||
|
||||
|
||||
TCP_PORT = 7000
|
||||
UDP_PORT = 7001
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -212,8 +223,6 @@ def test_security_group_without_rules(connectivity_test_resources,
|
|||
#. Add egress ICMP rule to client's security group
|
||||
#. Check that there are success pings from client to server
|
||||
"""
|
||||
TCP_PORT = 7000
|
||||
UDP_PORT = 7001
|
||||
|
||||
client, server = connectivity_test_resources.servers
|
||||
client_sg, server_sg = connectivity_test_resources.security_groups
|
||||
|
@ -293,3 +302,152 @@ def test_security_group_rules_uuid_in_contrail_and_neutron(contrail_api_client,
|
|||
for rule in group.security_group_entries.policy_rule:
|
||||
contrail_rules_uuids.add(rule.rule_uuid)
|
||||
assert_that(contrail_rules_uuids, equal_to(neutron_rules_uuids))
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'contrail_2_servers_different_networks', [dict(ubuntu=True)],
|
||||
indirect=True,
|
||||
ids=['ubuntu'])
|
||||
def test_add_remove_security_group_with_active_flow(
|
||||
contrail_2_servers_diff_nets_with_floating,
|
||||
security_group,
|
||||
contrail_api_client,
|
||||
contrail_network_policy,
|
||||
set_network_policy,
|
||||
os_faults_steps,
|
||||
port_steps,
|
||||
server_steps, ):
|
||||
"""Add/remove SG from VM when flow is active and traffic from both ends.
|
||||
|
||||
Steps:
|
||||
#. Create GS with allow all rules
|
||||
#. Create 2 networks
|
||||
#. Create 2 servers on different computes with created security group
|
||||
#. Generate iperf workload with TCP from server1 to server2
|
||||
#. Generate iperf workload with UDP from server2 to server1
|
||||
#. Check that TCP and UDP incoming traffics are present on both server1
|
||||
and server2
|
||||
#. Remove security group from server1
|
||||
#. Check that TCP and UDP incoming traffics are not present on both
|
||||
server1 and server2
|
||||
#. Add security group to server1
|
||||
#. Check that TCP and UDP incoming traffics are present on both server1
|
||||
and server2
|
||||
"""
|
||||
# Update policy
|
||||
contrail_network_policy.network_policy_entries = (
|
||||
policy.ALLOW_ALL_POLICY_ENTRY)
|
||||
contrail_api_client.network_policy_update(contrail_network_policy)
|
||||
|
||||
# Add policy to networks
|
||||
for network in contrail_2_servers_diff_nets_with_floating.networks:
|
||||
network = contrail_api_client.virtual_network_read(id=network['id'])
|
||||
set_network_policy(network, contrail_network_policy)
|
||||
|
||||
# Add rule to group
|
||||
contrail_sg = contrail_api_client.security_group_read(id=security_group.id)
|
||||
sg_entries = contrail_sg.security_group_entries
|
||||
rules = [
|
||||
types.PolicyRuleType(
|
||||
direction='>',
|
||||
protocol='any',
|
||||
action_list=types.ActionListType(simple_action='pass'),
|
||||
src_addresses=[
|
||||
types.AddressType(security_group=contrail_sg.get_fq_name_str())
|
||||
],
|
||||
src_ports=[types.PortType()],
|
||||
dst_addresses=[types.AddressType(security_group='local')],
|
||||
dst_ports=[types.PortType()], ),
|
||||
]
|
||||
sg_entries.policy_rule.extend(rules)
|
||||
contrail_sg.security_group_entries = sg_entries
|
||||
contrail_api_client.security_group_update(contrail_sg)
|
||||
server1, server2 = contrail_2_servers_diff_nets_with_floating.servers
|
||||
|
||||
# Get ips, nodes, interfaces information
|
||||
ips = []
|
||||
computes = []
|
||||
ifaces = []
|
||||
for server in server1, server2:
|
||||
port = port_steps.get_port(
|
||||
device_owner=stepler_config.PORT_DEVICE_OWNER_SERVER,
|
||||
device_id=server.id)
|
||||
|
||||
ips += [server_steps.get_fixed_ip(server)]
|
||||
|
||||
node_name = getattr(server, settings.SERVER_ATTR_HYPERVISOR_HOSTNAME)
|
||||
node = os_faults_steps.get_node(fqdns=[node_name])
|
||||
computes.append(node)
|
||||
|
||||
expected_name = 'tap{}'.format(port['id'])
|
||||
interfaces = nodes_steps.get_nodes_interfaces(os_faults_steps,
|
||||
node)[node_name]
|
||||
iface = next(x for x in interfaces if expected_name.startswith(x))
|
||||
ifaces.append(iface)
|
||||
|
||||
# install iperf
|
||||
with server_steps.get_server_ssh(server) as server_ssh:
|
||||
with server_ssh.sudo():
|
||||
server_ssh.check_call('apt-get install iperf -q -y')
|
||||
|
||||
ip1, ip2 = ips
|
||||
|
||||
udp_filter = "'(udp and src host {} and dst host {})'".format(ip1, ip2)
|
||||
tcp_filter = "'(tcp and src host {} and dst host {})'".format(ip2, ip1)
|
||||
|
||||
with contextlib.ExitStack() as stack:
|
||||
enter = stack.enter_context
|
||||
server1_ssh = enter(server_steps.get_server_ssh(server1))
|
||||
server2_ssh = enter(server_steps.get_server_ssh(server2))
|
||||
|
||||
# Start TCP and UDP traffic
|
||||
connectivity.start_iperf_pair(
|
||||
client_ssh=server1_ssh,
|
||||
server_ssh=server2_ssh,
|
||||
ip=ip2,
|
||||
port=UDP_PORT,
|
||||
udp=True,
|
||||
timeout=60 * 1000)
|
||||
connectivity.start_iperf_pair(
|
||||
client_ssh=server2_ssh,
|
||||
server_ssh=server1_ssh,
|
||||
ip=ip1,
|
||||
port=TCP_PORT,
|
||||
timeout=60 * 1000)
|
||||
|
||||
# Check that some packets are captured
|
||||
with connectivity.calc_packets_count(os_faults_steps, computes[0],
|
||||
ifaces[0],
|
||||
tcp_filter) as tcp_counts:
|
||||
with connectivity.calc_packets_count(os_faults_steps, computes[1],
|
||||
ifaces[1],
|
||||
udp_filter) as udp_counts:
|
||||
time.sleep(1)
|
||||
assert_that(next(iter(tcp_counts.values())), greater_than(0))
|
||||
assert_that(next(iter(udp_counts.values())), greater_than(0))
|
||||
|
||||
# Remove security group from server1
|
||||
server1.remove_security_group(security_group.id)
|
||||
|
||||
with connectivity.calc_packets_count(os_faults_steps, computes[0],
|
||||
ifaces[0],
|
||||
tcp_filter) as tcp_counts:
|
||||
with connectivity.calc_packets_count(os_faults_steps, computes[1],
|
||||
ifaces[1],
|
||||
udp_filter) as udp_counts:
|
||||
time.sleep(1)
|
||||
assert_that(next(iter(tcp_counts.values())), equal_to(0))
|
||||
assert_that(next(iter(udp_counts.values())), equal_to(0))
|
||||
|
||||
# Add security group from server1
|
||||
server1.add_security_group(security_group.id)
|
||||
|
||||
with connectivity.calc_packets_count(os_faults_steps, computes[0],
|
||||
ifaces[0],
|
||||
tcp_filter) as tcp_counts:
|
||||
with connectivity.calc_packets_count(os_faults_steps, computes[1],
|
||||
ifaces[1],
|
||||
udp_filter) as udp_counts:
|
||||
time.sleep(1)
|
||||
assert_that(next(iter(tcp_counts.values())), greater_than(0))
|
||||
assert_that(next(iter(udp_counts.values())), greater_than(0))
|
||||
|
|
Loading…
Reference in New Issue