def validate(self, remote, reconcile=True, env_map=None, **kwargs): """Attempts to validate package installation on the image. Even if reconcile=True, attempts to verify previous package installation offline before using networked tools to validate or install new packages. :param remote: A remote socket to the instance. :param reconcile: If false, all validators will only verify that a desired state is present, and fail if it is not. If true, all validators will attempt to enforce the desired state if possible, and succeed if this enforcement succeeds. :param env_map: A map of environment variables to pass to scripts. :raises ImageValidationError: If validation fails. """ env_distro = env_map[self.DISTRO_KEY] env_family = self._DISTRO_FAMILES[env_distro] check, install = self._DISTRO_TOOLS[env_family] if not env_family: raise p_ex.ImageValidationError( _("Unknown distro: cannot verify or install packages.")) try: check(self, remote) except (ex.SubprocessException, ex.RemoteCommandException): if reconcile: install(self, remote) check(self, remote) else: raise
def validate(self, remote, test_only=False, image_arguments=None, **kwargs): """Attempts to validate package installation on the image. Even if test_only=False, attempts to verify previous package installation offline before using networked tools to validate or install new packages. :param remote: A remote socket to the instance. :param test_only: If true, all validators will only verify that a desired state is present, and fail if it is not. If false, all validators will attempt to enforce the desired state if possible, and succeed if this enforcement succeeds. :param image_arguments: A dictionary of image argument values keyed by argument name. :raises ImageValidationError: If validation fails. """ env_distro = image_arguments[self.DISTRO_KEY] env_family = self._DISTRO_FAMILES[env_distro] check, install = self._DISTRO_TOOLS[env_family] if not env_family: raise p_ex.ImageValidationError( _("Unknown distro: cannot verify or install packages.")) try: check(self, remote) except (ex.SubprocessException, ex.RemoteCommandException, RuntimeError): if not test_only: install(self, remote) check(self, remote) else: raise
def validate(self, remote, test_only=False, image_arguments=None, **kwargs): """Attempts to validate depending on argument value. :param remote: A remote socket to the instance. :param test_only: If true, all validators will only verify that a desired state is present, and fail if it is not. If false, all validators will attempt to enforce the desired state if possible, and succeed if this enforcement succeeds. :param image_arguments: A dictionary of image argument values keyed by argument name. :raises ImageValidationError: If validation fails. """ arg = self.argument_name if arg not in image_arguments: raise p_ex.ImageValidationError( _("Argument {name} not found.").format(name=arg)) value = image_arguments[arg] if value in self.cases: self.cases[value].validate(remote, test_only=test_only, image_arguments=image_arguments)
def test_any_validator(self): cls = images.SaharaAnyValidator class FakeValidator(images.SaharaImageValidatorBase): def __init__(self, mock_validate): self.mock_validate = mock_validate def validate(self, remote, test_only=False, **kwargs): self.mock_validate(remote, test_only=test_only, **kwargs) # One success short circuits validation always_tells_the_truth = FakeValidator(mock.Mock()) validator = cls([always_tells_the_truth, always_tells_the_truth]) validator.validate(None, test_only=False) self.assertEqual(always_tells_the_truth.mock_validate.call_count, 1) # All failures fails, and calls with test_only=True on all first always_lies = FakeValidator( mock.Mock(side_effect=p_ex.ImageValidationError("Oh no!"))) validator = cls([always_lies, always_lies]) try: validator.validate(None, test_only=False) except p_ex.ImageValidationError: pass self.assertEqual(always_lies.mock_validate.call_count, 4) # But it fails after a first pass if test_only=True. always_lies = FakeValidator( mock.Mock(side_effect=p_ex.ImageValidationError("Oh no!"))) validator = cls([always_lies, always_lies]) try: validator.validate(None, test_only=True) except p_ex.ImageValidationError: pass self.assertEqual(always_lies.mock_validate.call_count, 2) # One failure doesn't end iteration. always_tells_the_truth = FakeValidator(mock.Mock()) always_lies = FakeValidator( mock.Mock(side_effect=p_ex.ImageValidationError("Oh no!"))) validator = cls([always_lies, always_tells_the_truth]) validator.validate(None, test_only=False) self.assertEqual(always_lies.mock_validate.call_count, 1) self.assertEqual(always_tells_the_truth.mock_validate.call_count, 1)
def test_all_validator(self): cls = images.SaharaAllValidator # All pass always_tells_the_truth = mock.Mock() validator = cls([always_tells_the_truth, always_tells_the_truth]) validator.validate(None, reconcile=True) self.assertEqual(always_tells_the_truth.validate.call_count, 2) always_tells_the_truth.validate.assert_called_with(None, reconcile=True, env_map=None) # Second fails always_tells_the_truth = mock.Mock() always_lies = mock.Mock(validate=mock.Mock( side_effect=p_ex.ImageValidationError("Boom!"))) validator = cls([always_tells_the_truth, always_lies]) try: validator.validate(None, reconcile=False) except p_ex.ImageValidationError: pass self.assertEqual(always_tells_the_truth.validate.call_count, 1) self.assertEqual(always_lies.validate.call_count, 1) always_tells_the_truth.validate.assert_called_with(None, reconcile=False, env_map=None) always_lies.validate.assert_called_with(None, reconcile=False, env_map=None) # First fails always_tells_the_truth = mock.Mock() always_lies = mock.Mock(validate=mock.Mock( side_effect=p_ex.ImageValidationError("Boom!"))) validator = cls([always_lies, always_tells_the_truth]) try: validator.validate(None, reconcile=False, env_map={}) except p_ex.ImageValidationError: pass self.assertEqual(always_lies.validate.call_count, 1) always_lies.validate.assert_called_with(None, reconcile=False, env_map={}) self.assertEqual(always_tells_the_truth.validate.call_count, 0)
def validate(self, remote, test_only=False, image_arguments=None, **kwargs): """Attempts to validate the image. Before deferring to contained validators, performs one-time setup steps such as distro discovery. :param remote: A remote socket to the instance. :param test_only: If true, all validators will only verify that a desired state is present, and fail if it is not. If false, all validators will attempt to enforce the desired state if possible, and succeed if this enforcement succeeds. :param image_arguments: A dictionary of image argument values keyed by argument name. :raises ImageValidationError: If validation fails. """ argument_values = {} for name, argument in six.iteritems(self.arguments): if name not in image_arguments: if argument.required: raise p_ex.ImageValidationError( _("Argument {name} is required for image " "processing.").format(name=name)) else: argument_values[name] = argument.default else: value = image_arguments[name] choices = argument.choices if choices and value not in choices: raise p_ex.ImageValidationError( _("Value for argument {name} must be one of " "{choices}.").format(name=name, choices=choices)) else: argument_values[name] = value argument_values[self.DISTRO_KEY] = remote.get_os_distrib() self.validator.validate(remote, test_only=test_only, image_arguments=argument_values)