Add fullstack test for logging

Since Queens, the security group logging has been merged. But there
is no fullstack test for this feature. So this patch add fullstack
test to avoid regression as https://review.openstack.org/#/c/587681

Co-Authored-By: Yushiro FURUKAWA <y.furukawa_2@jp.fujitsu.com>
Change-Id: Id9bbedc96e399338ea568556bdb17923392512b4
Partially-implements: blueprint security-group-logging
This commit is contained in:
Nguyen Phuong An 2017-12-15 12:58:45 +07:00
parent 9feb5db61c
commit 0649112113
4 changed files with 227 additions and 3 deletions

View File

@ -301,3 +301,16 @@ class ClientFixture(fixtures.Fixture):
spec.update(kwargs)
return self._create_resource(resource_type, spec)
def create_network_log(self, tenant_id, resource_type,
enabled=True, **kwargs):
spec = {'project_id': tenant_id,
'resource_type': resource_type,
'enabled': enabled}
spec.update(kwargs)
net_log = self.client.create_network_log({'log': spec})
self.addCleanup(
_safe_method(self.client.delete_network_log), net_log['log']['id'])
return net_log

View File

@ -23,6 +23,7 @@ from neutron.plugins.ml2.extensions import qos as qos_ext
from neutron.tests.common import config_fixtures
from neutron.tests.common.exclusive_resources import port
from neutron.tests.common import helpers as c_helpers
from neutron.tests.fullstack import base as fullstack_base
PHYSICAL_NETWORK_NAME = "physnet1"
@ -154,7 +155,7 @@ class ML2ConfigFixture(ConfigFixture):
class OVSConfigFixture(ConfigFixture):
def __init__(self, env_desc, host_desc, temp_dir, local_ip):
def __init__(self, env_desc, host_desc, temp_dir, local_ip, **kwargs):
super(OVSConfigFixture, self).__init__(
env_desc, host_desc, temp_dir,
base_filename='openvswitch_agent.ini')
@ -189,6 +190,14 @@ class OVSConfigFixture(ConfigFixture):
if env_desc.qos:
self.config['agent']['extensions'] = 'qos'
if env_desc.log:
self.config['agent']['extensions'] = 'log'
test_name = kwargs.get("test_name")
self.config.update({
'network_log': {
'local_output_log_base':
self._generate_temp_log_file(test_name)}
})
def _setUp(self):
if self.config['ovs']['of_interface'] == 'native':
@ -214,6 +223,13 @@ class OVSConfigFixture(ConfigFixture):
def _generate_tun_peer(self):
return utils.get_rand_device_name(prefix='patch-int')
def _generate_temp_log_file(self, test_name):
log_dir_path = fullstack_base.DEFAULT_LOG_DIR + '/' + test_name
if not os.path.exists(log_dir_path):
os.mkdir(log_dir_path, 0o755)
return '%s/%s.log' % (log_dir_path,
utils.get_rand_name(prefix="test-sg-"))
def get_br_int_name(self):
return self.config.ovs.integration_bridge

View File

@ -39,10 +39,11 @@ class EnvironmentDescription(object):
service_plugins='router', arp_responder=False,
agent_down_time=75, router_scheduler=None,
global_mtu=common_const.DEFAULT_NETWORK_MTU,
debug_iptables=False):
debug_iptables=False, log=False):
self.network_type = network_type
self.l2_pop = l2_pop
self.qos = qos
self.log = log
self.network_range = None
self.mech_drivers = mech_drivers
self.arp_responder = arp_responder
@ -53,6 +54,8 @@ class EnvironmentDescription(object):
self.debug_iptables = debug_iptables
if self.qos:
self.service_plugins += ',qos'
if self.log:
self.service_plugins += ',log'
@property
def tunneling_enabled(self):
@ -134,7 +137,7 @@ class Host(fixtures.Fixture):
def setup_host_with_ovs_agent(self):
agent_cfg_fixture = config.OVSConfigFixture(
self.env_desc, self.host_desc, self.neutron_config.temp_dir,
self.local_ip)
self.local_ip, test_name=self.test_name)
self.useFixture(agent_cfg_fixture)
if self.env_desc.tunneling_enabled:

View File

@ -0,0 +1,192 @@
# Copyright 2018 Fujitsu Limited
#
# 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 re
from neutron_lib import constants
from oslo_utils import uuidutils
from neutron.common import utils
from neutron.plugins.ml2.drivers.openvswitch.agent.common import (
constants as ovs_const)
from neutron.tests.common import net_helpers
from neutron.tests.fullstack import base
from neutron.tests.fullstack.resources import environment
from neutron.tests.fullstack.resources import machine
from neutron.tests.unit import testlib_api
load_tests = testlib_api.module_load_tests
class BaseLoggingTestCase(base.BaseFullStackTestCase):
of_interface = None
number_of_hosts = 1
def setUp(self):
host_desc = [
environment.HostDescription(
of_interface=self.of_interface,
l2_agent_type=constants.AGENT_TYPE_OVS,
firewall_driver='openvswitch',
dhcp_agent=True) for _ in range(self.number_of_hosts)]
env_desc = environment.EnvironmentDescription(
mech_drivers='openvswitch', log=True)
env = environment.Environment(env_desc, host_desc)
super(BaseLoggingTestCase, self).setUp(env)
self.tenant_id = uuidutils.generate_uuid()
self.network = self.safe_client.create_network(
self.tenant_id, 'network-test')
self.subnet = self.safe_client.create_subnet(
self.tenant_id, self.network['id'],
cidr='10.0.0.0/24',
gateway_ip='10.0.0.1',
name='subnet-test')
def assert_no_connection(self, *args, **kwargs):
netcat = net_helpers.NetcatTester(*args, **kwargs)
try:
utils.wait_until_true(netcat.test_no_connectivity)
finally:
netcat.stop_processes()
def _wait_for_log_rules_applied(self, vm, table, actions):
def _is_log_flow_set(table, actions):
flows = vm.bridge.dump_flows_for_table(table)
flows_list = flows.splitlines()
pattern = re.compile(
r"^.* table=%s.* actions=%s" % (table, actions))
for flow in flows_list:
if pattern.match(flow.strip()):
return True
return False
utils.wait_until_true(lambda: _is_log_flow_set(table, actions))
def _check_log(self, log_id, action, regex_str=None):
config = self.environment.hosts[0].ovs_agent.agent_config
def _is_log_event(log_id, action, regex_str):
regex_p = re.compile(
r"^.*action=%s.* log_resource_ids=\[[^\]]*%s" % (
action, log_id) + ".*" + regex_str if regex_str else "")
with open(config.network_log.local_output_log_base) as f:
for line in f.readlines():
if regex_p.match(line):
return True
return False
utils.wait_until_true(lambda: _is_log_event(log_id, action, regex_str))
class TestLogging(BaseLoggingTestCase):
scenarios = [
('ovs-openflow-native', {
'of_interface': 'native'})]
def _create_network_log(self, resource_type,
resource_id=None, target_id=None):
return self.safe_client.create_network_log(
tenant_id=self.tenant_id,
name='test-log',
resource_type=resource_type,
resource_id=resource_id,
target_id=target_id)
def _prepare_vms(self):
sgs = [self.safe_client.create_security_group(self.tenant_id)
for i in range(2)]
port1 = self.safe_client.create_port(
self.tenant_id, self.network['id'],
self.environment.hosts[0].hostname,
security_groups=[sgs[0]['id']])
port2 = self.safe_client.create_port(
self.tenant_id, self.network['id'],
self.environment.hosts[0].hostname,
security_groups=[sgs[1]['id']])
# insert security-group-rules allow icmp
self.safe_client.create_security_group_rule(
self.tenant_id, sgs[0]['id'],
direction=constants.INGRESS_DIRECTION,
ethertype=constants.IPv4,
protocol=constants.PROTO_NAME_ICMP)
# insert security-group-rules allow icmp
self.safe_client.create_security_group_rule(
self.tenant_id, sgs[1]['id'],
direction=constants.INGRESS_DIRECTION,
ethertype=constants.IPv4,
protocol=constants.PROTO_NAME_ICMP)
vm1 = self.useFixture(
machine.FakeFullstackMachine(
self.environment.hosts[0],
self.network['id'],
self.tenant_id,
self.safe_client,
neutron_port=port1))
vm2 = self.useFixture(
machine.FakeFullstackMachine(
self.environment.hosts[0],
self.network['id'],
self.tenant_id,
self.safe_client,
neutron_port=port2))
return machine.FakeFullstackMachinesList([vm1, vm2])
def test_logging(self):
vms = self._prepare_vms()
vms.block_until_all_boot()
sg_log = self._create_network_log(resource_type='security_group')
log_id = sg_log['log']['id']
for vm in vms:
self._wait_for_log_rules_applied(
vm, ovs_const.ACCEPTED_EGRESS_TRAFFIC_TABLE,
actions=r"resubmit\(,%d\),CONTROLLER:65535" % (
ovs_const.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE))
self._wait_for_log_rules_applied(
vm, ovs_const.ACCEPTED_INGRESS_TRAFFIC_TABLE,
actions="CONTROLLER:65535")
self._wait_for_log_rules_applied(
vm, ovs_const.DROPPED_TRAFFIC_TABLE,
actions="CONTROLLER:65535")
# ping all vm
vms.ping_all()
# check log accept packets for icmp
self._check_log(log_id=log_id, action='ACCEPT')
# Try to connect from VM1 to VM2 via ssh
self.assert_no_connection(
vms[0].namespace, vms[1].namespace, vms[1].ip, 22,
net_helpers.NetcatTester.TCP)
# Try to ssh from VM2 to VM1 via ssh
self.assert_no_connection(
vms[1].namespace, vms[0].namespace, vms[0].ip, 22,
net_helpers.NetcatTester.TCP)
# check log drop packets for ssh
self._check_log(log_id=log_id, action='DROP', regex_str="dst_port=22")