diff --git a/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/nicira/NiciraRestClient.java b/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/nicira/NiciraRestClient.java
index 6ade3a53777..de58a42607f 100644
--- a/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/nicira/NiciraRestClient.java
+++ b/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/nicira/NiciraRestClient.java
@@ -90,7 +90,7 @@ public class NiciraRestClient extends BasicRestClient {
if (HttpStatusCodeHelper.isUnauthorized(statusCode)) {
return handleUnauthorizedResponse(request, previousStatusCode, response, statusCode);
} else if (HttpStatusCodeHelper.isSuccess(statusCode)) {
- return handleSuccessResponse(response);
+ return handleSuccessResponse(request, response);
} else {
throw new CloudstackRESTException("Unexpecetd status code: " + statusCode);
}
@@ -110,8 +110,10 @@ public class NiciraRestClient extends BasicRestClient {
return execute(request, loginStatusCode);
}
- private CloseableHttpResponse handleSuccessResponse(final CloseableHttpResponse response) {
- counter.resetExecutionCounter();
+ private CloseableHttpResponse handleSuccessResponse(final HttpUriRequest request, final CloseableHttpResponse response) {
+ if (!request.getURI().getPath().contains(loginUrl)) {
+ counter.resetExecutionCounter();
+ }
return response;
}
diff --git a/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/NiciraRestClientTest.java b/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/NiciraRestClientTest.java
index 7fcab8001bb..3c5160cf958 100644
--- a/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/NiciraRestClientTest.java
+++ b/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/NiciraRestClientTest.java
@@ -20,6 +20,7 @@
package com.cloud.network.nicira;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.isEmptyOrNullString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
@@ -169,4 +170,45 @@ public class NiciraRestClientTest {
verifyPrivate(client).invoke("execute", HttpRequestMatcher.eq(loginRequest), eq(401));
}
}
+
+ @Test
+ public void testExecuteLiveLockWhenControllerAllowsLoginAndFollowsWithUnauthorizedButDoesNotRediect() throws Exception {
+ when(mockResponse.getStatusLine())
+ .thenReturn(HTTP_401_STATUSLINE)
+ .thenReturn(HTTP_200_STATUSLINE)
+ .thenReturn(HTTP_401_STATUSLINE)
+ .thenReturn(HTTP_200_STATUSLINE)
+ .thenReturn(HTTP_401_STATUSLINE)
+ .thenReturn(HTTP_200_STATUSLINE)
+ .thenReturn(HTTP_401_STATUSLINE)
+ .thenReturn(HTTP_200_STATUSLINE)
+ .thenReturn(HTTP_401_STATUSLINE);
+ when(httpClient.execute(eq(HTTP_HOST), HttpRequestMatcher.eq(request), eq(httpClientContext)))
+ .thenReturn(mockResponse)
+ .thenReturn(mockResponse)
+ .thenReturn(mockResponse)
+ .thenReturn(mockResponse)
+ .thenReturn(mockResponse);
+ when(httpClient.execute(eq(HTTP_HOST), HttpRequestMatcher.eq(loginRequest), eq(httpClientContext)))
+ .thenReturn(mockResponse)
+ .thenReturn(mockResponse)
+ .thenReturn(mockResponse)
+ .thenReturn(mockResponse);
+ final NiciraRestClient client = spy(NiciraRestClient.create()
+ .client(httpClient)
+ .clientContext(httpClientContext)
+ .hostname(LOCALHOST)
+ .username(ADMIN)
+ .password(ADMIN_PASSWORD)
+ .loginUrl(LOGIN_PATH)
+ .executionLimit(2)
+ .build());
+
+ try {
+ client.execute(request);
+ fail("Execution count should have been maxed out");
+ } catch (final CloudstackRESTException e) {
+ assertThat(e.getMessage(), containsString("Reached max executions limit of "));
+ }
+ }
}
diff --git a/pom.xml b/pom.xml
index 9ff47e26cef..d25274f29a2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -606,6 +606,7 @@
.checkstyle
.project
.classpath
+ .pmd*
diff --git a/test/integration/smoke/test_nicira_controller.py b/test/integration/plugins/test_nicira_controller.py
similarity index 66%
rename from test/integration/smoke/test_nicira_controller.py
rename to test/integration/plugins/test_nicira_controller.py
index 229612d451d..6c625b6297b 100644
--- a/test/integration/smoke/test_nicira_controller.py
+++ b/test/integration/plugins/test_nicira_controller.py
@@ -24,13 +24,23 @@ from marvin.lib.base import (
NetworkOffering,
NiciraNvp,
ServiceOffering,
+ NATRule,
+ PublicIPAddress,
Network,
VirtualMachine
)
-from marvin.lib.common import (get_domain, get_zone, get_template)
+from marvin.lib.common import (
+ get_domain,
+ get_zone,
+ get_template,
+ list_routers,
+ list_hosts,
+ findSuitableHostForMigration
+)
from nose.plugins.attrib import attr
from marvin.codes import (FAILED, PASS)
import time
+import logging
class TestNiciraContoller(cloudstackTestCase):
@@ -51,11 +61,13 @@ class TestNiciraContoller(cloudstackTestCase):
'name': 'NiciraEnabledNetwork',
'displaytext': 'NiciraEnabledNetwork',
'guestiptype': 'Isolated',
- 'supportedservices': 'SourceNat,Firewall,PortForwarding,Connectivity',
+ 'supportedservices': 'SourceNat,Dhcp,Dns,Firewall,PortForwarding,Connectivity',
'traffictype': 'GUEST',
'availability': 'Optional',
'serviceProviderList': {
'SourceNat': 'VirtualRouter',
+ 'Dhcp': 'VirtualRouter',
+ 'Dns': 'VirtualRouter',
'Firewall': 'VirtualRouter',
'PortForwarding': 'VirtualRouter',
'Connectivity': 'NiciraNvp'
@@ -128,6 +140,11 @@ class TestNiciraContoller(cloudstackTestCase):
cls.service_offering
]
+ cls.logger = logging.getLogger('TestNiciraContoller')
+ cls.stream_handler = logging.StreamHandler()
+ cls.logger.setLevel(logging.DEBUG)
+ cls.logger.addHandler(cls.stream_handler)
+
@classmethod
def tearDownClass(cls):
@@ -170,7 +187,7 @@ class TestNiciraContoller(cloudstackTestCase):
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)
+ self.logger.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),
@@ -201,18 +218,20 @@ class TestNiciraContoller(cloudstackTestCase):
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):
+
+ def add_nicira_device(self, hostname):
nicira_device = NiciraNvp.add(
self.api_client,
None,
self.physical_network_id,
- hostname=self.nicira_master_controller,
+ hostname=hostname,
username=self.nicira_credentials['username'],
password=self.nicira_credentials['password'],
transportzoneuuid=self.transport_zone_uuid)
self.test_cleanup.append(nicira_device)
+
+ def create_guest_network(self):
network_services = {
'name' : 'nicira_enabled_network',
'displaytext' : 'nicira_enabled_network',
@@ -226,7 +245,10 @@ class TestNiciraContoller(cloudstackTestCase):
domainid=self.domain.id,
)
self.test_cleanup.append(network)
+ return network
+
+ def create_virtual_machine(self, network):
virtual_machine = VirtualMachine.create(
self.api_client,
self.vm_services['small'],
@@ -237,9 +259,88 @@ class TestNiciraContoller(cloudstackTestCase):
mode=self.vm_services['mode']
)
self.test_cleanup.append(virtual_machine)
+ return virtual_machine
+
+
+ def get_routers_for_network(self, network):
+ return list_routers(
+ self.api_client,
+ account='admin',
+ domainid=self.domain.id,
+ networkid=network.id
+ )
+
+
+ def get_hosts(self):
+ return list_hosts(
+ self.api_client,
+ account='admin',
+ domainid=self.domain.id
+ )
+
+
+ def get_master_router(self, routers):
+ master = filter(lambda r: r.redundantstate == 'MASTER', routers)
+ self.logger.debug("Found %s master router(s): %s" % (master.size(), master))
+ return master[0]
+
+
+ def distribute_vm_and_routers_by_hosts(self, virtual_machine, routers):
+ if len(routers) > 1:
+ router = self.get_router(routers)
+ self.logger.debug("Master Router VM is %s" % router)
+ else:
+ router = routers[0]
+
+ if router.hostid == virtual_machine.hostid:
+ self.logger.debug("Master Router VM is on the same host as VM")
+ host = findSuitableHostForMigration(self.api_client, router.id)
+ if host is not None:
+ router.migrate(self.api_client, host)
+ self.logger.debug("Migrated Master Router VM to host %s" % host)
+ else:
+ self.fail('No suitable host to migrate Master Router VM to')
+ else:
+ self.logger.debug("Master Router VM is not on the same host as VM: %s, %s" % (router.hostid, virtual_machine.hostid))
+
+
+ def acquire_publicip(self, network):
+ self.logger.debug("Associating public IP for network: %s" % network.name)
+ public_ip = PublicIPAddress.create(
+ self.api_client,
+ accountid='admin',
+ zoneid=self.zone.id,
+ domainid=self.domain.id,
+ networkid=network.id
+ )
+ self.logger.debug("Associated %s with network %s" % (public_ip.ipaddress.ipaddress, network.id))
+ self.test_cleanup.append(public_ip)
+ return public_ip
+
+
+ def create_natrule(self, vm, public_ip, network):
+ self.logger.debug("Creating NAT rule in network for vm with public IP")
+ nat_rule = NATRule.create(
+ self.api_client,
+ vm,
+ self.vm_services['small'],
+ ipaddressid=public_ip.ipaddress.id,
+ openfirewall=True,
+ networkid=network.id
+ )
+ self.test_cleanup.append(nat_rule)
+ return nat_rule
+
+
+ @attr(tags = ["advanced", "smoke", "nicira"], required_hardware="true")
+ def test_01_nicira_controller(self):
+ self.add_nicira_device(self.nicira_master_controller)
+
+ network = self.create_guest_network()
+ virtual_machine = self.create_virtual_machine(network)
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.logger.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')
@@ -248,6 +349,7 @@ class TestNiciraContoller(cloudstackTestCase):
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):
"""
@@ -261,45 +363,15 @@ class TestNiciraContoller(cloudstackTestCase):
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)
+ self.logger.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)
+ self.add_nicira_device(nicira_slave)
- 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)
+ network = self.create_guest_network()
+ virtual_machine = self.create_virtual_machine(network)
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.logger.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')
@@ -308,3 +380,38 @@ class TestNiciraContoller(cloudstackTestCase):
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_03_nicira_tunnel_guest_network(self):
+ self.add_nicira_device(self.nicira_master_controller)
+ network = self.create_guest_network()
+ virtual_machine = self.create_virtual_machine(network)
+ public_ip = self.acquire_publicip(network)
+ nat_rule = self.create_natrule(virtual_machine, public_ip, network)
+
+ list_vm_response = VirtualMachine.list(self.api_client, id=virtual_machine.id)
+ self.logger.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')
+
+ routers = self.get_routers_for_network(network)
+
+ self.distribute_vm_and_routers_by_hosts(virtual_machine, routers)
+
+ ssh_command = 'ping -c 3 google.com'
+ result = 'failed'
+ try:
+ self.logger.debug("SSH into VM: %s" % public_ip.ipaddress.ipaddress)
+ ssh = virtual_machine.get_ssh_client(ipaddress=public_ip.ipaddress.ipaddress)
+ self.logger.debug('Ping to google.com from VM')
+ result = str(ssh.execute(ssh_command))
+ self.logger.debug("SSH result: %s; COUNT is ==> %s" % (result, result.count("3 packets received")))
+ except Exception as e:
+ self.fail("SSH Access failed for %s: %s" % (vmObj.get_ip(), e))
+
+ self.assertEqual(result.count('3 packets received'), 1, 'Ping to outside world from VM should be successful')