Add test_add_remove_security_group_with_active_flow

Change-Id: I0e0a60f397f188aea547825739f1141d663fed50
This commit is contained in:
Georgy Dyuldin 2017-02-16 11:30:26 +03:00
parent 8d17d7ca0a
commit cc0c9950f3
5 changed files with 291 additions and 28 deletions

View File

@ -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)

View File

@ -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))

View File

@ -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

View File

@ -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))

View File

@ -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))