mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	This is a new feature for CS that allows Admin users improved troubleshooting of network issues in CloudStack hosted networks. Description: For troubleshooting purposes, CloudStack administrators may wish to execute network utility commands remotely on system VMs, or request system VMs to ping/traceroute/arping to specific addresses over specific interfaces. An API command to provide such functionalities is being developed without altering any existing APIs. The targeted system VMs for this feature are the Virtual Router (VR), Secondary Storage VM (SSVM) and the Console Proxy VM (CPVM). FS: https://cwiki.apache.org/confluence/display/CLOUDSTACK/CloudStack+Remote+Diagnostics+API ML discussion: https://markmail.org/message/xt7owmb2c6iw7tva
		
			
				
	
	
		
			540 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			540 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			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.
 | |
| """ BVT tests for remote diagnostics of system VMs
 | |
| """
 | |
| # Import Local Modules
 | |
| from marvin.codes import FAILED
 | |
| from marvin.cloudstackTestCase import cloudstackTestCase
 | |
| from marvin.cloudstackAPI import runDiagnostics
 | |
| from marvin.lib.utils import (cleanup_resources)
 | |
| from marvin.lib.base import (Account,
 | |
|                              ServiceOffering,
 | |
|                              VirtualMachine)
 | |
| from marvin.lib.common import (get_domain,
 | |
|                                get_zone,
 | |
|                                get_test_template,
 | |
|                                list_ssvms,
 | |
|                                list_routers)
 | |
| 
 | |
| from nose.plugins.attrib import attr
 | |
| 
 | |
| 
 | |
| class TestRemoteDiagnostics(cloudstackTestCase):
 | |
|     """
 | |
|     Test remote diagnostics with system VMs and VR as root admin
 | |
|     """
 | |
| 
 | |
|     @classmethod
 | |
|     def setUpClass(cls):
 | |
| 
 | |
|         testClient = super(TestRemoteDiagnostics, cls).getClsTestClient()
 | |
|         cls.apiclient = testClient.getApiClient()
 | |
|         cls.services = testClient.getParsedTestDataConfig()
 | |
| 
 | |
|         # Get Zone, Domain and templates
 | |
|         cls.domain = get_domain(cls.apiclient)
 | |
|         cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
 | |
|         cls.hypervisor = testClient.getHypervisorInfo()
 | |
|         cls.services['mode'] = cls.zone.networktype
 | |
|         template = get_test_template(
 | |
|             cls.apiclient,
 | |
|             cls.zone.id,
 | |
|             cls.hypervisor
 | |
|         )
 | |
|         if template == FAILED:
 | |
|             cls.fail("get_test_template() failed to return template")
 | |
| 
 | |
|         cls.services["virtual_machine"]["zoneid"] = cls.zone.id
 | |
| 
 | |
|         # Create an account, network, VM and IP addresses
 | |
|         cls.account = Account.create(
 | |
|             cls.apiclient,
 | |
|             cls.services["account"],
 | |
|             domainid=cls.domain.id
 | |
|         )
 | |
|         cls.service_offering = ServiceOffering.create(
 | |
|             cls.apiclient,
 | |
|             cls.services["service_offerings"]["tiny"]
 | |
|         )
 | |
|         cls.vm_1 = VirtualMachine.create(
 | |
|             cls.apiclient,
 | |
|             cls.services["virtual_machine"],
 | |
|             templateid=template.id,
 | |
|             accountid=cls.account.name,
 | |
|             domainid=cls.account.domainid,
 | |
|             serviceofferingid=cls.service_offering.id
 | |
|         )
 | |
|         cls.cleanup = [
 | |
|             cls.account,
 | |
|             cls.service_offering
 | |
|         ]
 | |
| 
 | |
|     @classmethod
 | |
|     def tearDownClass(cls):
 | |
|         try:
 | |
|             cls.apiclient = super(
 | |
|                 TestRemoteDiagnostics,
 | |
|                 cls
 | |
|             ).getClsTestClient().getApiClient()
 | |
|             # Clean up, terminate the created templates
 | |
|             cleanup_resources(cls.apiclient, cls.cleanup)
 | |
| 
 | |
|         except Exception as e:
 | |
|             raise Exception("Warning: Exception during cleanup : %s" % e)
 | |
| 
 | |
|     def setUp(self):
 | |
|         self.apiclient = self.testClient.getApiClient()
 | |
|         self.hypervisor = self.testClient.getHypervisorInfo()
 | |
| 
 | |
|     @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
 | |
|     def test_01_ping_in_vr_success(self):
 | |
|         '''
 | |
|         Test Ping command execution in VR
 | |
|         '''
 | |
| 
 | |
|         # Validate the following:
 | |
|         # 1. Ping command is executed remotely on VR
 | |
| 
 | |
|         list_router_response = list_routers(
 | |
|             self.apiclient,
 | |
|             account=self.account.name,
 | |
|             domainid=self.account.domainid
 | |
|         )
 | |
|         self.assertEqual(
 | |
|             isinstance(list_router_response, list),
 | |
|             True,
 | |
|             "Check list response returns a valid list"
 | |
|         )
 | |
|         router = list_router_response[0]
 | |
|         self.debug('Starting the router with ID: %s' % router.id)
 | |
| 
 | |
|         cmd = runDiagnostics.runDiagnosticsCmd()
 | |
|         cmd.targetid = router.id
 | |
|         cmd.ipaddress = '8.8.8.8'
 | |
|         cmd.type = 'ping'
 | |
|         cmd_response = self.apiclient.runDiagnostics(cmd)
 | |
| 
 | |
|         self.assertEqual(
 | |
|             '0',
 | |
|             cmd_response.exitcode,
 | |
|             'Failed to run remote Ping in VR')
 | |
| 
 | |
|     @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
 | |
|     def test_02_ping_in_vr_failure(self):
 | |
|         '''
 | |
|         Test Ping command execution in VR
 | |
|         '''
 | |
| 
 | |
|         # Validate the following:
 | |
|         # 1. Ping command is executed remotely on VR
 | |
|         # 2. Validate Ping command execution with a non-existent/pingable IP address
 | |
| 
 | |
|         if self.hypervisor.lower() == 'simulator':
 | |
|             raise self.skipTest("Skipping negative test case for Simulator hypervisor")
 | |
| 
 | |
|         list_router_response = list_routers(
 | |
|             self.apiclient,
 | |
|             account=self.account.name,
 | |
|             domainid=self.account.domainid
 | |
|         )
 | |
|         self.assertEqual(
 | |
|             isinstance(list_router_response, list),
 | |
|             True,
 | |
|             "Check list response returns a valid list"
 | |
|         )
 | |
|         router = list_router_response[0]
 | |
|         self.debug('Starting the router with ID: %s' % router.id)
 | |
| 
 | |
|         cmd = runDiagnostics.runDiagnosticsCmd()
 | |
|         cmd.targetid = router.id
 | |
|         cmd.ipaddress = '192.0.2.2'
 | |
|         cmd.type = 'ping'
 | |
|         cmd_response = self.apiclient.runDiagnostics(cmd)
 | |
| 
 | |
|         self.assertNotEqual(
 | |
|             '0',
 | |
|             cmd_response.exitcode,
 | |
|             'Check diagnostics command returns a non-zero exit code')
 | |
| 
 | |
|     @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
 | |
|     def test_03_ping_in_ssvm_success(self):
 | |
|         '''
 | |
|         Test Ping command execution in SSVM
 | |
|         '''
 | |
| 
 | |
|         # Validate the following:
 | |
|         # 1. Ping command is executed remotely on SSVM
 | |
| 
 | |
|         list_ssvm_response = list_ssvms(
 | |
|             self.apiclient,
 | |
|             systemvmtype='secondarystoragevm',
 | |
|             state='Running',
 | |
|         )
 | |
| 
 | |
|         self.assertEqual(
 | |
|             isinstance(list_ssvm_response, list),
 | |
|             True,
 | |
|             'Check list response returns a valid list'
 | |
|         )
 | |
|         ssvm = list_ssvm_response[0]
 | |
| 
 | |
|         self.debug('Setting up SSVM with ID %s' % ssvm.id)
 | |
| 
 | |
|         cmd = runDiagnostics.runDiagnosticsCmd()
 | |
|         cmd.targetid = ssvm.id
 | |
|         cmd.ipaddress = '8.8.8.8'
 | |
|         cmd.type = 'ping'
 | |
|         cmd_response = self.apiclient.runDiagnostics(cmd)
 | |
| 
 | |
|         self.assertEqual(
 | |
|             '0',
 | |
|             cmd_response.exitcode,
 | |
|             'Failed to run remote Ping in SSVM'
 | |
|         )
 | |
| 
 | |
|     @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
 | |
|     def test_04_ping_in_ssvm_failure(self):
 | |
|         '''
 | |
|         Test Ping command execution in SSVM
 | |
|         '''
 | |
| 
 | |
|         # Validate the following:
 | |
|         # 1. Ping command is executed remotely on SSVM
 | |
|         # 2. Validate Ping command execution with a non-existent/pingable IP address
 | |
| 
 | |
|         if self.hypervisor.lower() == 'simulator':
 | |
|             raise self.skipTest("Skipping negative test case for Simulator hypervisor")
 | |
| 
 | |
|         list_ssvm_response = list_ssvms(
 | |
|             self.apiclient,
 | |
|             systemvmtype='secondarystoragevm',
 | |
|             state='Running',
 | |
|         )
 | |
| 
 | |
|         self.assertEqual(
 | |
|             isinstance(list_ssvm_response, list),
 | |
|             True,
 | |
|             'Check list response returns a valid list'
 | |
|         )
 | |
|         ssvm = list_ssvm_response[0]
 | |
| 
 | |
|         self.debug('Setting up SSVM with ID %s' % ssvm.id)
 | |
| 
 | |
|         cmd = runDiagnostics.runDiagnosticsCmd()
 | |
|         cmd.targetid = ssvm.id
 | |
|         cmd.ipaddress = '192.0.2.2'
 | |
|         cmd.type = 'ping'
 | |
|         cmd_response = self.apiclient.runDiagnostics(cmd)
 | |
| 
 | |
|         self.assertNotEqual(
 | |
|             '0',
 | |
|             cmd_response.exitcode,
 | |
|             'Failed to run remote Ping in SSVM'
 | |
|         )
 | |
| 
 | |
|     @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
 | |
|     def test_05_ping_in_cpvm_success(self):
 | |
|         '''
 | |
|         Test Ping command execution in CPVM
 | |
|         '''
 | |
| 
 | |
|         # Validate the following:
 | |
|         # 1. Ping command is executed remotely on CPVM
 | |
| 
 | |
|         list_ssvm_response = list_ssvms(
 | |
|             self.apiclient,
 | |
|             systemvmtype='consoleproxy',
 | |
|             state='Running',
 | |
|         )
 | |
| 
 | |
|         self.assertEqual(
 | |
|             isinstance(list_ssvm_response, list),
 | |
|             True,
 | |
|             'Check list response returns a valid list'
 | |
|         )
 | |
|         cpvm = list_ssvm_response[0]
 | |
| 
 | |
|         self.debug('Setting up CPVM with ID %s' % cpvm.id)
 | |
| 
 | |
|         cmd = runDiagnostics.runDiagnosticsCmd()
 | |
|         cmd.targetid = cpvm.id
 | |
|         cmd.ipaddress = '8.8.8.8'
 | |
|         cmd.type = 'ping'
 | |
|         cmd_response = self.apiclient.runDiagnostics(cmd)
 | |
| 
 | |
|         self.assertEqual(
 | |
|             '0',
 | |
|             cmd_response.exitcode,
 | |
|             'Failed to run remote Ping in CPVM'
 | |
|         )
 | |
| 
 | |
|     @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
 | |
|     def test_06_ping_in_cpvm_failure(self):
 | |
|         '''
 | |
|         Test Ping command execution in CPVM
 | |
|         '''
 | |
| 
 | |
|         # Validate the following:
 | |
|         # 1. Ping command is executed remotely on CPVM
 | |
|         # 2. Validate Ping command execution with a non-existent/pingable IP address
 | |
| 
 | |
|         if self.hypervisor.lower() == 'simulator':
 | |
|             raise self.skipTest("Skipping negative test case for Simulator hypervisor")
 | |
| 
 | |
|         list_ssvm_response = list_ssvms(
 | |
|             self.apiclient,
 | |
|             systemvmtype='consoleproxy',
 | |
|             state='Running',
 | |
|         )
 | |
| 
 | |
|         self.assertEqual(
 | |
|             isinstance(list_ssvm_response, list),
 | |
|             True,
 | |
|             'Check list response returns a valid list'
 | |
|         )
 | |
|         cpvm = list_ssvm_response[0]
 | |
| 
 | |
|         self.debug('Setting up CPVM with ID %s' % cpvm.id)
 | |
| 
 | |
|         cmd = runDiagnostics.runDiagnosticsCmd()
 | |
|         cmd.targetid = cpvm.id
 | |
|         cmd.ipaddress = '192.0.2.2'
 | |
|         cmd.type = 'ping'
 | |
|         cmd_response = self.apiclient.runDiagnostics(cmd)
 | |
| 
 | |
|         self.assertNotEqual(
 | |
|             '0',
 | |
|             cmd_response.exitcode,
 | |
|             'Check diagnostics command returns a non-zero exit code'
 | |
|         )
 | |
| 
 | |
|     @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
 | |
|     def test_07_arping_in_vr(self):
 | |
|         '''
 | |
|         Test Arping command execution in VR
 | |
|         '''
 | |
| 
 | |
|         # Validate the following:
 | |
|         # 1. Arping command is executed remotely on VR
 | |
| 
 | |
|         list_router_response = list_routers(
 | |
|             self.apiclient,
 | |
|             account=self.account.name,
 | |
|             domainid=self.account.domainid
 | |
|         )
 | |
|         self.assertEqual(
 | |
|             isinstance(list_router_response, list),
 | |
|             True,
 | |
|             "Check list response returns a valid list"
 | |
|         )
 | |
|         router = list_router_response[0]
 | |
|         self.debug('Starting the router with ID: %s' % router.id)
 | |
| 
 | |
|         cmd = runDiagnostics.runDiagnosticsCmd()
 | |
|         cmd.targetid = router.id
 | |
|         cmd.ipaddress = router.gateway
 | |
|         cmd.type = 'arping'
 | |
|         cmd.params = "-I eth2"
 | |
|         cmd_response = self.apiclient.runDiagnostics(cmd)
 | |
| 
 | |
|         self.assertEqual(
 | |
|             '0',
 | |
|             cmd_response.exitcode,
 | |
|             'Failed to run remote Arping in VR')
 | |
| 
 | |
|     @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
 | |
|     def test_08_arping_in_ssvm(self):
 | |
|         '''
 | |
|         Test Arping command execution in SSVM
 | |
|         '''
 | |
| 
 | |
|         # Validate the following:
 | |
|         # 1. Arping command is executed remotely on SSVM
 | |
| 
 | |
|         list_ssvm_response = list_ssvms(
 | |
|             self.apiclient,
 | |
|             systemvmtype='secondarystoragevm',
 | |
|             state='Running',
 | |
|         )
 | |
| 
 | |
|         self.assertEqual(
 | |
|             isinstance(list_ssvm_response, list),
 | |
|             True,
 | |
|             'Check list response returns a valid list'
 | |
|         )
 | |
|         ssvm = list_ssvm_response[0]
 | |
| 
 | |
|         self.debug('Setting up SSVM with ID %s' % ssvm.id)
 | |
| 
 | |
|         cmd = runDiagnostics.runDiagnosticsCmd()
 | |
|         cmd.targetid = ssvm.id
 | |
|         cmd.ipaddress = ssvm.gateway
 | |
|         cmd.type = 'arping'
 | |
|         cmd.params = '-I eth2'
 | |
|         cmd_response = self.apiclient.runDiagnostics(cmd)
 | |
| 
 | |
|         self.assertEqual(
 | |
|             '0',
 | |
|             cmd_response.exitcode,
 | |
|             'Failed to run remote Arping in SSVM'
 | |
|         )
 | |
| 
 | |
|     @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
 | |
|     def test_09_arping_in_cpvm(self):
 | |
|         '''
 | |
|         Test Arping command execution in CPVM
 | |
|         '''
 | |
| 
 | |
|         # Validate the following:
 | |
|         # 1. Arping command is executed remotely on CPVM
 | |
| 
 | |
|         list_cpvm_response = list_ssvms(
 | |
|             self.apiclient,
 | |
|             systemvmtype='secondarystoragevm',
 | |
|             state='Running',
 | |
|         )
 | |
| 
 | |
|         self.assertEqual(
 | |
|             isinstance(list_cpvm_response, list),
 | |
|             True,
 | |
|             'Check list response returns a valid list'
 | |
|         )
 | |
|         cpvm = list_cpvm_response[0]
 | |
| 
 | |
|         self.debug('Setting up CPVM with ID %s' % cpvm.id)
 | |
| 
 | |
|         cmd = runDiagnostics.runDiagnosticsCmd()
 | |
|         cmd.targetid = cpvm.id
 | |
|         cmd.ipaddress = cpvm.gateway
 | |
|         cmd.type = 'arping'
 | |
|         cmd.params = '-I eth2'
 | |
|         cmd_response = self.apiclient.runDiagnostics(cmd)
 | |
| 
 | |
|         self.assertEqual(
 | |
|             '0',
 | |
|             cmd_response.exitcode,
 | |
|             'Failed to run remote Arping in CPVM'
 | |
|         )
 | |
| 
 | |
|     @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
 | |
|     def test_10_traceroute_in_vr(self):
 | |
|         '''
 | |
|         Test Arping command execution in VR
 | |
|         '''
 | |
| 
 | |
|         # Validate the following:
 | |
|         # 1. Arping command is executed remotely on VR
 | |
| 
 | |
|         list_router_response = list_routers(
 | |
|             self.apiclient,
 | |
|             account=self.account.name,
 | |
|             domainid=self.account.domainid
 | |
|         )
 | |
|         self.assertEqual(
 | |
|             isinstance(list_router_response, list),
 | |
|             True,
 | |
|             "Check list response returns a valid list"
 | |
|         )
 | |
|         router = list_router_response[0]
 | |
|         self.debug('Starting the router with ID: %s' % router.id)
 | |
| 
 | |
|         cmd = runDiagnostics.runDiagnosticsCmd()
 | |
|         cmd.targetid = router.id
 | |
|         cmd.ipaddress = '8.8.4.4'
 | |
|         cmd.type = 'traceroute'
 | |
|         cmd.params = "-m 10"
 | |
|         cmd_response = self.apiclient.runDiagnostics(cmd)
 | |
| 
 | |
|         self.assertEqual(
 | |
|             '0',
 | |
|             cmd_response.exitcode,
 | |
|             'Failed to run remote Arping in VR')
 | |
| 
 | |
|     @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
 | |
|     def test_11_traceroute_in_ssvm(self):
 | |
|         '''
 | |
|         Test Traceroute command execution in SSVM
 | |
|         '''
 | |
| 
 | |
|         # Validate the following:
 | |
|         # 1. Traceroute command is executed remotely on SSVM
 | |
| 
 | |
|         list_ssvm_response = list_ssvms(
 | |
|             self.apiclient,
 | |
|             systemvmtype='secondarystoragevm',
 | |
|             state='Running',
 | |
|         )
 | |
| 
 | |
|         self.assertEqual(
 | |
|             isinstance(list_ssvm_response, list),
 | |
|             True,
 | |
|             'Check list response returns a valid list'
 | |
|         )
 | |
|         ssvm = list_ssvm_response[0]
 | |
| 
 | |
|         self.debug('Setting up SSVM with ID %s' % ssvm.id)
 | |
| 
 | |
|         cmd = runDiagnostics.runDiagnosticsCmd()
 | |
|         cmd.targetid = ssvm.id
 | |
|         cmd.ipaddress = '8.8.4.4'
 | |
|         cmd.type = 'traceroute'
 | |
|         cmd.params = '-m 10'
 | |
|         cmd_response = self.apiclient.runDiagnostics(cmd)
 | |
| 
 | |
|         self.assertEqual(
 | |
|             '0',
 | |
|             cmd_response.exitcode,
 | |
|             'Failed to run remote Traceroute in SSVM'
 | |
|         )
 | |
| 
 | |
|     @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
 | |
|     def test_12_traceroute_in_cpvm(self):
 | |
|         '''
 | |
|         Test Traceroute command execution in CPVMM
 | |
|         '''
 | |
| 
 | |
|         # Validate the following:
 | |
|         # 1. Traceroute command is executed remotely on CPVM
 | |
| 
 | |
|         list_cpvm_response = list_ssvms(
 | |
|             self.apiclient,
 | |
|             systemvmtype='consoleproxy',
 | |
|             state='Running',
 | |
|         )
 | |
| 
 | |
|         self.assertEqual(
 | |
|             isinstance(list_cpvm_response, list),
 | |
|             True,
 | |
|             'Check list response returns a valid list'
 | |
|         )
 | |
|         cpvm = list_cpvm_response[0]
 | |
| 
 | |
|         self.debug('Setting up CPVMM with ID %s' % cpvm.id)
 | |
| 
 | |
|         cmd = runDiagnostics.runDiagnosticsCmd()
 | |
|         cmd.targetid = cpvm.id
 | |
|         cmd.ipaddress = '8.8.4.4'
 | |
|         cmd.type = 'traceroute'
 | |
|         cmd.params = '-m 10'
 | |
|         cmd_response = self.apiclient.runDiagnostics(cmd)
 | |
| 
 | |
|         self.assertEqual(
 | |
|             '0',
 | |
|             cmd_response.exitcode,
 | |
|             'Failed to run remote Traceroute in CPVM'
 | |
|         )
 |