예제 #1
0
    def test_load_yaml_raises_error_if_wrong_format(self, yamlMock, osMock):
        yamlMock.safe_load.side_effect = YAMLError("error")

        with self.assertRaises(YAMLError):
            self.inv._load_yaml(self.source_data_path)
        self.assertEqual(
            str(self.logging.getLogger.return_value.error.mock_calls),
            str([call(YAMLError("error"))]),
        )
예제 #2
0
def yaml_load(obj):
    '''Safely loads the YAML-formatted object `obj` into a dict and returns
    that dict. Note that being YAML a superset of json, all properly
    json-formatted strings are also correctly loaded and the quote character
    ' is also allowed (in pure json, only " is allowed).

    :param obj: (dict, stream, string denoting an existing file path, or
        string denoting the file content in YAML syntax): If stream (i.e.,
        an object with the `read` attribute), uses it for reading and parsing
        its content into dict. If dict, this method is no-op and the dict is
        returned, if string denoting an existing file, a stream is opened
        from the file and processed as explained above (the stream will be
        closed in this case). If string, the string is treated as YAML
        content and parsed: in this case, the output must be a dict otherwise
        a YAMLError is thrown

    :raises: YAMLError
    '''
    if isinstance(obj, dict):
        return obj

    close_stream = False
    if isinstance(obj, str):
        close_stream = True
        if isfile(obj):  # file input
            stream = open(obj, 'r')
        else:
            stream = StringIO(obj)  # YAML content input
    elif not hasattr(obj, 'read'):
        # raise a general message meaningful for a Rest framework:
        raise YAMLError('Invalid input, expected data as string in YAML or '
                        'JSON syntax, found %s' % str(obj.__class__.__name__))
    else:
        stream = obj

    try:
        ret = safe_load(stream)
        # for some weird reason, in case of a string ret is the string itself,
        # and no error is raised. Let's do it here:
        if not isinstance(ret, dict):
            if isinstance(obj, (str, bytes)):
                raise YAMLError('The given string input is neither a valid '
                                'YAML content nor the path of an existing '
                                'YAML file')
            raise YAMLError('Unable to load input (%s) as YAML' %
                            (obj.__class__.__name__))
        return ret
    except YAMLError as _:
        raise
    finally:
        if close_stream:
            stream.close()
예제 #3
0
 def __load_config(config_path: str):
     """Loads config_path with pyyaml
     Args:
         config_path: Path to config file
     """
     try:
         with open(config_path, "r") as config_file:
             return yaml.load(stream=config_file, Loader=Loader)
     except FileNotFoundError:
         raise FileNotFoundError(f"No such File: '{config_path}'")
     except YAMLError:
         raise YAMLError("Error Parsing Config File")
예제 #4
0
def _constructor_env_variables(loader, node):
    """
    Extracts the environment variable from the node's value.
    :param yaml.Loader loader: the yaml loader
    :param node: the current node in the yaml
    :return: value of the environment variable
    """
    raw_value = loader.construct_scalar(node)
    new_value = os.environ.get(raw_value)
    if new_value is None:
        msg = "Cannot construct value from {node}: {value}".format(
            node=node, value=new_value)
        raise YAMLError(msg)
    return new_value
예제 #5
0
def yaml_load_clean(data):
    """Read YAML.

    Handles dependencies.

    Raises:
        YAMLError

    Returns:
        dict: Data.
    """
    from yaml import load, YAMLError
    try:
        return load(read_contents(data))
    except YAMLError:
        raise YAMLError('YAMLError: An unexpected error occurred when '
                        'attempting to read supplied YAML.')
예제 #6
0
def _constructor_envfile_variables(loader, node):
    """
    Extracts the environment variable from the node's value.
    :param yaml.Loader loader: the yaml loader
    :param node: the current node in the yaml
    :return: value read from file pointed to by environment variable
    """
    raw_value = loader.construct_scalar(node)
    filepath = os.environ.get(raw_value)
    try:
        with open(filepath, "r") as fd:
            new_value = fd.read()
    except (TypeError, IOError) as e:
        msg = "Cannot construct value from {node}: {path}".format(
            node=node, path=filepath)
        raise YAMLError(msg) from e
    else:
        return new_value
예제 #7
0
 def __init__(self, tasks=None):
     if tasks is None:
         self.tasks = []
     elif isinstance(tasks, str):
         try:
             self.tasks = [Task(title=x[0], state=x[1], estimate=x[2]) for x in get_dataset(tasks)]
         except YAMLError:
             raise YAMLError("Error in format")
         except ValueError as e:
             raise ValueError("Error in data")
         except OSError as e:
             raise OSError("Error in file")
         except Exception as e:
             raise Exception("Unknown")
     elif isinstance(tasks, list):
         if not all(isinstance(n, Task) for n in tasks):
             raise ValueError('Bad type of tasks')
         self.tasks = tasks
     else:
         raise ValueError("Not supported object provided")
예제 #8
0
def _raise_yamlerror(*args):
    raise YAMLError()
예제 #9
0
 def test_read_yaml_err(self, mock_obj):
     yaml_fn = self._fu.qualified_path(self.path, self.yaml)
     self.create_text_file(yaml_fn)
     mock_obj.side_effect = YAMLError('mock error')
     actual = self._fu.read_yaml(yamlFile=yaml_fn)
     self.assertIsNone(actual)
class TestWatcher(object):
    @pytest.fixture
    def spec_factory(self):
        with mock.patch(
                "fiaas_deploy_daemon.specs.factory.SpecFactory") as mockk:
            yield mockk

    @pytest.fixture
    def deploy_queue(self):
        return Queue()

    @pytest.fixture
    def watcher(self):
        return mock.create_autospec(spec=Watcher, spec_set=True, instance=True)

    @pytest.fixture
    def lifecycle(self):
        return mock.create_autospec(spec=Lifecycle,
                                    spec_set=True,
                                    instance=True)

    @pytest.fixture
    def crd_watcher(self, spec_factory, deploy_queue, watcher, lifecycle):
        crd_watcher = CrdWatcher(spec_factory, deploy_queue, Configuration([]),
                                 lifecycle)
        crd_watcher._watcher = watcher
        return crd_watcher

    @pytest.fixture(autouse=True)
    def status_get(self):
        with mock.patch(
                "fiaas_deploy_daemon.crd.status.FiaasApplicationStatus.get",
                spec_set=True) as m:
            m.side_effect = NotFound
            yield m

    def test_creates_custom_resource_definition_if_not_exists_when_watching_it(
            self, get, post, crd_watcher, watcher):
        get.side_effect = NotFound("Something")
        watcher.watch.side_effect = NotFound("Something")

        expected_application = {
            'metadata': {
                'namespace': 'default',
                'name': 'applications.fiaas.schibsted.io',
                'ownerReferences': [],
                'finalizers': [],
            },
            'spec': {
                'version': 'v1',
                'group': 'fiaas.schibsted.io',
                'names': {
                    'shortNames': ['app', 'fa'],
                    'kind': 'Application',
                    'plural': 'applications'
                }
            }
        }
        expected_status = {
            'metadata': {
                'namespace': 'default',
                'name': 'application-statuses.fiaas.schibsted.io',
                'ownerReferences': [],
                'finalizers': [],
            },
            'spec': {
                'version': 'v1',
                'group': 'fiaas.schibsted.io',
                'names': {
                    'shortNames': ['status', 'appstatus', 'fs'],
                    'kind': 'ApplicationStatus',
                    'plural': 'application-statuses'
                }
            }
        }

        def make_response(data):
            mock_response = mock.create_autospec(Response)
            mock_response.json.return_value = data
            return mock_response

        post.side_effect = [
            make_response(expected_application),
            make_response(expected_status)
        ]

        crd_watcher._watch(None)

        calls = [
            mock.call(
                "/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions/",
                expected_application),
            mock.call(
                "/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions/",
                expected_status)
        ]
        assert post.call_args_list == calls

    def test_is_able_to_watch_custom_resource_definition(
            self, crd_watcher, deploy_queue, watcher):
        watcher.watch.return_value = [WatchEvent(ADD_EVENT, FiaasApplication)]

        assert deploy_queue.qsize() == 0
        crd_watcher._watch(None)
        assert deploy_queue.qsize() == 1

    @pytest.mark.parametrize(
        "event,deployer_event_type,annotations,repository", [
            (ADD_EVENT, "UPDATE", None, None),
            (ADD_EVENT, "UPDATE", {
                "deployment": {
                    "fiaas/source-repository": "xyz"
                }
            }, "xyz"),
            (MODIFIED_EVENT, "UPDATE", None, None),
            (MODIFIED_EVENT, "UPDATE", {
                "deployment": {
                    "fiaas/source-repository": "xyz"
                }
            }, "xyz"),
            (DELETED_EVENT, "DELETE", None, None),
        ])
    def test_deploy(self, crd_watcher, deploy_queue, spec_factory, watcher,
                    app_spec, event, deployer_event_type, lifecycle,
                    annotations, repository):
        event["object"]["spec"]["config"]["annotations"] = annotations
        watcher.watch.return_value = [WatchEvent(event, FiaasApplication)]

        spec = event["object"]["spec"]
        app_name = spec["application"]
        namespace = event["object"]["metadata"]["namespace"]
        deployment_id = (
            event["object"]["metadata"]["labels"]["fiaas/deployment_id"]
            if deployer_event_type != "DELETE" else "deletion")

        app_spec = app_spec._replace(name=app_name,
                                     namespace=namespace,
                                     deployment_id=deployment_id)
        spec_factory.return_value = app_spec
        lifecycle_subject = Subject(app_name, namespace, deployment_id,
                                    repository, app_spec.labels.status,
                                    app_spec.annotations.status)
        lifecycle.initiate.return_value = lifecycle_subject

        crd_watcher._watch(None)

        if event in [ADD_EVENT, MODIFIED_EVENT]:
            lifecycle.initiate.assert_called_once_with(
                app_name=event["object"]["spec"]["application"],
                namespace=event["object"]["metadata"]["namespace"],
                deployment_id='deployment_id',
                repository=repository,
                labels=None,
                annotations=None)

        app_config = spec["config"]
        additional_labels = AdditionalLabelsOrAnnotations()
        additional_annotations = AdditionalLabelsOrAnnotations()
        spec_factory.assert_called_once_with(
            name=app_name,
            image=spec["image"],
            app_config=app_config,
            teams=[],
            tags=[],
            deployment_id=deployment_id,
            namespace=namespace,
            additional_labels=additional_labels,
            additional_annotations=additional_annotations)

        assert deploy_queue.qsize() == 1
        deployer_event = deploy_queue.get_nowait()
        if event in [ADD_EVENT, MODIFIED_EVENT]:
            assert deployer_event == DeployerEvent(deployer_event_type,
                                                   app_spec, lifecycle_subject)
        else:
            assert deployer_event == DeployerEvent(deployer_event_type,
                                                   app_spec, None)
        assert deploy_queue.empty()

    @pytest.mark.parametrize("namespace", [None, "default"])
    def test_watch_namespace(self, crd_watcher, watcher, namespace):
        crd_watcher._watch(namespace)
        watcher.watch.assert_called_once_with(namespace=namespace)

    @pytest.mark.parametrize(
        "event,deployer_event_type,error,annotations,repository", [
            (ADD_EVENT, "UPDATE", YAMLError("invalid yaml"), {}, None),
            (ADD_EVENT, "UPDATE", InvalidConfiguration("invalid config"), {},
             None),
            (MODIFIED_EVENT, "UPDATE", YAMLError("invalid yaml"), {}, None),
            (MODIFIED_EVENT, "UPDATE", InvalidConfiguration("invalid config"),
             {}, None),
            (MODIFIED_EVENT, "UPDATE", InvalidConfiguration("invalid config"),
             {
                 "deployment": {
                     "fiaas/source-repository": "xyz"
                 }
             }, "xyz"),
        ])
    def test_deploy_reports_failure_on_exception(
            self, crd_watcher, deploy_queue, spec_factory, watcher, event,
            deployer_event_type, error, lifecycle, annotations, repository):
        event["object"]["metadata"]["annotations"] = annotations
        watcher.watch.return_value = [WatchEvent(event, FiaasApplication)]

        spec_factory.side_effect = error

        lifecycle_subject = Subject(
            app_name=event["object"]["spec"]["application"],
            namespace=event["object"]["metadata"]["namespace"],
            deployment_id='deployment_id',
            repository=repository,
            labels=None,
            annotations=None)
        lifecycle.initiate.return_value = lifecycle_subject

        crd_watcher._watch(None)

        lifecycle.failed.assert_called_once_with(lifecycle_subject)
        assert deploy_queue.empty()

    @pytest.mark.parametrize("result, count", (
        ("SUCCESS", 0),
        ("FAILED", 1),
        ("RUNNING", 1),
        ("INITIATED", 1),
        ("ANY_OTHER_VALUE_THAN_SUCCESS", 1),
    ))
    def test_deploy_based_on_status_result(self, crd_watcher, deploy_queue,
                                           watcher, status_get, result, count):
        watcher.watch.return_value = [WatchEvent(ADD_EVENT, FiaasApplication)]
        status_get.side_effect = lambda *args, **kwargs: mock.DEFAULT  # disable default behavior of raising NotFound
        status_get.return_value = FiaasApplicationStatus(new=False,
                                                         result=result)

        assert deploy_queue.qsize() == 0
        crd_watcher._watch(None)
        assert deploy_queue.qsize() == count
class TestTprWatcher(object):
    @pytest.fixture
    def spec_factory(self):
        with mock.patch(
                "fiaas_deploy_daemon.specs.factory.SpecFactory") as mockk:
            yield mockk

    @pytest.fixture
    def deploy_queue(self):
        return Queue()

    @pytest.fixture
    def watcher(self):
        return mock.create_autospec(spec=Watcher, spec_set=True, instance=True)

    @pytest.fixture
    def lifecycle(self):
        return mock.create_autospec(spec=Lifecycle,
                                    spec_set=True,
                                    instance=True)

    @pytest.fixture
    def tpr_watcher(self, spec_factory, deploy_queue, watcher, lifecycle):
        mock_watcher = TprWatcher(spec_factory, deploy_queue,
                                  Configuration([]), lifecycle)
        mock_watcher._watcher = watcher
        return mock_watcher

    def test_creates_third_party_resource_if_not_exists_when_watching_it(
            self, get, post, tpr_watcher, watcher):
        get.side_effect = NotFound("Something")
        watcher.watch.side_effect = NotFound("Something")

        expected_application = {
            'metadata': {
                'namespace': 'default',
                'name': 'paasbeta-application.schibsted.io',
                'ownerReferences': [],
                'finalizers': [],
            },
            'description': 'A paas application definition',
            'versions': [{
                'name': 'v1beta'
            }]
        }
        expected_status = {
            'metadata': {
                'namespace': 'default',
                'name': 'paasbeta-status.schibsted.io',
                'ownerReferences': [],
                'finalizers': [],
            },
            'description': 'A paas application status',
            'versions': [{
                'name': 'v1beta'
            }]
        }

        def make_response(data):
            mock_response = mock.create_autospec(Response)
            mock_response.json.return_value = data
            return mock_response

        post.side_effect = [
            make_response(expected_application),
            make_response(expected_status)
        ]

        tpr_watcher._watch(None)

        calls = [
            mock.call("/apis/extensions/v1beta1/thirdpartyresources/",
                      expected_application),
            mock.call("/apis/extensions/v1beta1/thirdpartyresources/",
                      expected_status)
        ]
        assert post.call_args_list == calls

    def test_is_able_to_watch_third_party_resource(self, tpr_watcher,
                                                   deploy_queue, watcher):
        watcher.watch.return_value = [
            WatchEvent(ADD_EVENT, PaasbetaApplication)
        ]

        assert deploy_queue.qsize() == 0
        tpr_watcher._watch(None)
        assert deploy_queue.qsize() == 1

    @pytest.mark.parametrize(
        "event,deployer_event_type,annotations,repository", [
            (ADD_EVENT, "UPDATE", None, None),
            (ADD_EVENT, "UPDATE", {
                "deployment": {
                    "fiaas/source-repository": "xyz"
                }
            }, "xyz"),
            (MODIFIED_EVENT, "UPDATE", None, None),
            (MODIFIED_EVENT, "UPDATE", {
                "deployment": {
                    "fiaas/source-repository": "xyz"
                }
            }, "xyz"),
            (DELETED_EVENT, "DELETE", None, None),
        ])
    def test_deploy(self, tpr_watcher, deploy_queue, spec_factory, watcher,
                    app_spec, event, deployer_event_type, lifecycle,
                    annotations, repository):
        event["object"]["metadata"]["annotations"] = annotations
        watcher.watch.return_value = [WatchEvent(event, PaasbetaApplication)]

        spec = event["object"]["spec"]
        app_name = spec["application"]
        namespace = event["object"]["metadata"]["namespace"]
        deployment_id = (
            event["object"]["metadata"]["labels"]["fiaas/deployment_id"]
            if deployer_event_type != "DELETE" else "deletion")

        app_spec = app_spec._replace(name=app_name,
                                     namespace=namespace,
                                     deployment_id=deployment_id)
        spec_factory.return_value = app_spec

        tpr_watcher._watch(None)

        if event in [ADD_EVENT, MODIFIED_EVENT]:
            lifecycle.initiate.assert_called_once_with(
                app_name=event["object"]["spec"]["application"],
                namespace=event["object"]["metadata"]["namespace"],
                deployment_id='deployment_id',
                repository=repository)
        app_config = spec["config"]
        spec_factory.assert_called_once_with(name=app_name,
                                             image=spec["image"],
                                             app_config=app_config,
                                             teams=[],
                                             tags=[],
                                             deployment_id=deployment_id,
                                             namespace=namespace)

        assert deploy_queue.qsize() == 1
        deployer_event = deploy_queue.get_nowait()
        assert deployer_event == DeployerEvent(deployer_event_type, app_spec)
        assert deploy_queue.empty()

    @pytest.mark.parametrize("namespace", [None, "default"])
    def test_watch_namespace(self, tpr_watcher, watcher, namespace):
        tpr_watcher._watch(namespace)
        watcher.watch.assert_called_once_with(namespace=namespace)

    @pytest.mark.parametrize(
        "event,deployer_event_type,error,annotations,repository", [
            (ADD_EVENT, "UPDATE", YAMLError("invalid yaml"), None, None),
            (ADD_EVENT, "UPDATE", InvalidConfiguration("invalid config"), None,
             None),
            (MODIFIED_EVENT, "UPDATE", YAMLError("invalid yaml"), None, None),
            (MODIFIED_EVENT, "UPDATE", InvalidConfiguration("invalid config"),
             None, None),
            (MODIFIED_EVENT, "UPDATE", InvalidConfiguration("invalid config"),
             {
                 "deployment": {
                     "fiaas/source-repository": "xyz"
                 }
             }, "xyz"),
        ])
    def test_deploy_reports_failure_on_exception(
            self, tpr_watcher, deploy_queue, spec_factory, watcher, event,
            deployer_event_type, error, lifecycle, annotations, repository):
        event["object"]["metadata"]["annotations"] = annotations
        watcher.watch.return_value = [WatchEvent(event, PaasbetaApplication)]

        spec_factory.side_effect = error

        tpr_watcher._watch(None)

        lifecycle.failed.assert_called_once_with(
            app_name=event["object"]["spec"]["application"],
            namespace=event["object"]["metadata"]["namespace"],
            deployment_id='deployment_id',
            repository=repository)
        assert deploy_queue.empty()
예제 #12
0
 def test_main_raises_ConfigurationParsingError_on_load_YAMLError(
         self, mockOpen, mockYamlLoad):
     mockYamlLoad.side_effect = YAMLError('boom')
     with self.assertRaises(ConfigurationParsingError):
         main('file')
예제 #13
0
 def test_load_config(self, mock):
     mock.side_effect = [self.config, IOError(), YAMLError()]
     self.assertEqual(main.load_config(), self.config)
     self.assertEqual(main.load_config(), {})
     self.assertEqual(main.load_config(), {})
     self.assertIn("ooni", self.config)
예제 #14
0
def fails(*args, **kwargs):
    raise YAMLError()