Ejemplo n.º 1
0
    def test_service_configuration(self):
        invalid_config = {"active": True, SERVICE_URL_PARAM: ""}
        valid_config = {
            "active": True,
            SERVICE_URL_PARAM: "https://service.domain",
            SERVICE_WORKSPACE_DIR_PARAM: "/"
        }

        # Should raise if the config does not include a required param
        with pytest.raises(ServiceConfigurationException):
            GoodService(ServiceFactory().settings, "GoodService",
                        **invalid_config)

        # Should raise if the service does not define its required params
        with pytest.raises(NotImplementedError):
            BadService(ServiceFactory().settings, "BadService", **valid_config)

        # Should raise if a service defines an invalid param
        with pytest.raises(Exception):
            BadParamService("BadParamService", **valid_config)

        svc = GoodService(ServiceFactory().settings, "GoodService",
                          **valid_config)
        assert getattr(svc,
                       SERVICE_URL_PARAM) == valid_config[SERVICE_URL_PARAM]
        assert getattr(svc, SERVICE_WORKSPACE_DIR_PARAM
                       ) == valid_config[SERVICE_WORKSPACE_DIR_PARAM]
Ejemplo n.º 2
0
    def test_service_factory(self):
        # Test singleton
        inst1 = ServiceFactory().get_service("Magpie")
        inst2 = ServiceFactory().get_service("Magpie")
        assert inst1 is inst2
        assert len(ServiceFactory().services) == 1
        assert ServiceFactory().services["Magpie"] is inst1

        # Test services config
        active_services = [
            service.name for service in ServiceFactory().get_active_services()
        ]
        # Every active service should be in test data
        for service in active_services:
            assert service in TestServiceFactory.test_data["services"]
            assert TestServiceFactory.test_data["services"][service]["active"]

        # Every activated test service should be in the active services
        for test_service, config in TestServiceFactory.test_data[
                "services"].items():
            if config["active"]:
                assert test_service in active_services
            else:
                assert test_service not in active_services

        # Prioritize services should appear in the proper order
        for idx, svc in enumerate(self.priority):
            assert active_services[idx] == svc
Ejemplo n.º 3
0
    def test_webhooks(self):
        with contextlib.ExitStack() as stack:
            stack.enter_context(
                mock.patch("cowbird.services.impl.magpie.Magpie",
                           side_effect=utils.MockMagpieService))
            data = {
                "event":
                "created",
                "user_name":
                "test_user",
                "callback_url":
                "http://magpie.domain.ca/tmp/109e1d0d-e27c-4601-9d45-984c9b61ebff"
            }
            resp = utils.test_request(self.app,
                                      "POST",
                                      "/webhooks/users",
                                      json=data)
            utils.check_response_basic_info(resp, 200, expected_method="POST")
            utils.check_response_basic_info(resp)
            magpie = ServiceFactory().get_service("Magpie")
            assert len(magpie.json()["event_users"]) == 1
            assert magpie.json()["event_users"][0] == data["user_name"]

            data["event"] = "deleted"
            data.pop("callback_url")
            resp = utils.test_request(self.app,
                                      "POST",
                                      "/webhooks/users",
                                      json=data)
            utils.check_response_basic_info(resp, 200, expected_method="POST")
            assert len(magpie.json()["event_users"]) == 0

            data = {
                "event": "created",
                "service_name": "string",
                "resource_id": "string",
                "resource_full_name": "thredds/birdhouse/file.nc",
                "name": "read",
                "access": "allow",
                "scope": "recursive",
                "user": "******",
                "group": "string"
            }
            resp = utils.test_request(self.app,
                                      "POST",
                                      "/webhooks/permissions",
                                      json=data)
            utils.check_response_basic_info(resp, 200, expected_method="POST")
            magpie = ServiceFactory().get_service("Magpie")
            assert len(magpie.json()["event_perms"]) == 1
            assert magpie.json(
            )["event_perms"][0] == data["resource_full_name"]

            data["event"] = "deleted"
            resp = utils.test_request(self.app,
                                      "POST",
                                      "/webhooks/permissions",
                                      json=data)
            utils.check_response_basic_info(resp, 200, expected_method="POST")
            assert len(magpie.json()["event_perms"]) == 0
Ejemplo n.º 4
0
def dispatch(svc_fct):
    exceptions = []
    event_name = inspect.getsource(svc_fct).split(":")[1].strip()
    for svc in ServiceFactory().get_active_services():
        # Allow every service to be notified even if one of them throw an error
        try:
            LOGGER.info("Dispatching event [%s] for service [%s]", event_name, svc.name)
            svc_fct(svc)
        except Exception as exception:  # noqa
            exceptions.append(exception)
            LOGGER.error("Exception raised while handling event [%s] for service [%s] : [%r]",
                         event_name, svc.name, exception)
    if exceptions:
        raise Exception(exceptions)
Ejemplo n.º 5
0
    def __init__(self,
                 services,    # type: SyncPointServicesType
                 mapping      # type: SyncPointMappingType
                 ):           # type: (...) -> None
        """
        Init the sync point, holding services with their respective resources root and how access are mapped between
        them.

        @param services: Dict, where the service is the key and its resources root is the value
        @param mapping: List of dict where the service is the key and an access list is the value
        """
        available_services = ServiceFactory().services_cfg.keys()
        # Make sure that only active services are used
        self.services = {svc: svc_cfg for svc, svc_cfg in services.items() if svc in available_services}
        self.mapping = [{svc: perms for svc, perms in mapping_pt.items() if svc in available_services}
                        for mapping_pt in mapping]
Ejemplo n.º 6
0
    def sync(self, perm_operation, permission):
        # type: (Callable[Permission], Permission) -> None
        """
        Create or delete the same permission on each service sharing the same resource.

        @param perm_operation Magpie create_permission or delete_permission function
        @param permission Permission to synchronize with others services
        """
        res_common_part_idx = len(self.services[permission.service_name])
        for svc, perm_name in self.find_match(permission):
            new_permission = copy.copy(permission)
            new_permission.service_name = svc
            new_permission.resource_full_name = self.services[svc] + \
                permission.resource_full_name[res_common_part_idx:]
            new_permission.resource_id = ServiceFactory().get_service(svc).get_resource_id(
                new_permission.resource_full_name)
            new_permission.name = perm_name
            perm_operation(new_permission)
Ejemplo n.º 7
0
 def get_instance():
     """
     Return the Geoserver singleton instance from the class name used to retrieve the FSMonitor from the DB.
     """
     return ServiceFactory().get_service("Geoserver")
Ejemplo n.º 8
0
def test_register_unregister_monitor():
    with tempfile.TemporaryDirectory() as tmpdir:
        test_file = os.path.join(tmpdir, "testfile")
        test_subdir = os.path.join(tmpdir, "subdir")
        test_subdir_file = os.path.join(test_subdir, "test_subdir_file")
        mv_test_file = os.path.join(test_subdir, "moved_testfile")
        mv_test_subdir_file = os.path.join(tmpdir, "moved_test_subdir_file")
        os.mkdir(test_subdir)

        # Test registering directly a callback instance
        mon = TestMonitor()
        internal_mon = Monitoring().register(tmpdir, False, mon)
        assert internal_mon.callback_instance == mon

        # Test registering a callback via class name
        internal_mon2 = Monitoring().register(tmpdir, True, TestMonitor2)
        mon2 = internal_mon2.callback_instance
        internal_mon3 = Monitoring().register(test_subdir, False, TestMonitor)
        mon3 = internal_mon3.callback_instance
        assert isinstance(mon2, TestMonitor2)
        assert isinstance(mon3, TestMonitor)

        # Test collision when 2 monitors are registered using the same path and class name
        assert not internal_mon3.recursive
        internal_mon4 = Monitoring().register(test_subdir, True, TestMonitor)
        assert internal_mon4 is internal_mon3
        assert internal_mon3.recursive  # Recursive should take precedence when a collision occurs

        # monitors first level is distinct path to monitor : (tmp_dir and test_subdir)
        assert len(Monitoring().monitors) == 2

        # monitors second level is distinct callback, for tmpdir : (TestMonitor and TestMonitor2)
        assert len(Monitoring().monitors[tmpdir]) == 2

        # Do some io operations that should be picked by the monitors
        file_io(test_file, mv_test_file)
        file_io(test_subdir_file, mv_test_subdir_file)
        sleep(1)

        # Root dir non-recursive
        assert len(mon.created) == 2
        assert mon.created[0] == test_file
        assert mon.created[1] == mv_test_subdir_file
        assert mon.created == mon.deleted
        assert sorted(set(mon.modified)) == [tmpdir, test_file]

        # Root dir recursive
        assert len(mon2.created) == 4
        assert mon2.created[0] == test_file
        assert mon2.created[1] == mv_test_file
        assert mon2.created[2] == test_subdir_file
        assert mon2.created[3] == mv_test_subdir_file
        assert mon2.created == mon2.deleted
        assert sorted(set(mon2.modified)) == [tmpdir, test_subdir,
                                              test_subdir_file, test_file]

        # Subdir
        assert len(mon3.created) == 2
        assert mon3.created[0] == mv_test_file
        assert mon3.created[1] == test_subdir_file
        assert mon3.created == mon3.deleted
        assert sorted(set(mon3.modified)) == [test_subdir,
                                              test_subdir_file]

        # Validate cleanup
        Monitoring().unregister(tmpdir, mon)
        Monitoring().unregister(tmpdir, mon2)
        assert not Monitoring().unregister(test_subdir, mon2)  # Here we try to unregister a path with a bad class type
        Monitoring().unregister(test_subdir, mon3)  # Here we have the good class type
        assert len(Monitoring().monitors) == 0
        assert not Monitoring().unregister(tmpdir, mon)

        # Test registering a callback via a qualified class name string
        catalog_mon = Monitoring().register(tmpdir, False, "cowbird.services.impl.catalog.Catalog").callback_instance
        assert catalog_mon == ServiceFactory().get_service("Catalog")
    def test_sync(self):
        """
        This test parses the sync config and checks that when a permission is created in the `PermissionSynchronizer`
        the proper permission is created for every synchronized service.

        The `PermissionSynchronizer` `create_permission` function will first find if the applied permission exists in
        the config. Then for every configured service it will obtain the equivalent permission for this service and
        apply it to the mocked Magpie service. The `outbound_perm` dict of the mocked Magpie service is then checked
        to validate that every permission that should have been created in Magpie exists.
        """
        with contextlib.ExitStack() as stack:
            stack.enter_context(mock.patch("cowbird.services.impl.magpie.Magpie",
                                           side_effect=utils.MockMagpieService))
            stack.enter_context(mock.patch("cowbird.services.impl.geoserver.Geoserver",
                                           side_effect=utils.MockAnyService))
            stack.enter_context(mock.patch("cowbird.services.impl.thredds.Thredds",
                                           side_effect=utils.MockAnyService))

            magpie = ServiceFactory().get_service("Magpie")

            resource_name = "resource1"
            # Loop over every service having a permission that must be synchronized to another one
            for svc in self.test_services:
                for perm_name in self.sync_perm_name[svc]:
                    # Create the permission for this service that would be provided by `Magpie` as a hook
                    permission = Permission(
                        service_name=svc,
                        resource_id="0",
                        resource_full_name=self.res_root[svc] + resource_name,
                        name=perm_name,
                        access="string1",
                        scope="string2",
                        user="******")

                    # Apply this permission to the synchronizer (this is the function that is tested!)
                    PermissionSynchronizer(magpie).create_permission(permission)

                    # `magpie`, which is mocked, will store every permission request that should have been done to the
                    # Magpie service in the `outbound_perms` dict.
                    assert len(magpie.json()["outbound_perms"]) == len(self.sync_perm_name[self.mapped_service[svc]])

                    # Validate that the mocked `magpie` instance has received a permission request for every mapped
                    # permission
                    for idx, mapped_perm_name in enumerate(self.sync_perm_name[self.mapped_service[svc]]):
                        outbound_perm = magpie.json()["outbound_perms"][idx]
                        assert outbound_perm.service_name == self.mapped_service[svc]
                        assert outbound_perm.resource_id == utils.MockAnyService.ResourceId
                        assert outbound_perm.resource_full_name == \
                            self.res_root[self.mapped_service[svc]] + resource_name
                        assert outbound_perm.name == mapped_perm_name
                        assert outbound_perm.access == permission.access
                        assert outbound_perm.scope == permission.scope
                        assert outbound_perm.user == permission.user

                    # This is the second function being tested which should make remove permission requests to `magpie`
                    # for every mapped permission
                    PermissionSynchronizer(magpie).delete_permission(permission)

                    # Again the mocked `magpie` instance should remove every permission from its `outbound_perms` rather
                    # than making the remove permission request to the Magpie service.
                    assert len(magpie.json()["outbound_perms"]) == 0
Ejemplo n.º 10
0
 def get_instance():
     """
     Return the Catalog singleton instance from the class name used to retrieve the FSMonitor from the DB.
     """
     from cowbird.services.service_factory import ServiceFactory
     return ServiceFactory().get_service("Catalog")
Ejemplo n.º 11
0
def get_services(container):
    # type: (AnySettingsContainer) -> List[Service]
    """
    Obtains the services managed by the application.
    """
    return ServiceFactory().get_active_services()