text: # 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.
  
  """ Component tests VM life cycle in VPC network functionality
  """
  #Import Local Modules
  import marvin
  from nose.plugins.attrib import attr
  from marvin.cloudstackTestCase import *
  from marvin.cloudstackAPI import *
  from marvin.integration.lib.utils import *
  from marvin.integration.lib.base import *
  from marvin.integration.lib.common import *
  from marvin.sshClient import SshClient
  import datetime
  
  
  class Services:
      """Test VM life cycle in VPC network services
      """
  
      def __init__(self):
          self.services = {
                           "account": {
                                      "email": "test@test.com",
                                      "firstname": "Test",
                                      "lastname": "User",
                                      "username": "test",
                                      # Random characters are appended for unique
                                      # username
                                      "password": "password",
                                      },
                           "service_offering": {
                                      "name": "Tiny Instance",
                                      "displaytext": "Tiny Instance",
                                      "cpunumber": 1,
                                      "cpuspeed": 100,
                                      "memory": 64,
                                      },
                          "service_offering_1": {
                                      "name": "Tiny Instance- tagged host 1",
                                      "displaytext": "Tiny off-tagged host2",
                                      "cpunumber": 1,
                                      "cpuspeed": 100,
                                      "memory": 64,
                                      "tags": "HOST_TAGS_HERE"
                                      },
                           "service_offering_2": {
                                      "name": "Tiny Instance- tagged host 2",
                                      "displaytext": "Tiny off-tagged host2",
                                      "cpunumber": 1,
                                      "cpuspeed": 100,
                                      "memory": 64,
                                      "tags": "HOST_TAGS_HERE"
                                      },
                           "network_offering": {
                                      "name": 'VPC Network offering',
                                      "displaytext": 'VPC Network off',
                                      "guestiptype": 'Isolated',
                                      "supportedservices": 'Dhcp,Dns,SourceNat,PortForwarding,Lb,UserData,StaticNat,NetworkACL',
                                      "traffictype": 'GUEST',
                                      "availability": 'Optional',
                                      "useVpc": 'on',
                                      "serviceProviderList": {
                                              "Dhcp": 'VpcVirtualRouter',
                                              "Dns": 'VpcVirtualRouter',
                                              "SourceNat": 'VpcVirtualRouter',
                                              "PortForwarding": 'VpcVirtualRouter',
                                              "Lb": 'VpcVirtualRouter',
                                              "UserData": 'VpcVirtualRouter',
                                              "StaticNat": 'VpcVirtualRouter',
                                              "NetworkACL": 'VpcVirtualRouter'
                                          },
                                  },
                           "network_offering_no_lb": {
                                      "name": 'VPC Network offering',
                                      "displaytext": 'VPC Network off',
                                      "guestiptype": 'Isolated',
                                      "supportedservices": 'Dhcp,Dns,SourceNat,PortForwarding,UserData,StaticNat,NetworkACL',
                                      "traffictype": 'GUEST',
                                      "availability": 'Optional',
                                      "useVpc": 'on',
                                      "serviceProviderList": {
                                              "Dhcp": 'VpcVirtualRouter',
                                              "Dns": 'VpcVirtualRouter',
                                              "SourceNat": 'VpcVirtualRouter',
                                              "PortForwarding": 'VpcVirtualRouter',
                                              "UserData": 'VpcVirtualRouter',
                                              "StaticNat": 'VpcVirtualRouter',
                                              "NetworkACL": 'VpcVirtualRouter'
                                          },
                                  },
                           "network_off_shared": {
                                      "name": 'Shared Network offering',
                                      "displaytext": 'Shared Network offering',
                                      "guestiptype": 'Shared',
                                      "traffictype": 'GUEST',
                                      "availability": 'Optional',
                                      "useVpc": 'on',
                                      "specifyIpRanges": True,
                                      "specifyVlan": True
                                      },
                           "vpc_offering": {
                                      "name": 'VPC off',
                                      "displaytext": 'VPC off',
                                      "supportedservices": 'Dhcp,Dns,SourceNat,PortForwarding,Lb,UserData,StaticNat',
                                  },
                           "vpc": {
                                   "name": "TestVPC",
                                   "displaytext": "TestVPC",
                                   "cidr": '10.0.0.1/24'
                                   },
                           "network": {
                                    "name": "Test Network",
                                    "displaytext": "Test Network",
                                    "netmask": '255.255.255.0',
                                    "limit": 5,
                                    # Max networks allowed as per hypervisor
                                    # Xenserver -> 5, VMWare -> 9
                                  },
                           "lbrule": {
                                      "name": "SSH",
                                      "alg": "leastconn",
                                      # Algorithm used for load balancing
                                      "privateport": 22,
                                      "publicport": 2222,
                                      "openfirewall": False,
                                      "startport": 2222,
                                      "endport": 2222,
                                      "protocol": "TCP",
                                      "cidrlist": '0.0.0.0/0',
                                  },
                           "natrule": {
                                      "privateport": 22,
                                      "publicport": 22,
                                      "startport": 22,
                                      "endport": 22,
                                      "protocol": "TCP",
                                      "cidrlist": '0.0.0.0/0',
                                  },
                           "fw_rule": {
                                      "startport": 1,
                                      "endport": 6000,
                                      "cidr": '0.0.0.0/0',
                                      # Any network (For creating FW rule)
                                      "protocol": "TCP"
                                  },
                           "http_rule": {
                                      "startport": 80,
                                      "endport": 80,
                                      "cidrlist": '0.0.0.0/0',
                                      "protocol": "ICMP"
                                  },
                           "virtual_machine": {
                                      "displayname": "Test VM",
                                      "username": "root",
                                      "password": "password",
                                      "ssh_port": 22,
                                      "hypervisor": 'XenServer',
                                      # Hypervisor type should be same as
                                      # hypervisor type of cluster
                                      "privateport": 22,
                                      "publicport": 22,
                                      "protocol": 'TCP',
                                      "userdata": 'This is sample data',
                                  },
                           "ostype": 'CentOS 5.3 (64-bit)',
                           # Cent OS 5.3 (64 bit)
                           "sleep": 60,
                           "timeout": 10,
                           "mode": 'advanced'
                      }
  
  
  class TestVMLifeCycleHostmaintenance(cloudstackTestCase):
  
      @classmethod
      def setUpClass(cls):
          cls.api_client = super(
                                 TestVMLifeCycleHostmaintenance,
                                 cls
                                 ).getClsTestClient().getApiClient()
          cls.services = Services().services
          # Get Zone, Domain and templates
          cls.domain = get_domain(cls.api_client, cls.services)
          cls.zone = get_zone(cls.api_client, cls.services)
          cls.template = get_template(
                              cls.api_client,
                              cls.zone.id,
                              cls.services["ostype"]
                              )
          cls.services["virtual_machine"]["zoneid"] = cls.zone.id
          cls.services["virtual_machine"]["template"] = cls.template.id
  
          cls.service_offering_1 = ServiceOffering.create(
                                              cls.api_client,
                                              cls.services["service_offering_1"]
                                              )
          cls.service_offering_2 = ServiceOffering.create(
                                              cls.api_client,
                                              cls.services["service_offering_2"]
                                              )
          cls.vpc_off = VpcOffering.create(
                                       cls.api_client,
                                       cls.services["vpc_offering"]
                                       )
          cls.vpc_off.update(cls.api_client, state='Enabled')
  
          cls.account = Account.create(
                                       cls.api_client,
                                       cls.services["account"],
                                       admin=True,
                                       domainid=cls.domain.id
                                       )
  
          cls.vpc_off = VpcOffering.create(
                                       cls.api_client,
                                       cls.services["vpc_offering"]
                                       )
  
          cls.vpc_off.update(cls.api_client, state='Enabled')
  
          cls.services["vpc"]["cidr"] = '10.1.1.1/16'
          cls.vpc = VPC.create(
                           cls.api_client,
                           cls.services["vpc"],
                           vpcofferingid=cls.vpc_off.id,
                           zoneid=cls.zone.id,
                           account=cls.account.name,
                           domainid=cls.account.domainid
                           )
  
          cls.nw_off = NetworkOffering.create(
                                              cls.api_client,
                                              cls.services["network_offering"],
                                              conservemode=False
                                              )
          # Enable Network offering
          cls.nw_off.update(cls.api_client, state='Enabled')
  
          # Creating network using the network offering created
          cls.network_1 = Network.create(
                                  cls.api_client,
                                  cls.services["network"],
                                  accountid=cls.account.name,
                                  domainid=cls.account.domainid,
                                  networkofferingid=cls.nw_off.id,
                                  zoneid=cls.zone.id,
                                  gateway='10.1.1.1',
                                  vpcid=cls.vpc.id
                                  )
          cls.nw_off_no_lb = NetworkOffering.create(
                                      cls.api_client,
                                      cls.services["network_offering_no_lb"],
                                      conservemode=False
                                      )
          # Enable Network offering
          cls.nw_off_no_lb.update(cls.api_client, state='Enabled')
  
          # Creating network using the network offering created
          cls.network_2 = Network.create(
                                  cls.api_client,
                                  cls.services["network"],
                                  accountid=cls.account.name,
                                  domainid=cls.account.domainid,
                                  networkofferingid=cls.nw_off_no_lb.id,
                                  zoneid=cls.zone.id,
                                  gateway='10.1.2.1',
                                  vpcid=cls.vpc.id
                                  )
          # Spawn an instance in that network
          cls.vm_1 = VirtualMachine.create(
                                    cls.api_client,
                                    cls.services["virtual_machine"],
                                    accountid=cls.account.name,
                                    domainid=cls.account.domainid,
                                    serviceofferingid=cls.service_offering_1.id,
                                    networkids=[str(cls.network_1.id)]
                                    )
          # Spawn an instance in that network
          cls.vm_2 = VirtualMachine.create(
                                    cls.api_client,
                                    cls.services["virtual_machine"],
                                    accountid=cls.account.name,
                                    domainid=cls.account.domainid,
                                    serviceofferingid=cls.service_offering_1.id,
                                    networkids=[str(cls.network_1.id)]
                                    )
          cls.vm_3 = VirtualMachine.create(
                                    cls.api_client,
                                    cls.services["virtual_machine"],
                                    accountid=cls.account.name,
                                    domainid=cls.account.domainid,
                                    serviceofferingid=cls.service_offering_2.id,
                                    networkids=[str(cls.network_2.id)]
                                    )
          routers = Router.list(
                                cls.api_client,
                                account=cls.account.name,
                                domainid=cls.account.domainid,
                                listall=True
                                )
          if isinstance(routers, list):
              cls.vpcvr = routers[0]
  
          cls._cleanup = [
                          cls.service_offering_1,
                          cls.service_offering_2,
                          cls.nw_off,
                          cls.nw_off_no_lb,
                          ]
          return
  
      @classmethod
      def tearDownClass(cls):
          try:
              cls.account.delete(cls.api_client)
              wait_for_cleanup(cls.api_client, ["account.cleanup.interval"])
              #Cleanup resources used
              cleanup_resources(cls.api_client, cls._cleanup)
              cls.vpc_off.delete(cls.api_client)
          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.debug("Check the status of VPC virtual router")
          routers = Router.list(
                                self.apiclient,
                                networkid=self.network_1.id,
                                listall=True
                                )
          if not isinstance(routers, list):
              raise Exception("No response from list routers API")
  
          self.router = routers[0]
          if self.router.state == "Running":
              Router.stop(self.apiclient, id=self.router.id)
  
          self.cleanup = []
          return
  
      def tearDown(self):
          try:
              #Clean up, terminate the created network offerings
              cleanup_resources(self.apiclient, self.cleanup)
          except Exception as e:
              raise Exception("Warning: Exception during cleanup : %s" % e)
          return
  
      def validate_vm_deployment(self):
          """Validates VM deployment on different hosts"""
  
          vms = VirtualMachine.list(
                                    self.apiclient,
                                    account=self.account.name,
                                    domainid=self.account.domainid,
                                    networkid=self.network_1.id,
                                    listall=True
                                    )
          self.assertEqual(
                           isinstance(vms, list),
                           True,
                           "List VMs shall return a valid response"
                           )
          host_1 = vms[0].hostid
          self.debug("Host for network 1: %s" % vms[0].hostid)
  
          vms = VirtualMachine.list(
                                    self.apiclient,
                                    account=self.account.name,
                                    domainid=self.account.domainid,
                                    networkid=self.network_2.id,
                                    listall=True
                                    )
          self.assertEqual(
                           isinstance(vms, list),
                           True,
                           "List VMs shall return a valid response"
                           )
          host_2 = vms[0].hostid
          self.debug("Host for network 2: %s" % vms[0].hostid)
  
          self.assertNotEqual(
                  host_1,
                  host_2,
                  "Both the virtual machines should be deployed on diff hosts "
                  )
          return
  
      @attr(tags=["advanced", "intervlan"])
      def test_01_enable_maintenance_with_vpc_nw(self):
          """ Test enable Maintenance Mode on Hosts which have VPC elements
          """
  
          # Validate the following
          # 1. Create a VPC with cidr - 10.1.1.1/16
          # 2. Add network1(10.1.1.1/24) and network2(10.1.2.1/24) to this VPC.
          # 3. Deploy vm1 and vm2 in network1 and vm3 and vm4 in network2. Make
          #    sure vm1 and vm3 are deployed on one host in the cluster while
          #    vm2 and vm4 are deployed on the other host in the cluster. This
          #    can be done using host's tags & service offerings with host tags
          # Steps:
          # 1.Enable Maintenance on one of host on which VPCVR is present
          # Validations:
          # 1. Successfully push the host into maintenance mode.
          # 2. VMs present on the above host should successfully migrate to the
          #    other host present in the cluster
  
          self.validate_vm_deployment()
          self.debug("Stop the host on which the VPC virtual router is running")
          try:
              Host.enableMaintenance(self.apiclient, id=self.vpcvr.hostid)
          except Exception as e:
              self.fail("Failed to enable maintenance mode on host: %s" % e)
  
          self.debug(
              "Check if all instances belonging to the account are up again?")
          routers = Router.list(
                                self.apiclient,
                                account=self.account.name,
                                domainid=self.account.domainid,
                                listall=True
                                )
          self.assertEqual(
                           isinstance(routers, list),
                           True,
                           "List routers shall return a valid VPCVR for account"
                           )
          for router in routers:
              self.assertEqual(
                               router.state,
                               "Running",
                               "Router state should be running after migration"
                               )
          vms = VirtualMachine.list(
                                    self.apiclient,
                                    account=self.account.name,
                                    domainid=self.account.domainid,
                                    listall=True
                                    )
          self.assertEqual(
                      isinstance(vms, list),
                      True,
                      "VM response should return instances running for account"
                      )
          for vm in vms:
              self.assertEqual(
                               vm.state,
                               "Ruuning",
                               "Vm state should be running after migration"
                               )
          return
  
      @attr(tags=["advanced", "intervlan"])
      def test_02_cancel_maintenance(self):
          """ Test cancel Maintenance Mode on the above Hosts + Migrate VMs Back
          """
  
          # Steps
          # 1. Cancel Maintenance Mode on the host.
          # 2. Migrate the VMs back onto the host on which Maintenance mode is
          #    cancelled.
          # Validate the following
          # 1. Successfully cancel the Maintenance mode on the host.
          # 2. Migrate the VMs back successfully onto the host.
          # 3. Check that the network connectivity exists with the migrated VMs.
  
          self.debug("Cancel host maintenence on which the VPCVR is running")
          try:
              Host.cancelMaintenance(self.apiclient, id=self.vpcvr.hostid)
          except Exception as e:
              self.fail("Failed to enable maintenance mode on host: %s" % e)
  
          self.debug(
              "Migrating the instances back to the host: %s" %
                                                          self.vpcvr.hostid)
          try:
              cmd = migrateSystemVm.migrateSystemVmCmd()
              cmd.hostid = self.vpcvr.hostid
              cmd.virtualmachineid = self.vpcvr.id
              self.apiclient.migrateSystemVm(cmd)
          except Exception as e:
              self.fail("Failed to migrate VPCVR back: %s" % e)
  
          self.debug("Check the status of router after migration")
          routers = Router.list(
                                self.apiclient,
                                id=self.vpcvr.id,
                                listall=True
                                )
          self.assertEqual(
                           isinstance(routers, list),
                           True,
                           "List routers shall return the valid response"
                           )
          self.assertEqual(
                           routers[0].state,
                           "Running",
                           "Router state should be running"
                           )
          #  TODO: Check for the network connectivity
          return
  
      @attr(tags=["advanced", "intervlan"])
      def test_03_reconnect_host(self):
          """ Test reconnect Host which has VPC elements
          """
  
          # Steps:
          # 1.Reconnect one of the host on which VPC Virtual Router is present.
          # Validate the following
          # 1. Host should successfully reconnect.
          # 2. Network connectivity to all the VMs on the host should not be
          #    effected due to reconnection.
  
          self.debug("Reconnecting the host where VPC VR is running")
          try:
              Host.reconnect(self.apiclient, id=self.vpcvr.hostid)
          except Exception as e:
              self.fail("Failed to reconnect to host: %s" % e)
  
          self.debug("Check the status of router after migration")
          routers = Router.list(
                                self.apiclient,
                                id=self.vpcvr.id,
                                listall=True
                                )
          self.assertEqual(
                           isinstance(routers, list),
                           True,
                           "List routers shall return the valid response"
                           )
          self.assertEqual(
                           routers[0].state,
                           "Running",
                           "Router state should be running"
                           )
          #  TODO: Check for the network connectivity
          return