Add Marvin test for Nicira NVP plugin

Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/98dd7717
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/98dd7717
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/98dd7717

Branch: refs/heads/deploy-from-snapshot
Commit: 98dd7717026d3da6c034140fbadb06eb88eaf41d
Parents: abb824e
Author: Miguel Ferreira <miguelferre...@me.com>
Authored: Fri Aug 21 17:39:02 2015 +0200
Committer: Miguel Ferreira <miguelferre...@me.com>
Committed: Tue Aug 25 14:50:30 2015 +0200

----------------------------------------------------------------------
 .../integration/smoke/test_nicira_controller.py | 310 +++++++++++++++++++
 tools/marvin/marvin/cloudstackTestCase.py       |   4 +
 tools/marvin/marvin/lib/base.py                 |  46 +++
 3 files changed, 360 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/98dd7717/test/integration/smoke/test_nicira_controller.py
----------------------------------------------------------------------
diff --git a/test/integration/smoke/test_nicira_controller.py 
b/test/integration/smoke/test_nicira_controller.py
new file mode 100644
index 0000000..229612d
--- /dev/null
+++ b/test/integration/smoke/test_nicira_controller.py
@@ -0,0 +1,310 @@
+#!/usr/bin/env python
+# 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.
+
+import requests
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.lib.utils import cleanup_resources
+from marvin.lib.base import (
+    PhysicalNetwork,
+    NetworkOffering,
+    NiciraNvp,
+    ServiceOffering,
+    Network,
+    VirtualMachine
+)
+from marvin.lib.common import (get_domain, get_zone, get_template)
+from nose.plugins.attrib import attr
+from marvin.codes import (FAILED, PASS)
+import time
+
+class TestNiciraContoller(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        test_case = super(TestNiciraContoller, cls)
+
+        test_client    = test_case.getClsTestClient()
+        cls.config     = test_case.getClsConfig()
+        cls.api_client = test_client.getApiClient()
+
+        cls.physical_networks = cls.config.zones[0].physical_networks
+        cls.nicira_hosts      = cls.config.niciraNvp.hosts
+
+        cls.physical_network_id = 
cls.get_nicira_enabled_physical_network_id(cls.physical_networks)
+
+        cls.network_offerring_services = {
+            'name':              'NiciraEnabledNetwork',
+            'displaytext':       'NiciraEnabledNetwork',
+            'guestiptype':       'Isolated',
+            'supportedservices': 
'SourceNat,Firewall,PortForwarding,Connectivity',
+            'traffictype':       'GUEST',
+            'availability':      'Optional',
+            'serviceProviderList': {
+                    'SourceNat':      'VirtualRouter',
+                    'Firewall':       'VirtualRouter',
+                    'PortForwarding': 'VirtualRouter',
+                    'Connectivity':   'NiciraNvp'
+            }
+        }
+
+        cls.network_offering = NetworkOffering.create(cls.api_client, 
cls.network_offerring_services)
+        cls.network_offering.update(cls.api_client, state='Enabled')
+
+        cls.nicira_credentials = {
+            'username': 'admin',
+            'password': 'admin'
+        }
+
+        cls.nicira_master_controller = cls.determine_master_controller(
+            cls.nicira_hosts,
+            cls.nicira_credentials
+        )
+
+        cls.transport_zone_uuid = cls.get_transport_zone_from_controller(
+            cls.nicira_master_controller,
+            cls.nicira_credentials
+        )
+
+        cls.domain = get_domain(cls.api_client)
+        cls.zone   = get_zone(cls.api_client, test_client.getZoneForTests())
+
+        template = get_template(
+            cls.api_client,
+            cls.zone.id
+        )
+        if template == FAILED:
+            raise Exception("get_template() failed to return template with 
description %s" % cls.services['ostype'])
+
+        cls.vm_services = {
+            'mode': cls.zone.networktype,
+            'small': {
+                'zoneid':      cls.zone.id,
+                'template':    template.id,
+                'displayname': 'testserver',
+                'username':    
cls.config.zones[0].pods[0].clusters[0].hosts[0].username,
+                'password':    
cls.config.zones[0].pods[0].clusters[0].hosts[0].password,
+                'ssh_port':    22,
+                'hypervisor':  
cls.config.zones[0].pods[0].clusters[0].hypervisor,
+                'privateport': 22,
+                'publicport':  22,
+                'protocol':    'TCP',
+            },
+            'service_offerings': {
+                'tiny': {
+                    'name':        'Tiny Instance',
+                    'displaytext': 'Tiny Instance',
+                    'cpunumber':   1,
+                    'cpuspeed':    100,
+                    'memory':      64,
+                }
+            }
+        }
+
+        if cls.zone.localstorageenabled == True:
+            cls.vm_services['service_offerings']['tiny']['storagetype'] = 
'local'
+
+        cls.service_offering = ServiceOffering.create(
+            cls.api_client,
+            cls.vm_services['service_offerings']['tiny']
+        )
+
+        cls.cleanup = [
+            cls.network_offering,
+            cls.service_offering
+        ]
+
+
+    @classmethod
+    def tearDownClass(cls):
+        try:
+            cleanup_resources(cls.api_client, reversed(cls.cleanup))
+        except Exception as e:
+            raise Exception("Warning: Exception during class cleanup : %s" % e)
+
+    def setUp(self):
+        self.test_cleanup = []
+
+    def tearDown(self):
+        try:
+            cleanup_resources(self.api_client, reversed(self.test_cleanup))
+        except Exception as e:
+            raise Exception("Warning: Exception during test cleanup : %s" % e)
+
+
+    @classmethod
+    def determine_master_controller(cls, hosts, credentials):
+        for host in hosts:
+            r1 = requests.post("https://%s/ws.v1/login"; % host, credentials, 
verify=False)
+            r2 = requests.get("https://%s/ws.v1/control-cluster/status"; % 
host, verify=False, cookies=r1.cookies)
+            status_code = r2.status_code
+            if status_code == 401:
+                continue
+            elif status_code == 200:
+                return host
+        raise Exception("None of the supplied hosts (%s) is a Nicira 
controller" % hosts)
+
+
+    @classmethod
+    def get_transport_zone_from_controller(cls, controller_host, credentials):
+        r1 = requests.post("https://%s/ws.v1/login"; % controller_host, 
credentials, verify=False)
+        r2 = requests.get("https://%s/ws.v1/transport-zone"; % controller_host, 
verify=False, cookies=r1.cookies)
+        status_code = r2.status_code
+        if status_code == 200:
+            list_transport_zone_response = r2.json()
+            result_count = list_transport_zone_response['result_count']
+            if result_count == 0:
+                raise Exception('Nicira controller did not return any 
Transport Zones')
+            elif result_count > 1:
+                self.debug("Nicira controller returned %s Transport Zones, 
picking first one" % resultCount)
+            transport_zone_api_url = 
list_transport_zone_response['results'][0]['_href']
+            r3 = requests.get(
+                "https://%s%s"; % (controller_host, transport_zone_api_url),
+                verify=False,
+                cookies=r1.cookies
+            )
+            return r3.json()['uuid']
+        else:
+            raise Exception("Unexpected response from Nicira controller. 
Status code = %s, content = %s" % status_code)
+
+
+    @classmethod
+    def get_nicira_enabled_physical_network_id(cls, physical_networks):
+        nicira_physical_network_name = None
+        for physical_network in physical_networks:
+            for provider in physical_network.providers:
+                if provider.name == 'NiciraNvp':
+                    nicira_physical_network_name = physical_network.name
+        if nicira_physical_network_name is None:
+            raise Exception('Did not find a Nicira enabled physical network in 
configuration')
+        return PhysicalNetwork.list(cls.api_client, 
name=nicira_physical_network_name)[0].id
+
+
+    def determine_slave_conroller(self, hosts, master_controller):
+        slaves = [ s for s in hosts if s != master_controller ]
+        if len(slaves) > 0:
+            return slaves[0]
+        else:
+            raise Exception("None of the supplied hosts (%s) is a Nicira 
slave" % hosts)
+
+    @attr(tags = ["advanced", "smoke", "nicira"], required_hardware="true")
+    def test_01_nicira_controller(self):
+        nicira_device = NiciraNvp.add(
+            self.api_client,
+            None,
+            self.physical_network_id,
+            hostname=self.nicira_master_controller,
+            username=self.nicira_credentials['username'],
+            password=self.nicira_credentials['password'],
+            transportzoneuuid=self.transport_zone_uuid)
+        self.test_cleanup.append(nicira_device)
+
+        network_services = {
+            'name'            : 'nicira_enabled_network',
+            'displaytext'     : 'nicira_enabled_network',
+            'zoneid'          : self.zone.id,
+            'networkoffering' : self.network_offering.id
+        }
+        network = Network.create(
+            self.api_client,
+            network_services,
+            accountid='admin',
+            domainid=self.domain.id,
+        )
+        self.test_cleanup.append(network)
+
+        virtual_machine = VirtualMachine.create(
+            self.api_client,
+            self.vm_services['small'],
+            accountid='admin',
+            domainid=self.domain.id,
+            serviceofferingid=self.service_offering.id,
+            networkids=[network.id],
+            mode=self.vm_services['mode']
+        )
+        self.test_cleanup.append(virtual_machine)
+
+        list_vm_response = VirtualMachine.list(self.api_client, 
id=virtual_machine.id)
+        self.debug("Verify listVirtualMachines response for virtual machine: 
%s" % virtual_machine.id)
+
+        self.assertEqual(isinstance(list_vm_response, list), True, 'Response 
did not return a valid list')
+        self.assertNotEqual(len(list_vm_response), 0, 'List of VMs is empty')
+
+        vm_response = list_vm_response[0]
+        self.assertEqual(vm_response.id, virtual_machine.id, 'Virtual machine 
in response does not match request')
+        self.assertEqual(vm_response.state, 'Running', 'VM is not in Running 
state')
+
+    @attr(tags = ["advanced", "smoke", "nicira"], required_hardware="true")
+    def test_02_nicira_controller_redirect(self):
+        """
+            Nicira clusters will redirect clients (in this case ACS) to the 
master node.
+            This test assumes that a Nicira cluster is present and configured 
properly, and
+            that it has at least two controller nodes. The test will check 
that ASC follows
+            redirects by:
+                - adding a Nicira Nvp device that points to one of the 
cluster's slave controllers,
+                - create a VM in a Nicira backed network
+            If all is well, no matter what controller is specified (slaves or 
master), the vm (and respective router VM)
+            should be created without issues.
+        """
+        nicira_slave = self.determine_slave_conroller(self.nicira_hosts, 
self.nicira_master_controller)
+        self.debug("Nicira slave controller is: %s " % nicira_slave)
+
+        nicira_device = NiciraNvp.add(
+            self.api_client,
+            None,
+            self.physical_network_id,
+            hostname=nicira_slave,
+            username=self.nicira_credentials['username'],
+            password=self.nicira_credentials['password'],
+            transportzoneuuid=self.transport_zone_uuid)
+        self.test_cleanup.append(nicira_device)
+
+        network_services = {
+            'name'            : 'nicira_enabled_network',
+            'displaytext'     : 'nicira_enabled_network',
+            'zoneid'          : self.zone.id,
+            'networkoffering' : self.network_offering.id
+        }
+        network = Network.create(
+            self.api_client,
+            network_services,
+            accountid='admin',
+            domainid=self.domain.id,
+        )
+        self.test_cleanup.append(network)
+
+        virtual_machine = VirtualMachine.create(
+            self.api_client,
+            self.vm_services['small'],
+            accountid='admin',
+            domainid=self.domain.id,
+            serviceofferingid=self.service_offering.id,
+            networkids=[network.id],
+            mode=self.vm_services['mode']
+        )
+        self.test_cleanup.append(virtual_machine)
+
+        list_vm_response = VirtualMachine.list(self.api_client, 
id=virtual_machine.id)
+        self.debug("Verify listVirtualMachines response for virtual machine: 
%s" % virtual_machine.id)
+
+        self.assertEqual(isinstance(list_vm_response, list), True, 'Response 
did not return a valid list')
+        self.assertNotEqual(len(list_vm_response), 0, 'List of VMs is empty')
+
+        vm_response = list_vm_response[0]
+        self.assertEqual(vm_response.id, virtual_machine.id, 'Virtual machine 
in response does not match request')
+        self.assertEqual(vm_response.state, 'Running', 'VM is not in Running 
state')
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/98dd7717/tools/marvin/marvin/cloudstackTestCase.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/cloudstackTestCase.py 
b/tools/marvin/marvin/cloudstackTestCase.py
index 5cb4a10..692e817 100644
--- a/tools/marvin/marvin/cloudstackTestCase.py
+++ b/tools/marvin/marvin/cloudstackTestCase.py
@@ -52,3 +52,7 @@ class cloudstackTestCase(unittest.case.TestCase):
     @classmethod
     def getClsTestClient(cls):
         return cls.clstestclient
+
+    @classmethod
+    def getClsConfig(cls):
+        return cls.config

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/98dd7717/tools/marvin/marvin/lib/base.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py
index aca7fd1..54922c8 100755
--- a/tools/marvin/marvin/lib/base.py
+++ b/tools/marvin/marvin/lib/base.py
@@ -3834,6 +3834,52 @@ class NetScaler:
             cmd.listall = True
         return(apiclient.listNetscalerLoadBalancers(cmd))
 
+class NiciraNvp:
+
+    def __init__(self, items):
+        self.__dict__.update(items)
+
+    @classmethod
+    def add(cls, apiclient, services, physicalnetworkid,
+            hostname=None, username=None, password=None, 
transportzoneuuid=None):
+        cmd = addNiciraNvpDevice.addNiciraNvpDeviceCmd()
+        cmd.physicalnetworkid = physicalnetworkid
+        if hostname:
+            cmd.hostname = hostname
+        else:
+            cmd.hostname = services['hostname']
+
+        if username:
+            cmd.username = username
+        else:
+            cmd.username = services['username']
+
+        if password:
+            cmd.password = password
+        else:
+            cmd.password = services['password']
+
+        if transportzoneuuid:
+            cmd.transportzoneuuid = transportzoneuuid
+        else:
+            cmd.transportzoneuuid = services['transportZoneUuid']
+
+        return NiciraNvp(apiclient.addNiciraNvpDevice(cmd).__dict__)
+
+    def delete(self, apiclient):
+        cmd = deleteNiciraNvpDevice.deleteNiciraNvpDeviceCmd()
+        cmd.nvpdeviceid = self.nvpdeviceid
+        apiclient.deleteNiciraNvpDevice(cmd)
+        return
+
+    @classmethod
+    def list(cls, apiclient, **kwargs):
+        cmd = listNiciraNvpDevices.listNiciraNvpDevicesCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        if 'account' in kwargs.keys() and 'domainid' in kwargs.keys():
+            cmd.listall = True
+        return(apiclient.listNiciraNvpDevices(cmd))
+
 
 class NetworkServiceProvider:
     """Manage network serivce providers for CloudStack"""

Reply via email to