# 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 urllib

from marvin.cloudstackAPI import (runDiagnostics, getDiagnosticsData)
from marvin.cloudstackTestCase import cloudstackTestCase
# Import Local Modules
from marvin.codes import FAILED
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 marvin.lib.utils import (cleanup_resources)
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'
        )

    '''
    Add Get Diagnostics data BVT
    '''

    @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
    def test_13_retrieve_vr_default_files(self):
        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('Setting up VR with ID %s' % router.id)
        cmd = getDiagnosticsData.getDiagnosticsDataCmd()
        cmd.targetid = router.id

        response = self.apiclient.getDiagnosticsData(cmd)
        is_valid_url = self.check_url(response.url)

        self.assertEqual(
            True,
            is_valid_url,
            msg="Failed to create valid download url response"
        )

    def check_url(self, url):
        import urllib2
        try:
            r = urllib.urlopen(url)
            if r.code == 200:
                return True
        except urllib2.HTTPError:
            return False
        except urllib2.URLError:
            return False
        return True

    @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
    def test_14_retrieve_vr_one_file(self):
        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('Setting up VR with ID %s' % router.id)
        cmd = getDiagnosticsData.getDiagnosticsDataCmd()
        cmd.targetid = router.id
        cmd.type = "/var/log/cloud.log"

        response = self.apiclient.getDiagnosticsData(cmd)

        is_valid_url = self.check_url(response.url)

        self.assertEqual(
            True,
            is_valid_url,
            msg="Failed to create valid download url response"
        )

    @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
    def test_15_retrieve_ssvm_default_files(self):
        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 = getDiagnosticsData.getDiagnosticsDataCmd()
        cmd.targetid = ssvm.id

        response = self.apiclient.getDiagnosticsData(cmd)

        is_valid_url = self.check_url(response.url)

        self.assertEqual(
            True,
            is_valid_url,
            msg="Failed to create valid download url response"
        )

    @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
    def test_16_retrieve_ssvm_single_file(self):
        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 = getDiagnosticsData.getDiagnosticsDataCmd()
        cmd.targetid = ssvm.id
        cmd.type = "/var/log/cloud.log"

        response = self.apiclient.getDiagnosticsData(cmd)

        is_valid_url = self.check_url(response.url)

        self.assertEqual(
            True,
            is_valid_url,
            msg="Failed to create valid download url response"
        )

    @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
    def test_17_retrieve_cpvm_default_files(self):
        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 CPVM with ID %s' % cpvm.id)

        cmd = getDiagnosticsData.getDiagnosticsDataCmd()
        cmd.targetid = cpvm.id

        response = self.apiclient.getDiagnosticsData(cmd)

        is_valid_url = self.check_url(response.url)

        self.assertEqual(
            True,
            is_valid_url,
            msg="Failed to create valid download url response"
        )

    @attr(tags=["advanced", "advancedns", "ssh", "smoke"], required_hardware="true")
    def test_18_retrieve_cpvm_single_file(self):
        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 CPVM with ID %s' % cpvm.id)

        cmd = getDiagnosticsData.getDiagnosticsDataCmd()
        cmd.targetid = cpvm.id
        cmd.type = "/var/log/cloud.log"

        response = self.apiclient.getDiagnosticsData(cmd)

        is_valid_url = self.check_url(response.url)

        self.assertEqual(
            True,
            is_valid_url,
            msg="Failed to create valid download url response"
        )
