Browse Source

Add NAT service instance test

Change-Id: Ib7e71232655ea4abc391336e739d287f5074aeed
Georgy Dyuldin 1 year ago
parent
commit
eb1dbe1873

+ 27
- 0
plugin_test/vapor/create_nat_image.sh View File

@@ -0,0 +1,27 @@
1
+#!/bin/bash
2
+
3
+# Script to create NAT service image from ubuntu image
4
+
5
+guestfish << _EOF_
6
+add $IMAGE
7
+run
8
+mount /dev/sda1 /
9
+download /etc/sysctl.conf /tmp/sysctl.conf
10
+! echo "net.ipv4.ip_forward = 1" >> /tmp/sysctl.conf
11
+upload /tmp/sysctl.conf /etc/sysctl.conf
12
+! echo "dhclient" > /tmp/rc.local
13
+! echo "/sbin/iptables -t nat -A POSTROUTING -o eth2 -j MASQUERADE" >> /tmp/rc.local
14
+! echo "/sbin/iptables -A FORWARD -i eth2 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT" >> /tmp/rc.local
15
+! echo "/sbin/iptables -A FORWARD -i eth1 -o eth2 -j ACCEPT" >> /tmp/rc.local
16
+! echo "exit 0" >> /tmp/rc.local
17
+upload /tmp/rc.local /etc/rc.local
18
+echo "Set root password to 'password'"
19
+download /etc/shadow /tmp/shadow
20
+! sed -i 's/^root:[^:]\+:/root:$1$h2thgSpv$lAm04bPzOoldW8H0EVwVA0:/' /tmp/shadow
21
+upload /tmp/shadow /etc/shadow
22
+echo "Permit root login"
23
+download /etc/ssh/sshd_config /tmp/sshd_config
24
+! sed -i 's/^PasswordAuthentication.*$/PasswordAuthentication yes/' /tmp/sshd_config
25
+! sed -i 's/^PermitRootLogin.*$/PermitRootLogin yes/' /tmp/sshd_config
26
+upload /tmp/sshd_config /etc/ssh/sshd_config
27
+_EOF_

+ 2
- 0
plugin_test/vapor/vapor/conftest.py View File

@@ -10,12 +10,14 @@ from vapor.fixtures.contrail import *  # noqa
10 10
 from vapor.fixtures.contrail_resources import *  # noqa
11 11
 from vapor.fixtures.different_tenants_resources import *  # noqa
12 12
 from vapor.fixtures.dns import *  # noqa
13
+from vapor.fixtures.images import *  # noqa
13 14
 from vapor.fixtures.instance_ip import *  # noqa
14 15
 from vapor.fixtures.ipams import *  # noqa
15 16
 from vapor.fixtures.networks import *  # noqa
16 17
 from vapor.fixtures.nodes import *  # noqa
17 18
 from vapor.fixtures.policies import *  # noqa
18 19
 from vapor.fixtures.security_groups import *  # noqa
20
+from vapor.fixtures.service_chain import *  # noqa
19 21
 from vapor.fixtures.skip import *  # noqa
20 22
 from vapor.fixtures.subnets import *  # noqa
21 23
 from vapor.fixtures.system_services import *  # noqa

+ 39
- 0
plugin_test/vapor/vapor/fixtures/images.py View File

@@ -0,0 +1,39 @@
1
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+# not use this file except in compliance with the License. You may obtain
3
+# a copy of the License at
4
+
5
+#     http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+# Unless required by applicable law or agreed to in writing, software
8
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+# License for the specific language governing permissions and limitations
11
+# under the License.
12
+
13
+import pytest
14
+from stepler.glance.fixtures import images
15
+from stepler.third_party import utils
16
+
17
+from vapor import settings
18
+
19
+
20
+@pytest.fixture(scope='session')
21
+def nat_service_image(get_glance_steps, uncleanable, credentials):
22
+    """Session fixture to create ubuntu image.
23
+    Creates image from config.UBUNTU_QCOW2_URL with default options.
24
+
25
+    Args:
26
+        get_glance_steps (function): function to get glance steps
27
+        uncleanable (AttrDict): data structure with skipped resources
28
+        credentials (object): CredentialsManager instance
29
+
30
+    Returns:
31
+        object: ubuntu glance image
32
+    """
33
+    with images.create_images_context(
34
+            get_glance_steps,
35
+            uncleanable,
36
+            credentials,
37
+            utils.generate_ids('nat'),
38
+            settings.NAT_SERVICE_IMAGE_URL) as created_images:
39
+        yield created_images[0]

+ 82
- 0
plugin_test/vapor/vapor/fixtures/service_chain.py View File

@@ -0,0 +1,82 @@
1
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+# not use this file except in compliance with the License. You may obtain
3
+# a copy of the License at
4
+
5
+#     http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+# Unless required by applicable law or agreed to in writing, software
8
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+# License for the specific language governing permissions and limitations
11
+# under the License.
12
+
13
+import functools
14
+
15
+import pycontrail.types as types
16
+import pytest
17
+from stepler import config as stepler_config
18
+from stepler.third_party import utils
19
+
20
+from vapor.helpers import service_chain
21
+
22
+
23
+@pytest.fixture
24
+def add_neutron_user_to_project(current_project, role_steps, user_steps):
25
+    """Workaround to allow contrail to boot service instances."""
26
+    neutron_user = user_steps.get_user(name='neutron')
27
+    role = role_steps.get_role(name=stepler_config.ROLE_MEMBER)
28
+    role_steps.grant_role(role, neutron_user, project=current_project)
29
+
30
+
31
+@pytest.fixture
32
+def service_template(contrail_api_client, nat_service_image, flavor):
33
+    name = next(utils.generate_ids('nat_template'))
34
+    interface_types = [
35
+        types.ServiceTemplateInterfaceType(
36
+            service_interface_type='management'),
37
+        types.ServiceTemplateInterfaceType(service_interface_type='left'),
38
+        types.ServiceTemplateInterfaceType(service_interface_type='right'),
39
+    ]
40
+    template_properties = types.ServiceTemplateType(
41
+        version=1,
42
+        service_mode=u'in-network',
43
+        service_type=u'firewall',
44
+        image_name=nat_service_image.name,
45
+        flavor=flavor.name,
46
+        interface_type=interface_types,
47
+        ordered_interfaces=True,
48
+        service_virtualization_type=u'virtual-machine')
49
+    template = types.ServiceTemplate(
50
+        name=name, service_template_properties=template_properties)
51
+    contrail_api_client.service_template_create(template)
52
+    yield template
53
+    contrail_api_client.service_template_delete(id=template.uuid)
54
+
55
+
56
+@pytest.fixture
57
+def service_instance(request, contrail_api_client, contrail_current_project,
58
+                     service_template, contrail_2_networks, server_steps,
59
+                     add_neutron_user_to_project):
60
+    left_vn, right_vn = contrail_2_networks.networks
61
+    left_fq_name = ':'.join(left_vn['contrail:fq_name'])
62
+    right_fq_name = ':'.join(right_vn['contrail:fq_name'])
63
+    name = next(utils.generate_ids('nat_instance'))
64
+    instance_properties = types.ServiceInstanceType(
65
+        scale_out=types.ServiceScaleOutType(1),
66
+        management_virtual_network='',
67
+        left_virtual_network=left_fq_name,
68
+        right_virtual_network=right_fq_name)
69
+    instance = types.ServiceInstance(
70
+        name=name,
71
+        parent_obj=contrail_current_project,
72
+        service_instance_properties=instance_properties)
73
+    instance.set_service_template(service_template)
74
+    contrail_api_client.service_instance_create(instance)
75
+
76
+    request.addfinalizer(
77
+        functools.partial(service_chain.delete_service_instance,
78
+                          contrail_api_client, instance, server_steps))
79
+
80
+    service_chain.check_service_instance_ready(contrail_api_client, instance,
81
+                                               server_steps)
82
+    return instance

+ 67
- 0
plugin_test/vapor/vapor/helpers/service_chain.py View File

@@ -0,0 +1,67 @@
1
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+# not use this file except in compliance with the License. You may obtain
3
+# a copy of the License at
4
+
5
+#     http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+# Unless required by applicable law or agreed to in writing, software
8
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+# License for the specific language governing permissions and limitations
11
+# under the License.
12
+
13
+import re
14
+
15
+from stepler import config as stepler_config
16
+from stepler.third_party import waiter
17
+
18
+from vapor import settings
19
+
20
+
21
+def check_service_instance_ready(contrail_api_client, service_instance,
22
+                                 server_steps):
23
+    """Check that service instance creates nova server and it's booted."""
24
+
25
+    def _get_virtual_machine_uuid():
26
+        fresh_instance = contrail_api_client.service_instance_read(
27
+            id=service_instance.uuid)
28
+        refs = fresh_instance.get_virtual_machine_back_refs()
29
+        if refs:
30
+            return refs[0]['uuid']
31
+
32
+    server_uuid = waiter.wait(
33
+        _get_virtual_machine_uuid,
34
+        timeout_seconds=settings.SERVICE_INSTANCE_CREATE_TIMEOUT)
35
+
36
+    server = next(server for server in server_steps.get_servers()
37
+                  if server.id == server_uuid)
38
+
39
+    server_steps.check_server_status(
40
+        server,
41
+        expected_statuses=[stepler_config.STATUS_ACTIVE],
42
+        transit_statuses=[stepler_config.STATUS_BUILD],
43
+        timeout=stepler_config.SERVER_ACTIVE_TIMEOUT)
44
+
45
+    def _check_record_in_log():
46
+        server.get()
47
+        console = server.get_console_output()
48
+        return re.search(settings.SERVICE_INSTANCE_BOOT_DONE_PATTERN, console)
49
+
50
+    waiter.wait(
51
+        _check_record_in_log,
52
+        timeout_seconds=settings.SERVICE_INSTANCE_BOOT_TIMEOUT)
53
+
54
+
55
+def delete_service_instance(contrail_api_client, service_instance,
56
+                            server_steps):
57
+    """"Delete service instance."""
58
+    refs = service_instance.get_virtual_machine_back_refs()
59
+    contrail_api_client.service_instance_delete(id=service_instance.uuid)
60
+    if refs:
61
+        server_uuid = refs[0]['uuid']
62
+        server = next(server for server in server_steps.get_servers()
63
+                      if server.id == server_uuid)
64
+        server_steps.check_server_presence(
65
+            server,
66
+            present=False,
67
+            timeout=stepler_config.SERVER_DELETE_TIMEOUT)

+ 10
- 0
plugin_test/vapor/vapor/settings.py View File

@@ -220,3 +220,13 @@ SECURITY_GROUP_SSH_PING_RULES = (stepler_config.SECURITY_GROUP_SSH_RULES +
220 220
                                  SECURITY_GROUP_PING_RULES)
221 221
 
222 222
 DPDK_ENABLED_GROUP = u'Network devices using DPDK-compatible driver'
223
+
224
+
225
+
226
+# Service chaining
227
+# TODO(gdyuldin): relace with real URL
228
+NAT_SERVICE_IMAGE_URL = os.environ.get('NAT_SERVICE_IMAGE_URL',
229
+                                       '/home/jenkins/nat.qcow2')
230
+SERVICE_INSTANCE_CREATE_TIMEOUT = 2 * 60
231
+SERVICE_INSTANCE_BOOT_TIMEOUT = 10 * 60
232
+SERVICE_INSTANCE_BOOT_DONE_PATTERN = 'Cloud-init .+ finished'

+ 156
- 0
plugin_test/vapor/vapor/tests/test_service_instance.py View File

@@ -0,0 +1,156 @@
1
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+# not use this file except in compliance with the License. You may obtain
3
+# a copy of the License at
4
+
5
+#     http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+# Unless required by applicable law or agreed to in writing, software
8
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+# License for the specific language governing permissions and limitations
11
+# under the License.
12
+
13
+import time
14
+
15
+from hamcrest import assert_that, all_of, contains_string, is_not
16
+import pycontrail.types as types
17
+from stepler import config as stepler_config
18
+
19
+
20
+def _get_tcpdump_log_with_ping(server_steps, left_vm, right_vm, left_vm_fip,
21
+                               right_vm_fip, right_vm_fixed_ip):
22
+    """Start ping from left to right vm, returns right vm tcpdump's log."""
23
+    log_file = '/tmp/tcpdump'
24
+    with server_steps.get_server_ssh(
25
+            right_vm, right_vm_fip['floating_ip_address']) as right_ssh:
26
+        with right_ssh.sudo():
27
+            right_ssh.check_call('apt-get install -y tcpdump')
28
+            with server_steps.get_server_ssh(
29
+                    left_vm, left_vm_fip['floating_ip_address']) as left_ssh:
30
+                with server_steps.check_ping_loss_context(
31
+                        right_vm_fixed_ip, server_ssh=left_ssh):
32
+                    tcpdump_pid = right_ssh.background_call(
33
+                        'tcpdump -i eth0 icmp', stdout=log_file)
34
+                    time.sleep(10)
35
+                    right_ssh.check_call('kill {}'.format(tcpdump_pid))
36
+            return right_ssh.check_call('cat {}'.format(log_file)).stdout
37
+
38
+
39
+def test_nat_service_instance(flavor, ubuntu_image, keypair, public_network,
40
+                              neutron_security_group, contrail_2_networks,
41
+                              create_floating_ip, contrail_network_policy,
42
+                              set_network_policy, contrail_api_client,
43
+                              server_steps, port_steps, service_instance):
44
+    """Test contrail NAT service chain.
45
+
46
+    Steps:
47
+        #. Create flavor
48
+        #. Create ubuntu image
49
+        #. Create keypair
50
+        #. Create security group
51
+        #. Create left and right networks with subnets
52
+        #. Create service template
53
+        #. Create service instance with NAT service
54
+        #. Create policy
55
+        #. Assign policy to networks
56
+        #. Create left and right vm on corresponding networks
57
+        #. Start ping from left to right vm
58
+        #. Check that left vm ip is present on tcpdump output on right vm
59
+        #. Stop ping
60
+        #. Add service instance to policy rule
61
+        #. Start ping from left to right vm
62
+        #. Check that left vm ip is absent on tcpdump output on right vm and
63
+            right interface ip of service instance is present on tcpdump output
64
+        #. Stop ping
65
+    """
66
+    # Add security group to NAT instance
67
+    nat_vm_id = service_instance.get_virtual_machine_back_refs()[0]['uuid']
68
+    nova_nat_instance = next(server for server in server_steps.get_servers()
69
+                             if server.id == nat_vm_id)
70
+    nova_nat_instance.add_security_group(neutron_security_group['id'])
71
+
72
+    left_vn, right_vn = [
73
+        contrail_api_client.virtual_network_read(id=net['id'])
74
+        for net in contrail_2_networks.networks
75
+    ]
76
+
77
+    # Create policy rule with service
78
+    rule = types.PolicyRuleType(
79
+        action_list=types.ActionListType(simple_action='pass'),
80
+        direction='<>',
81
+        protocol='any',
82
+        src_addresses=[
83
+            types.AddressType(virtual_network=left_vn.get_fq_name_str())
84
+        ],
85
+        src_ports=[types.PortType()],
86
+        dst_addresses=[
87
+            types.AddressType(virtual_network=right_vn.get_fq_name_str())
88
+        ],
89
+        dst_ports=[types.PortType()])
90
+    contrail_network_policy.set_network_policy_entries(
91
+        types.PolicyEntriesType(policy_rule=[rule]))
92
+    contrail_api_client.network_policy_update(contrail_network_policy)
93
+
94
+    # Assign policy to networks
95
+    set_network_policy(left_vn, contrail_network_policy)
96
+    set_network_policy(right_vn, contrail_network_policy)
97
+
98
+    # Create 2 servers
99
+    servers = []
100
+    floating_ips = []
101
+    for net in contrail_2_networks.networks:
102
+        server = server_steps.create_servers(
103
+            flavor=flavor,
104
+            image=ubuntu_image,
105
+            networks=[net],
106
+            security_groups=[neutron_security_group],
107
+            keypair=keypair,
108
+            username=stepler_config.UBUNTU_USERNAME)[0]
109
+
110
+        servers.append(server)
111
+
112
+        server_port = port_steps.get_port(
113
+            device_owner=stepler_config.PORT_DEVICE_OWNER_SERVER,
114
+            device_id=server.id)
115
+        floating_ip = create_floating_ip(public_network, port=server_port)
116
+
117
+        floating_ips.append(floating_ip)
118
+
119
+    left_vm, right_vm = servers
120
+    left_vm_fip, right_vm_fip = floating_ips
121
+
122
+    # Install tcpdump on right vm
123
+    with server_steps.get_server_ssh(
124
+            right_vm, right_vm_fip['floating_ip_address']) as right_ssh:
125
+        with right_ssh.sudo():
126
+            right_ssh.check_call('apt-get install -y tcpdump')
127
+
128
+    right_vm_fixed_ip = server_steps.get_fixed_ip(right_vm)
129
+    nat_right_ip = nova_nat_instance.addresses[right_vn.name][0]['addr']
130
+    left_vm_fixed_ip = server_steps.get_fixed_ip(left_vm)
131
+
132
+    # Start ping from left to right server and tcpdump on right server
133
+    tcpdump_stdout = _get_tcpdump_log_with_ping(
134
+        server_steps, left_vm, right_vm, left_vm_fip, right_vm_fip,
135
+        right_vm_fixed_ip)
136
+
137
+    # Check that ICMP packets contains left vm ip address
138
+    assert_that(tcpdump_stdout, contains_string(left_vm_fixed_ip))
139
+
140
+    # Update policy rule
141
+    rule.action_list.apply_service = [service_instance.get_fq_name_str()]
142
+    contrail_network_policy.set_network_policy_entries(
143
+        types.PolicyEntriesType(policy_rule=[rule]))
144
+    contrail_api_client.network_policy_update(contrail_network_policy)
145
+
146
+    # Start ping from left to right server and tcpdump on right server
147
+    tcpdump_stdout = _get_tcpdump_log_with_ping(
148
+        server_steps, left_vm, right_vm, left_vm_fip, right_vm_fip,
149
+        right_vm_fixed_ip)
150
+
151
+    # Check that ICMP packets has NAT right ip address and no contains left
152
+    # vm ip address
153
+    assert_that(tcpdump_stdout,
154
+                all_of(
155
+                    contains_string(nat_right_ip),
156
+                    is_not(contains_string(left_vm_fixed_ip))))

Loading…
Cancel
Save