예제 #1
0
    def setUp(self):
        super(TestKvmRuntime, self).setUp()
        kvm_class = 'ganeti.hypervisor.hv_kvm.KVMHypervisor'
        self.MockOut('qmp',
                     mock.patch('ganeti.hypervisor.hv_kvm.QmpConnection'))
        self.MockOut('run_cmd', mock.patch('ganeti.utils.RunCmd'))
        self.MockOut('ensure_dirs', mock.patch('ganeti.utils.EnsureDirs'))
        self.MockOut('write_file', mock.patch('ganeti.utils.WriteFile'))
        self.MockOut(mock.patch(kvm_class + '.ValidateParameters'))
        self.MockOut(
            mock.patch('ganeti.hypervisor.hv_kvm.OpenTap',
                       return_value=('test_nic', [], [])))
        self.MockOut(mock.patch(kvm_class + '._ConfigureNIC'))
        self.MockOut(
            'pid_alive',
            mock.patch(kvm_class + '._InstancePidAlive',
                       return_value=('file', -1, False)))
        self.MockOut(mock.patch(kvm_class + '._ExecuteCpuAffinity'))
        self.MockOut(mock.patch(kvm_class + '._CallMonitorCommand'))

        self.cfg = ConfigMock()
        params = constants.HVC_DEFAULTS[constants.HT_KVM].copy()
        beparams = constants.BEC_DEFAULTS.copy()
        self.instance = self.cfg.AddNewInstance(name='name.example.com',
                                                hypervisor='kvm',
                                                hvparams=params,
                                                beparams=beparams)
class TestKvmRuntime(testutils.GanetiTestCase):
  """The _ExecuteKvmRuntime is at the core of all KVM operations."""

  def setUp(self):
    super(TestKvmRuntime, self).setUp()
    kvm_class = 'ganeti.hypervisor.hv_kvm.KVMHypervisor'
    self.MockOut('qmp', mock.patch('ganeti.hypervisor.hv_kvm.QmpConnection'))
    self.MockOut('run_cmd', mock.patch('ganeti.utils.RunCmd'))
    self.MockOut('ensure_dirs', mock.patch('ganeti.utils.EnsureDirs'))
    self.MockOut('write_file', mock.patch('ganeti.utils.WriteFile'))
    self.MockOut(mock.patch(kvm_class + '.ValidateParameters'))
    self.MockOut(mock.patch('ganeti.hypervisor.hv_kvm.OpenTap',
                            return_value=('test_nic', [], [])))
    self.MockOut(mock.patch(kvm_class + '._ConfigureNIC'))
    self.MockOut('pid_alive', mock.patch(kvm_class + '._InstancePidAlive',
                                         return_value=('file', -1, False)))
    self.MockOut(mock.patch(kvm_class + '._ExecuteCpuAffinity'))
    self.MockOut(mock.patch(kvm_class + '._CallMonitorCommand'))

    self.cfg = ConfigMock()
    self.params = constants.HVC_DEFAULTS[constants.HT_KVM].copy()
    self.beparams = constants.BEC_DEFAULTS.copy()
    self.instance = self.cfg.AddNewInstance(name='name.example.com',
                                            hypervisor='kvm',
                                            hvparams=self.params,
                                            beparams=self.beparams)

  def testDirectoriesCreated(self):
    hypervisor = hv_kvm.KVMHypervisor()
    self.mocks['ensure_dirs'].assert_called_with([
        (PostfixMatcher('/run/ganeti/kvm-hypervisor'), 0775),
        (PostfixMatcher('/run/ganeti/kvm-hypervisor/pid'), 0775),
        (PostfixMatcher('/run/ganeti/kvm-hypervisor/uid'), 0775),
        (PostfixMatcher('/run/ganeti/kvm-hypervisor/ctrl'), 0775),
        (PostfixMatcher('/run/ganeti/kvm-hypervisor/conf'), 0775),
        (PostfixMatcher('/run/ganeti/kvm-hypervisor/nic'), 0775),
        (PostfixMatcher('/run/ganeti/kvm-hypervisor/chroot'), 0775),
        (PostfixMatcher('/run/ganeti/kvm-hypervisor/chroot-quarantine'), 0775),
        (PostfixMatcher('/run/ganeti/kvm-hypervisor/keymap'), 0775)])

  def testStartInstance(self):
    hypervisor = hv_kvm.KVMHypervisor()
    def RunCmd(cmd, **kwargs):
      if '--help' in cmd:
        return mock.Mock(
            failed=False, output=testutils.ReadTestData("kvm_1.1.2_help.txt"))
      if '-S' in cmd:
        self.mocks['pid_alive'].return_value = ('file', -1, True)
        return mock.Mock(failed=False)
      elif '-M' in cmd:
        return mock.Mock(failed=False, output='')
      elif '-device' in cmd:
        return mock.Mock(failed=False, output='name "virtio-blk-pci"')
      else:
        raise errors.ProgrammerError('Unexpected command: %s' % cmd)
    self.mocks['run_cmd'].side_effect = RunCmd
    hypervisor.StartInstance(self.instance, [], False)
예제 #3
0
    def ResetMocks(self):
        """Resets all mocks back to their initial state.

    This is useful if you want to execute more than one opcode in a single
    test.

    """
        self.cfg = ConfigMock()
        self.rpc = CreateRpcRunnerMock()
        self.ctx = GanetiContextMock(self)
        self.wconfd = WConfdMock()
        self.mcpu = ProcessorMock(self.ctx, self.wconfd)

        self._StopPatchers()
        try:
            self._iallocator_patcher = patchIAllocator(self._GetTestModule())
            self.iallocator_cls = self._iallocator_patcher.start()
        except (ImportError, AttributeError):
            # this test module does not use iallocator, no patching performed
            self._iallocator_patcher = None

        try:
            self._netutils_patcher = patchNetutils(self._GetTestModule())
            self.netutils_mod = self._netutils_patcher.start()
            SetupDefaultNetutilsMock(self.netutils_mod, self.cfg)
        except (ImportError, AttributeError):
            # this test module does not use netutils, no patching performed
            self._netutils_patcher = None

        try:
            self._ssh_patcher = patchSsh(self._GetTestModule())
            self.ssh_mod = self._ssh_patcher.start()
        except (ImportError, AttributeError):
            # this test module does not use ssh, no patching performed
            self._ssh_patcher = None

        try:
            self._rpc_patcher = patchRpc(self._GetTestModule())
            self.rpc_mod = self._rpc_patcher.start()
            SetupDefaultRpcModuleMock(self.rpc_mod)
        except (ImportError, AttributeError):
            # this test module does not use rpc, no patching performed
            self._rpc_patcher = None
예제 #4
0
 def _get_object_mock(self):
   """Returns a mocked instance of ConfigWriter"""
   cfg = ConfigMock(cfg_file=self.cfg_file)
   return cfg
예제 #5
0
class CmdlibTestCase(testutils.GanetiTestCase):
    """Base class for cmdlib tests.

  This class sets up a mocked environment for the execution of
  L{ganeti.cmdlib.base.LogicalUnit} subclasses.

  The environment can be customized via the following fields:

    * C{cfg}: @see L{ConfigMock}
    * C{rpc}: @see L{CreateRpcRunnerMock}
    * C{iallocator_cls}: @see L{patchIAllocator}
    * C{mcpu}: @see L{ProcessorMock}
    * C{netutils_mod}: @see L{patchNetutils}
    * C{ssh_mod}: @see L{patchSsh}

  """

    REMOVE = object()

    cluster = property(fget=lambda self: self.cfg.GetClusterInfo(),
                       doc="Cluster configuration object")
    master = property(fget=lambda self: self.cfg.GetMasterNodeInfo(),
                      doc="Master node")
    master_uuid = property(fget=lambda self: self.cfg.GetMasterNode(),
                           doc="Master node UUID")
    # pylint: disable=W0212
    group = property(fget=lambda self: self._GetDefaultGroup(),
                     doc="Default node group")

    os = property(fget=lambda self: self.cfg.GetDefaultOs(), doc="Default OS")
    os_name_variant = property(fget=lambda self: self.os.name + objects.OS.
                               VARIANT_DELIM + self.os.supported_variants[0],
                               doc="OS name and variant string")

    def setUp(self):
        super(CmdlibTestCase, self).setUp()
        self._iallocator_patcher = None
        self._netutils_patcher = None
        self._ssh_patcher = None
        self._rpc_patcher = None

        try:
            runtime.InitArchInfo()
        except errors.ProgrammerError:
            # during tests, the arch info can be initialized multiple times
            pass

        self.ResetMocks()
        self._cleanups = []

    def _StopPatchers(self):
        if self._iallocator_patcher is not None:
            self._iallocator_patcher.stop()
            self._iallocator_patcher = None
        if self._netutils_patcher is not None:
            self._netutils_patcher.stop()
            self._netutils_patcher = None
        if self._ssh_patcher is not None:
            self._ssh_patcher.stop()
            self._ssh_patcher = None
        if self._rpc_patcher is not None:
            self._rpc_patcher.stop()
            self._rpc_patcher = None

    def tearDown(self):
        super(CmdlibTestCase, self).tearDown()

        self._StopPatchers()

        while self._cleanups:
            f, args, kwargs = self._cleanups.pop(-1)
            try:
                f(*args, **kwargs)
            except BaseException as e:
                sys.stderr.write('Error in cleanup: %s\n' % e)

    def _GetTestModule(self):
        module = inspect.getsourcefile(self.__class__).split("/")[-1]
        suffix = "_unittest.py"
        assert module.endswith(suffix), "Naming convention for cmdlib test" \
                                        " modules is: <module>%s (found '%s')"\
                                        % (suffix, module)
        return module[:-len(suffix)]

    def ResetMocks(self):
        """Resets all mocks back to their initial state.

    This is useful if you want to execute more than one opcode in a single
    test.

    """
        self.cfg = ConfigMock()
        self.rpc = CreateRpcRunnerMock()
        self.ctx = GanetiContextMock(self)
        self.wconfd = WConfdMock()
        self.mcpu = ProcessorMock(self.ctx, self.wconfd)

        self._StopPatchers()
        try:
            self._iallocator_patcher = patchIAllocator(self._GetTestModule())
            self.iallocator_cls = self._iallocator_patcher.start()
        except (ImportError, AttributeError):
            # this test module does not use iallocator, no patching performed
            self._iallocator_patcher = None

        try:
            self._netutils_patcher = patchNetutils(self._GetTestModule())
            self.netutils_mod = self._netutils_patcher.start()
            SetupDefaultNetutilsMock(self.netutils_mod, self.cfg)
        except (ImportError, AttributeError):
            # this test module does not use netutils, no patching performed
            self._netutils_patcher = None

        try:
            self._ssh_patcher = patchSsh(self._GetTestModule())
            self.ssh_mod = self._ssh_patcher.start()
        except (ImportError, AttributeError):
            # this test module does not use ssh, no patching performed
            self._ssh_patcher = None

        try:
            self._rpc_patcher = patchRpc(self._GetTestModule())
            self.rpc_mod = self._rpc_patcher.start()
            SetupDefaultRpcModuleMock(self.rpc_mod)
        except (ImportError, AttributeError):
            # this test module does not use rpc, no patching performed
            self._rpc_patcher = None

    def GetMockLU(self):
        """Creates a mock L{LogialUnit} with access to the mocked config etc.

    @rtype: L{LogialUnit}
    @return: A mock LU

    """
        return MockLU(self.mcpu, mock.MagicMock(), self.cfg, self.rpc,
                      (1234, "/tmp/mock/livelock"), self.wconfd)

    def RpcResultsBuilder(self, use_node_names=False):
        """Creates a pre-configured L{RpcResultBuilder}

    @type use_node_names: bool
    @param use_node_names: @see L{RpcResultBuilder}
    @rtype: L{RpcResultBuilder}
    @return: a pre-configured builder for RPC results

    """
        return RpcResultsBuilder(cfg=self.cfg, use_node_names=use_node_names)

    def ExecOpCode(self, opcode):
        """Executes the given opcode.

    @param opcode: the opcode to execute
    @return: the result of the LU's C{Exec} method

    """
        return self.mcpu.ExecOpCodeAndRecordOutput(opcode)

    def ExecOpCodeExpectException(self,
                                  opcode,
                                  expected_exception,
                                  expected_regex=None):
        """Executes the given opcode and expects an exception.

    @param opcode: @see L{ExecOpCode}
    @type expected_exception: class
    @param expected_exception: the exception which must be raised
    @type expected_regex: string
    @param expected_regex: if not C{None}, a regular expression which must be
          present in the string representation of the exception

    """
        try:
            self.ExecOpCode(opcode)
        except expected_exception as e:
            if expected_regex is not None:
                assert re.search(expected_regex, str(e)) is not None, \
                        "Caught exception '%s' did not match '%s'" % \
                          (str(e), expected_regex)
        except Exception as e:
            tb = traceback.format_exc()
            raise AssertionError("%s\n(See original exception above)\n"
                                 "Expected exception '%s' was not raised,"
                                 " got '%s' of class '%s' instead." %
                                 (tb, expected_exception, e, e.__class__))
        else:
            raise AssertionError("Expected exception '%s' was not raised" %
                                 expected_exception)

    def ExecOpCodeExpectOpPrereqError(self, opcode, expected_regex=None):
        """Executes the given opcode and expects a L{errors.OpPrereqError}

    @see L{ExecOpCodeExpectException}

    """
        self.ExecOpCodeExpectException(opcode, errors.OpPrereqError,
                                       expected_regex)

    def ExecOpCodeExpectOpExecError(self, opcode, expected_regex=None):
        """Executes the given opcode and expects a L{errors.OpExecError}

    @see L{ExecOpCodeExpectException}

    """
        self.ExecOpCodeExpectException(opcode, errors.OpExecError,
                                       expected_regex)

    def RunWithLockedLU(self, opcode, test_func):
        """Takes the given opcode, creates a LU and runs func on it.

    The passed LU did already perform locking, but no methods which actually
    require locking are executed on the LU.

    @param opcode: the opcode to get the LU for.
    @param test_func: the function to execute with the LU as parameter.
    @return: the result of test_func

    """
        return self.mcpu.RunWithLockedLU(opcode, test_func)

    def assertLogContainsMessage(self, expected_msg):
        """Shortcut for L{ProcessorMock.assertLogContainsMessage}

    """
        self.mcpu.assertLogContainsMessage(expected_msg)

    def assertLogContainsRegex(self, expected_regex):
        """Shortcut for L{ProcessorMock.assertLogContainsRegex}

    """
        self.mcpu.assertLogContainsRegex(expected_regex)

    def assertHooksCall(self,
                        nodes,
                        hook_path,
                        phase,
                        environment=None,
                        count=None,
                        index=0):
        """Asserts a call to C{rpc.call_hooks_runner}

    @type nodes: list of string
    @param nodes: node UUID's or names hooks run on
    @type hook_path: string
    @param hook_path: path (or name) of the hook run
    @type phase: string
    @param phase: phase in which the hook runs in
    @type environment: dict
    @param environment: the environment passed to the hooks. C{None} to skip
            asserting it
    @type count: int
    @param count: the number of hook invocations. C{None} to skip asserting it
    @type index: int
    @param index: the index of the hook invocation to assert

    """
        if count is not None:
            self.assertEqual(count, self.rpc.call_hooks_runner.call_count)

        args = self.rpc.call_hooks_runner.call_args[index]

        self.assertEqual(set(nodes), set(args[0]))
        self.assertEqual(hook_path, args[1])
        self.assertEqual(phase, args[2])
        if environment is not None:
            self.assertEqual(environment, args[3])

    def assertSingleHooksCall(self, nodes, hook_path, phase, environment=None):
        """Asserts a single call to C{rpc.call_hooks_runner}

    @see L{assertHooksCall} for parameter description.

    """
        self.assertHooksCall(nodes,
                             hook_path,
                             phase,
                             environment=environment,
                             count=1)

    def CopyOpCode(self, opcode, **kwargs):
        """Creates a copy of the given opcode and applies modifications to it

    @type opcode: opcode.OpCode
    @param opcode: the opcode to copy
    @type kwargs: dict
    @param kwargs: dictionary of fields to overwrite in the copy. The special
          value L{REMOVE} can be used to remove fields from the copy.
    @return: a copy of the given opcode

    """
        state = opcode.__getstate__()

        for key, value in kwargs.items():
            if value == self.REMOVE and key in state:
                del state[key]
            else:
                state[key] = value

        return opcodes.OpCode.LoadOpCode(state)

    def _GetDefaultGroup(self):
        for group in self.cfg.GetAllNodeGroupsInfo().values():
            if group.name == "default":
                return group
        assert False

    def _MatchMasterParams(self):
        return ConfigObjectMatcher(self.cfg.GetMasterNetworkParameters())

    def MockOut(self, *args, **kwargs):
        """Immediately start mock.patch.object."""
        patcher = mock.patch.object(*args, **kwargs)
        mocked = patcher.start()
        self.AddCleanup(patcher.stop)
        return mocked

    # Simplified backport of 2.7 feature
    def AddCleanup(self, func, *args, **kwargs):
        self._cleanups.append((func, args, kwargs))

    def assertIn(self, first, second, msg=None):
        if first not in second:
            if msg is None:
                msg = "%r not found in %r" % (first, second)
            self.fail(msg)