# 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 Persistent Networks without running VMs feature"""
from marvin.lib.utils import (cleanup_resources,
                              validateList,
                              get_hypervisor_type, get_process_status)
from marvin.lib.base import (Account,
                             VPC,
                             VirtualMachine,
                             LoadBalancerRule,
                             Network,
                             Domain,
                             Router,
                             NetworkACL,
                             PublicIPAddress,
                             VpcOffering,
                             ServiceOffering,
                             Project,
                             NetworkOffering,
                             NATRule,
                             FireWallRule,
                             Host,
                             StaticNATRule)
from marvin.lib.common import (get_domain,
                               get_zone,
                               get_template,
                               verifyNetworkState,
                               add_netscaler,
                               wait_for_cleanup, list_routers, list_hosts, list_clusters)
from nose.plugins.attrib import attr
from marvin.codes import PASS, FAIL, FAILED
from marvin.sshClient import SshClient
from marvin.cloudstackTestCase import cloudstackTestCase
import unittest
from ddt import ddt, data
import time

@ddt
class TestPersistentNetworks(cloudstackTestCase):
    '''
    Test Persistent Networks without running VMs
    '''

    @classmethod
    def setUpClass(cls):
        cls.testClient = super(TestPersistentNetworks, cls).getClsTestClient()
        cls.api_client = cls.testClient.getApiClient()

        # Fill services from the external config file
        cls.services = cls.testClient.getParsedTestDataConfig()
        cls.hostConfig = cls.config.__dict__["zones"][0].__dict__["pods"][0].__dict__["clusters"][0].__dict__["hosts"][
            0].__dict__
        # Get Zone, Domain and templates
        cls.hypervisor = cls.testClient.getHypervisorInfo()
        cls.domain = get_domain(cls.api_client)
        cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
        cls.cluster = list_clusters(cls.api_client)[0]
        cls.template = get_template(
            cls.api_client,
            cls.zone.id,
            cls.services["ostype"]
        )
        cls.account = Account.create(
            cls.api_client,
            cls.services["account"],
            domainid=cls.domain.id
        )
        cls.services["virtual_machine"]["zoneid"] = cls.zone.id
        cls.services["virtual_machine"]["template"] = cls.template.id
        cls.service_offering = ServiceOffering.create(
            cls.api_client,
            cls.services["service_offering"]
        )
        cls.isolated_persistent_network_offering = cls.createNetworkOffering(
            "nw_off_isolated_persistent")
        cls.isolated_persistent_network_offering_netscaler = \
            cls.createNetworkOffering(
                "nw_off_isolated_persistent_netscaler"
            )
        cls.isolated_persistent_network_offering_RVR = \
            cls.createNetworkOffering(
                "nw_off_persistent_RVR"
            )
        cls.isolated_network_offering = cls.createNetworkOffering(
            "isolated_network_offering")
        cls.isolated_network_offering_netscaler = cls.createNetworkOffering(
            "nw_off_isolated_netscaler")

        cls.services["configurableData"]["netscaler"]["lbdevicededicated"] = \
            False

        # Configure Netscaler device
        # If configuration succeeds, set ns_configured to True so that
        # Netscaler tests are executed
        cls.ns_configured = False
        try:
            cls.netscaler = add_netscaler(
                cls.api_client,
                cls.zone.id,
                cls.services["configurableData"]["netscaler"])
            cls._cleanup.append(cls.netscaler)
            cls.ns_configured = True
        except Exception:
            cls.ns_configured = False

        # network will be deleted as part of account cleanup
        cls._cleanup = [
            cls.account,
            cls.service_offering,
            cls.isolated_persistent_network_offering,
            cls.isolated_network_offering,
            cls.isolated_persistent_network_offering_RVR,
            cls.isolated_persistent_network_offering_netscaler,
            cls.isolated_network_offering_netscaler]
        return

    @classmethod
    def tearDownClass(cls):
        try:
            # Cleanup resources used
            cleanup_resources(cls.api_client, cls._cleanup)
        except Exception as e:
            raise Exception("Warning: Exception during cleanup : %s" % e)
        return

    @classmethod
    def createNetworkOffering(cls, network_offering_type):
        network_offering = NetworkOffering.create(
            cls.api_client,
            cls.services[network_offering_type],
            conservemode=False
        )
        # Update network offering state from disabled to enabled.
        NetworkOffering.update(
            network_offering,
            cls.api_client,
            id=network_offering.id,
            state="enabled")
        return network_offering

    def checkRouterAccessibility(self, router):
        """Check if router is accessible through its linklocalip"""

        hypervisor = str(get_hypervisor_type(self.api_client))

        if hypervisor.lower() in ('vmware', 'hyperv'):
            # SSH is done via management server for Vmware and Hyper-V
            sourceip = self.api_client.connection.mgtSvr
        else:
            # For others, we will have to get the ipaddress of host connected
            # to vm
            hosts = Host.list(self.api_client, id=router.hostid)
            self.assertEqual(
                validateList(hosts)[0],
                PASS,
                "hosts list validation failed, list is %s" %
                hosts)
            host = hosts[0]
            sourceip = host.ipaddress
            # end else

        try:
            sshClient = SshClient(
                host=sourceip,
                port=self.services['configurableData']['host']["publicport"],
                user=self.hostConfig['username'],
                passwd=self.hostConfig["password"])
            res = sshClient.execute("ping -c 1 %s" % (
                router.linklocalip
            ))
            self.debug("SSH result: %s" % res)
        except Exception as e:
            self.fail("SSH Access failed for %s: %s" %
                      (sourceip, e)
                      )
        result = str(res)
        self.assertEqual(
            result.count("1 received"),
            1,
            "Ping to router should be successful"
        )
        return

    def verifyVmExpungement(self, virtual_machine):
        """verify if vm is expunged"""
        isVmExpunged = False
        # Verify if it is expunged
        retriesCount = 20
        while True:
            vms = VirtualMachine.list(self.api_client, id=virtual_machine.id)
            # When vm is expunged, list will be None
            if vms is None:
                isVmExpunged = True
                break
            elif retriesCount == 0:
                break
            time.sleep(60)
            retriesCount -= 1
            # end while

        if not isVmExpunged:
            self.fail("Failed to expunge vm even after 20 minutes")
        return

    def setUp(self):
        self.apiclient = self.testClient.getApiClient()
        self.dbclient = self.testClient.getDbConnection()
        self.cleanup = []
        return

    def tearDown(self):
        try:
            # Clean up, terminate the resources created
            cleanup_resources(self.apiclient, self.cleanup)
            self.cleanup[:] = []
        except Exception as e:
            raise Exception("Warning: Exception during cleanup : %s" % e)
        return

    '''
    Verifies creation of bridge on KVM host
    '''
    def verify_bridge_creation(self, host, vlan_id):
        username = self.hostConfig["username"]
        password = self.hostConfig["password"]
        try:
            ssh_client = self.get_ssh_client(host.ipaddress, username, password)
            res = ssh_client.execute("ip addr | grep breth.*-" + str(vlan_id) + " > /dev/null 2>&1; echo $?")
            return res[0]
        except Exception as e:
            self.fail(e)

    def validate_persistent_network_resources_created_on_host(self, network_vlan):
        hosts = self.list_all_hosts_in_zone(self.zone.id)
        for host in hosts:
            result = self.verify_bridge_creation(host, network_vlan)
            self.assertEqual(
                int(result),
                0,
                "Failed to find bridge on the breth0-" + str(network_vlan))

    def list_all_hosts_in_zone(self, zone_id):
        hosts = Host.list(
            self.apiclient,
            type='Routing',
            resourcestate='Enabled',
            state='Up',
            zoneid=zone_id
        )
        return hosts

    def get_ssh_client(self, ip, username, password, retries=10):
        """ Setup ssh client connection and return connection """
        try:
            ssh_client = SshClient(ip, 22, username, password, retries)
        except Exception as e:
            raise unittest.SkipTest("Unable to create ssh connection: " % e)

        self.assertIsNotNone(
            ssh_client, "Failed to setup ssh connection to ip=%s" % ip)

        return ssh_client

    @attr(tags=["advanced", "xx"], required_hardware="false")
    def test_newly_added_host_for_persistent_network_resources(self):
        # steps
        # 1. identify hosts in the zone, and remove the first
        # 2. create a L2 persistent network
        # 3. add the host back to the zone
        #
        # validation
        # 1. Persistent network state should be implemented before adding the host
        # 2. Host should be added back in successfully
        # 3. Host should have the persistent networks resources after being added

        if self.hypervisor.lower() == 'simulator':
            raise self.skipTest("Skipping test case for Simulator hypervisor")

        l2_persistent_network_offering = self.createNetworkOffering("nw_off_L2_persistent")
        hosts = list_hosts(self.apiclient, clusterid=self.cluster.id)
        host = hosts[0]
        vlan_id = 991

        Host(hosts[0].__dict__).delete(self.apiclient)  # remove host from zone before creating network

        network = Network.create(
            self.apiclient,
            self.services["l2_network"],
            networkofferingid=l2_persistent_network_offering.id,
            accountid=self.account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id,
            vlan=vlan_id
        )

        self.cleanup.append(network)
        self.cleanup.append(l2_persistent_network_offering)

        response = verifyNetworkState(
            self.apiclient,
            network.id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if exceptionOccurred or (not isNetworkInDesiredState):
            self.fail(exceptionMessage)
        self.assertIsNotNone(
            network.vlan,
            "vlan must not be null for persistent network")

        newHost = {
            "username": "root",
            "password": "P@ssword123",
            "url": "http://" + host.ipaddress,
            "podid": host.podid,
            "zoneid": host.zoneid
        }

        # add host back to the zone after creating network
        try:
            Host.create(
                self.apiclient,
                self.cluster,
                newHost,
                hypervisor=host.hypervisor
            )
        except Exception as e:
            self.fail("Host creation failed: %s" % e)

        self.validate_persistent_network_resources_created_on_host(network.vlan)

    @attr(tags=["advanced"], required_hardware="false")
    def test_network_state_after_destroying_vms(self):
        # steps
        # 1. Create an isolated persistent network
        # 2. Deploy virtual machine in network
        # 3. destroy created virtual machine
        #
        # validation
        # 1. Persistent network state should be implemented before VM creation
        #    and have some vlan assigned
        # 2. virtual machine should be created successfully
        # 3. Network state should be implemented even after destroying all vms
        # in network

        # Creating isolated persistent network
        network = Network.create(
            self.apiclient,
            self.services["isolated_network"],
            networkofferingid=self.isolated_persistent_network_offering.id,
            accountid=self.account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)
        self.cleanup.append(network)
        response = verifyNetworkState(
            self.apiclient,
            network.id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        self.assertIsNotNone(
            network.vlan,
            "vlan must not be null for persistent network")

        try:
            virtual_machine = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    network.id],
                serviceofferingid=self.service_offering.id,
                accountid=self.account.name,
                domainid=self.domain.id)
            virtual_machine.delete(self.apiclient)
        except Exception as e:
            self.fail("vm creation failed: %s" % e)

        # Verify VM is expunged
        self.verifyVmExpungement(virtual_machine)

        # wait for time such that, network is cleaned up
        # assuming that it will change its state to allocated after this much
        # period
        wait_for_cleanup(
            self.api_client, [
                "network.gc.interval", "network.gc.wait"])

        verifyNetworkState(self.api_client, network.id, "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        return

    @attr(tags=["advanced"], required_hardware="false")
    def test_shared_network_offering_with_persistent(self):
        # steps
        # 1. create shared network offering with persistent field enabled
        #
        # validation
        # 1. network offering should throw an exception
        try:
            shared_persistent_network_offering = self.createNetworkOffering(
                "nw_offering_shared_persistent")
            shared_persistent_network_offering.delete(self.apiclient)
            self.fail(
                "Shared network got created with ispersistent flag\
                True in the offering, it should have failed")
        except Exception:
            pass

    @attr(tags=["advanced"])
    def test_persistent_network_offering_with_VPCVR_services(self):
        # steps
        # 1. create network offering with persistent field enabled and
        #    all the services through VpcVirtualRouter
        #
        # validation
        # 1. network offering should be created successfully
        try:
            persistent_network_offering_VPCVR = self.createNetworkOffering(
                "nw_off_persistent_VPCVR_LB")
            persistent_network_offering_VPCVR.delete(self.apiclient)
        except Exception as e:
            self.fail(
                "Failed creating persistent network offering\
                with VPCVR services: %s" %
                e)

    @attr(tags=["advanced"])
    def test_list_persistent_network_offering(self):
        # steps
        # 1. create isolated network offering with ispersistent True
        # 2. List network offerings by id and check ispersistent flag
        #
        # validation
        # 1. ispersistent flag should list as True
        network_offering = self.createNetworkOffering(
            "nw_off_isolated_persistent")
        self.cleanup.append(network_offering)
        nw_offering_list = NetworkOffering.list(
            self.api_client,
            id=network_offering.id)
        self.assertEqual(
            validateList(nw_offering_list)[0],
            PASS,
            "network offerings' list validation failed, list is %s" %
            nw_offering_list)
        self.assertEqual(
            nw_offering_list[0].ispersistent,
            True,
            "ispersistent flag should be true for the network offering")
        return

    @data("LB-VR", "LB-NS")
    @attr(tags=["advanced", "advancedns"], required_hardware="true")
    def test_upgrade_to_persistent_services_VR(self, value):

        # This test is run against two networks (one with LB as virtual router
        # and other one is LB with Netscaler)
        # All other services through VR

        # steps
        # 1. create isolated network with network offering which
        #    has ispersistent field disabled
        # 2. upgrade isolated network offering to network offering
        #    which has ispersistent field enabled
        # 3. Deploy VM ,acquire IP, create Firewall, NAT rules
        # 4. Verify the working of NAT, Firewall rules
        # 5. Delete VM
        # 6. Verify network state after network cleanup interval
        #
        # validation
        # 1. update of network should happen successfully
        # 2. NAT and Firewall rule should work as expected
        # 3. After network clenaup interval, network state should be
        # implemented and have some vlan assigned

        # Set network offering as required (either LB through VR or LB through
        # Netscaler)
        networkOffering = self.isolated_network_offering

        # This will be true in case of Netscaler case, you have to change cidr
        # while updating network
        changecidr = False

        # In case Netscaler is used for LB
        if value == "LB-NS":
            if self.ns_configured:
                networkOffering = self.isolated_network_offering_netscaler
                changecidr = True
            else:
                self.skipTest(
                    "Skipping - this test required netscaler\
                    configured in the network")

        # Create Account
        account = Account.create(
            self.api_client,
            self.services["account"],
            domainid=self.domain.id)
        self.cleanup.append(account)

        # create network with the appropriate offering (not persistent)
        isolated_network = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=networkOffering.id,
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)
        response = verifyNetworkState(
            self.api_client,
            isolated_network.id,
            "allocated")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)

        # Update the network with persistent network offering
        isolated_network.update(
            self.apiclient,
            networkofferingid=self.isolated_persistent_network_offering.id,
            changecidr=changecidr,
            forced=True)

        try:
            virtual_machine = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    isolated_network.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)
        except Exception as e:
            self.fail("vm creation failed: %s" % e)

        # Acquire public ip and open firewall for it
        self.debug(
            "Associating public IP for network: %s" %
            isolated_network.id)
        ipaddress = PublicIPAddress.create(
            self.api_client,
            accountid=account.name,
            zoneid=self.zone.id,
            domainid=account.domainid,
            networkid=isolated_network.id)

        FireWallRule.create(
            self.apiclient,
            ipaddressid=ipaddress.ipaddress.id,
            protocol='TCP',
            cidrlist=[
                self.services["fwrule"]["cidr"]],
            startport=self.services["fwrule"]["startport"],
            endport=self.services["fwrule"]["endport"])

        # Create NAT rule
        NATRule.create(
            self.api_client,
            virtual_machine,
            self.services["natrule"],
            ipaddressid=ipaddress.ipaddress.id,
            networkid=isolated_network.id)

        # Check if SSH works
        try:
            virtual_machine.get_ssh_client(
                ipaddress=ipaddress.ipaddress.ipaddress)
        except Exception as e:
            self.fail(
                "Exception while SSHing to VM %s with IP %s" %
                (virtual_machine.id, ipaddress.ipaddress.ipaddress))

        # Delete VM
        virtual_machine.delete(self.api_client)

        # Verify VM is expunged
        self.verifyVmExpungement(virtual_machine)

        # wait for time such that, network is cleaned up
        wait_for_cleanup(
            self.api_client, [
                "network.gc.interval", "network.gc.wait"])

        # Check network state now, this will bolster that network updation has
        # taken effect
        response = verifyNetworkState(
            self.api_client,
            isolated_network.id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        return

    @attr(tags=["advanced"], required_hardware="true")
    def test_upgrade_network_VR_to_PersistentRVR(self):
        # steps
        # 1. create isolated network with network offering which has
        #    ispersistent field disabled (services through VR)
        # 2. upgrade isolated network offering to network offering which
        #    has ispersistent field enabled (with RVR)
        # 3. Deploy VM ,acquire IP, create Firewall, NAT rules
        # 4. Verify the working of NAT, Firewall rules
        # 5. Delete VM
        # 6. Verify network state after network cleanup interval
        #
        # validation
        # 1. update of network should happen successfully
        # 2. NAT and Firewall rule should work as expected
        # 3. After network clenaup interval, network state should be
        # implemented and have some vlan assigned

        # Create Account and isolated network in it
        account = Account.create(
            self.api_client,
            self.services["account"],
            domainid=self.domain.id)
        self.cleanup.append(account)
        isolated_network = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=self.isolated_network_offering.id,
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)
        response = verifyNetworkState(
            self.api_client,
            isolated_network.id,
            "allocated")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)

        # Update network with network offering which has RVR
        isolated_network.update(
            self.apiclient,
            networkofferingid=self.isolated_persistent_network_offering_RVR.id)

        # Deploy VM
        try:
            virtual_machine = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    isolated_network.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)
        except Exception as e:
            self.fail("vm creation failed: %s" % e)

        # Acquire public IP and open firewall rule, create NAT rule
        self.debug(
            "Associating public IP for network: %s" %
            isolated_network.id)
        ipaddress = PublicIPAddress.create(
            self.api_client,
            accountid=account.name,
            zoneid=self.zone.id,
            domainid=account.domainid,
            networkid=isolated_network.id)

        FireWallRule.create(
            self.apiclient,
            ipaddressid=ipaddress.ipaddress.id,
            protocol='TCP',
            cidrlist=[
                self.services["fwrule"]["cidr"]],
            startport=self.services["fwrule"]["startport"],
            endport=self.services["fwrule"]["endport"])

        NATRule.create(
            self.api_client,
            virtual_machine,
            self.services["natrule"],
            ipaddressid=ipaddress.ipaddress.id,
            networkid=isolated_network.id)

        try:
            virtual_machine.get_ssh_client(
                ipaddress=ipaddress.ipaddress.ipaddress)
        except Exception as e:
            self.fail(
                "Exception while SSHing to VM %s with IP %s" %
                (virtual_machine.id, ipaddress.ipaddress.ipaddress))

        virtual_machine.delete(self.api_client)

        # Verify VM is expunged
        self.verifyVmExpungement(virtual_machine)

        # wait for time such that, network is cleaned up
        wait_for_cleanup(
            self.api_client, [
                "network.gc.interval", "network.gc.wait"])

        # Check network state now, this will bolster that network updation has
        # taken effect
        response = verifyNetworkState(
            self.api_client,
            isolated_network.id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        return

    @attr(tags=["advanced", "advancedns"])
    def test_upgrade_network_NS_to_persistent_NS(self):
        # steps
        # 1. create isolated network with network offering which
        #    has ispersistent field disabled
        #    and LB service through Netscaler
        # 2. upgrade isolated network offering to network offering
        #    which has ispersistent field enabled
        #    and LB service through Netscaler
        # 3. Deploy VM ,acquire IP, create Firewall, NAT rules
        # 4. Verify the working of NAT, Firewall rules
        # 5. Delete VM
        # 6. Verify network state after network cleanup interval
        #
        # validation
        # 1. update of network should happen successfully
        # 2. NAT and Firewall rule should work as expected
        # 3. After network clenaup interval, network state should be
        # implemented and have some vlan assigned

        # Skip test if Netscaler is not configured
        if not self.ns_configured:
            self.skipTest(
                "Skipping - this test required netscaler\
                configured in the network")

        # Create Account and create isolated network in it
        account = Account.create(
            self.api_client,
            self.services["account"],
            domainid=self.domain.id)
        self.cleanup.append(account)
        isolated_network = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=self.isolated_network_offering_netscaler.id,
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)
        response = verifyNetworkState(
            self.api_client,
            isolated_network.id,
            "allocated")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)

        isolated_network.update(
            self.apiclient,
            networkofferingid=(
                self.isolated_persistent_network_offering_netscaler.id),
            changecidr=True)

        # Deploy VM
        try:
            virtual_machine = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    isolated_network.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)
        except Exception as e:
            self.fail("vm creation failed: %s" % e)

        self.debug(
            "Associating public IP for network: %s" %
            isolated_network.id)
        ipaddress = PublicIPAddress.create(
            self.api_client,
            accountid=account.name,
            zoneid=self.zone.id,
            domainid=account.domainid,
            networkid=isolated_network.id)

        FireWallRule.create(
            self.apiclient,
            ipaddressid=ipaddress.ipaddress.id,
            protocol='TCP',
            cidrlist=[
                self.services["fwrule"]["cidr"]],
            startport=self.services["fwrule"]["startport"],
            endport=self.services["fwrule"]["endport"])

        NATRule.create(
            self.api_client,
            virtual_machine,
            self.services["natrule"],
            ipaddressid=ipaddress.ipaddress.id,
            networkid=isolated_network.id)

        try:
            virtual_machine.get_ssh_client(
                ipaddress=ipaddress.ipaddress.ipaddress)
        except Exception as e:
            self.fail(
                "Exception while SSHing to VM %s with IP %s" %
                (virtual_machine.id, ipaddress.ipaddress.ipaddress))

        virtual_machine.delete(self.api_client)

        # Verify VM is expunged
        self.verifyVmExpungement(virtual_machine)

        # wait for time such that, network is cleaned up
        wait_for_cleanup(
            self.api_client, [
                "network.gc.interval", "network.gc.wait"])

        # Check network state now, this will bolster that network updation has
        # taken effect
        response = verifyNetworkState(
            self.api_client,
            isolated_network.id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        return

    @data("LB-VR", "LB-Netscaler")
    @attr(tags=["advanced", "advancedns"], required_hardware="true")
    def test_pf_nat_rule_persistent_network(self, value):

        # This test shall run with two scenarios, one with LB services
        # through VR and other through LB service
        # through Netscaler"""

        # steps
        # 1. create isolated network with network offering which has
        #    ispersistent field enabled
        #    and LB service through VR or Netscaler
        # 2. Check routers belonging to network and verify that router
        #    is reachable through host using linklocalip
        # 3. Deploy VM ,acquire IP, create Firewall, NAT rules
        # 4. Verify the working of NAT, Firewall rules
        #
        # validation
        # 1. Router should be reachable
        # 2. NAT and Firewall rule should work as expected

        # Set network offering according to data passed to test case
        networkOffering = self.isolated_persistent_network_offering
        if value == "LB-Netscaler":
            if self.ns_configured:
                networkOffering = (
                    self.isolated_persistent_network_offering_netscaler)
            else:
                self.skipTest(
                    "Skipping - this test required netscaler\
                    configured in the network")

        # Create account and network in it
        account = Account.create(
            self.api_client,
            self.services["account"],
            domainid=self.domain.id)
        self.cleanup.append(account)
        isolated_persistent_network = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=networkOffering.id,
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)
        self.assertEqual(
            str(
                isolated_persistent_network.state).lower(),
            "implemented",
            "network state should be implemented, it is %s" %
            isolated_persistent_network.state)
        self.assertIsNotNone(
            isolated_persistent_network.vlan,
            "vlan must not be null for persistent network")

        # Check if router is assigned to the persistent network
        routers = Router.list(self.api_client, account=account.name,
                              domainid=account.domainid,
                              networkid=isolated_persistent_network.id)

        self.assertEqual(
            validateList(routers)[0],
            PASS,
            "Routers list validation failed, list is %s" %
            routers)
        router = routers[0]

        # Check if router if reachable from the host
        self.checkRouterAccessibility(router)

        # Deploy VM in the network
        try:
            virtual_machine = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    isolated_persistent_network.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)
        except Exception as e:
            self.fail("vm creation failed: %s" % e)

        # Acquire IP address, create Firewall, NAT rule
        self.debug(
            "Associating public IP for network: %s" %
            isolated_persistent_network.id)
        ipaddress = PublicIPAddress.create(
            self.api_client,
            accountid=account.name,
            zoneid=self.zone.id,
            domainid=account.domainid,
            networkid=isolated_persistent_network.id)

        FireWallRule.create(
            self.apiclient,
            ipaddressid=ipaddress.ipaddress.id,
            protocol='TCP',
            cidrlist=[
                self.services["fwrule"]["cidr"]],
            startport=self.services["fwrule"]["startport"],
            endport=self.services["fwrule"]["endport"])
        NATRule.create(
            self.api_client,
            virtual_machine,
            self.services["natrule"],
            ipaddressid=ipaddress.ipaddress.id,
            networkid=isolated_persistent_network.id)

        # Check working of PF, NAT rules
        try:
            virtual_machine.get_ssh_client(
                ipaddress=ipaddress.ipaddress.ipaddress)
        except Exception as e:
            self.fail(
                "Exception while SSHing to VM %s with IP %s" %
                (virtual_machine.id, ipaddress.ipaddress.ipaddress))
        return

    @attr(tags=["advanced"], required_hardware="true")
    def test_persistent_network_with_RVR(self):
        # steps
        # 1. create account and isolated network with network
        #    offering which has ispersistent field enabled
        #    and supporting Redundant Virtual Router in it
        # 2. Check the Primary and Backup Routers are present
        # 3. Deploy VM ,acquire IP, create Firewall, NAT rules
        # 4. Verify the working of NAT, Firewall rules
        #
        # validation
        # 1. Two routers should belong to the network and
        #    they should be reachable from host
        # 2. NAT and Firewall rule should work as expected

        # Create account and create isolated persistent network with RVR in it
        account = Account.create(
            self.api_client,
            self.services["account"],
            domainid=self.domain.id)
        self.cleanup.append(account)

        # Create isolated persistent network with RVR
        isolated_persistent_network_RVR = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=self.isolated_persistent_network_offering_RVR.id,
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)
        self.assertEqual(
            str(
                isolated_persistent_network_RVR.state).lower(),
            "implemented",
            "network state should be implemented, it is %s" %
            isolated_persistent_network_RVR.state)
        self.assertIsNotNone(
            isolated_persistent_network_RVR.vlan,
            "vlan must not be null for persistent network")

        # Check if two routers belong to the network
        self.debug(
            "Listing routers for network: %s" %
            isolated_persistent_network_RVR.name)
        routers = Router.list(self.api_client, listall=True,
                              networkid=isolated_persistent_network_RVR.id)

        self.assertEqual(
            validateList(routers)[0],
            PASS,
            "Routers list validation failed, list is %s" %
            routers)
        self.assertEqual(
            len(routers),
            2,
            "Length of the list router should be 2 (Backup & Primary)")

        # Check if routers are reachable from the host
        for router in routers:
            self.checkRouterAccessibility(router)

        # Deploy VM
        try:
            virtual_machine = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    isolated_persistent_network_RVR.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)
        except Exception as e:
            self.fail("vm creation failed: %s" % e)

        # Acquire public ip, create Firewall, NAT rule
        self.debug(
            "Associating public IP for network: %s" %
            isolated_persistent_network_RVR.id)
        ipaddress = PublicIPAddress.create(
            self.api_client,
            accountid=account.name,
            zoneid=self.zone.id,
            domainid=account.domainid,
            networkid=isolated_persistent_network_RVR.id)

        FireWallRule.create(
            self.apiclient,
            ipaddressid=ipaddress.ipaddress.id,
            protocol='TCP',
            cidrlist=[
                self.services["fwrule"]["cidr"]],
            startport=self.services["fwrule"]["startport"],
            endport=self.services["fwrule"]["endport"])
        NATRule.create(
            self.api_client,
            virtual_machine,
            self.services["natrule"],
            ipaddressid=ipaddress.ipaddress.id,
            networkid=isolated_persistent_network_RVR.id)

        # Check if Firewall, NAT rule work as expected
        try:
            virtual_machine.get_ssh_client(
                ipaddress=ipaddress.ipaddress.ipaddress)
        except Exception as e:
            self.fail(
                "Exception while SSHing to VM %s with IP %s" %
                (virtual_machine.id, ipaddress.ipaddress.ipaddress))
        return

    @attr(tags=["advanced"], required_hardware="true")
    def test_vm_deployment_two_persistent_networks(self):
        # steps
        # 1. Deploy VM in two persistent networks
        # 2. Check working of NAT, Firewall rules in both the networks
        #
        # validation
        # 1. VM should be deployed successfully in two networks
        # 2. All network rules should work as expected

        account = Account.create(
            self.api_client,
            self.services["account"],
            domainid=self.domain.id)
        self.cleanup.append(account)
        isolated_persistent_network_1 = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=self.isolated_persistent_network_offering.id,
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)
        self.assertEqual(
            str(
                isolated_persistent_network_1.state).lower(),
            "implemented",
            "network state should be implemented, it is %s" %
            isolated_persistent_network_1.state)
        self.assertIsNotNone(
            isolated_persistent_network_1.vlan,
            "vlan must not be null for persistent network")

        isolated_persistent_network_2 = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=self.isolated_persistent_network_offering.id,
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)
        self.assertEqual(
            str(
                isolated_persistent_network_2.state).lower(),
            "implemented",
            "network state should be implemented, it is %s" %
            isolated_persistent_network_2.state)
        self.assertIsNotNone(
            isolated_persistent_network_2.vlan,
            "vlan must not be null for persistent network")

        self.debug(
            "Listing routers for network: %s" %
            isolated_persistent_network_1.name)
        routers_nw_1 = Router.list(self.api_client, listall=True,
                                   networkid=isolated_persistent_network_1.id)

        self.assertEqual(
            validateList(routers_nw_1)[0],
            PASS,
            "Routers list validation failed, list is %s" %
            routers_nw_1)

        # Check if router is reachable from the host
        for router in routers_nw_1:
            self.checkRouterAccessibility(router)

        self.debug(
            "Listing routers for network: %s" %
            isolated_persistent_network_2.name)
        routers_nw_2 = Router.list(self.api_client, listall=True,
                                   networkid=isolated_persistent_network_2.id)

        self.assertEqual(
            validateList(routers_nw_2)[0],
            PASS,
            "Routers list validation failed, list is %s" %
            routers_nw_2)

        # Check if router is reachable from the host
        for router in routers_nw_2:
            self.checkRouterAccessibility(router)
        try:
            virtual_machine = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    isolated_persistent_network_1.id,
                    isolated_persistent_network_2.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)
        except Exception as e:
            self.fail("vm creation failed: %s" % e)

        self.debug(
            "Associating public IP for network: %s" %
            isolated_persistent_network_1.id)
        ipaddress_nw_1 = PublicIPAddress.create(
            self.api_client,
            accountid=account.name,
            zoneid=self.zone.id,
            domainid=account.domainid,
            networkid=isolated_persistent_network_1.id)

        FireWallRule.create(
            self.apiclient,
            ipaddressid=ipaddress_nw_1.ipaddress.id,
            protocol='TCP',
            cidrlist=[
                self.services["fwrule"]["cidr"]],
            startport=self.services["fwrule"]["startport"],
            endport=self.services["fwrule"]["endport"])

        self.debug(
            "Associating public IP for network: %s" %
            isolated_persistent_network_2.id)
        ipaddress_nw_2 = PublicIPAddress.create(
            self.api_client,
            accountid=account.name,
            zoneid=self.zone.id,
            domainid=account.domainid,
            networkid=isolated_persistent_network_2.id)

        FireWallRule.create(
            self.apiclient,
            ipaddressid=ipaddress_nw_2.ipaddress.id,
            protocol='TCP',
            cidrlist=[
                self.services["fwrule"]["cidr"]],
            startport=self.services["fwrule"]["startport"],
            endport=self.services["fwrule"]["endport"])
        NATRule.create(
            self.api_client,
            virtual_machine,
            self.services["natrule"],
            ipaddressid=ipaddress_nw_1.ipaddress.id,
            networkid=isolated_persistent_network_1.id)

        try:
            virtual_machine.get_ssh_client(
                ipaddress=ipaddress_nw_1.ipaddress.ipaddress)
        except Exception as e:
            self.fail(
                "Exception while SSHing to VM %s with IP %s" %
                (virtual_machine.id, ipaddress_nw_1.ipaddress.ipaddress))

        NATRule.create(
            self.api_client,
            virtual_machine,
            self.services["natrule"],
            ipaddressid=ipaddress_nw_2.ipaddress.id,
            networkid=isolated_persistent_network_2.id)

        try:
            virtual_machine.get_ssh_client(
                ipaddress=ipaddress_nw_2.ipaddress.ipaddress)
        except Exception as e:
            self.fail(
                "Exception while SSHing to VM %s with IP %s" %
                (virtual_machine.id, ipaddress_nw_2.ipaddress.ipaddress))
        return

    @attr(tags=["advanced"], required_hardware="true")
    def test_vm_deployment_persistent_and_non_persistent_networks(self):
        # steps
        # 1. create account and create two networks in it
        #    (persistent and non persistent)
        # 2. Deploy virtual machine in these two networks
        # 3. Associate ip address with both the accounts and
        #    create firewall,port forwarding rule
        # 4. Try to SSH to VM through both the IPs
        #
        # validation
        # 1. Both persistent and non persistent networks should be created
        # 2. virtual machine should be created successfully
        # 3. SSH should be successful through both the IPs

        account = Account.create(
            self.api_client,
            self.services["account"],
            domainid=self.domain.id)
        self.cleanup.append(account)
        network_1 = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=self.isolated_persistent_network_offering.id,
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)
        self.assertEqual(
            str(
                network_1.state).lower(),
            "implemented",
            "network state should be implemented, it is %s" %
            network_1.state)
        self.assertIsNotNone(
            network_1.vlan,
            "vlan must not be null for persistent network")

        network_2 = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=self.isolated_network_offering.id,
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)

        try:
            virtual_machine = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    network_1.id,
                    network_2.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)
        except Exception as e:
            self.fail("vm creation failed: %s" % e)

        self.debug("Associating public IP for network: %s" % network_1.id)
        ipaddress_nw_1 = PublicIPAddress.create(
            self.api_client,
            accountid=account.name,
            zoneid=self.zone.id,
            domainid=account.domainid,
            networkid=network_1.id)

        FireWallRule.create(
            self.apiclient,
            ipaddressid=ipaddress_nw_1.ipaddress.id,
            protocol='TCP',
            cidrlist=[
                self.services["fwrule"]["cidr"]],
            startport=self.services["fwrule"]["startport"],
            endport=self.services["fwrule"]["endport"])
        NATRule.create(
            self.api_client,
            virtual_machine,
            self.services["natrule"],
            ipaddressid=ipaddress_nw_1.ipaddress.id,
            networkid=network_1.id)

        try:
            virtual_machine.get_ssh_client(
                ipaddress=ipaddress_nw_1.ipaddress.ipaddress)
        except Exception as e:
            self.fail(
                "Exception while SSHing to VM %s with IP %s" %
                (virtual_machine.id, ipaddress_nw_1.ipaddress.ipaddress))

        self.debug("Associating public IP for network: %s" % network_2.id)
        ipaddress_nw_2 = PublicIPAddress.create(
            self.api_client,
            accountid=account.name,
            zoneid=self.zone.id,
            domainid=account.domainid,
            networkid=network_2.id)

        FireWallRule.create(
            self.apiclient,
            ipaddressid=ipaddress_nw_2.ipaddress.id,
            protocol='TCP',
            cidrlist=[
                self.services["fwrule"]["cidr"]],
            startport=self.services["fwrule"]["startport"],
            endport=self.services["fwrule"]["endport"])
        NATRule.create(
            self.api_client,
            virtual_machine,
            self.services["natrule"],
            ipaddressid=ipaddress_nw_2.ipaddress.id,
            networkid=network_2.id)

        try:
            virtual_machine.get_ssh_client(
                ipaddress=ipaddress_nw_2.ipaddress.ipaddress)
        except Exception as e:
            self.fail(
                "Exception while SSHing to VM %s with IP %s" %
                (virtual_machine.id, ipaddress_nw_2.ipaddress.ipaddress))
        return

    @attr(tags=["advanced"], required_hardware="true")
    def test_change_persistent_network_to_non_persistent(self):
        # steps
        # 1. Create a persistent network and deploy VM in it
        # 2. Update network with non persistent network offering
        # 3. Acquire IP, create NAT, firewall rules
        # 4. Test NAT, Firewall rules
        # 5. Delete VM
        # 6. Check the network state after network clenaup interval
        #
        # validation
        # 1. Network updation should be successful
        # 2. Network rules should work as expected
        # 3. Network state should be allocated after network cleanup interval

        # Create account and create persistent network in it
        account = Account.create(
            self.api_client,
            self.services["account"],
            domainid=self.domain.id)
        self.cleanup.append(account)
        network = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=self.isolated_persistent_network_offering.id,
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)
        self.assertEqual(str(network.state).lower(),
                         "implemented",
                         "network state should be implemented, it is %s"
                         % network.state)
        self.assertIsNotNone(
            network.vlan,
            "vlan must not be null for persistent network")

        # Update network with non persistent network offering
        network.update(
            self.apiclient,
            networkofferingid=self.isolated_network_offering.id)

        # Deploy VM, acquire IP, create NAT, firewall rules
        try:
            virtual_machine = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    network.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)
        except Exception as e:
            self.fail("vm creation failed: %s" % e)

        self.debug("Associating public IP for network: %s" % network.id)
        ipaddress = PublicIPAddress.create(
            self.api_client,
            accountid=account.name,
            zoneid=self.zone.id,
            domainid=account.domainid,
            networkid=network.id)

        FireWallRule.create(
            self.apiclient,
            ipaddressid=ipaddress.ipaddress.id,
            protocol='TCP',
            cidrlist=[
                self.services["fwrule"]["cidr"]],
            startport=self.services["fwrule"]["startport"],
            endport=self.services["fwrule"]["endport"])
        NATRule.create(
            self.api_client,
            virtual_machine,
            self.services["natrule"],
            ipaddressid=ipaddress.ipaddress.id,
            networkid=network.id)

        # Verify working of network rules
        try:
            virtual_machine.get_ssh_client(
                ipaddress=ipaddress.ipaddress.ipaddress)
        except Exception as e:
            self.fail(
                "Exception while SSHing to VM %s with IP %s" %
                (virtual_machine.id, ipaddress.ipaddress.ipaddress))

        # Delete VM
        virtual_machine.delete(self.api_client)

        # Verify VM is expunged
        self.verifyVmExpungement(virtual_machine)

        # wait for time such that, network is cleaned up
        wait_for_cleanup(
            self.api_client, [
                "network.gc.interval", "network.gc.wait"])

        # Check network state now, this will bolster that network updation has
        # taken effect
        response = verifyNetworkState(self.api_client, network.id, "allocated")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        return

    # @attr(tags=["advanced"], required_hardware="true")
    @attr(tags=["TODO"], required_hardware="true")
    def test_delete_account(self):
        # steps
        # 1. create persistent network and deploy VM in it
        # 2. Deploy VM in it and acquire IP address, create NAT, firewall rules
        # 3. Delete the account in which network is created
        #
        # validation
        # 1. Persistent network state should be implemented before VM creation
        #    and have some vlan assigned
        # 2. Network rules should work as expected
        # 3. Network and IPs should be freed after account is deleted

        account = Account.create(
            self.api_client,
            self.services["account"],
            domainid=self.domain.id)
        network = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=self.isolated_persistent_network_offering.id,
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)

        try:
            virtual_machine = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    network.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)
        except Exception as e:
            self.fail("vm creation failed: %s" % e)
        self.debug("Associating public IP for network: %s" % network.id)
        ipaddress = PublicIPAddress.create(
            self.api_client,
            accountid=account.name,
            zoneid=self.zone.id,
            domainid=account.domainid,
            networkid=network.id)

        FireWallRule.create(
            self.apiclient,
            ipaddressid=ipaddress.ipaddress.id,
            protocol='TCP',
            cidrlist=[
                self.services["fwrule"]["cidr"]],
            startport=self.services["fwrule"]["startport"],
            endport=self.services["fwrule"]["endport"])
        NATRule.create(
            self.api_client,
            virtual_machine,
            self.services["natrule"],
            ipaddressid=ipaddress.ipaddress.id,
            networkid=network.id)

        try:
            virtual_machine.get_ssh_client(
                ipaddress=ipaddress.ipaddress.ipaddress)
        except Exception as e:
            self.fail(
                "Exception while SSHing to VM %s with IP %s" %
                (virtual_machine.id, ipaddress.ipaddress.ipaddress))

        # Delete the account
        account.delete(self.api_client)

        # Verify the resources belonging to account have been cleaned up
        networks = Network.list(self.apiclient, id=network.id)
        self.assertEqual(
            validateList(networks)[0],
            FAIL,
            "network list should be enmpty, it is %s" %
            networks)

        public_ips = PublicIPAddress.list(
            self.apiclient,
            id=ipaddress.ipaddress.id)
        self.assertEqual(
            validateList(public_ips)[0],
            FAIL,
            "Public Ip list be empty, it is %s" %
            public_ips)

        return

    @attr(tags=["advanced"], required_hardware="true")
    def test_volume_delete_event_errorState(self):
        """
        @summary: Test volume delete event generation in error state condition
        @Steps:
        Step1: Create  a network using network created in Step1
        Step2: Verifying that  network creation is successful
        Step3: Login to Virtual router and add iptable  rule to block insertion of vm rules
        Step6: deploy a vm using network created in step2
        Step7: check the Vm status for failure
        Step8: destroy and expunge the vm
        Step9: list the generated events for volume delete event.
        """

        # Listing all the networks available

        account = Account.create(
            self.api_client,
            self.services["account"],
            domainid=self.domain.id)
        network = Network.create(
            self.apiclient,
            self.services["isolated_network"],
            networkofferingid=self.isolated_persistent_network_offering.id,
            accountid=self.account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)
        response = verifyNetworkState(
            self.apiclient,
            network.id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        self.assertIsNotNone(
            network.vlan,
            "vlan must not be null for persistent network")
        try:
            list_router_response = list_routers(
                self.apiclient,
                account=self.account.name,
                domainid=self.account.domainid
            )

            self.assertEqual(validateList(list_router_response)[0], PASS, "Check list response returns a valid list")
            router = list_router_response[0]

            self.debug("Router ID: %s, state: %s" % (router.id, router.state))

            self.assertEqual(
                router.state,
                'Running',
                "Check list router response for router state"
            )
            self.hypervisor = self.testClient.getHypervisorInfo()
            if self.hypervisor.lower() in ('vmware', 'hyperv'):
                result = get_process_status(
                    self.apiclient.connection.mgtSvr,
                    22,
                    self.apiclient.connection.user,
                    self.apiclient.connection.passwd,
                    router.linklocalip,
                    "iptables -I INPUT 1 -j DROP",
                    hypervisor=self.hypervisor
                )
            else:
                try:
                    hosts = list_hosts(
                        self.apiclient,
                        zoneid=router.zoneid,
                        type='Routing',
                        state='Up',
                        id=router.hostid
                    )
                    self.assertEqual(validateList(hosts)[0], PASS, "Check list host returns a valid list")
                    host = hosts[0]
                    result = get_process_status(
                        host.ipaddress, 22,
                        self.hostConfig["username"],
                        self.hostConfig["password"],
                        router.linklocalip,
                        "iptables -I INPUT 1 -j DROP"
                    )
                except Exception as e:
                    raise Exception("Exception raised in accessing/running the command on hosts  : %s " % e)
        except Exception as e:
            raise Exception("Exception raised in getting hostcredentials: %s " % e)

        with self.assertRaises(Exception) as context:
            virtual_machine = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    network.id],
                serviceofferingid=self.service_offering.id,
                accountid=self.account.name,
                domainid=self.domain.id)
        # self.assertTrue('This is broken' in context.exception)
        try:
            account.delete(self.api_client)
        except Exception as e:
            self.cleanup.append(account)
        qresultset = self.dbclient.execute(
            "select id from usage_event where type = '%s' ORDER BY id DESC LIMIT 1;" %
            str("VOLUME.DELETE"))
        self.assertNotEqual(
            len(qresultset),
            0,
            "Check DB Query result set")
        return


@ddt
class TestAssignVirtualMachine(cloudstackTestCase):
    """Test Persistent Network creation with
    assigning VM to different account/domain
    """

    @classmethod
    def setUpClass(cls):
        cls.testClient = super(
            TestAssignVirtualMachine,
            cls).getClsTestClient()
        cls.api_client = cls.testClient.getApiClient()

        # Fill services from the external config file
        cls.services = cls.testClient.getParsedTestDataConfig()

        # Get Zone, Domain and templates
        cls.domain = get_domain(cls.api_client)
        cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
        cls.template = get_template(
            cls.api_client,
            cls.zone.id,
            cls.services["ostype"]
        )
        if cls.template == FAILED:
            assert False, "get_template() failed to return template\
                with description %s" % cls.services["ostype"]
        cls.services["virtual_machine"]["zoneid"] = cls.zone.id
        cls.services["virtual_machine"]["template"] = cls.template.id
        cls.service_offering = ServiceOffering.create(
            cls.api_client,
            cls.services["service_offering"]
        )
        cls.isolated_persistent_network_offering = cls.createNetworkOffering(
            "nw_off_isolated_persistent")
        cls.isolated_persistent_network_offering_RVR = \
            cls.createNetworkOffering(
                "nw_off_persistent_RVR"
            )
        cls.persistent_network_offering_netscaler = cls.createNetworkOffering(
            "nw_off_isolated_persistent_netscaler")

        cls.services["configurableData"]["netscaler"]["lbdevicededicated"] = \
            False

        # Configure Netscaler device
        # If configuration succeeds, set ns_configured to True so that
        # Netscaler tests are executed
        cls.ns_configured = False
        try:
            cls.netscaler = add_netscaler(
                cls.api_client,
                cls.zone.id,
                cls.services["configurableData"]["netscaler"])
            cls._cleanup.append(cls.netscaler)
            cls.ns_configured = True
        except Exception:
            cls.ns_configured = False

        # network will be deleted as part of account cleanup
        cls._cleanup = [
            cls.service_offering, cls.isolated_persistent_network_offering,
            cls.isolated_persistent_network_offering_RVR,
            cls.persistent_network_offering_netscaler
        ]
        return

    @classmethod
    def tearDownClass(cls):
        try:
            # Cleanup resources used
            cleanup_resources(cls.api_client, cls._cleanup)
        except Exception as e:
            raise Exception("Warning: Exception during cleanup : %s" % e)
        return

    @classmethod
    def createNetworkOffering(cls, network_offering_type):
        network_offering = NetworkOffering.create(
            cls.api_client,
            cls.services[network_offering_type],
            conservemode=False
        )
        # Update network offering state from disabled to enabled.
        NetworkOffering.update(
            network_offering,
            cls.api_client,
            id=network_offering.id,
            state="enabled")
        return network_offering

    def setUp(self):
        self.apiclient = self.testClient.getApiClient()
        self.dbclient = self.testClient.getDbConnection()
        self.cleanup = []
        return

    def tearDown(self):
        try:
            # Clean up, terminate the resources created
            cleanup_resources(self.apiclient, self.cleanup)
            self.cleanup[:] = []
        except Exception as e:
            raise Exception("Warning: Exception during cleanup : %s" % e)
        return

    @data("VR", "RVR", "LB-NS")
    @attr(tags=["advanced", "advancedns"])
    def test_assign_vm_different_account_VR(self, value):

        # This test shall be run with three types of persistent networks
        # a) All services through VR
        # b) LB service through Netscaler
        # c) with Redundant Virtual Router facility

        # steps
        # 1. create two accounts (account1 and account2)
        # 2. Create a persistent network (with VR/RVR/Netscaler-LB
        #    with VR services) in account1 and deploy VM in it with
        #    this network
        # 3. Stop the VM and assign the VM to account2
        #
        # validation
        # 1. Assign VM operation should be successful
        # 2. New network should be created in the other account

        # Create Accounts
        account_1 = Account.create(
            self.apiclient,
            self.services["account"],
            domainid=self.domain.id)
        self.cleanup.append(account_1)

        account_2 = Account.create(
            self.apiclient,
            self.services["account"],
            domainid=self.domain.id)
        self.cleanup.append(account_2)

        # Set the network offering according to the test scenario (data passed
        # to the test case
        if value == "VR":
            network_offering = self.isolated_persistent_network_offering
        elif value == "RVR":
            network_offering = self.isolated_persistent_network_offering_RVR
        elif value == "LB-NS":
            if self.ns_configured:
                network_offering = self.persistent_network_offering_netscaler
            else:
                self.skipTest(
                    "This test requires netscaler to be\
                    configured in the network")

        network = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=network_offering.id,
            accountid=account_1.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)
        response = verifyNetworkState(
            self.api_client,
            network.id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        self.assertIsNotNone(
            network.vlan,
            "vlan must not be null for persistent network")

        try:
            virtual_machine = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    network.id],
                serviceofferingid=self.service_offering.id,
                accountid=account_1.name,
                domainid=self.domain.id)

            virtual_machine.stop(self.apiclient)

            # Assign virtual machine to different account
            virtual_machine.assign_virtual_machine(
                self.apiclient,
                account=account_2.name,
                domainid=self.domain.id)

            # Start VM
            virtual_machine.start(self.apiclient)

            # Verify that new network is created in other account
            networks = Network.list(
                self.apiclient,
                account=account_2.name,
                domainid=account_2.domainid)
            self.assertEqual(
                validateList(networks)[0],
                PASS,
                "networks list validation failed, list is %s" %
                networks)
        except Exception as e:
            self.fail("Exception occurred: %s" % e)
        return


@ddt
class TestProjectAccountOperations(cloudstackTestCase):
    """Test suspend/disable/lock account/project operations
    when they have persistent network
    """

    @classmethod
    def setUpClass(cls):
        cls.testClient = super(
            TestProjectAccountOperations,
            cls).getClsTestClient()
        cls.api_client = cls.testClient.getApiClient()

        # Fill services from the external config file
        cls.services = cls.testClient.getParsedTestDataConfig()

        # Get Zone, Domain and templates
        cls.domain = get_domain(cls.api_client)
        cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
        cls.template = get_template(
            cls.api_client,
            cls.zone.id,
            cls.services["ostype"]
        )
        if cls.template == FAILED:
            assert False, "get_template() failed to return\
                template with description %s" % cls.services["ostype"]
        cls.services["virtual_machine"]["zoneid"] = cls.zone.id
        cls.services["virtual_machine"]["template"] = cls.template.id
        cls.service_offering = ServiceOffering.create(
            cls.api_client,
            cls.services["service_offering"]
        )
        cls.isolated_persistent_network_offering = NetworkOffering.create(
            cls.api_client,
            cls.services["nw_off_isolated_persistent"],
            conservemode=False
        )
        # Update network offering state from disabled to enabled.
        cls.isolated_persistent_network_offering.update(
            cls.api_client,
            state="enabled")

        # network will be deleted as part of account cleanup
        cls._cleanup = [
            cls.service_offering, cls.isolated_persistent_network_offering
        ]
        return

    @classmethod
    def tearDownClass(cls):
        try:
            # Cleanup resources used
            cleanup_resources(cls.api_client, cls._cleanup)
        except Exception as e:
            raise Exception("Warning: Exception during cleanup : %s" % e)
        return

    def setUp(self):
        self.apiclient = self.testClient.getApiClient()
        self.dbclient = self.testClient.getDbConnection()
        self.cleanup = []
        return

    def tearDown(self):
        try:
            # Clean up, terminate the resources created
            cleanup_resources(self.apiclient, self.cleanup)
            self.cleanup[:] = []
        except Exception as e:
            raise Exception("Warning: Exception during cleanup : %s" % e)
        return

    @data("locked", "disabled")
    @attr(tags=["advanced"])
    def test_account_operations(self, value):
        # steps
        # 1. create account and create persistent network in it
        # 2. Disable/lock the account
        #
        # validation
        # 3. Wait for network cleanup interval and verify that network
        #    is not cleaned up and it is still in implemented state

        account = Account.create(
            self.apiclient,
            self.services["account"],
            domainid=self.domain.id)
        self.cleanup.append(account)

        network = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=self.isolated_persistent_network_offering.id,
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)
        response = verifyNetworkState(
            self.api_client,
            network.id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        self.assertIsNotNone(
            network.vlan,
            "vlan must not be null for persistent network")

        if value == "disabled":
            account.disable(self.apiclient)
        elif value == "locked":
            account.disable(self.apiclient, lock=True)

        accounts = Account.list(self.apiclient, id=account.id)
        self.assertEqual(
            validateList(accounts)[0],
            PASS,
            "accounts list validation failed, list id %s" %
            accounts)
        self.assertEqual(str(accounts[0].state).lower(
        ), value, "account state should be %s, it is %s"
                  % (value, accounts[0].state))

        # Wait for network cleanup interval
        wait_for_cleanup(
            self.api_client, [
                "network.gc.interval", "network.gc.wait"])

        networks = Network.list(
            self.apiclient,
            account=account.name,
            domainid=account.domainid)
        self.assertEqual(
            validateList(networks)[0],
            PASS,
            "networks list validation failed, list is %s" %
            networks)

        response = verifyNetworkState(
            self.api_client,
            networks[0].id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        self.assertIsNotNone(
            networks[0].vlan,
            "vlan must not be null for persistent network")
        return

    @attr(tags=["advanced"])
    def test_project_operations(self):
        # steps
        # 1. create account and create persistent network in it
        # 2. Add account to project
        # 3. Suspend the project
        #
        # validation
        # 1. Verify that account has been added to the project
        # 2. Wait for network cleanup interval and verify that network
        #    is not cleaned up and it is still in
        #    implemented state

        # Create Account
        account = Account.create(
            self.apiclient,
            self.services["account"],
            domainid=self.domain.id)
        self.cleanup.append(account)

        # Create Project
        project = Project.create(self.apiclient, self.services["project"])
        self.cleanup.append(project)

        network = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=self.isolated_persistent_network_offering.id,
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)

        # Add account to the project
        project.addAccount(self.apiclient, account=account.name)

        # Verify the account name in the list of accounts belonging to the
        # project
        projectAccounts = Project.listAccounts(
            self.apiclient,
            projectid=project.id)
        self.assertEqual(
            validateList(projectAccounts)[0],
            PASS,
            "project accounts list validation failed, list is %s" %
            projectAccounts)

        accountNames = [
            projectAccount.account for projectAccount in projectAccounts]
        self.assertTrue(
            account.name in accountNames,
            "account %s is not present in account list %s of project %s" %
            (account.name,
             accountNames,
             project.id))

        # Suspend Project
        project.suspend(self.apiclient)

        # Verify the project is suspended
        projects = Project.list(self.apiclient, id=project.id)
        self.assertEqual(
            validateList(projects)[0],
            PASS,
            "projects list validation failed, list is %s" %
            projects)
        self.assertEqual(
            str(
                projects[0].state).lower(),
            "suspended",
            "project state should be suspended, it is %s" %
            projects[0].state)

        # Wait for network cleanup interval
        wait_for_cleanup(
            self.api_client, [
                "network.gc.interval", "network.gc.wait"])

        response = verifyNetworkState(
            self.apiclient,
            network.id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        return


@ddt
class TestRestartPersistentNetwork(cloudstackTestCase):
    """Test restart persistent network with cleanup parameter true and false
    """

    @classmethod
    def setUpClass(cls):
        cls.testClient = super(
            TestRestartPersistentNetwork,
            cls).getClsTestClient()
        cls.api_client = cls.testClient.getApiClient()

        # Fill services from the external config file
        cls.services = cls.testClient.getParsedTestDataConfig()
        cls.hostConfig = cls.config.__dict__["zones"][0].__dict__["pods"][0].__dict__["clusters"][0].__dict__["hosts"][
            0].__dict__
        # Get Zone, Domain and templates
        cls.domain = get_domain(cls.api_client)
        cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
        cls.template = get_template(
            cls.api_client,
            cls.zone.id,
            cls.services["ostype"]
        )
        if cls.template == FAILED:
            assert False, "get_template() failed to return\
                template with description %s" % cls.services["ostype"]
        cls.services["virtual_machine"]["zoneid"] = cls.zone.id
        cls.services["virtual_machine"]["template"] = cls.template.id
        cls.service_offering = ServiceOffering.create(
            cls.api_client,
            cls.services["service_offering"]
        )
        cls.isolated_persistent_network_offering = NetworkOffering.create(
            cls.api_client,
            cls.services["nw_off_isolated_persistent_lb"],
            conservemode=False)

        cls.isolated_persistent_network_offering_netscaler = \
            NetworkOffering.create(
                cls.api_client,
                cls.services["nw_off_isolated_persistent_netscaler"],
                conservemode=False
            )
        # Update network offering state from disabled to enabled.
        cls.isolated_persistent_network_offering.update(
            cls.api_client,
            state="enabled")
        cls.isolated_persistent_network_offering_netscaler.update(
            cls.api_client,
            state="enabled")

        cls.services["configurableData"]["netscaler"]["lbdevicededicated"] = \
            False

        # Configure Netscaler device
        # If configuration succeeds, set ns_configured to True so that
        # Netscaler tests are executed
        cls.ns_configured = False
        try:
            cls.netscaler = add_netscaler(
                cls.api_client,
                cls.zone.id,
                cls.services["configurableData"]["netscaler"])
            cls._cleanup.append(cls.netscaler)
            cls.ns_configured = True
        except Exception:
            cls.ns_configured = False

        # network will be deleted as part of account cleanup
        cls._cleanup = [
            cls.service_offering, cls.isolated_persistent_network_offering,
            cls.isolated_persistent_network_offering_netscaler
        ]
        return

    @classmethod
    def tearDownClass(cls):
        try:
            # Cleanup resources used
            cleanup_resources(cls.api_client, cls._cleanup)
        except Exception as e:
            raise Exception("Warning: Exception during cleanup : %s" % e)
        return

    def setUp(self):
        self.apiclient = self.testClient.getApiClient()
        self.dbclient = self.testClient.getDbConnection()
        self.cleanup = []
        return

    def tearDown(self):
        try:
            # Clean up, terminate the resources created
            cleanup_resources(self.apiclient, self.cleanup)
            self.cleanup[:] = []
        except Exception as e:
            raise Exception("Warning: Exception during cleanup : %s" % e)
        return

    def checkRouterAccessibility(self, router):
        """Check if router is accessible through its linklocalip"""

        hypervisor = str(get_hypervisor_type(self.api_client))

        if hypervisor.lower() in ('vmware', 'hyperv'):
            # SSH is done via management server for Vmware and Hyper-V
            sourceip = self.api_client.connection.mgtSvr
        else:
            # For others, we will have to get the ipaddress of host connected
            # to vm
            hosts = Host.list(self.api_client, id=router.hostid)
            self.assertEqual(
                validateList(hosts)[0],
                PASS,
                "hosts list validation failed, list is %s" %
                hosts)
            host = hosts[0]
            sourceip = host.ipaddress
            # end else

        try:
            sshClient = SshClient(
                host=sourceip,
                port=self.services['configurableData']['host']["publicport"],
                user=self.hostConfig['username'],
                passwd=self.hostConfig['password'])
            res = sshClient.execute("ping -c 1 %s" % (
                router.linklocalip
            ))
        except Exception as e:
            self.fail("SSH Access failed for %s: %s" %
                      (sourceip, e)
                      )
        result = str(res)
        self.assertEqual(
            result.count("1 received"),
            1,
            "ping to router should be successful"
        )
        return

    @data("true", "false")
    @attr(tags=["advanced"], required_hardware="true")
    def test_cleanup_persistent_network(self, value):
        # steps
        # 1. Create account and create persistent network in it
        # 2. Verify that router is reachable from the host
        # 3. Acquire public IP, open firewall and create LB rule
        # 4. Restart the network with clenup parameter true/false
        # 5. Check network state after restart, it should be implemented
        # 6. Deploy VM, assign LB rule to it, and verify the LB rule

        account = Account.create(
            self.apiclient,
            self.services["account"],
            domainid=self.domain.id)
        self.cleanup.append(account)

        isolated_persistent_network = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=self.isolated_persistent_network_offering.id,
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)
        response = verifyNetworkState(
            self.apiclient,
            isolated_persistent_network.id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        self.assertIsNotNone(
            isolated_persistent_network.vlan,
            "vlan must not be null for persistent network")

        self.debug(
            "Listing routers for network: %s" %
            isolated_persistent_network.name)
        routers = Router.list(self.api_client, listall=True,
                              networkid=isolated_persistent_network.id)

        self.assertEqual(
            validateList(routers)[0],
            PASS,
            "Routers list validation failed, list is %s" %
            routers)

        # Check if router is reachable from the host
        for router in routers:
            self.checkRouterAccessibility(router)

        self.debug(
            "Associating public IP for network: %s" %
            isolated_persistent_network.id)
        ipaddress = PublicIPAddress.create(
            self.api_client,
            accountid=account.name,
            zoneid=self.zone.id,
            domainid=account.domainid,
            networkid=isolated_persistent_network.id)

        FireWallRule.create(
            self.apiclient,
            ipaddressid=ipaddress.ipaddress.id,
            protocol='TCP',
            cidrlist=[
                self.services["fwrule"]["cidr"]],
            startport=self.services["fwrule"]["startport"],
            endport=self.services["fwrule"]["endport"])

        # Create LB Rule
        lb_rule = LoadBalancerRule.create(
            self.apiclient,
            self.services["lbrule"],
            ipaddressid=ipaddress.ipaddress.id,
            accountid=account.name,
            networkid=isolated_persistent_network.id,
            domainid=account.domainid)

        # Restart Network
        isolated_persistent_network.restart(self.apiclient, cleanup=value)

        # List networks
        networks = Network.list(
            self.apiclient,
            account=account.name,
            domainid=account.domainid)
        self.assertEqual(
            validateList(networks)[0],
            PASS,
            "networks list validation failed, list is %s" %
            networks)

        verifyNetworkState(self.apiclient, networks[0].id, "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        self.assertIsNotNone(
            networks[0].vlan,
            "vlan must not be null for persistent network")

        # Deploy VM
        try:
            virtual_machine = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    isolated_persistent_network.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)
        except Exception as e:
            self.fail("vm creation failed: %s" % e)

        lb_rule.assign(self.api_client, [virtual_machine])

        try:
            virtual_machine.get_ssh_client(
                ipaddress=ipaddress.ipaddress.ipaddress,
                port=self.services["lbrule"]["publicport"])
        except Exception as e:
            self.fail(
                "Exception while SSHing to VM %s with IP %s" %
                (virtual_machine.id, ipaddress.ipaddress.ipaddress))

        return

    @data("true", "false")
    @attr(tags=["advanced", "advancedns"])
    def test_cleanup_persistent_network_lb_netscaler(self, value):
        # steps
        # 1. Create account and create persistent network in
        #    it with LB service provided by netscaler
        # 2. Verify that router is reachable from the host
        # 3. Acquire public IP, open firewall and create LB rule
        # 4. Restart the network with clenup parameter true/false
        # 5. Check network state after restart, it should be implemented
        # 6. Deploy VM, assign LB rule to it, and verify the LB rule

        if not self.ns_configured:
            self.skipTest(
                "This test required netscaler to be configured in the network")

        account = Account.create(
            self.apiclient,
            self.services["account"],
            domainid=self.domain.id)
        self.cleanup.append(account)

        isolated_persistent_network = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=(
                self.isolated_persistent_network_offering_netscaler.id),
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id)
        response = verifyNetworkState(
            self.apiclient,
            isolated_persistent_network.id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        self.assertIsNotNone(
            isolated_persistent_network.vlan,
            "vlan must not be null for persistent network")

        self.debug(
            "Listing routers for network: %s" %
            isolated_persistent_network.name)
        routers = Router.list(self.api_client, listall=True,
                              networkid=isolated_persistent_network.id)

        self.assertEqual(
            validateList(routers)[0],
            PASS,
            "Routers list validation failed, list is %s" %
            routers)

        # Check if router is reachable from the host
        for router in routers:
            self.checkRouterAccessibility(router)

        self.debug(
            "Associating public IP for network: %s" %
            isolated_persistent_network.id)
        ipaddress = PublicIPAddress.create(
            self.api_client,
            accountid=account.name,
            zoneid=self.zone.id,
            domainid=account.domainid,
            networkid=isolated_persistent_network.id)

        # Create LB Rule
        lb_rule = LoadBalancerRule.create(
            self.apiclient,
            self.services["lbrule"],
            ipaddressid=ipaddress.ipaddress.id,
            accountid=account.name,
            networkid=isolated_persistent_network.id,
            domainid=account.domainid)

        # Restart Network
        isolated_persistent_network.restart(self.apiclient, cleanup=value)

        # List networks
        networks = Network.list(
            self.apiclient,
            account=account.name,
            domainid=account.domainid)
        self.assertEqual(
            validateList(networks)[0],
            PASS,
            "networks list validation failed, list is %s" %
            networks)

        response = verifyNetworkState(
            self.apiclient,
            networks[0].id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        self.assertIsNotNone(
            networks[0].vlan,
            "vlan must not be null for persistent network")

        # Deploy VM
        try:
            virtual_machine = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    isolated_persistent_network.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)
        except Exception as e:
            self.fail("vm creation failed: %s" % e)

        lb_rule.assign(self.api_client, [virtual_machine])

        try:
            virtual_machine.get_ssh_client(
                ipaddress=ipaddress.ipaddress.ipaddress)
        except Exception as e:
            self.fail(
                "Exception while SSHing to VM %s with IP %s" %
                (virtual_machine.id, ipaddress.ipaddress.ipaddress))

        return


@ddt
class TestVPCNetworkOperations(cloudstackTestCase):
    """Test VPC network operations consisting persistent networks
    """

    @classmethod
    def setUpClass(cls):
        cls.testClient = super(
            TestVPCNetworkOperations,
            cls).getClsTestClient()
        cls.api_client = cls.testClient.getApiClient()

        # Fill services from the external config file
        cls.services = cls.testClient.getParsedTestDataConfig()

        # Get Zone, Domain and templates
        cls.domain = get_domain(cls.api_client)
        cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
        cls.template = get_template(
            cls.api_client,
            cls.zone.id,
            cls.services["ostype"]
        )
        if cls.template == FAILED:
            assert False, "get_template() failed to return\
                template with description %s" % cls.services[
                "ostype"]

        cls.services["virtual_machine"]["zoneid"] = cls.zone.id
        cls.services["virtual_machine"]["template"] = cls.template.id
        cls.service_offering = ServiceOffering.create(
            cls.api_client,
            cls.services["service_offerings"]["small"]
        )
        cls.persistent_network_offering_NoLB = NetworkOffering.create(
            cls.api_client,
            cls.services["nw_off_persistent_VPCVR_NoLB"],
            conservemode=False)
        # Update network offering state from disabled to enabled.
        cls.persistent_network_offering_NoLB.update(
            cls.api_client,
            state="enabled")

        cls.persistent_network_offering_LB = NetworkOffering.create(
            cls.api_client,
            cls.services["nw_off_persistent_VPCVR_LB"],
            conservemode=False)
        # Update network offering state from disabled to enabled.
        cls.persistent_network_offering_LB.update(
            cls.api_client,
            state="enabled")

        cls.vpc_off = VpcOffering.create(
            cls.api_client,
            cls.services["vpc_offering"])
        cls.vpc_off.update(cls.api_client, state='Enabled')

        # network will be deleted as part of account cleanup
        cls._cleanup = [
            cls.service_offering,
            cls.persistent_network_offering_NoLB,
            cls.vpc_off,
            cls.persistent_network_offering_LB]
        return

    @classmethod
    def tearDownClass(cls):
        try:
            # Cleanup resources used
            cleanup_resources(cls.api_client, cls._cleanup)
        except Exception as e:
            raise Exception("Warning: Exception during cleanup : %s" % e)
        return

    def setUp(self):
        self.apiclient = self.testClient.getApiClient()
        self.dbclient = self.testClient.getDbConnection()
        self.cleanup = []
        return

    def tearDown(self):
        try:
            # Clean up, terminate the resources created
            cleanup_resources(self.apiclient, self.cleanup)
            self.cleanup[:] = []
        except Exception as e:
            raise Exception("Warning: Exception during cleanup : %s" % e)
        return

    def GetAssociatedIpForNetwork(self, networkid, vpcid, account):
        """ Associate IP address with the network and open firewall for it
            return associated IPaddress"""

        ipaddress = PublicIPAddress.create(
            self.api_client,
            zoneid=self.zone.id,
            networkid=networkid,
            vpcid=vpcid,
            accountid=account.name,
            domainid=account.domainid)

        return ipaddress

    def CreateIngressEgressNetworkACLForNetwork(self, networkid):

        try:
            ingressAcl = NetworkACL.create(
                self.apiclient,
                networkid=networkid,
                services=self.services["natrule"],
                traffictype='Ingress')
            egressAcl = NetworkACL.create(
                self.apiclient,
                networkid=networkid,
                services=self.services["icmprule"],
                traffictype='Egress')
        except Exception as e:
            self.fail(
                "Failed while creating Network ACL rule\
                for network %s with error %s" %
                (networkid, e))
        return ingressAcl, egressAcl

    def CheckIngressEgressConnectivityofVM(self, virtual_machine, ipaddress,
                                           port=22):
        try:
            ssh = SshClient(
                ipaddress,
                port,
                virtual_machine.username,
                virtual_machine.password
            )
            # Ping to outsite world
            res = ssh.execute("ping -c 1 www.google.com")
            # res = 64 bytes from maa03s17-in-f20.1e100.net (74.125.236.212):
            # icmp_req=1 ttl=57 time=25.9 ms
            # --- www.l.google.com ping statistics ---
            # 1 packets transmitted, 1 received, 0% packet loss, time 0ms
            # rtt min/avg/max/mdev = 25.970/25.970/25.970/0.000 ms
        except Exception as e:
            self.fail("SSH Access failed for vm %s with IP address %s: %s" %
                      (virtual_machine.id, ipaddress, e))
        result = str(res)
        self.assertEqual(
            result.count("1 received"),
            1,
            "Ping to outside world from VM should be successful")
        return

    def VerifyNetworkCleanup(self, networkid):
        """Verify that network is cleaned up"""

        networks = Network.list(self.apiclient, id=networkid)
        self.assertEqual(
            validateList(networks)[0],
            FAIL,
            "networks list should be empty, it is %s" %
            networks)
        return

    def VerifyVpcCleanup(self, vpcid):
        """Verify that VPC is cleaned up"""
        vpcs = VPC.list(self.apiclient, id=vpcid)
        self.assertEqual(
            validateList(vpcs)[0],
            FAIL,
            "VPC list should be empty, it is %s" %
            vpcs)
        return

    def VerifyVirtualMachineCleanup(self, vmid):
        """Verify that virtual machine is cleaned up"""
        vms = VirtualMachine.list(self.apiclient, id=vmid)
        self.assertEqual(
            validateList(vms)[0],
            FAIL,
            "vms list should be empty, it is %s" %
            vms)
        return

    def VerifyAclRuleCleanup(self, aclRuleId):
        """Verify that network ACL rule is cleaned up"""
        networkAcls = NetworkACL.list(self.apiclient, id=aclRuleId)
        self.assertEqual(
            validateList(networkAcls)[0],
            FAIL,
            "networkAcls list should be empty, it is %s" %
            networkAcls)
        return

    @data("delete", "restart")
    @attr(tags=["advanced"])
    def test_vpc_network_life_cycle(self, value):
        # steps
        # 1. Create account and create VPC network in the account
        # 2. Create two persistent networks within this VPC
        # 3. Restart/delete VPC network

        # Validations
        # 1. In case of Restart operation, restart should be successful
        #    and persistent networks should be back in persistent state
        # 2. In case of Delete operation, VR servicing the VPC should get
        # destroyed and sourceNAT ip should get released

        account = Account.create(
            self.apiclient,
            self.services["account"],
            domainid=self.domain.id)
        self.cleanup.append(account)

        self.services["vpc"]["cidr"] = "10.1.1.1/16"
        self.debug("creating a VPC network in the account: %s" %
                   account.name)
        vpc = VPC.create(self.apiclient, self.services["vpc"],
                         vpcofferingid=self.vpc_off.id, zoneid=self.zone.id,
                         account=account.name, domainid=account.domainid)
        vpcs = VPC.list(self.apiclient, id=vpc.id)
        self.assertEqual(
            validateList(vpcs)[0],
            PASS,
            "VPC list validation failed, vpc list is %s" %
            vpcs)

        VpcRouters = Router.list(self.apiclient, vpcid=vpc.id, listall=True)
        self.assertEqual(
            validateList(VpcRouters)[0],
            PASS,
            "VpcRouters list validation failed, list is %s" %
            VpcRouters)
        vpcrouter = VpcRouters[0]

        publicipaddresses = PublicIPAddress.list(
            self.apiclient,
            vpcid=vpc.id,
            listall=True)
        self.assertEqual(
            validateList(publicipaddresses)[0],
            PASS,
            "Public IP Addresses list validation failed, list is %s" %
            publicipaddresses)

        persistent_network_1 = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=self.persistent_network_offering_NoLB.id,
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id,
            vpcid=vpc.id,
            gateway="10.1.1.1",
            netmask="255.255.255.0")
        response = verifyNetworkState(
            self.apiclient,
            persistent_network_1.id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        self.assertIsNotNone(
            persistent_network_1.vlan,
            "vlan must not be null for persistent network %s" %
            persistent_network_1.id)

        persistent_network_2 = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=self.persistent_network_offering_NoLB.id,
            accountid=account.name,
            domainid=self.domain.id,
            zoneid=self.zone.id,
            vpcid=vpc.id,
            gateway="10.1.2.1",
            netmask="255.255.255.0")
        response = verifyNetworkState(
            self.apiclient,
            persistent_network_2.id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        self.assertIsNotNone(
            persistent_network_2.vlan,
            "vlan must not be null for persistent network: %s" %
            persistent_network_2.id)

        if value == "restart":
            # Restart VPC
            vpc.restart(self.apiclient)
            response = verifyNetworkState(
                self.apiclient,
                persistent_network_1.id,
                "implemented")
            exceptionOccurred = response[0]
            isNetworkInDesiredState = response[1]
            exceptionMessage = response[2]

            if (exceptionOccurred or (not isNetworkInDesiredState)):
                self.fail(exceptionMessage)
            response = verifyNetworkState(
                self.apiclient,
                persistent_network_2.id,
                "implemented")
            exceptionOccurred = response[0]
            isNetworkInDesiredState = response[1]
            exceptionMessage = response[2]

            if (exceptionOccurred or (not isNetworkInDesiredState)):
                self.fail(exceptionMessage)

        elif value == "delete":
            persistent_network_1.delete(self.apiclient)
            persistent_network_2.delete(self.apiclient)
            vpc.delete(self.apiclient)
            vpcs = VPC.list(self.apiclient, id=vpc.id)
            self.assertEqual(
                validateList(vpcs)[0],
                FAIL,
                "vpc list should be empty, list is %s" %
                vpcs)

            # Check if router is deleted or not
            routers = Router.list(self.apiclient, id=vpcrouter.id)
            self.assertEqual(
                validateList(routers)[0],
                FAIL,
                "routers list should be empty, it is %s" %
                routers)

            # Check if source nat IP address is released
            ipaddresses = PublicIPAddress.list(
                self.apiclient,
                id=publicipaddresses[0].id,
                state="Allocated")
            self.assertEqual(
                validateList(ipaddresses)[0],
                FAIL,
                "public ip addresses list should be empty, list is %s" %
                ipaddresses)
        return

    @attr(tags=["advanced"])
    def test_vpc_force_delete_domain(self):
        # steps
        # 1. Create account and create VPC network in the account
        # 2. Create two persistent networks within this VPC
        # 3. Restart/delete VPC network

        # Validations
        # 1. In case of Restart operation, restart should be successful
        #    and persistent networks should be back in persistent state
        # 2. In case of Delete operation, VR servicing the VPC should
        #    get destroyed and sourceNAT ip should get released

        child_domain = Domain.create(self.apiclient,
                                     services=self.services["domain"],
                                     parentdomainid=self.domain.id)

        try:
            account_1 = Account.create(
                self.apiclient, self.services["account"],
                domainid=child_domain.id
            )
            account_2 = Account.create(
                self.apiclient, self.services["account"],
                domainid=child_domain.id
            )

            self.services["vpc"]["cidr"] = "10.1.1.1/16"
            vpc_1 = VPC.create(
                self.apiclient,
                self.services["vpc"],
                vpcofferingid=self.vpc_off.id,
                zoneid=self.zone.id,
                account=account_1.name,
                domainid=account_1.domainid)
            vpcs = VPC.list(self.apiclient, id=vpc_1.id)
            self.assertEqual(
                validateList(vpcs)[0],
                PASS,
                "VPC list validation failed, vpc list is %s" %
                vpcs)

            vpc_2 = VPC.create(
                self.apiclient,
                self.services["vpc"],
                vpcofferingid=self.vpc_off.id,
                zoneid=self.zone.id,
                account=account_2.name,
                domainid=account_2.domainid)
            vpcs = VPC.list(self.apiclient, id=vpc_2.id)
            self.assertEqual(
                validateList(vpcs)[0],
                PASS,
                "VPC list validation failed, vpc list is %s" %
                vpcs)

            persistent_network_1 = Network.create(
                self.api_client, self.services["isolated_network"],
                networkofferingid=self.persistent_network_offering_NoLB.id,
                accountid=account_1.name, domainid=account_1.domainid,
                zoneid=self.zone.id, vpcid=vpc_1.id, gateway="10.1.1.1",
                netmask="255.255.255.0")

            response = verifyNetworkState(self.apiclient,
                                          persistent_network_1.id,
                                          "implemented"
                                          )
            exceptionOccurred = response[0]
            isNetworkInDesiredState = response[1]
            exceptionMessage = response[2]

            if (exceptionOccurred or (not isNetworkInDesiredState)):
                raise Exception(exceptionMessage)
            self.assertIsNotNone(
                persistent_network_1.vlan,
                "vlan must not be null for persistent network %s" %
                persistent_network_1.id)

            persistent_network_2 = Network.create(
                self.api_client, self.services["isolated_network"],
                networkofferingid=self.persistent_network_offering_NoLB.id,
                accountid=account_2.name, domainid=account_2.domainid,
                zoneid=self.zone.id, vpcid=vpc_2.id, gateway="10.1.1.1",
                netmask="255.255.255.0")
            response = verifyNetworkState(
                self.apiclient,
                persistent_network_2.id,
                "implemented")
            exceptionOccurred = response[0]
            isNetworkInDesiredState = response[1]
            exceptionMessage = response[2]

            if (exceptionOccurred or (not isNetworkInDesiredState)):
                raise Exception(exceptionMessage)
            self.assertIsNotNone(
                persistent_network_2.vlan,
                "vlan must not be null for persistent network: %s" %
                persistent_network_2.id)

        except Exception as e:
            self.cleanup.append(account_1)
            self.cleanup.append(account_2)
            self.cleanup.append(child_domain)
            self.fail(e)

        # Force delete domain
        child_domain.delete(self.apiclient, cleanup=True)

        self.debug("Waiting for account.cleanup.interval" +
                   " to cleanup any remaining resources")
        # Sleep 3*account.gc to ensure that all resources are deleted
        wait_for_cleanup(self.apiclient, ["account.cleanup.interval"] * 3)

        with self.assertRaises(Exception):
            Domain.list(self.apiclient, id=child_domain.id)

        with self.assertRaises(Exception):
            Account.list(
                self.apiclient, name=account_1.name,
                domainid=account_1.domainid, listall=True
            )

        with self.assertRaises(Exception):
            Account.list(
                self.apiclient, name=account_2.name,
                domainid=account_2.domainid, listall=True
            )

        self.VerifyVpcCleanup(vpc_1.id)
        self.VerifyVpcCleanup(vpc_2.id)
        self.VerifyNetworkCleanup(persistent_network_1.id)
        self.VerifyNetworkCleanup(persistent_network_2.id)
        return

    # @attr(tags=["advanced"], required_hardware="true")
    @attr(tags=["TODO"], required_hardware="true")
    def test_vpc_delete_account(self):
        # steps
        # 1. Create account and create VPC network in the account
        # 2. Create two persistent networks within this VPC
        # 3. Restart/delete VPC network

        # Validations
        # 1. In case of Restart operation, restart should be successful and
        #    persistent networks should be back in persistent state
        # 2. In case of Delete operation, VR servicing the VPC should get
        # destroyed and sourceNAT ip should get released

        try:
            # Create Account
            account = Account.create(
                self.apiclient,
                self.services["account"],
                domainid=self.domain.id)

            # Create VPC
            self.services["vpc"]["cidr"] = "10.1.1.1/16"
            vpc = VPC.create(
                self.apiclient,
                self.services["vpc"],
                vpcofferingid=self.vpc_off.id,
                zoneid=self.zone.id,
                account=account.name,
                domainid=account.domainid)
            vpcs = VPC.list(self.apiclient, id=vpc.id)
            self.assertEqual(
                validateList(vpcs)[0],
                PASS,
                "VPC list validation failed, vpc list is %s" %
                vpcs)

            # Create Persistent Networks as tiers of VPC
            persistent_network_1 = Network.create(
                self.api_client,
                self.services["isolated_network"],
                networkofferingid=self.persistent_network_offering_NoLB.id,
                accountid=account.name,
                domainid=account.domainid,
                zoneid=self.zone.id,
                vpcid=vpc.id,
                gateway="10.1.1.1",
                netmask="255.255.255.0")
            response = verifyNetworkState(
                self.apiclient,
                persistent_network_1.id,
                "implemented")
            exceptionOccurred = response[0]
            isNetworkInDesiredState = response[1]
            exceptionMessage = response[2]

            if (exceptionOccurred or (not isNetworkInDesiredState)):
                raise Exception(exceptionMessage)
            self.assertIsNotNone(
                persistent_network_1.vlan,
                "vlan must not be null for persistent network %s" %
                persistent_network_1.id)

            persistent_network_2 = Network.create(
                self.api_client,
                self.services["isolated_network"],
                networkofferingid=self.persistent_network_offering_LB.id,
                accountid=account.name,
                domainid=account.domainid,
                zoneid=self.zone.id,
                vpcid=vpc.id,
                gateway="10.1.2.1",
                netmask="255.255.255.0")
            response = verifyNetworkState(
                self.apiclient,
                persistent_network_2.id,
                "implemented")
            exceptionOccurred = response[0]
            isNetworkInDesiredState = response[1]
            exceptionMessage = response[2]

            if (exceptionOccurred or (not isNetworkInDesiredState)):
                raise Exception(exceptionMessage)
            self.assertIsNotNone(
                persistent_network_2.vlan,
                "vlan must not be null for persistent network: %s" %
                persistent_network_2.id)

            # Deploy VMs in above networks (VM1, VM2 in network1 and VM3, VM4
            # in network2)
            virtual_machine_1 = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    persistent_network_1.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)

            virtual_machine_2 = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    persistent_network_1.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)

            virtual_machine_3 = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    persistent_network_2.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)

            virtual_machine_4 = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    persistent_network_2.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)

            # Associate IP addresses to persistent networks
            ipaddress_1 = self.GetAssociatedIpForNetwork(
                persistent_network_1.id,
                vpcid=vpc.id,
                account=account)
            ipaddress_2 = self.GetAssociatedIpForNetwork(
                persistent_network_1.id,
                vpcid=vpc.id,
                account=account)
            ipaddress_3 = self.GetAssociatedIpForNetwork(
                persistent_network_2.id,
                vpcid=vpc.id,
                account=account)

            # Create NAT rule for VM 1
            NATRule.create(
                self.api_client,
                virtual_machine_1,
                self.services["natrule"],
                ipaddressid=ipaddress_1.ipaddress.id,
                networkid=persistent_network_1.id)

            # Create Static NAT rule for VM 2
            StaticNATRule.enable(
                self.apiclient,
                ipaddressid=ipaddress_2.ipaddress.id,
                virtualmachineid=virtual_machine_2.id,
                networkid=persistent_network_1.id)

            # Create load balancer rule for ipaddress3 and assign to VM3 and
            # VM4
            lb_rule = LoadBalancerRule.create(
                self.apiclient,
                self.services["lbrule"],
                ipaddressid=ipaddress_3.ipaddress.id,
                accountid=account.name,
                networkid=persistent_network_2.id,
                domainid=account.domainid)
            lb_rule.assign(
                self.api_client, [
                    virtual_machine_3, virtual_machine_4])

            # Create network ACL for both ther persistent networks (tiers of
            # VPC)
            ingressAclNetwork1, egressAclNetwork1 = \
                self.CreateIngressEgressNetworkACLForNetwork(
                    persistent_network_1.id
                )
            ingressAclNetwork2, egressAclNetwork2 = \
                self.CreateIngressEgressNetworkACLForNetwork(
                    persistent_network_2.id
                )

            # CLOUDSTACK-8451 needs to be fixed in order to work
            self.CheckIngressEgressConnectivityofVM(
                virtual_machine_1,
                ipaddress_1.ipaddress.ipaddress)
            self.CheckIngressEgressConnectivityofVM(
                virtual_machine_2,
                ipaddress_2.ipaddress.ipaddress)
            self.CheckIngressEgressConnectivityofVM(
                virtual_machine_3,
                ipaddress_3.ipaddress.ipaddress,
                port=self.services["lbrule"]["publicport"])
            self.CheckIngressEgressConnectivityofVM(
                virtual_machine_4,
                ipaddress_3.ipaddress.ipaddress,
                port=self.services["lbrule"]["publicport"])
        except Exception as e:
            self.cleanup.append(account)
            self.fail(e)

        # Delete account
        account.delete(self.apiclient)

        # Verify all the resources owned by the account are deleted
        self.debug("Waiting for account.cleanup.interval" +
                   " to cleanup any remaining resources")
        # Sleep 3*account.gc to ensure that all resources are deleted
        wait_for_cleanup(self.apiclient, ["account.cleanup.interval"] * 3)

        self.VerifyVpcCleanup(vpc.id)
        self.VerifyNetworkCleanup(persistent_network_1.id)
        self.VerifyNetworkCleanup(persistent_network_2.id)
        self.VerifyVirtualMachineCleanup(virtual_machine_1.id)
        self.VerifyVirtualMachineCleanup(virtual_machine_2.id)
        self.VerifyVirtualMachineCleanup(virtual_machine_3.id)
        self.VerifyVirtualMachineCleanup(virtual_machine_4.id)
        self.VerifyAclRuleCleanup(ingressAclNetwork1.id)
        self.VerifyAclRuleCleanup(egressAclNetwork1.id)
        self.VerifyAclRuleCleanup(ingressAclNetwork2.id)
        self.VerifyAclRuleCleanup(egressAclNetwork2.id)
        return

    @unittest.skip("WIP")
    @attr(tags=["advanced"])
    def test_vpc_private_gateway_static_route(self):
        # steps
        # 1. Create account and create VPC network in the account
        # 2. Create two persistent networks within this VPC
        # 3. Restart/delete VPC network

        # Validations
        # 1. In case of Restart operation, restart should be successful
        #    and persistent networks should be back in persistent state
        # 2. In case of Delete operation, VR servicing the VPC should get
        # destroyed and sourceNAT ip should get released

        # Create Account
        account = Account.create(
            self.apiclient,
            self.services["account"],
            domainid=self.domain.id)
        self.cleanup.append(account)

        # Create VPC
        self.services["vpc"]["cidr"] = "10.1.1.1/16"
        vpc = VPC.create(self.apiclient, self.services["vpc"],
                         vpcofferingid=self.vpc_off.id, zoneid=self.zone.id,
                         account=account.name, domainid=account.domainid)
        vpcs = VPC.list(self.apiclient, id=vpc.id)
        self.assertEqual(
            validateList(vpcs)[0],
            PASS,
            "VPC list validation failed, vpc list is %s" %
            vpcs)

        # Create Persistent Networks as tiers of VPC
        persistent_network_1 = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=self.persistent_network_offering_NoLB.id,
            accountid=account.name,
            domainid=account.domainid,
            zoneid=self.zone.id,
            vpcid=vpc.id,
            gateway="10.1.1.1",
            netmask="255.255.255.0")
        response = verifyNetworkState(
            self.apiclient,
            persistent_network_1.id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        self.assertIsNotNone(
            persistent_network_1.vlan,
            "vlan must not be null for persistent network %s" %
            persistent_network_1.id)

        persistent_network_2 = Network.create(
            self.api_client,
            self.services["isolated_network"],
            networkofferingid=self.persistent_network_offering_LB.id,
            accountid=account.name,
            domainid=account.domainid,
            zoneid=self.zone.id,
            vpcid=vpc.id,
            gateway="10.1.2.1",
            netmask="255.255.255.0")
        response = verifyNetworkState(
            self.apiclient,
            persistent_network_2.id,
            "implemented")
        exceptionOccurred = response[0]
        isNetworkInDesiredState = response[1]
        exceptionMessage = response[2]

        if (exceptionOccurred or (not isNetworkInDesiredState)):
            self.fail(exceptionMessage)
        self.assertIsNotNone(
            persistent_network_2.vlan,
            "vlan must not be null for persistent network: %s" %
            persistent_network_2.id)

        # Deploy VMs in above networks (VM1, VM2 in network1 and VM3, VM4 in
        # network2)
        try:
            virtual_machine_1 = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    persistent_network_1.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)

            virtual_machine_2 = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    persistent_network_1.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)

            virtual_machine_3 = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    persistent_network_2.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)

            virtual_machine_4 = VirtualMachine.create(
                self.apiclient,
                self.services["virtual_machine"],
                networkids=[
                    persistent_network_2.id],
                serviceofferingid=self.service_offering.id,
                accountid=account.name,
                domainid=self.domain.id)
        except Exception as e:
            self.fail("vm creation failed: %s" % e)

        # Associate IP addresses to persistent networks
        ipaddress_1 = self.GetAssociatedIpForNetwork(
            persistent_network_1.id,
            vpcid=vpc.id,
            account=account)
        ipaddress_2 = self.GetAssociatedIpForNetwork(
            persistent_network_1.id,
            vpcid=vpc.id,
            account=account)
        ipaddress_3 = self.GetAssociatedIpForNetwork(
            persistent_network_2.id,
            vpcid=vpc.id,
            account=account)

        # Create NAT rule for VM 1
        NATRule.create(
            self.api_client,
            virtual_machine_1,
            self.services["natrule"],
            ipaddressid=ipaddress_1.ipaddress.id,
            networkid=persistent_network_1.id)

        # Create Static NAT rule for VM 2
        StaticNATRule.enable(
            self.apiclient,
            ipaddressid=ipaddress_2.ipaddress.id,
            virtualmachineid=virtual_machine_2.id,
            networkid=persistent_network_1.id)

        # Create load balancer rule for ipaddress3 and assign to VM3 and VM4
        lb_rule = LoadBalancerRule.create(
            self.apiclient,
            self.services["lbrule"],
            ipaddressid=ipaddress_3.ipaddress.id,
            accountid=account.name,
            networkid=persistent_network_2.id,
            domainid=account.domainid)
        lb_rule.assign(self.api_client, [virtual_machine_3, virtual_machine_4])

        # Create network ACL for both ther persistent networks (tiers of VPC)
        ingressAclNetwork1, egressAclNetwork1 = \
            self.CreateIngressEgressNetworkACLForNetwork(
                persistent_network_1.id
            )
        ingressAclNetwork2, egressAclNetwork2 = \
            self.CreateIngressEgressNetworkACLForNetwork(
                persistent_network_2.id
            )

        """private_gateway = PrivateGateway.create(
            self.apiclient,gateway='10.1.4.1',
            ipaddress='10.1.4.100',
            netmask='255.255.255.0',
            vlan=679,
            vpcid=vpc.id)

        gateways = PrivateGateway.list(
            self.apiclient,
            id=private_gateway.id,
            listall=True)
        self.assertEqual(
            validateList(gateways)[0],
            PASS,
            "gateways list validation failed, list is %s" % gateways
            )

        static_route = StaticRoute.create(
            self.apiclient,
            cidr='11.1.1.1/24',
            gatewayid=private_gateway.id)
        static_routes = StaticRoute.list(
            self.apiclient,
            id=static_route.id,
            listall=True)
        self.assertEqual(
            validateList(static_routes)[0],
            PASS,
            "static routes list validation failed, list is %s"
            % static_routes)"""

        self.CheckIngressEgressConnectivityofVM(
            virtual_machine_1,
            ipaddress_1.ipaddress.ipaddress)
        self.CheckIngressEgressConnectivityofVM(
            virtual_machine_2,
            ipaddress_2.ipaddress.ipaddress)
        self.CheckIngressEgressConnectivityofVM(
            virtual_machine_3,
            ipaddress_3.ipaddress.ipaddress)
        """self.CheckIngressEgressConnectivityofVM(virtual_machine_4,
        ipaddress_3.ipaddress.ipaddress)"""

        vpc.restart(self.apiclient)

        self.CheckIngressEgressConnectivityofVM(
            virtual_machine_1,
            ipaddress_1.ipaddress.ipaddress)
        self.CheckIngressEgressConnectivityofVM(
            virtual_machine_2,
            ipaddress_2.ipaddress.ipaddress)
        self.CheckIngressEgressConnectivityofVM(
            virtual_machine_3,
            ipaddress_3.ipaddress.ipaddress)
        """self.CheckIngressEgressConnectivityofVM(virtual_machine_4,
        ipaddress_3.ipaddress.ipaddress)"""
        return
