Пример #1
0
    def setUp(self):
        """Test case setup function called automatically prior to each test."""
        super(TestCOTDeployESXi, self).setUp()
        self.instance = COTDeployESXi(UI())
        self.instance.package = self.input_ovf
        self.instance.hypervisor = 'esxi'
        # Stub out all ovftool dependencies
        self._ovftool_path = self.instance.ovftool._path
        self._check_call = self.instance.ovftool._check_call
        self._ovftool_version = self.instance.ovftool._version
        self.instance.ovftool._path = "/fake/ovftool"
        self.instance.ovftool._check_call = self.stub_check_call
        self.instance.ovftool._version = StrictVersion("4.0.0")

        self.last_argv = []
Пример #2
0
class TestCOTDeployESXi(COT_UT):
    """Test cases for COTDeployESXi class."""

    # Some WARNING logger messages we may expect at various points:
    SERIAL_PORT_NOT_FIXED = {
        'levelname': 'WARNING',
        'msg': 'serial port.*will not be created or configured',
    }
    VSPHERE_ENV_WARNING = {
        'levelname': 'WARNING',
        'msg': "deploying.*vSphere.*power-on.*environment properties.*ignored",
    }
    OVFTOOL_VER_TOO_LOW = {
        'levelname': 'WARNING',
        'msg': "ovftool version is too low.*environment properties.*ignored",
    }
    BAD_CERTIFICATE = {
        'levelname': 'WARNING',
        'msg': "certificate verify failed",
    }
    SESSION_FAILED = {
        'levelname': 'ERROR',
        'msg': "Session failed",
    }

    def stub_check_call(self, argv, require_success=True):
        """Stub for check_call - capture calls to ovftool."""
        logger.info("stub_check_call({0}, {1})".format(argv, require_success))
        if argv[0] == 'ovftool':
            self.last_argv = argv
            logger.info("Caught ovftool invocation")
            return
        return self._check_call(argv, require_success)

    def setUp(self):
        """Test case setup function called automatically prior to each test."""
        super(TestCOTDeployESXi, self).setUp()
        self.instance = COTDeployESXi(UI())
        self.instance.package = self.input_ovf
        self.instance.hypervisor = 'esxi'
        # Stub out all ovftool dependencies
        self._ovftool_path = self.instance.ovftool._path
        self._check_call = self.instance.ovftool._check_call
        self._ovftool_version = self.instance.ovftool._version
        self.instance.ovftool._path = "/fake/ovftool"
        self.instance.ovftool._check_call = self.stub_check_call
        self.instance.ovftool._version = StrictVersion("4.0.0")

        self.last_argv = []

    def tearDown(self):
        """Test case cleanup function called automatically."""
        # Remove our stub
        self.instance.ovftool._path = self._ovftool_path
        self.instance.ovftool._check_call = self._check_call
        self.instance.ovftool._version = self._ovftool_version
        super(TestCOTDeployESXi, self).tearDown()

    def test_not_ready_with_no_args(self):
        """Verify ready_to_run() is False without all mandatory args."""
        ready, reason = self.instance.ready_to_run()
        self.assertEqual(ready, False)
        self.assertTrue(re.search("LOCATOR.*mandatory", reason))
        self.assertRaises(InvalidInputError, self.instance.run)

        self.instance.locator = "localhost"
        self.instance.package = None
        ready, reason = self.instance.ready_to_run()
        self.assertEqual(ready, False)
        self.assertTrue(re.search("PACKAGE.*mandatory", reason))
        self.assertRaises(InvalidInputError, self.instance.run)

    def test_invalid_args(self):
        """Negative tests for various arguments."""
        with self.assertRaises(InvalidInputError):
            self.instance.configuration = ""
        with self.assertRaises(InvalidInputError):
            self.instance.configuration = "X"
        with self.assertRaises(InvalidInputError):
            self.instance.power_on = "frobozz"

    def test_ovftool_args_basic(self):
        """Test that ovftool is called with the basic arguments."""
        self.instance.locator = "localhost"
        self.instance.run()
        self.assertEqual([
            'ovftool',
            '--deploymentOption=4CPU-4GB-3NIC',    # default configuration
            '--name=input',
            self.input_ovf,
            'vi://{user}:passwd@localhost'.format(user=getpass.getuser())
        ], self.last_argv)
        self.assertLogged(**self.VSPHERE_ENV_WARNING)
        self.assertLogged(**self.SERIAL_PORT_NOT_FIXED)

    def test_ovftool_args_advanced(self):
        """Test that ovftool is called with more involved arguments."""
        self.instance.locator = "localhost/host/foo"
        self.instance.datastore = "datastore1"
        self.instance.configuration = "2CPU-2GB-1NIC"
        self.instance.vm_name = "myVM"
        self.instance.power_on = True
        self.instance.ovftool_args = "--overwrite --vService:'A B=C D'"
        self.instance.username = "******"
        self.instance.password = "******"
        self.instance.network_map = ["VM Network=VM Network"]

        self.instance.run()
        self.assertEqual([
            'ovftool',
            '--overwrite',
            '--vService:A B=C D',
            '--deploymentOption=2CPU-2GB-1NIC',
            '--net:VM Network=VM Network',
            '--name=myVM',
            '--powerOn',
            '--datastore=datastore1',
            self.input_ovf,
            'vi://*****:*****@localhost/host/foo',
        ], self.last_argv)
        self.assertLogged(**self.SERIAL_PORT_NOT_FIXED)

    def test_ovftool_vsphere_env_fixup(self):
        """Test fixup of environment when deploying directly to vSphere."""
        # With 4.0.0 (our default) and no power_on, there's no fixup.
        # This is tested by test_ovftool_args_basic() above.

        # With 4.0.0 and power_on, we fixup when deploying to vSphere:
        self.instance.locator = "vsphere"
        self.instance.power_on = True
        self.instance.run()
        self.assertEqual([
            'ovftool',
            '--X:injectOvfEnv',
            '--deploymentOption=4CPU-4GB-3NIC',     # default configuration
            '--name=input',
            '--powerOn',
            self.input_ovf,
            'vi://{user}:passwd@vsphere'.format(user=getpass.getuser()),
        ], self.last_argv)
        self.assertLogged(**self.SERIAL_PORT_NOT_FIXED)
        # Make sure we DON'T see the ENV_WARNING message
        self.logging_handler.assertNoLogsOver(logging.INFO)

        # With 4.0.0, we don't (need to) fixup when deploying to vCenter.
        # This is tested by test_ovftool_args_advanced() above.

        # With <4.0.0, we don't (can't) fixup, regardless.
        # Discard cached information and update the info that will be returned
        self.instance.ovftool._version = StrictVersion("3.5.0")
        self.instance.run()
        self.assertEqual([
            'ovftool',
            # Nope! #'--X:injectOvfEnv',
            '--deploymentOption=4CPU-4GB-3NIC',     # default configuration
            '--name=input',
            '--powerOn',
            self.input_ovf,
            'vi://{user}:passwd@vsphere'.format(user=getpass.getuser()),
        ], self.last_argv)
        self.assertLogged(**self.OVFTOOL_VER_TOO_LOW)
        self.assertLogged(**self.SERIAL_PORT_NOT_FIXED)

    def test_serial_fixup_connection_error(self):
        """Call fixup_serial_ports() to connect to an invalid host."""
        self.instance.locator = "localhost"
        self.instance.serial_connection = ['tcp::2222', 'tcp::2223']
        with self.assertRaises((requests.exceptions.ConnectionError,
                                socket.error)) as cm:
            self.instance.fixup_serial_ports(2)
        # In requests 2.7 and earlier, we get the errno,
        # while in requests 2.8+, it's munged into a string only
        if cm.exception.errno is not None:
            self.assertEqual(cm.exception.errno, errno.ECONNREFUSED)
        self.assertRegexpMatches(
            cm.exception.strerror,
            "(Error connecting to localhost:443: )?.*Connection refused")

    @mock.patch('pyVim.connect.__Login')
    @mock.patch('pyVim.connect.__FindSupportedVersion')
    def test_serial_fixup_stubbed(self, mock_fsv, mock_login):
        """Test fixup_serial_ports by mocking pyVmomi library."""
        self.instance.locator = "localhost"
        self.instance.vm_name = "mockery"

        mock_fsv.return_value = ['vim25']
        mock_si = mock.create_autospec(COT.deploy_esxi.vim.ServiceInstance)
        mock_login.return_value = (mock_si, None)

        mock_sic = mock.create_autospec(
            COT.deploy_esxi.vim.ServiceInstanceContent)
        mock_si.RetrieveContent.return_value = mock_sic
        mock_sic.rootFolder = 'vim.Folder:group-d1'

        mock_v = mock.create_autospec(COT.deploy_esxi.vim.ViewManager)
        mock_sic.viewManager = mock_v

        mock_cv = mock.create_autospec(COT.deploy_esxi.vim.view.ContainerView)
        mock_v.CreateContainerView.return_value = mock_cv

        mock_vm = mock.create_autospec(COT.deploy_esxi.vim.VirtualMachine)
        mock_vm.name = self.instance.vm_name
        mock_cv.view = [mock_vm]

        self.instance.serial_connection = ['tcp:localhost:2222',
                                           'tcp::2223,server',
                                           '/dev/ttyS0']
        self.instance.fixup_serial_ports(3)

        self.assertTrue(mock_vm.ReconfigVM_Task.called)
        args, kwargs = mock_vm.ReconfigVM_Task.call_args
        spec = kwargs['spec']
        self.assertEqual(3, len(spec.deviceChange))
        s1, s2, s3 = spec.deviceChange
        self.assertEqual('add', s1.operation)
        self.assertEqual('add', s2.operation)
        self.assertEqual('add', s3.operation)
        self.assertEqual('tcp://*****:*****@mock.patch('COT.deploy_esxi.SmartConnection.__enter__')
    def test_serial_fixup_SSL_failure(self, mock_parent):
        """Test SSL failure in pyVmomi.

        Only applicable to 2.7+ and 3.4+ that have the new certificate logic.
        """
        if hasattr(ssl, '_create_unverified_context'):
            mock_parent.side_effect = vim.fault.HostConnectFault(
                msg="certificate verify failed")
            self.instance.locator = "localhost"
            self.instance.serial_connection = ['tcp://localhost:2222']
            self.assertRaises(vim.fault.HostConnectFault,
                              self.instance.fixup_serial_ports, 1)
            self.assertLogged(**self.BAD_CERTIFICATE)