Example #1
0
    async def unregister(cls, request):
        """ Unregister a service

        :Example: curl -X DELETE  http://localhost:8082/foglamp/service/dc9bfc01-066a-4cc0-b068-9c35486db87f
        """

        try:
            service_id = request.match_info.get('service_id', None)

            if not service_id:
                raise web.HTTPBadRequest(reason='Service id is required')

            try:
                ServiceRegistry.get(idx=service_id)
            except service_registry_exceptions.DoesNotExist:
                raise web.HTTPBadRequest(
                    reason='Service with {} does not exist'.format(service_id))

            ServiceRegistry.unregister(service_id)

            _resp = {'id': str(service_id), 'message': 'Service unregistered'}

            return web.json_response(_resp)
        except ValueError as ex:
            raise web.HTTPNotFound(reason=str(ex))
Example #2
0
    async def test__monitor_good_uptime(self):
        async def async_mock(return_value):
            return return_value

        # used to mock client session context manager

        class AsyncSessionContextManagerMock(MagicMock):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)

            async def __aenter__(self):
                client_response_mock = MagicMock(spec=aiohttp.ClientResponse)
                # mock response (good)
                client_response_mock.text.side_effect = [
                    async_mock('{"uptime": "bla"}')
                ]
                return client_response_mock

            async def __aexit__(self, *args):
                return None

        # as monitor loop is as infinite loop, this exception is thrown when we need to exit the loop

        class TestMonitorException(Exception):
            pass

        # register a service
        with patch.object(ServiceRegistry._logger, 'info') as log_info:
            s_id_1 = ServiceRegistry.register('sname1', 'Storage', 'saddress1',
                                              1, 1, 'protocol1')
        assert 1 == log_info.call_count
        args, kwargs = log_info.call_args
        assert args[0].startswith('Registered service instance id=')
        assert args[0].endswith(
            ': <sname1, type=Storage, protocol=protocol1, address=saddress1, service port=1, '
            'management port=1, status=1>')
        monitor = Monitor()
        monitor._sleep_interval = Monitor._DEFAULT_SLEEP_INTERVAL
        monitor._max_attempts = Monitor._DEFAULT_MAX_ATTEMPTS

        # throw the TestMonitorException when sleep is called (end of infinite loop)
        with patch.object(Monitor,
                          '_sleep',
                          side_effect=TestMonitorException()):
            with patch.object(aiohttp.ClientSession,
                              'get',
                              return_value=AsyncSessionContextManagerMock()):
                with pytest.raises(Exception) as excinfo:
                    await monitor._monitor_loop()
                assert excinfo.type is TestMonitorException
        # service is good, so it should remain in the service registry
        assert len(ServiceRegistry.get(idx=s_id_1)) is 1
        assert ServiceRegistry.get(
            idx=s_id_1)[0]._status is ServiceRecord.Status.Running
Example #3
0
    async def get_service(cls, request):
        """ Returns a list of all services or as per name &|| type filter

        :Example:
            curl -X GET  http://localhost:<core mgt port>/foglamp/service
            curl -X GET  http://localhost:<core mgt port>/foglamp/service?name=X&type=Storage
        """
        service_name = request.query[
            'name'] if 'name' in request.query else None
        service_type = request.query[
            'type'] if 'type' in request.query else None

        try:
            if not service_name and not service_type:
                services_list = ServiceRegistry.all()
            elif service_name and not service_type:
                services_list = ServiceRegistry.get(name=service_name)
            elif not service_name and service_type:
                services_list = ServiceRegistry.get(s_type=service_type)
            else:
                services_list = ServiceRegistry.filter_by_name_and_type(
                    name=service_name, s_type=service_type)
        except service_registry_exceptions.DoesNotExist as ex:
            if not service_name and not service_type:
                msg = 'No service found'
            elif service_name and not service_type:
                msg = 'Service with name {} does not exist'.format(
                    service_name)
            elif not service_name and service_type:
                msg = 'Service with type {} does not exist'.format(
                    service_type)
            else:
                msg = 'Service with name {} and type {} does not exist'.format(
                    service_name, service_type)

            raise web.HTTPNotFound(reason=msg)

        services = []
        for service in services_list:
            svc = dict()
            svc["id"] = service._id
            svc["name"] = service._name
            svc["type"] = service._type
            svc["address"] = service._address
            svc["management_port"] = service._management_port
            svc["protocol"] = service._protocol
            svc["status"] = ServiceRecord.Status(int(
                service._status)).name.lower()
            if service._port:
                svc["service_port"] = service._port
            services.append(svc)

        return web.json_response({"services": services})
Example #4
0
 async def test_get_fail(self):
     with pytest.raises(DoesNotExist) as excinfo:
         with patch.object(Service._logger, 'info') as log_info:
             Service.register("StorageService", "Storage", "127.0.0.1",
                              8888, 9999)
             Service.get('incorrect_id')
         assert 1 == log_info.call_count
         args, kwargs = log_info.call_args
         assert args[0].startswith('Registered service instance id=')
         assert args[0].endswith(
             ': <StorageService1, type=Storage, protocol=http, address=127.0.0.1, service port=8888,'
             ' management port=9999, status=1>')
     assert str(excinfo).endswith('DoesNotExist')
Example #5
0
    async def test_unregister(self):
        # register a service
        idx = Service.register("StorageService2", "Storage", "127.0.0.1", 8888,
                               1888)
        assert str(uuid.UUID(idx, version=4)) == idx

        # deregister the same
        t = Service.unregister(idx)
        assert idx == t

        with pytest.raises(DoesNotExist) as excinfo:
            Service.get(idx)
        assert str(excinfo).endswith('DoesNotExist')
Example #6
0
    async def unregister(cls, request):
        """ Unregister a service

        :Example:
            curl -X DELETE  http://localhost:<core mgt port>/foglamp/service/dc9bfc01-066a-4cc0-b068-9c35486db87f
        """

        try:
            service_id = request.match_info.get('service_id', None)

            try:
                services = ServiceRegistry.get(idx=service_id)
            except service_registry_exceptions.DoesNotExist:
                raise ValueError(
                    'Service with {} does not exist'.format(service_id))

            ServiceRegistry.unregister(service_id)

            if cls._storage_client_async is not None and services[
                    0]._name not in ("FogLAMP Storage", "FogLAMP Core"):
                try:
                    cls._audit = AuditLogger(cls._storage_client_async)
                    await cls._audit.information('SRVUN',
                                                 {'name': services[0]._name})
                except Exception as ex:
                    _logger.exception(str(ex))

            _resp = {'id': str(service_id), 'message': 'Service unregistered'}

            return web.json_response(_resp)
        except ValueError as ex:
            raise web.HTTPNotFound(reason=str(ex))
Example #7
0
    async def test_get(self):
        s = Service.register("StorageService", "Storage", "localhost", 8881, 1888)
        c = Service.register("CoreService", "Core", "localhost", 7771, 1777)
        d = Service.register("SouthService", "Southbound", "127.0.0.1", 9991, 1999, "https")

        l = Service.get()
        assert 3 == len(l)

        assert s == l[0]._id
        assert "StorageService" == l[0]._name
        assert "Storage" == l[0]._type
        assert "localhost" == l[0]._address
        assert 8881 == int(l[0]._port)
        assert 1888 == int(l[0]._management_port)
        # validates default set to HTTP
        assert "http" == l[0]._protocol

        assert c == l[1]._id
        assert "CoreService" == l[1]._name
        assert "Core" == l[1]._type
        assert "localhost" == l[1]._address
        assert 7771 == int(l[1]._port)
        assert 1777 == int(l[1]._management_port)
        # validates default set to HTTP
        assert "http" == l[1]._protocol

        assert d == l[2]._id
        assert "SouthService" == l[2]._name
        assert "Southbound" == l[2]._type
        assert "127.0.0.1" == l[2]._address
        assert 9991 == int(l[2]._port)
        assert 1999 == int(l[2]._management_port)
        assert "https" == l[2]._protocol
Example #8
0
    async def test_unregister(self, mocker):
        # register a service
        with patch.object(Service._logger, 'info') as log_info:
            idx = Service.register("StorageService2", "Storage", "127.0.0.1",
                                   8888, 1888)
            assert str(uuid.UUID(idx, version=4)) == idx
        assert 1 == log_info.call_count
        arg, kwarg = log_info.call_args
        assert arg[0].startswith('Registered service instance id=')
        assert arg[0].endswith(
            ': <StorageService2, type=Storage, protocol=http, address=127.0.0.1, service port=8888,'
            ' management port=1888, status=1>')

        mocker.patch.object(InterestRegistry, '__init__', return_value=None)
        mocker.patch.object(InterestRegistry, 'get', return_value=list())

        # deregister the same
        with patch.object(Service._logger, 'info') as log_info2:
            t = Service.unregister(idx)
            assert idx == t
        assert 1 == log_info2.call_count
        args, kwargs = log_info2.call_args
        assert args[0].startswith('Stopped service instance id=')
        assert args[0].endswith(
            ': <StorageService2, type=Storage, protocol=http, address=127.0.0.1, '
            'service port=8888, management port=1888, status=2>')

        s = Service.get(idx)
        assert s[0]._status == 2  # Unregistered
Example #9
0
async def get_plugin(request):
    """ GET lists of rule plugins and delivery plugins

    :Example:
        curl -X GET http://localhost:8081/foglamp/notification/plugin
    """
    try:
        notification_service = ServiceRegistry.get(
            s_type=ServiceRecord.Type.Notification.name)
        _address, _port = notification_service[
            0]._address, notification_service[0]._port
    except service_registry_exceptions.DoesNotExist:
        raise web.HTTPNotFound(reason="No Notification service available.")

    try:
        url = 'http://{}:{}/notification/rules'.format(_address, _port)
        rule_plugins = json.loads(await _hit_get_url(url))

        url = 'http://{}:{}/notification/delivery'.format(_address, _port)
        delivery_plugins = json.loads(await _hit_get_url(url))
    except Exception as ex:
        raise web.HTTPInternalServerError(reason=ex)
    else:
        return web.json_response({
            'rules': rule_plugins,
            'delivery': delivery_plugins
        })
    def test_unregister(self, mocker):
        mocker.patch.object(InterestRegistry, '__init__', return_value=None)
        mocker.patch.object(InterestRegistry, 'get', return_value=list())

        with patch.object(ServiceRegistry._logger, 'info') as log_info1:
            reg_id = ServiceRegistry.register("A name", "Storage", "127.0.0.1",
                                              1234, 4321, 'http')
            assert 1 == len(ServiceRegistry._registry)
        assert 1 == log_info1.call_count
        arg, kwarg = log_info1.call_args
        assert arg[0].startswith('Registered service instance id=')
        assert arg[0].endswith(
            ': <A name, type=Storage, protocol=http, address=127.0.0.1, service port=1234,'
            ' management port=4321, status=1>')

        with patch.object(ServiceRegistry._logger, 'info') as log_info2:
            s_id = ServiceRegistry.unregister(reg_id)
            assert 36 == len(s_id)  # uuid version 4 len
            assert 1 == len(ServiceRegistry._registry)
            s = ServiceRegistry.get(idx=s_id)
            assert s[0]._status == 2
        assert 1 == log_info2.call_count
        args, kwargs = log_info2.call_args
        assert args[0].startswith('Stopped service instance id=')
        assert args[0].endswith(
            ': <A name, type=Storage, protocol=http, address=127.0.0.1, service port=1234,'
            ' management port=4321, status=2>')
Example #11
0
    def stop_storage(cls):
        """ stop Storage service """

        # TODO: FOGL-653 shutdown implementation
        # remove me, and allow this call in service registry API

        found_services = ServiceRegistry.get(name="FogLAMP Storage")
        svc = found_services[0]
        if svc is None:
            return

        management_api_url = '{}:{}'.format(svc._address, svc._management_port)

        conn = http.client.HTTPConnection(management_api_url)
        # TODO: need to set http / https based on service protocol

        conn.request('POST', url='/foglamp/service/shutdown', body=None)
        r = conn.getresponse()

        # TODO: FOGL-615
        # log error with message if status is 4xx or 5xx
        if r.status in range(400, 500):
            _logger.error("Client error code: %d", r.status)
        if r.status in range(500, 600):
            _logger.error("Server error code: %d", r.status)

        res = r.read().decode()
        conn.close()
        return json.loads(res)
Example #12
0
async def _services_with_assets(storage_client, south_services):
    sr_list = list()
    try:
        try:
            services_from_registry = ServiceRegistry.get(s_type="Southbound")
        except DoesNotExist:
            services_from_registry = []

        def is_svc_in_service_registry(name):
            return next(
                (svc for svc in services_from_registry if svc._name == name),
                None)

        for s_record in services_from_registry:
            sr_list.append({
                'name':
                s_record._name,
                'address':
                s_record._address,
                'management_port':
                s_record._management_port,
                'service_port':
                s_record._port,
                'protocol':
                s_record._protocol,
                'status':
                ServiceRecord.Status(int(s_record._status)).name.lower(),
                'assets':
                await _get_tracked_assets_and_readings(storage_client,
                                                       s_record._name),
                'schedule_enabled':
                await _get_schedule_status(storage_client, s_record._name)
            })
        for s_name in south_services:
            south_svc = is_svc_in_service_registry(s_name)
            if not south_svc:
                sr_list.append({
                    'name':
                    s_name,
                    'address':
                    '',
                    'management_port':
                    '',
                    'service_port':
                    '',
                    'protocol':
                    '',
                    'status':
                    '',
                    'assets':
                    await
                    _get_tracked_assets_and_readings(storage_client, s_name),
                    'schedule_enabled':
                    await _get_schedule_status(storage_client, s_name)
                })
    except:
        raise
    else:
        return sr_list
Example #13
0
def get_storage():
    """ Storage Object """
    try:
        services = ServiceRegistry.get(name="FogLAMP Storage")
        storage_svc = services[0]
        _storage = StorageClient(core_management_host=None, core_management_port=None,
                                 svc=storage_svc)
        # _logger.info(type(_storage))
    except Exception as ex:
        _logger.exception(str(ex))
        raise
    return _storage
Example #14
0
 async def _get_storage_client(cls):
     storage_service = None
     while storage_service is None and cls._storage_client_async is None:
         try:
             found_services = ServiceRegistry.get(name="FogLAMP Storage")
             storage_service = found_services[0]
             cls._storage_client_async = StorageClientAsync(
                 cls._host, cls.core_management_port, svc=storage_service)
         except (service_registry_exceptions.DoesNotExist,
                 InvalidServiceInstance, StorageServiceUnavailable,
                 Exception) as ex:
             await asyncio.sleep(5)
Example #15
0
async def run(category_name):
    """ Callback run by configuration category to notify changes to interested microservices

    Note: this method is async as needed

    Args:
        configuration_name (str): name of category that was changed
    """

    # get all interest records regarding category_name
    cfg_mgr = ConfigurationManager()
    interest_registry = InterestRegistry(cfg_mgr)
    try:
        interest_records = interest_registry.get(category_name=category_name)
    except interest_registry_exceptions.DoesNotExist:
        return

    category_value = await cfg_mgr.get_category_all_items(category_name)
    payload = {"category": category_name, "items": category_value}
    headers = {'content-type': 'application/json'}

    # for each microservice interested in category_name, notify change
    for i in interest_records:
        # get microservice management server info of microservice through service registry
        try:
            service_record = ServiceRegistry.get(idx=i._microservice_uuid)[0]
        except service_registry_exceptions.DoesNotExist:
            _LOGGER.exception(
                "Unable to notify microservice with uuid %s as it is not found in the service registry",
                i._microservice_uuid)
            continue
        url = "{}://{}:{}/foglamp/change".format(
            service_record._protocol, service_record._address,
            service_record._management_port)
        async with aiohttp.ClientSession() as session:
            try:
                async with session.post(url,
                                        data=json.dumps(payload,
                                                        sort_keys=True),
                                        headers=headers) as resp:
                    result = await resp.text()
                    status_code = resp.status
                    if status_code in range(400, 500):
                        _LOGGER.error("Bad request error code: %d, reason: %s",
                                      status_code, resp.reason)
                    if status_code in range(500, 600):
                        _LOGGER.error("Server error code: %d, reason: %s",
                                      status_code, resp.reason)
            except Exception as ex:
                _LOGGER.exception(
                    "Unable to notify microservice with uuid %s due to exception: %s",
                    i._microservice_uuid, str(ex))
                continue
Example #16
0
    async def get_service(cls, request):
        """ Returns a list of all services or of the selected service

        :Example: curl -X GET  http://localhost:8082/foglamp/service
        :Example: curl -X GET  http://localhost:8082/foglamp/service?name=X&type=Storage
        """
        service_name = request.query[
            'name'] if 'name' in request.query else None
        service_type = request.query[
            'type'] if 'type' in request.query else None

        try:
            if not service_name and not service_type:
                services_list = ServiceRegistry.all()
            elif service_name and not service_type:
                services_list = ServiceRegistry.get(name=service_name)
            elif not service_name and service_type:
                services_list = ServiceRegistry.get(s_type=service_type)
            else:
                services_list = ServiceRegistry.filter_by_name_and_type(
                    name=service_name, s_type=service_type)
        except service_registry_exceptions.DoesNotExist as ex:
            raise web.HTTPBadRequest(
                reason="Invalid service name and/or type provided" + str(ex))

        services = []
        for service in services_list:
            svc = dict()
            svc["id"] = service._id
            svc["name"] = service._name
            svc["type"] = service._type
            svc["address"] = service._address
            svc["management_port"] = service._management_port
            svc["protocol"] = service._protocol
            svc["status"] = service._status
            if service._port:
                svc["service_port"] = service._port
            services.append(svc)

        return web.json_response({"services": services})
Example #17
0
async def delete_service(request):
    """ Delete an existing service

    :Example:
        curl -X DELETE http://localhost:8081/foglamp/service/<svc name>
    """
    try:
        svc = request.match_info.get('service_name', None)
        storage = connect.get_storage_async()

        result = await get_schedule(storage, svc)
        if result['count'] == 0:
            return web.HTTPNotFound(
                reason='{} service does not exist.'.format(svc))

        config_mgr = ConfigurationManager(storage)

        # In case of notification service, if notifications exists, then deletion is not allowed
        if 'notification' in result['rows'][0]['process_name']:
            notf_children = await config_mgr.get_category_child(
                category_name="Notifications")
            children = [x['key'] for x in notf_children]
            if len(notf_children) > 0:
                return web.HTTPBadRequest(
                    reason=
                    'Notification service `{}` can not be deleted, as {} notification instances exist.'
                    .format(svc, children))

        # First disable the schedule
        svc_schedule = result['rows'][0]
        sch_id = uuid.UUID(svc_schedule['id'])
        if svc_schedule['enabled'].lower() == 't':
            await server.Server.scheduler.disable_schedule(sch_id)

        # Delete all configuration for the service name
        await config_mgr.delete_category_and_children_recursively(svc)

        # Remove from registry as it has been already shutdown via disable_schedule() and since
        # we intend to delete the schedule also, there is no use of its Service registry entry
        try:
            services = ServiceRegistry.get(name=svc)
            ServiceRegistry.remove_from_registry(services[0]._id)
        except service_registry_exceptions.DoesNotExist:
            pass

        # Delete schedule
        await server.Server.scheduler.delete_schedule(sch_id)
    except Exception as ex:
        raise web.HTTPInternalServerError(reason=ex)
    else:
        return web.json_response(
            {'result': 'Service {} deleted successfully.'.format(svc)})
Example #18
0
def get_readings_async():
    """ Storage Object """
    try:
        services = ServiceRegistry.get(name="FogLAMP Storage")
        storage_svc = services[0]
        _readings = ReadingsStorageClientAsync(core_mgt_host=None,
                                               core_mgt_port=None,
                                               svc=storage_svc)
        # _logger.info(type(_storage))
    except Exception as ex:
        _logger.exception(str(ex))
        raise
    return _readings
Example #19
0
    async def test_unregister(self, mocker):
        # register a service
        idx = Service.register("StorageService2", "Storage", "127.0.0.1", 8888, 1888)
        assert str(uuid.UUID(idx, version=4)) == idx

        mocker.patch.object(InterestRegistry, '__init__', return_value=None)
        mocker.patch.object(InterestRegistry, 'get', return_value=list())

        # deregister the same
        t = Service.unregister(idx)
        assert idx == t

        s = Service.get(idx)
        assert s[0]._status == 2  # Unregistered
Example #20
0
    async def stop_storage(cls):
        """Stops Storage service """

        try:
            found_services = ServiceRegistry.get(name="FogLAMP Storage")
        except service_registry_exceptions.DoesNotExist:
            raise

        svc = found_services[0]
        if svc is None:
            _logger.info(
                "FogLAMP Storage shut down requested, but could not be found.")
            return
        await cls._request_microservice_shutdown(svc)
Example #21
0
    async def test__monitor_exceed_attempts(self, reset_service_registry):
        async def async_mock(return_value):
            return return_value

        # used to mock client session context manager

        class AsyncSessionContextManagerMock(MagicMock):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)

            async def __aenter__(self):
                # mock response (error- exception)
                raise Exception()

            async def __aexit__(self, *args):
                return None

        # as monitor loop is as infinite loop, this exception is thrown when we need to exit the loop

        class TestMonitorException(Exception):
            pass

        # register a service
        s_id_1 = ServiceRegistry.register('sname1', 'Storage', 'saddress1', 1,
                                          1, 'protocol1')
        monitor = Monitor()
        monitor._sleep_interval = Monitor._DEFAULT_SLEEP_INTERVAL
        monitor._max_attempts = Monitor._DEFAULT_MAX_ATTEMPTS

        sleep_side_effect_list = list()
        # _MAX_ATTEMPTS is 15
        # throw exception on the 16th time sleep is called - the first 15 sleeps are used during retries
        for i in range(0, 15):
            sleep_side_effect_list.append(async_mock(None))
        sleep_side_effect_list.append(TestMonitorException())
        with patch.object(Monitor,
                          '_sleep',
                          side_effect=sleep_side_effect_list):
            with patch.object(aiohttp.ClientSession,
                              'get',
                              return_value=AsyncSessionContextManagerMock()):
                with pytest.raises(TestMonitorException) as excinfo:
                    await monitor._monitor_loop()

        assert ServiceRegistry.get(
            idx=s_id_1)[0]._status is ServiceRecord.Status.Failed
Example #22
0
async def delete_notification(request):
    """ Delete an existing notification

    :Example:
        curl -X DELETE http://localhost:8081/foglamp/notification/<notification_name>
    """
    try:
        notification_service = ServiceRegistry.get(
            s_type=ServiceRecord.Type.Notification.name)
        _address, _port = notification_service[
            0]._address, notification_service[0]._port
    except service_registry_exceptions.DoesNotExist:
        raise web.HTTPNotFound(reason="No Notification service available.")

    try:
        notif = request.match_info.get('notification_name', None)
        if notif is None:
            raise ValueError("Notification name is required for deletion.")

        # Stop & remove notification
        url = 'http://{}:{}/notification/{}'.format(_address, _port,
                                                    urllib.parse.quote(notif))

        notification = json.loads(await _hit_delete_url(url))

        # Removes the child categories for the rule and delivery plugins, Removes the category for the notification itself
        storage = connect.get_storage_async()
        config_mgr = ConfigurationManager(storage)

        await config_mgr.delete_category_and_children_recursively(notif)

        audit = AuditLogger(storage)
        await audit.information('NTFDL', {"name": notif})
    except ValueError as ex:
        raise web.HTTPBadRequest(reason=str(ex))
    except Exception as ex:
        raise web.HTTPInternalServerError(reason=str(ex))
    else:
        return web.json_response(
            {'result': 'Notification {} deleted successfully.'.format(notif)})
Example #23
0
    async def test_get(self):
        with patch.object(Service._logger, 'info') as log_info:
            s = Service.register("StorageService", "Storage", "localhost",
                                 8881, 1888)
            c = Service.register("CoreService", "Core", "localhost", 7771,
                                 1777)
            d = Service.register("SouthService", "Southbound", "127.0.0.1",
                                 9991, 1999, "https")
        assert 3 == log_info.call_count

        _service = Service.get()
        assert 3 == len(_service)

        assert s == _service[0]._id
        assert "StorageService" == _service[0]._name
        assert "Storage" == _service[0]._type
        assert "localhost" == _service[0]._address
        assert 8881 == int(_service[0]._port)
        assert 1888 == int(_service[0]._management_port)
        # validates default set to HTTP
        assert "http" == _service[0]._protocol

        assert c == _service[1]._id
        assert "CoreService" == _service[1]._name
        assert "Core" == _service[1]._type
        assert "localhost" == _service[1]._address
        assert 7771 == int(_service[1]._port)
        assert 1777 == int(_service[1]._management_port)
        # validates default set to HTTP
        assert "http" == _service[1]._protocol

        assert d == _service[2]._id
        assert "SouthService" == _service[2]._name
        assert "Southbound" == _service[2]._type
        assert "127.0.0.1" == _service[2]._address
        assert 9991 == int(_service[2]._port)
        assert 1999 == int(_service[2]._management_port)
        assert "https" == _service[2]._protocol
Example #24
0
    async def stop_microservices(cls):
        """ call shutdown endpoint for non core micro-services

        There are 3 types of services
           - Core
           - Storage
           - Southbound
        """
        try:
            found_services = ServiceRegistry.get()
            services_to_stop = list()

            for fs in found_services:
                if fs._name in ("FogLAMP Storage", "FogLAMP Core"):
                    continue
                if fs._status not in [
                        ServiceRecord.Status.Running,
                        ServiceRecord.Status.Unresponsive
                ]:
                    continue
                services_to_stop.append(fs)

            if len(services_to_stop) == 0:
                _logger.info(
                    "No service found except the core, and(or) storage.")
                return

            tasks = [
                cls._request_microservice_shutdown(svc)
                for svc in services_to_stop
            ]
            await asyncio.wait(tasks)
        except service_registry_exceptions.DoesNotExist:
            pass
        except Exception as ex:
            _logger.exception(str(ex))
Example #25
0
async def post_notification(request):
    """
    Create a new notification to run a specific plugin

    :Example:
             curl -X POST http://localhost:8081/foglamp/notification -d '{"name": "Test Notification", "description":"Test Notification", "rule": "threshold", "channel": "email", "notification_type": "one shot", "enabled": false}'
             curl -X POST http://localhost:8081/foglamp/notification -d '{"name": "Test Notification", "description":"Test Notification", "rule": "threshold", "channel": "email", "notification_type": "one shot", "enabled": false, "rule_config": {}, "delivery_config": {}}'
    """
    try:
        notification_service = ServiceRegistry.get(s_type=ServiceRecord.Type.Notification.name)
        _address, _port = notification_service[0]._address, notification_service[0]._port
    except service_registry_exceptions.DoesNotExist:
        raise web.HTTPNotFound(reason="No Notification service available.")

    try:
        data = await request.json()
        if not isinstance(data, dict):
            raise ValueError('Data payload must be a valid JSON')

        name = data.get('name', None)
        description = data.get('description', None)
        rule = data.get('rule', None)
        channel = data.get('channel', None)
        notification_type = data.get('notification_type', None)
        enabled = data.get('enabled', None)
        rule_config = data.get('rule_config', {})
        delivery_config = data.get('delivery_config', {})

        if name is None or name.strip() == "":
            raise ValueError('Missing name property in payload.')
        if description is None:
            raise ValueError('Missing description property in payload.')
        if rule is None:
            raise ValueError('Missing rule property in payload.')
        if channel is None:
            raise ValueError('Missing channel property in payload.')
        if notification_type is None:
            raise ValueError('Missing notification_type property in payload.')

        if utils.check_reserved(name) is False:
            raise ValueError('Invalid name property in payload.')
        if utils.check_reserved(rule) is False:
            raise ValueError('Invalid rule property in payload.')
        if utils.check_reserved(channel) is False:
            raise ValueError('Invalid channel property in payload.')
        if notification_type not in NOTIFICATION_TYPE:
            raise ValueError('Invalid notification_type property in payload.')

        if enabled is not None:
            if enabled not in ['true', 'false', True, False]:
                raise ValueError('Only "true", "false", true, false are allowed for value of enabled.')
        is_enabled = "true" if ((type(enabled) is str and enabled.lower() in ['true']) or (
            (type(enabled) is bool and enabled is True))) else "false"

        try:
            # Get default config for rule and channel plugins
            url = '{}/plugin'.format(request.url)
            list_plugins = json.loads(await _hit_get_url(url))
            r = list(filter(lambda rules: rules['name'] == rule, list_plugins['rules']))
            c = list(filter(lambda channels: channels['name'] == channel, list_plugins['delivery']))
            if len(r) == 0 or len(c) == 0: raise KeyError
            rule_plugin_config = r[0]['config']
            delivery_plugin_config = c[0]['config']
        except KeyError:
            raise ValueError("Invalid rule plugin:[{}] and/or delivery plugin:[{}] supplied.".format(rule, channel))

        # Verify if rule_config contains valid keys
        if rule_config != {}:
            for k, v in rule_config.items():
                if k not in rule_plugin_config:
                    raise ValueError("Invalid key:[{}] in rule_config:[{}] supplied for plugin [{}].".format(k, rule_config, rule))

        # Verify if delivery_config contains valid keys
        if delivery_config != {}:
            for k, v in delivery_config.items():
                if k not in delivery_plugin_config:
                    raise ValueError(
                        "Invalid key:[{}] in delivery_config:[{}] supplied for plugin [{}].".format(k, delivery_config, channel))

        # First create templates for notification and rule, channel plugins
        post_url = 'http://{}:{}/notification/{}'.format(_address, _port, urllib.parse.quote(name))
        await _hit_post_url(post_url)  # Create Notification template
        post_url = 'http://{}:{}/notification/{}/rule/{}'.format(_address, _port, urllib.parse.quote(name),
                                                                         urllib.parse.quote(rule))
        await _hit_post_url(post_url)  # Create Notification rule template
        post_url = 'http://{}:{}/notification/{}/delivery/{}'.format(_address, _port, urllib.parse.quote(name),
                                                                             urllib.parse.quote(channel))
        await _hit_post_url(post_url)  # Create Notification delivery template

        # Create configurations
        storage = connect.get_storage_async()
        config_mgr = ConfigurationManager(storage)
        notification_config = {
            "rule": rule,
            "channel": channel,
            "notification_type": notification_type,
            "enable":is_enabled,
        }
        await _update_configurations(config_mgr, name, notification_config, rule_config, delivery_config)

        audit = AuditLogger(storage)
        await audit.information('NTFAD', {"name": name})
    except ValueError as ex:
        raise web.HTTPBadRequest(reason=str(ex))
    except Exception as e:
        raise web.HTTPInternalServerError(reason=str(e))
    else:
        return web.json_response({'result': "Notification {} created successfully".format(name)})
Example #26
0
async def put_notification(request):
    """
    Update an existing notification

    :Example:
             curl -X PUT http://localhost:8081/foglamp/notification/<notification_name> -d '{"description":"Test Notification modified"}'
             curl -X PUT http://localhost:8081/foglamp/notification/<notification_name> -d '{"rule": "threshold", "channel": "email"}'
             curl -X PUT http://localhost:8081/foglamp/notification/<notification_name> -d '{"notification_type": "one shot", "enabled": false}'
             curl -X PUT http://localhost:8081/foglamp/notification/<notification_name> -d '{"enabled": false}'
             curl -X PUT http://localhost:8081/foglamp/notification/<notification_name> -d '{"description":"Test Notification", "rule": "threshold", "channel": "email", "notification_type": "one shot", "enabled": false, "rule_config": {}, "delivery_config": {}}'
    """
    try:
        notification_service = ServiceRegistry.get(s_type=ServiceRecord.Type.Notification.name)
        _address, _port = notification_service[0]._address, notification_service[0]._port
    except service_registry_exceptions.DoesNotExist:
        raise web.HTTPNotFound(reason="No Notification service available.")

    try:
        notif = request.match_info.get('notification_name', None)
        if notif is None:
            raise ValueError("Notification name is required for updation.")

        # TODO: Stop notification before update

        data = await request.json()
        if not isinstance(data, dict):
            raise ValueError('Data payload must be a valid JSON')

        description = data.get('description', None)
        rule = data.get('rule', None)
        channel = data.get('channel', None)
        notification_type = data.get('notification_type', None)
        enabled = data.get('enabled', None)
        rule_config = data.get('rule_config', {})
        delivery_config = data.get('delivery_config', {})

        if utils.check_reserved(notif) is False:
            raise ValueError('Invalid notification name parameter.')
        if rule is not None and utils.check_reserved(rule) is False:
            raise ValueError('Invalid rule property in payload.')
        if channel is not None and utils.check_reserved(channel) is False:
            raise ValueError('Invalid channel property in payload.')
        if notification_type is not None and notification_type not in NOTIFICATION_TYPE:
            raise ValueError('Invalid notification_type property in payload.')

        if enabled is not None:
            if enabled not in ['true', 'false', True, False]:
                raise ValueError('Only "true", "false", true, false are allowed for value of enabled.')
        is_enabled = "true" if ((type(enabled) is str and enabled.lower() in ['true']) or (
            (type(enabled) is bool and enabled is True))) else "false"

        storage = connect.get_storage_async()
        config_mgr = ConfigurationManager(storage)

        current_config = await config_mgr._read_category_val(notif)
        rule_changed = True if rule is not None and rule != current_config['rule']['value'] else False
        channel_changed = True if channel is not None and channel != current_config['channel']['value'] else False

        try:
            # Get default config for rule and channel plugins
            url = str(request.url)
            url_parts = url.split("/foglamp/notification")
            url = '{}/foglamp/notification/plugin'.format(url_parts[0])
            list_plugins = json.loads(await _hit_get_url(url))

            search_rule = rule if rule_changed else current_config['rule']['value']
            r = list(filter(lambda rules: rules['name'] == search_rule, list_plugins['rules']))
            if len(r) == 0: raise KeyError
            rule_plugin_config = r[0]['config']

            search_channel = channel if channel_changed else current_config['channel']['value']
            c = list(filter(lambda channels: channels['name'] == search_channel, list_plugins['delivery']))
            if len(c) == 0: raise KeyError
            delivery_plugin_config = c[0]['config']
        except KeyError:
            raise ValueError("Invalid rule plugin:{} and/or delivery plugin:{} supplied.".format(rule, channel))

        # Verify if rule_config contains valid keys
        if rule_config != {}:
            for k, v in rule_config.items():
                if k not in rule_plugin_config:
                    raise ValueError("Invalid key:{} in rule plugin:{}".format(k, rule_plugin_config))

        # Verify if delivery_config contains valid keys
        if delivery_config != {}:
            for k, v in delivery_config.items():
                if k not in delivery_plugin_config:
                    raise ValueError(
                        "Invalid key:{} in delivery plugin:{}".format(k, delivery_plugin_config))

        if rule_changed:  # A new rule has been supplied
            category_desc = rule_plugin_config['plugin']['description']
            category_name = "rule{}".format(notif)
            await config_mgr.create_category(category_name=category_name,
                                             category_description=category_desc,
                                             category_value=rule_plugin_config,
                                             keep_original_items=False)
        if channel_changed:  # A new delivery has been supplied
            category_desc = delivery_plugin_config['plugin']['description']
            category_name = "delivery{}".format(notif)
            await config_mgr.create_category(category_name=category_name,
                                             category_description=category_desc,
                                             category_value=delivery_plugin_config,
                                             keep_original_items=False)
        notification_config = {}
        if description is not None:
            notification_config.update({"description": description})
        if rule is not None:
            notification_config.update({"rule": rule})
        if channel is not None:
            notification_config.update({"channel": channel})
        if notification_type is not None:
            notification_config.update({"notification_type": notification_type})
        if enabled is not None:
            notification_config.update({"enable": is_enabled})
        await _update_configurations(config_mgr, notif, notification_config, rule_config, delivery_config)
    except ValueError as ex:
        raise web.HTTPBadRequest(reason=str(ex))
    except Exception as e:
        raise web.HTTPInternalServerError(reason=str(e))
    else:
        # TODO: Start notification after update
        return web.json_response({'result': "Notification {} updated successfully".format(notif)})
Example #27
0
 async def test_get_fail(self):
     with pytest.raises(DoesNotExist) as excinfo:
         Service.register("StorageService", "Storage", "127.0.0.1", 8888, 9999)
         Service.get('incorrect_id')
     assert str(excinfo).endswith('DoesNotExist')