# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you 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.
""" Tests for VPN in VPC
"""
# Import Local Modules
from marvin.codes import PASS, FAILED
from marvin.cloudstackTestCase import cloudstackTestCase
from marvin.lib.utils import (validateList,
                              wait_until)

from marvin.lib.base import (Account,
                             VPC,
                             VpcOffering,
                             ServiceOffering,
                             NetworkOffering,
                             Network,
                             PublicIPAddress,
                             NATRule,
                             NetworkACLList,
                             VirtualMachine,
                             Vpn,
                             VpnCustomerGateway,
                             VpnUser
                             )

from marvin.sshClient import SshClient


from marvin.lib.common import (get_zone,
                               get_domain,
                               get_test_template)

from nose.plugins.attrib import attr

import logging
import time

class TestVpcRemoteAccessVpn(cloudstackTestCase):

    @classmethod
    def setUpClass(cls):

        cls.logger = logging.getLogger('TestVPCRemoteAccessVPN')
        cls.stream_handler = logging.StreamHandler()
        cls.logger.setLevel(logging.DEBUG)
        cls.logger.addHandler(cls.stream_handler)

        testClient = super(TestVpcRemoteAccessVpn, cls).getClsTestClient()
        cls.apiclient = testClient.getApiClient()
        cls.services = testClient.getParsedTestDataConfig()

        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
        cls.domain = get_domain(cls.apiclient)

        cls._cleanup = []

        cls.compute_offering = ServiceOffering.create(
            cls.apiclient,
            cls.services["vpc_vpn"]["compute_offering"]
        )
        cls._cleanup.append(cls.compute_offering)
        cls.account = Account.create(
            cls.apiclient, services=cls.services["vpc_vpn"]["account"])
        cls._cleanup.append(cls.account)

        cls.hypervisor = testClient.getHypervisorInfo()

        cls.template = get_test_template(cls.apiclient, cls.zone.id, cls.hypervisor)
        if cls.template == FAILED:
            assert False, "get_test_template() failed to return template"

        cls.logger.debug("Successfully created account: %s, id: \
                   %s" % (cls.account.name,
                          cls.account.id))

        return

    @attr(tags=["advanced"], required_hardware="true")
    def test_01_vpc_remote_access_vpn(self):
        """Test Remote Access VPN in VPC"""

        self.logger.debug("Starting test: test_01_vpc_remote_access_vpn")

        # 0) Get the default network offering for VPC
        self.logger.debug("Retrieving default VPC offering")
        networkOffering = NetworkOffering.list(
            self.apiclient, name="DefaultIsolatedNetworkOfferingForVpcNetworks")
        self.assertTrue(networkOffering is not None and len(
            networkOffering) > 0, "No VPC based network offering")

        # 1) Create VPC
        vpcOffering = VpcOffering.list(self.apiclient, name="Default VPC offering")
        self.assertTrue(vpcOffering is not None and len(
            vpcOffering) > 0, "No VPC offerings found")

        vpc = None
        try:
            vpc = VPC.create(
                apiclient=self.apiclient,
                services=self.services["vpc_vpn"]["vpc"],
                networkDomain="vpc.vpn",
                vpcofferingid=vpcOffering[0].id,
                zoneid=self.zone.id,
                account=self.account.name,
                domainid=self.domain.id
            )
            self.cleanup.append(vpc)
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(vpc is not None, "VPC creation failed")
            self.logger.debug("VPC %s created" % (vpc.id))

        try:
            # 2) Create network in VPC
            ntwk = Network.create(
                apiclient=self.apiclient,
                services=self.services["vpc_vpn"]["network_1"],
                accountid=self.account.name,
                domainid=self.domain.id,
                networkofferingid=networkOffering[0].id,
                zoneid=self.zone.id,
                vpcid=vpc.id
            )
            self.cleanup.append(ntwk)
        except Exception as e:
            self.fail(e)
        finally:
            self.assertIsNotNone(ntwk, "Network failed to create")
            self.logger.debug(
                "Network %s created in VPC %s" % (ntwk.id, vpc.id))

        try:
            # 3) Deploy a vm
            vm = VirtualMachine.create(self.apiclient, services=self.services["vpc_vpn"]["virtual_machine"],
                                       templateid=self.template.id,
                                       zoneid=self.zone.id,
                                       accountid=self.account.name,
                                       domainid=self.domain.id,
                                       serviceofferingid=self.compute_offering.id,
                                       networkids=ntwk.id,
                                       hypervisor=self.hypervisor
                                       )
            self.cleanup.append(vm)
            self.debug("VM %s deployed in VPC %s" % (vm.id, vpc.id))
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(vm is not None, "VM failed to deploy")
            self.assertTrue(vm.state == 'Running', "VM is not running")
            self.logger.debug("Deployed virtual machine: OK")

        try:
            # 4) Enable VPN for VPC
            src_nat_list = PublicIPAddress.list(
                self.apiclient,
                account=self.account.name,
                domainid=self.account.domainid,
                listall=True,
                issourcenat=True,
                vpcid=vpc.id
            )
            ip = src_nat_list[0]
        except Exception as e:
            self.fail(e)
        finally:
            self.logger.debug("Acquired public ip address: OK")

        vpn = None
        try:
            vpn = Vpn.create(self.apiclient,
                             publicipid=ip.id,
                             account=self.account.name,
                             domainid=self.account.domainid,
                             iprange=self.services["vpc_vpn"]["vpn"]["iprange"],
                             fordisplay=self.services["vpc_vpn"]["vpn"]["fordisplay"]
                             )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertIsNotNone(vpn, "Failed to create Remote Access VPN")
            self.logger.debug("Created Remote Access VPN: OK")

        vpnUser = None
        # 5) Add VPN user for VPC
        try:
            vpnUser = VpnUser.create(self.apiclient,
                                     account=self.account.name,
                                     domainid=self.account.domainid,
                                     username=self.services["vpc_vpn"]["vpn"]["vpn_user"],
                                     password=self.services["vpc_vpn"]["vpn"]["vpn_pass"]
                                     )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertIsNotNone(
                vpnUser, "Failed to create Remote Access VPN User")
            self.logger.debug("Created VPN User: OK")

        # TODO: Add an actual remote vpn connection test from a remote vpc

        try:
            # 9) Disable VPN for VPC
            vpn.delete(self.apiclient)
        except Exception as e:
            self.fail(e)
        finally:
            self.logger.debug("Deleted the Remote Access VPN: OK")

    @classmethod
    def tearDownClass(cls):
        super(TestVpcRemoteAccessVpn, cls).tearDownClass()

    def setUp(self):
        self.apiclient = self.testClient.getApiClient()
        self.hypervisor = self.testClient.getHypervisorInfo()
        self.cleanup = []

    def tearDown(self):
        super(TestVpcRemoteAccessVpn, self).tearDown()


class TestVpcSite2SiteVpn(cloudstackTestCase):

    @classmethod
    def setUpClass(cls):
        cls.logger = logging.getLogger('TestVPCSite2SiteVPN')
        cls.stream_handler = logging.StreamHandler()
        cls.logger.setLevel(logging.DEBUG)
        cls.logger.addHandler(cls.stream_handler)

        testClient = super(TestVpcSite2SiteVpn, cls).getClsTestClient()
        cls.apiclient = testClient.getApiClient()
        cls.services = testClient.getParsedTestDataConfig()

        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
        cls.domain = get_domain(cls.apiclient)

        cls._cleanup = []

        cls.compute_offering = ServiceOffering.create(
            cls.apiclient,
            cls.services["vpc_vpn"]["compute_offering"]
        )
        cls._cleanup.append(cls.compute_offering)

        cls.account = Account.create(
            cls.apiclient, services=cls.services["vpc_vpn"]["account"])
        cls._cleanup.append(cls.account)

        cls.hypervisor = testClient.getHypervisorInfo()

        cls.template = get_test_template(cls.apiclient, cls.zone.id, cls.hypervisor)
        if cls.template == FAILED:
            assert False, "get_test_template() failed to return template"

        cls.logger.debug("Successfully created account: %s, id: \
                   %s" % (cls.account.name,
                          cls.account.id))
        return

    def setUp(self):
        self.apiclient = self.testClient.getApiClient()
        self.hypervisor = self.testClient.getHypervisorInfo()
        self.cleanup = []

    def _get_ssh_client(self, virtual_machine, services, retries):
        """ Setup ssh client connection and return connection
        vm requires attributes public_ip, public_port, username, password """

        try:
            ssh_client = SshClient(
                virtual_machine.public_ip,
                services["vpc_vpn"]["virtual_machine"]["ssh_port"],
                services["vpc_vpn"]["virtual_machine"]["username"],
                services["vpc_vpn"]["virtual_machine"]["password"],
                retries)

        except Exception as e:
            self.fail("Unable to create ssh connection: " % e)

        self.assertIsNotNone(
            ssh_client, "Failed to setup ssh connection to vm=%s on public_ip=%s" % (virtual_machine.name, virtual_machine.public_ip))

        return ssh_client

    def _create_natrule(self, vpc, vm, public_port, private_port, public_ip, network, services=None):
        self.logger.debug("Creating NAT rule in network for vm with public IP")
        if not services:
            self.services["vpc_vpn"]["natrule"]["privateport"] = private_port
            self.services["vpc_vpn"]["natrule"]["publicport"] = public_port
            self.services["vpc_vpn"]["natrule"]["startport"] = public_port
            self.services["vpc_vpn"]["natrule"]["endport"] = public_port
            services = self.services["vpc_vpn"]["natrule"]

        nat_rule = NATRule.create(
            apiclient=self.apiclient,
            services=services,
            ipaddressid=public_ip.ipaddress.id,
            virtual_machine=vm,
            networkid=network.id
        )
        self.assertIsNotNone(
            nat_rule, "Failed to create NAT Rule for %s" % public_ip.ipaddress.ipaddress)
        self.logger.debug(
            "Adding NetworkACL rules to make NAT rule accessible")

        vm.ssh_ip = nat_rule.ipaddress
        vm.public_ip = nat_rule.ipaddress
        vm.public_port = int(public_port)
        return nat_rule

    def _validate_vpc_offering(self, vpc_offering):

        self.logger.debug("Check if the VPC offering is created successfully?")
        vpc_offs = VpcOffering.list(
            self.apiclient,
            id=vpc_offering.id
        )
        offering_list = validateList(vpc_offs)
        self.assertEqual(offering_list[0],
                         PASS,
                         "List VPC offerings should return a valid list"
                         )
        self.assertEqual(
            vpc_offering.name,
            vpc_offs[0].name,
            "Name of the VPC offering should match with listVPCOff data"
        )
        self.logger.debug(
            "VPC offering is created successfully - %s" %
            vpc_offering.name)
        return

    def _create_vpc_offering(self, offering_name):

        vpc_off = None
        if offering_name is not None:

            self.logger.debug("Creating VPC offering: %s", offering_name)
            vpc_off = VpcOffering.create(
                self.apiclient,
                self.services["vpc_vpn"][offering_name]
            )

            self._validate_vpc_offering(vpc_off)
            self.cleanup.append(vpc_off)

        return vpc_off

    @attr(tags=["advanced"], required_hardware="true")
    def test_01_vpc_site2site_vpn(self):
        """Test Site 2 Site VPN Across VPCs"""
        self.logger.debug("Starting test: test_01_vpc_site2site_vpn")
        # 0) Get the default network offering for VPC
        networkOffering = NetworkOffering.list(
            self.apiclient, name="DefaultIsolatedNetworkOfferingForVpcNetworks")
        self.assertTrue(networkOffering is not None and len(
            networkOffering) > 0, "No VPC based network offering")

        # Create and Enable VPC offering
        vpc_offering = self._create_vpc_offering('vpc_offering')
        self.assertTrue(vpc_offering is not None, "Failed to create VPC Offering")
        vpc_offering.update(self.apiclient, state='Enabled')

        vpc1 = None
        # Create VPC 1
        try:
            vpc1 = VPC.create(
                apiclient=self.apiclient,
                services=self.services["vpc_vpn"]["vpc"],
                networkDomain="vpc1.vpn",
                vpcofferingid=vpc_offering.id,
                zoneid=self.zone.id,
                account=self.account.name,
                domainid=self.domain.id
            )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(vpc1 is not None, "VPC1 creation failed")
        self.cleanup.append(vpc1)
        self.logger.debug("VPC1 %s created" % vpc1.id)

        vpc2 = None
        # Create VPC 2
        try:
            vpc2 = VPC.create(
                apiclient=self.apiclient,
                services=self.services["vpc_vpn"]["vpc2"],
                networkDomain="vpc2.vpn",
                vpcofferingid=vpc_offering.id,
                zoneid=self.zone.id,
                account=self.account.name,
                domainid=self.account.domainid
            )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(vpc2 is not None, "VPC2 creation failed")
        self.cleanup.append(vpc2)
        self.logger.debug("VPC2 %s created" % vpc2.id)

        default_acl = NetworkACLList.list(
            self.apiclient, name="default_allow")[0]

        ntwk1 = None
        # Create network in VPC 1
        try:
            ntwk1 = Network.create(
                apiclient=self.apiclient,
                services=self.services["vpc_vpn"]["network_1"],
                accountid=self.account.name,
                domainid=self.account.domainid,
                networkofferingid=networkOffering[0].id,
                zoneid=self.zone.id,
                vpcid=vpc1.id,
                aclid=default_acl.id
            )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertIsNotNone(ntwk1, "Network failed to create")
        self.cleanup.append(ntwk1)
        self.logger.debug("Network %s created in VPC %s" % (ntwk1.id, vpc1.id))

        ntwk2 = None
        # Create network in VPC 2
        try:
            ntwk2 = Network.create(
                apiclient=self.apiclient,
                services=self.services["vpc_vpn"]["network_2"],
                accountid=self.account.name,
                domainid=self.account.domainid,
                networkofferingid=networkOffering[0].id,
                zoneid=self.zone.id,
                vpcid=vpc2.id,
                aclid=default_acl.id
            )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertIsNotNone(ntwk2, "Network failed to create")
        self.cleanup.append(ntwk2)
        self.logger.debug("Network %s created in VPC %s" % (ntwk2.id, vpc2.id))

        vm1 = None
        # Deploy a vm in network 1
        try:
            vm1 = VirtualMachine.create(self.apiclient, services=self.services["vpc_vpn"]["virtual_machine"],
                                        templateid=self.template.id,
                                        zoneid=self.zone.id,
                                        accountid=self.account.name,
                                        domainid=self.account.domainid,
                                        serviceofferingid=self.compute_offering.id,
                                        networkids=ntwk1.id,
                                        hypervisor=self.hypervisor
                                        )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(vm1 is not None, "VM failed to deploy")
            self.assertTrue(vm1.state == 'Running', "VM is not running")
        self.cleanup.append(vm1)
        self.logger.debug("VM %s deployed in VPC %s" % (vm1.id, vpc1.id))

        vm2 = None
        # Deploy a vm in network 2
        try:
            vm2 = VirtualMachine.create(self.apiclient, services=self.services["vpc_vpn"]["virtual_machine"],
                                        templateid=self.template.id,
                                        zoneid=self.zone.id,
                                        accountid=self.account.name,
                                        domainid=self.account.domainid,
                                        serviceofferingid=self.compute_offering.id,
                                        networkids=ntwk2.id,
                                        hypervisor=self.hypervisor
                                        )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(vm2 is not None, "VM failed to deploy")
            self.assertTrue(vm2.state == 'Running', "VM is not running")
        self.cleanup.append(vm2)
        self.debug("VM %s deployed in VPC %s" % (vm2.id, vpc2.id))

        # 4) Enable Site-to-Site VPN for VPC
        vpn1_response = Vpn.createVpnGateway(self.apiclient, vpc1.id)
        self.assertTrue(
            vpn1_response is not None, "Failed to enable VPN Gateway 1")
        self.logger.debug("VPN gateway for VPC %s enabled" % vpc1.id)

        vpn2_response = Vpn.createVpnGateway(self.apiclient, vpc2.id)
        self.assertTrue(
            vpn2_response is not None, "Failed to enable VPN Gateway 2")
        self.logger.debug("VPN gateway for VPC %s enabled" % vpc2.id)

        # 5) Add VPN Customer gateway info
        src_nat_list = PublicIPAddress.list(
            self.apiclient,
            account=self.account.name,
            domainid=self.account.domainid,
            listall=True,
            issourcenat=True,
            vpcid=vpc1.id
        )
        ip1 = src_nat_list[0]
        src_nat_list = PublicIPAddress.list(
            self.apiclient,
            account=self.account.name,
            domainid=self.account.domainid,
            listall=True,
            issourcenat=True,
            vpcid=vpc2.id
        )
        ip2 = src_nat_list[0]

        services = self.services["vpc_vpn"]["vpncustomergateway"]
        customer1_response = VpnCustomerGateway.create(
            self.apiclient, services, "Peer VPC1", ip1.ipaddress, vpc1.cidr, self.account.name, self.domain.id)
        self.debug("VPN customer gateway added for VPC %s enabled" % vpc1.id)
        self.logger.debug(vars(customer1_response))

        customer2_response = VpnCustomerGateway.create(
            self.apiclient, services, "Peer VPC2", ip2.ipaddress, vpc2.cidr, self.account.name, self.domain.id)
        self.debug("VPN customer gateway added for VPC %s enabled" % vpc2.id)
        self.logger.debug(vars(customer2_response))

        # 6) Connect two VPCs
        vpnconn1_response = Vpn.createVpnConnection(
            self.apiclient, customer1_response.id, vpn2_response['id'], True)
        self.debug("VPN passive connection created for VPC %s" % vpc2.id)

        vpnconn2_response = Vpn.createVpnConnection(
            self.apiclient, customer2_response.id, vpn1_response['id'])
        self.debug("VPN connection created for VPC %s" % vpc1.id)

        def checkVpnConnected():
            connections = Vpn.listVpnConnection(
                self.apiclient,
                listall='true',
                vpcid=vpc2.id)
            if isinstance(connections, list):
                return connections[0].state == 'Connected', None
            return False, None

        # Wait up to 60 seconds for passive connection to show up as Connected
        res, _ = wait_until(2, 30, checkVpnConnected)
        if not res:
            self.fail("Failed to connect between VPCs, see VPN state as Connected")

        # acquire an extra ip address to use to ssh into vm2
        try:
            vm2.public_ip = PublicIPAddress.create(
                apiclient=self.apiclient,
                accountid=self.account.name,
                zoneid=self.zone.id,
                domainid=self.account.domainid,
                services=self.services,
                networkid=ntwk2.id,
                vpcid=vpc2.id)
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(
                vm2.public_ip is not None, "Failed to aqcuire public ip for vm2")

        natrule = None
        # Create port forward to be able to ssh into vm2
        try:
            natrule = self._create_natrule(
                vpc2, vm2, 22, 22, vm2.public_ip, ntwk2)
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(
                natrule is not None, "Failed to create portforward for vm2")
            time.sleep(20)

        # setup ssh connection to vm2
        ssh_client = self._get_ssh_client(vm2, self.services, 30)

        if ssh_client:
            # run ping test
            packet_loss = ssh_client.execute("/bin/ping -c 3 -t 10 " + vm1.nic[0].ipaddress + " | grep packet | sed 's/.*received, //g' | sed 's/[% ]*packet.*//g'")[0]
            # during startup, some packets may not reply due to link/ipsec-route setup
            self.assertTrue(int(packet_loss) < 50, "Ping did not succeed")
        else:
            self.fail("Failed to setup ssh connection to %s" % vm2.public_ip)

    @classmethod
    def tearDownClass(cls):
        super(TestVpcSite2SiteVpn, cls).tearDownClass()

    def tearDown(self):
        super(TestVpcSite2SiteVpn, self).tearDown()


class TestRVPCSite2SiteVpn(cloudstackTestCase):

    @classmethod
    def setUpClass(cls):
        cls.logger = logging.getLogger('TestRVPCSite2SiteVPN')
        cls.stream_handler = logging.StreamHandler()
        cls.logger.setLevel(logging.DEBUG)
        cls.logger.addHandler(cls.stream_handler)

        testClient = super(TestRVPCSite2SiteVpn, cls).getClsTestClient()
        cls.apiclient = testClient.getApiClient()
        cls.services = testClient.getParsedTestDataConfig()

        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
        cls.domain = get_domain(cls.apiclient)
        cls._cleanup = []

        cls.compute_offering = ServiceOffering.create(
            cls.apiclient,
            cls.services["vpc_vpn"]["compute_offering"]
        )
        cls._cleanup.append(cls.compute_offering)

        cls.account = Account.create(
            cls.apiclient, services=cls.services["vpc_vpn"]["account"])
        cls._cleanup.append(cls.account)

        cls.hypervisor = testClient.getHypervisorInfo()

        cls.template = get_test_template(cls.apiclient, cls.zone.id, cls.hypervisor)
        if cls.template == FAILED:
            assert False, "get_test_template() failed to return template"

        cls.logger.debug("Successfully created account: %s, id: \
                   %s" % (cls.account.name,
                          cls.account.id))
        return

    def _validate_vpc_offering(self, vpc_offering):

        self.logger.debug("Check if the VPC offering is created successfully?")
        vpc_offs = VpcOffering.list(
            self.apiclient,
            id=vpc_offering.id
        )
        offering_list = validateList(vpc_offs)
        self.assertEqual(offering_list[0],
                         PASS,
                         "List VPC offerings should return a valid list"
                         )
        self.assertEqual(
            vpc_offering.name,
            vpc_offs[0].name,
            "Name of the VPC offering should match with listVPCOff data"
        )
        self.logger.debug(
            "VPC offering is created successfully - %s" %
            vpc_offering.name)
        return

    def _create_vpc_offering(self, offering_name):

        vpc_off = None
        if offering_name is not None:

            self.logger.debug("Creating VPC offering: %s", offering_name)
            vpc_off = VpcOffering.create(
                self.apiclient,
                self.services["vpc_vpn"][offering_name]
            )

            self._validate_vpc_offering(vpc_off)
            self.cleanup.append(vpc_off)

        return vpc_off

    def _get_ssh_client(self, virtual_machine, services, retries):
        """ Setup ssh client connection and return connection
        vm requires attributes public_ip, public_port, username, password """

        try:
            ssh_client = SshClient(
                virtual_machine.public_ip,
                services["vpc_vpn"]["virtual_machine"]["ssh_port"],
                services["vpc_vpn"]["virtual_machine"]["username"],
                services["vpc_vpn"]["virtual_machine"]["password"],
                retries)

        except Exception as e:
            self.fail("Unable to create ssh connection: %s" % e)

        self.assertIsNotNone(
            ssh_client, "Failed to setup ssh connection to vm=%s on public_ip=%s" % (virtual_machine.name, virtual_machine.public_ip))

        return ssh_client

    def _create_natrule(self, vpc, vm, public_port, private_port, public_ip, network, services=None):
        self.logger.debug("Creating NAT rule in network for vm with public IP")
        if not services:
            self.services["vpc_vpn"]["natrule"]["privateport"] = private_port
            self.services["vpc_vpn"]["natrule"]["publicport"] = public_port
            self.services["vpc_vpn"]["natrule"]["startport"] = public_port
            self.services["vpc_vpn"]["natrule"]["endport"] = public_port
            services = self.services["vpc_vpn"]["natrule"]

        nat_rule = NATRule.create(
            apiclient=self.apiclient,
            services=services,
            ipaddressid=public_ip.ipaddress.id,
            virtual_machine=vm,
            networkid=network.id
        )
        self.assertIsNotNone(
            nat_rule, "Failed to create NAT Rule for %s" % public_ip.ipaddress.ipaddress)
        self.logger.debug(
            "Adding NetworkACL rules to make NAT rule accessible")

        vm.ssh_ip = nat_rule.ipaddress
        vm.public_ip = nat_rule.ipaddress
        vm.public_port = int(public_port)
        return nat_rule

    @attr(tags=["advanced"], required_hardware="true")
    def test_01_redundant_vpc_site2site_vpn(self):
        """Test Site 2 Site VPN Across redundant VPCs"""
        self.logger.debug("Starting test: test_02_redundant_vpc_site2site_vpn")

        # 0) Get the default network offering for VPC
        networkOffering = NetworkOffering.list(
            self.apiclient, name="DefaultIsolatedNetworkOfferingForVpcNetworks")
        self.assertTrue(networkOffering is not None and len(
            networkOffering) > 0, "No VPC based network offering")

        # Create and enable redundant VPC offering
        redundant_vpc_offering = self._create_vpc_offering(
            'redundant_vpc_offering')
        self.assertTrue(redundant_vpc_offering is not None,
                     "Failed to create redundant VPC Offering")
        redundant_vpc_offering.update(self.apiclient, state='Enabled')

        # Create VPC 1
        vpc1 = None
        try:
            vpc1 = VPC.create(
                apiclient=self.apiclient,
                services=self.services["vpc_vpn"]["vpc"],
                networkDomain="vpc1.vpn",
                vpcofferingid=redundant_vpc_offering.id,
                zoneid=self.zone.id,
                account=self.account.name,
                domainid=self.domain.id
            )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(vpc1 is not None, "VPC1 creation failed")
        self.cleanup.append(vpc1)
        self.logger.debug("VPC1 %s created" % vpc1.id)

        # Create VPC 2
        vpc2 = None
        try:
            vpc2 = VPC.create(
                apiclient=self.apiclient,
                services=self.services["vpc_vpn"]["vpc2"],
                networkDomain="vpc2.vpn",
                vpcofferingid=redundant_vpc_offering.id,
                zoneid=self.zone.id,
                account=self.account.name,
                domainid=self.account.domainid
            )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(vpc2 is not None, "VPC2 creation failed")
        self.cleanup.append(vpc2)
        self.logger.debug("VPC2 %s created" % vpc2.id)

        default_acl = NetworkACLList.list(
            self.apiclient, name="default_allow")[0]

        # Create network in VPC 1
        ntwk1 = None
        try:
            ntwk1 = Network.create(
                apiclient=self.apiclient,
                services=self.services["vpc_vpn"]["network_1"],
                accountid=self.account.name,
                domainid=self.account.domainid,
                networkofferingid=networkOffering[0].id,
                zoneid=self.zone.id,
                vpcid=vpc1.id,
                aclid=default_acl.id
            )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertIsNotNone(ntwk1, "Network failed to create")
        self.cleanup.append(ntwk1)
        self.logger.debug("Network %s created in VPC %s" % (ntwk1.id, vpc1.id))

        # Create network in VPC 2
        ntwk2 = None
        try:
            ntwk2 = Network.create(
                apiclient=self.apiclient,
                services=self.services["vpc_vpn"]["network_2"],
                accountid=self.account.name,
                domainid=self.account.domainid,
                networkofferingid=networkOffering[0].id,
                zoneid=self.zone.id,
                vpcid=vpc2.id,
                aclid=default_acl.id
            )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertIsNotNone(ntwk2, "Network failed to create")
        self.cleanup.append(ntwk2)
        self.logger.debug("Network %s created in VPC %s" % (ntwk2.id, vpc2.id))

        # Deploy a vm in network 1
        vm1 = None
        try:
            vm1 = VirtualMachine.create(self.apiclient, services=self.services["vpc_vpn"]["virtual_machine"],
                                        templateid=self.template.id,
                                        zoneid=self.zone.id,
                                        accountid=self.account.name,
                                        domainid=self.account.domainid,
                                        serviceofferingid=self.compute_offering.id,
                                        networkids=ntwk1.id,
                                        hypervisor=self.hypervisor
                                        )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(vm1 is not None, "VM failed to deploy")
            self.assertTrue(vm1.state == 'Running', "VM is not running")
        self.cleanup.append(vm1)
        self.logger.debug("VM %s deployed in VPC %s" % (vm1.id, vpc1.id))

        # Deploy a vm in network 2
        vm2 = None
        try:
            vm2 = VirtualMachine.create(self.apiclient, services=self.services["vpc_vpn"]["virtual_machine"],
                                        templateid=self.template.id,
                                        zoneid=self.zone.id,
                                        accountid=self.account.name,
                                        domainid=self.account.domainid,
                                        serviceofferingid=self.compute_offering.id,
                                        networkids=ntwk2.id,
                                        hypervisor=self.hypervisor
                                        )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(vm2 is not None, "VM failed to deploy")
            self.assertTrue(vm2.state == 'Running', "VM is not running")
        self.cleanup.append(vm2)
        self.debug("VM %s deployed in VPC %s" % (vm2.id, vpc2.id))

        # 4) Enable Site-to-Site VPN for VPC
        vpn1_response = Vpn.createVpnGateway(self.apiclient, vpc1.id)
        self.assertTrue(
            vpn1_response is not None, "Failed to enable VPN Gateway 1")
        self.logger.debug("VPN gateway for VPC %s enabled" % vpc1.id)

        vpn2_response = Vpn.createVpnGateway(self.apiclient, vpc2.id)
        self.assertTrue(
            vpn2_response is not None, "Failed to enable VPN Gateway 2")
        self.logger.debug("VPN gateway for VPC %s enabled" % vpc2.id)

        # 5) Add VPN Customer gateway info
        src_nat_list = PublicIPAddress.list(
            self.apiclient,
            account=self.account.name,
            domainid=self.account.domainid,
            listall=True,
            issourcenat=True,
            vpcid=vpc1.id
        )
        ip1 = src_nat_list[0]
        src_nat_list = PublicIPAddress.list(
            self.apiclient,
            account=self.account.name,
            domainid=self.account.domainid,
            listall=True,
            issourcenat=True,
            vpcid=vpc2.id
        )
        ip2 = src_nat_list[0]

        services = self.services["vpc_vpn"]["vpncustomergateway"]
        customer1_response = VpnCustomerGateway.create(
            self.apiclient, services, "Peer VPC1", ip1.ipaddress, vpc1.cidr, self.account.name, self.domain.id)
        self.debug("VPN customer gateway added for VPC %s enabled" % vpc1.id)
        self.logger.debug(vars(customer1_response))

        customer2_response = VpnCustomerGateway.create(
            self.apiclient, services, "Peer VPC2", ip2.ipaddress, vpc2.cidr, self.account.name, self.domain.id)
        self.debug("VPN customer gateway added for VPC %s enabled" % vpc2.id)
        self.logger.debug(vars(customer2_response))

        # 6) Connect two VPCs
        vpnconn1_response = Vpn.createVpnConnection(
            self.apiclient, customer1_response.id, vpn2_response['id'], True)
        self.debug("VPN passive connection created for VPC %s" % vpc2.id)

        vpnconn2_response = Vpn.createVpnConnection(
            self.apiclient, customer2_response.id, vpn1_response['id'])
        self.debug("VPN connection created for VPC %s" % vpc1.id)

        def checkVpnConnected():
            connections = Vpn.listVpnConnection(
                self.apiclient,
                listall='true',
                vpcid=vpc2.id)
            if isinstance(connections, list):
                return connections[0].state == 'Connected', None
            return False, None

        # Wait up to 60 seconds for passive connection to show up as Connected
        res, _ = wait_until(2, 30, checkVpnConnected)
        if not res:
            self.fail("Failed to connect between VPCs, see VPN state as Connected")

        # acquire an extra ip address to use to ssh into vm2
        try:
            vm2.public_ip = PublicIPAddress.create(
                apiclient=self.apiclient,
                accountid=self.account.name,
                zoneid=self.zone.id,
                domainid=self.account.domainid,
                services=self.services,
                networkid=ntwk2.id,
                vpcid=vpc2.id)
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(
                vm2.public_ip is not None, "Failed to aqcuire public ip for vm2")

        # Create port forward to be able to ssh into vm2
        natrule = None
        try:
            natrule = self._create_natrule(
                vpc2, vm2, 22, 22, vm2.public_ip, ntwk2)
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(
                natrule is not None, "Failed to create portforward for vm2")
            time.sleep(20)

        # setup ssh connection to vm2
        ssh_client = self._get_ssh_client(vm2, self.services, 10)

        if ssh_client:
            # run ping test
            packet_loss = ssh_client.execute("/bin/ping -c 3 -t 10 " + vm1.nic[0].ipaddress + " | grep packet | sed 's/.*received, //g' | sed 's/[% ]*packet.*//g'")[0]
            self.assertTrue(int(packet_loss) < 50, "Ping did not succeed")
        else:
            self.fail("Failed to setup ssh connection to %s" % vm2.public_ip)

    @classmethod
    def tearDownClass(cls):
        super(TestRVPCSite2SiteVpn, cls).tearDownClass()

    def setUp(self):
        self.apiclient = self.testClient.getApiClient()
        self.hypervisor = self.testClient.getHypervisorInfo()
        self.cleanup = []

    def tearDown(self):
        super(TestRVPCSite2SiteVpn, self).tearDown()

class TestVPCSite2SiteVPNMultipleOptions(cloudstackTestCase):

    @classmethod
    def setUpClass(cls):
        cls.logger = logging.getLogger('TestVPCSite2SiteVPNMultipleOptions')
        cls.stream_handler = logging.StreamHandler()
        cls.logger.setLevel(logging.DEBUG)
        cls.logger.addHandler(cls.stream_handler)

        testClient = super(TestVPCSite2SiteVPNMultipleOptions, cls).getClsTestClient()
        cls.apiclient = testClient.getApiClient()
        cls.services = testClient.getParsedTestDataConfig()

        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
        cls.domain = get_domain(cls.apiclient)

        cls._cleanup = []

        cls.compute_offering = ServiceOffering.create(
            cls.apiclient,
            cls.services["vpc_vpn"]["compute_offering"]
        )
        cls._cleanup.append(cls.compute_offering)

        cls.account = Account.create(
            cls.apiclient, services=cls.services["vpc_vpn"]["account"])
        cls._cleanup.append(cls.account)

        cls.hypervisor = testClient.getHypervisorInfo()

        cls.template = get_test_template(cls.apiclient, cls.zone.id, cls.hypervisor)
        if cls.template == FAILED:
            assert False, "get_test_template() failed to return template"

        cls.logger.debug("Successfully created account: %s, id: \
                   %s" % (cls.account.name,
                          cls.account.id))
        return

    def setUp(self):
        self.apiclient = self.testClient.getApiClient()
        self.hypervisor = self.testClient.getHypervisorInfo()
        self.cleanup = []

    def _get_ssh_client(self, virtual_machine, services, retries):
        """ Setup ssh client connection and return connection
        vm requires attributes public_ip, public_port, username, password """

        try:
            ssh_client = SshClient(
                virtual_machine.public_ip,
                services["vpc_vpn"]["virtual_machine"]["ssh_port"],
                services["vpc_vpn"]["virtual_machine"]["username"],
                services["vpc_vpn"]["virtual_machine"]["password"],
                retries)

        except Exception as e:
            self.fail("Unable to create ssh connection: " % e)

        self.assertIsNotNone(
            ssh_client, "Failed to setup ssh connection to vm=%s on public_ip=%s" % (virtual_machine.name, virtual_machine.public_ip))

        return ssh_client

    def _create_natrule(self, vpc, vm, public_port, private_port, public_ip, network, services=None):
        self.logger.debug("Creating NAT rule in network for vm with public IP")
        if not services:
            self.services["vpc_vpn"]["natrule"]["privateport"] = private_port
            self.services["vpc_vpn"]["natrule"]["publicport"] = public_port
            self.services["vpc_vpn"]["natrule"]["startport"] = public_port
            self.services["vpc_vpn"]["natrule"]["endport"] = public_port
            services = self.services["vpc_vpn"]["natrule"]

        nat_rule = NATRule.create(
            apiclient=self.apiclient,
            services=services,
            ipaddressid=public_ip.ipaddress.id,
            virtual_machine=vm,
            networkid=network.id
        )
        self.assertIsNotNone(
            nat_rule, "Failed to create NAT Rule for %s" % public_ip.ipaddress.ipaddress)
        self.logger.debug(
            "Adding NetworkACL rules to make NAT rule accessible")

        vm.ssh_ip = nat_rule.ipaddress
        vm.public_ip = nat_rule.ipaddress
        vm.public_port = int(public_port)
        return nat_rule

    def _validate_vpc_offering(self, vpc_offering):

        self.logger.debug("Check if the VPC offering is created successfully?")
        vpc_offs = VpcOffering.list(
            self.apiclient,
            id=vpc_offering.id
        )
        offering_list = validateList(vpc_offs)
        self.assertEqual(offering_list[0],
                         PASS,
                         "List VPC offerings should return a valid list"
                         )
        self.assertEqual(
            vpc_offering.name,
            vpc_offs[0].name,
            "Name of the VPC offering should match with listVPCOff data"
        )
        self.logger.debug(
            "VPC offering is created successfully - %s" %
            vpc_offering.name)
        return

    def _create_vpc_offering(self, offering_name):

        vpc_off = None
        if offering_name is not None:

            self.logger.debug("Creating VPC offering: %s", offering_name)
            vpc_off = VpcOffering.create(
                self.apiclient,
                self.services["vpc_vpn"][offering_name]
            )

            self._validate_vpc_offering(vpc_off)
            self.cleanup.append(vpc_off)

        return vpc_off

    @attr(tags=["advanced"], required_hardware="true")
    def test_01_vpc_site2site_vpn_multiple_options(self):
        """Test Site 2 Site VPN Across VPCs"""
        self.logger.debug("Starting test: test_01_vpc_site2site_vpn_multiple_options")
        # 0) Get the default network offering for VPC
        networkOffering = NetworkOffering.list(
            self.apiclient, name="DefaultIsolatedNetworkOfferingForVpcNetworks")
        self.assertTrue(networkOffering is not None and len(
            networkOffering) > 0, "No VPC based network offering")

        # Create and Enable VPC offering
        vpc_offering = self._create_vpc_offering('vpc_offering')
        self.assertTrue(vpc_offering is not None, "Failed to create VPC Offering")
        vpc_offering.update(self.apiclient, state='Enabled')

        vpc1 = None
        # Create VPC 1
        try:
            vpc1 = VPC.create(
                apiclient=self.apiclient,
                services=self.services["vpc_vpn"]["vpc"],
                networkDomain="vpc1.vpn",
                vpcofferingid=vpc_offering.id,
                zoneid=self.zone.id,
                account=self.account.name,
                domainid=self.domain.id
            )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(vpc1 is not None, "VPC1 creation failed")
        self.cleanup.append(vpc1)
        self.logger.debug("VPC1 %s created" % vpc1.id)

        vpc2 = None
        # Create VPC 2
        try:
            vpc2 = VPC.create(
                apiclient=self.apiclient,
                services=self.services["vpc_vpn"]["vpc2"],
                networkDomain="vpc2.vpn",
                vpcofferingid=vpc_offering.id,
                zoneid=self.zone.id,
                account=self.account.name,
                domainid=self.domain.id
            )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(vpc2 is not None, "VPC2 creation failed")
        self.cleanup.append(vpc2)
        self.logger.debug("VPC2 %s created" % vpc2.id)

        default_acl = NetworkACLList.list(
            self.apiclient, name="default_allow")[0]

        ntwk1 = None
        # Create network in VPC 1
        try:
            ntwk1 = Network.create(
                apiclient=self.apiclient,
                services=self.services["vpc_vpn"]["network_1"],
                accountid=self.account.name,
                domainid=self.account.domainid,
                networkofferingid=networkOffering[0].id,
                zoneid=self.zone.id,
                vpcid=vpc1.id,
                aclid=default_acl.id
            )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertIsNotNone(ntwk1, "Network failed to create")
        self.cleanup.append(ntwk1)
        self.logger.debug("Network %s created in VPC %s" % (ntwk1.id, vpc1.id))

        ntwk2 = None
        # Create network in VPC 2
        try:
            ntwk2 = Network.create(
                apiclient=self.apiclient,
                services=self.services["vpc_vpn"]["network_2"],
                accountid=self.account.name,
                domainid=self.account.domainid,
                networkofferingid=networkOffering[0].id,
                zoneid=self.zone.id,
                vpcid=vpc2.id,
                aclid=default_acl.id
            )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertIsNotNone(ntwk2, "Network failed to create")
        self.cleanup.append(ntwk2)
        self.logger.debug("Network %s created in VPC %s" % (ntwk2.id, vpc2.id))

        vm1 = None
        # Deploy a vm in network 1
        try:
            vm1 = VirtualMachine.create(self.apiclient, services=self.services["vpc_vpn"]["virtual_machine"],
                                        templateid=self.template.id,
                                        zoneid=self.zone.id,
                                        accountid=self.account.name,
                                        domainid=self.account.domainid,
                                        serviceofferingid=self.compute_offering.id,
                                        networkids=ntwk1.id,
                                        hypervisor=self.hypervisor
                                        )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(vm1 is not None, "VM failed to deploy")
            self.assertTrue(vm1.state == 'Running', "VM is not running")
        self.cleanup.append(vm1)
        self.logger.debug("VM %s deployed in VPC %s" % (vm1.id, vpc1.id))

        vm2 = None
        # Deploy a vm in network 2
        try:
            vm2 = VirtualMachine.create(self.apiclient, services=self.services["vpc_vpn"]["virtual_machine"],
                                        templateid=self.template.id,
                                        zoneid=self.zone.id,
                                        accountid=self.account.name,
                                        domainid=self.account.domainid,
                                        serviceofferingid=self.compute_offering.id,
                                        networkids=ntwk2.id,
                                        hypervisor=self.hypervisor
                                        )
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(vm2 is not None, "VM failed to deploy")
            self.assertTrue(vm2.state == 'Running', "VM is not running")
        self.cleanup.append(vm2)
        self.debug("VM %s deployed in VPC %s" % (vm2.id, vpc2.id))

        # default config
        config = {
            'ike_enc'       :'aes128',
            'ike_hash'      :'sha1',
            'ike_dh'        :'modp1536',
            'esp_enc'       :'aes128',
            'esp_hash'      :'sha1',
            'esp_pfs'       :'modp1536',
            'psk'           :'secreatKey',
            'ike_life'      :86400,
            'esp_life'      :3600,
            'dpd'           :True,
            'force_encap'   :False,
            'passive_1'     :False,
            'passive_2'     :False
        }
        test_confs = [
            {}, # default
            {'force_encap': True},
            {'ike_life': ''},
            {'esp_life': ''},
            {'ike_life': '', 'esp_life': ''},
            {'passive_1': True, 'passive_2': True},
            {'passive_1': False, 'passive_2': True},
            {'passive_1': True, 'passive_2': False},
            {'passive_1': False, 'passive_2': False, 'dpd': False},
            {'passive_1': True, 'passive_2': True, 'dpd': False},
            {'passive_1': True, 'passive_2': False, 'dpd': False},
            {'passive_1': False, 'passive_2': True, 'dpd': False},
            {'passive_1': True, 'passive_2': False, 'esp_pfs': ''},
            {'ike_dh': 'modp3072', 'ike_hash': 'sha256', 'esp_pfs': 'modp2048', 'esp_hash':'sha384'},
            {'ike_dh': 'modp4096', 'ike_hash': 'sha384', 'esp_pfs': 'modp6144', 'esp_hash':'sha512'},
            {'ike_dh': 'modp8192', 'ike_hash': 'sha512', 'esp_pfs': 'modp8192', 'esp_hash':'sha384'}
        ]

        # 4) Enable Site-to-Site VPN for VPC
        vpn1_response = Vpn.createVpnGateway(self.apiclient, vpc1.id)
        self.assertTrue(
            vpn1_response is not None, "Failed to enable VPN Gateway 1")
        self.logger.debug("VPN gateway for VPC %s enabled" % vpc1.id)

        vpn2_response = Vpn.createVpnGateway(self.apiclient, vpc2.id)
        self.assertTrue(
            vpn2_response is not None, "Failed to enable VPN Gateway 2")
        self.logger.debug("VPN gateway for VPC %s enabled" % vpc2.id)

        # 5) Add VPN Customer gateway info
        src_nat_list = PublicIPAddress.list(
            self.apiclient,
            account=self.account.name,
            domainid=self.account.domainid,
            listall=True,
            issourcenat=True,
            vpcid=vpc1.id
        )
        ip1 = src_nat_list[0]
        src_nat_list = PublicIPAddress.list(
            self.apiclient,
            account=self.account.name,
            domainid=self.account.domainid,
            listall=True,
            issourcenat=True,
            vpcid=vpc2.id
        )
        ip2 = src_nat_list[0]

        # acquire an extra ip address to use to ssh into vm2
        try:
            vm2.public_ip = PublicIPAddress.create(
                apiclient=self.apiclient,
                accountid=self.account.name,
                zoneid=self.zone.id,
                domainid=self.account.domainid,
                services=self.services,
                networkid=ntwk2.id,
                vpcid=vpc2.id)
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(
                vm2.public_ip is not None, "Failed to aqcuire public ip for vm2")

        natrule = None
        # Create port forward to be able to ssh into vm2
        try:
            natrule = self._create_natrule(
                vpc2, vm2, 22, 22, vm2.public_ip, ntwk2)
        except Exception as e:
            self.fail(e)
        finally:
            self.assertTrue(
                natrule is not None, "Failed to create portforward for vm2")
            time.sleep(20)

        # setup ssh connection to vm2
        ssh_client = self._get_ssh_client(vm2, self.services, 10)
        if not ssh_client:
            self.fail("Failed to setup ssh connection to %s" % vm2.public_ip)

        for test_c in test_confs:
            c = config.copy()
            c.update(test_c)
            services = self._get_vpn_config(c)
            self.logger.debug(services)
            customer1_response = VpnCustomerGateway.create(
                self.apiclient,
                services,
                "Peer VPC1",
                ip1.ipaddress,
                vpc1.cidr,
                account=self.account.name,
                domainid=self.account.domainid)
            self.logger.debug("VPN customer gateway added for VPC %s enabled" % vpc1.id)

            customer2_response = VpnCustomerGateway.create(
                self.apiclient,
                services,
                "Peer VPC2",
                ip2.ipaddress,
                vpc2.cidr,
                account=self.account.name,
                domainid=self.account.domainid)
            self.logger.debug("VPN customer gateway added for VPC %s enabled" % vpc2.id)

            # 6) Connect two VPCs
            vpnconn1_response = Vpn.createVpnConnection(
                self.apiclient, customer1_response.id, vpn2_response['id'], c['passive_1'])
            self.logger.debug("VPN connection created for VPC %s" % vpc2.id)
            time.sleep(5)
            vpnconn2_response = Vpn.createVpnConnection(
                self.apiclient, customer2_response.id, vpn1_response['id'], c['passive_2'])
            self.logger.debug("VPN connection created for VPC %s" % vpc1.id)

            def checkVpnConnected():
                connections = Vpn.listVpnConnection(
                    self.apiclient,
                    listall='true',
                    vpcid=vpc2.id)
                if isinstance(connections, list):
                    return connections[0].state == 'Connected', None
                return False, None

            # Wait up to 60 seconds for passive connection to show up as Connected
            res, _ = wait_until(2, 30, checkVpnConnected)
            if not res:
                self.logger.debug("Failed to see VPN state as Connected, we'll attempt ssh+pinging")

            # run ping test
            packet_loss = ssh_client.execute("/bin/ping -c 3 -t 10 " + vm1.nic[0].ipaddress + " | grep packet | sed 's/.*received, //g' | sed 's/[% ]*packet.*//g'")[0]
            self.logger.debug("Packet loss %s" % packet_loss)
            self.assertTrue(int(packet_loss) < 50, "Ping did not succeed")

            # Cleanup
            Vpn.deleteVpnConnection(self.apiclient, vpnconn1_response['id'])
            Vpn.deleteVpnConnection(self.apiclient, vpnconn2_response['id'])
            customer1_response.delete(self.apiclient)
            customer2_response.delete(self.apiclient)

    def _get_vpn_config(self, c):
        ike_policy = '%s-%s;%s' % (c['ike_enc'], c['ike_hash'], c['ike_dh']) if c['ike_dh'] else '%s-%s' % (c['ike_enc'], c['ike_hash'])
        esp_policy = '%s-%s;%s' % (c['esp_enc'], c['esp_hash'], c['esp_pfs']) if c['esp_pfs'] else '%s-%s' % (c['esp_enc'], c['esp_hash'])
        out =  {
            'ipsecpsk': c['psk'],
            'ikepolicy':ike_policy,
            'esppolicy':esp_policy,
            'dpd':c['dpd'],
            'forceencap':c['force_encap']
        }
        if c['ike_life']:
            out['ikelifetime'] = c['ike_life']
        if c['esp_life']:
            out['esplifetime'] = c['esp_life']
        return out

    @classmethod
    def tearDownClass(cls):
        super(TestVPCSite2SiteVPNMultipleOptions, cls).tearDownClass()
