def test_constructor_configuration_manager_defined_no_configuration_manager_passed(
         self, reset_singleton):
     configuration_manager_mock = MagicMock(spec=ConfigurationManager)
     i_reg = InterestRegistry(configuration_manager_mock)
     # second time initializing InterestRegistry without configuration manager
     i_reg2 = InterestRegistry()
     assert hasattr(i_reg2, '_configuration_manager')
     assert isinstance(i_reg2._configuration_manager, ConfigurationManager)
     assert hasattr(i_reg2, '_registered_interests')
     assert len(i_reg._registered_interests) == 0
 def test_constructor_configuration_manager_defined_configuration_manager_passed(
         self, reset_singleton):
     configuration_manager_mock = MagicMock(spec=ConfigurationManager)
     # second time initializing InterestRegistry with new configuration manager
     # works
     configuration_manager_mock2 = MagicMock(spec=ConfigurationManager)
     i_reg = InterestRegistry(configuration_manager_mock)
     i_reg2 = InterestRegistry(configuration_manager_mock2)
     assert hasattr(i_reg2, '_configuration_manager')
     # ignore new configuration manager
     assert isinstance(i_reg2._configuration_manager, ConfigurationManager)
     assert hasattr(i_reg2, '_registered_interests')
Esempio n. 3
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
    async def test_run_general_exception(self):
        storage_client_mock = MagicMock(spec=StorageClientAsync)
        cfg_mgr = ConfigurationManager(storage_client_mock)

        with patch.object(ServiceRegistry._logger, 'info') as log_info:
            s_id_1 = ServiceRegistry.register('sname1', 'Storage', 'saddress1',
                                              1, 1, 'http')
        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=http, address=saddress1, service port=1, management port=1, status=1>'
        )

        i_reg = InterestRegistry(cfg_mgr)
        i_reg.register(s_id_1, 'catname1')

        # used to mock client session context manager
        async def async_mock(return_value):
            return return_value

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

            async def __aenter__(self):
                raise Exception

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

        with patch.object(ConfigurationManager,
                          'get_category_all_items',
                          return_value=async_mock(None)) as cm_get_patch:
            with patch.object(aiohttp.ClientSession,
                              'post',
                              return_value=AsyncSessionContextManagerMock()
                              ) as post_patch:
                with patch.object(cb._LOGGER, 'exception') as exception_patch:
                    await cb.run('catname1')
                exception_patch.assert_called_once_with(
                    'Unable to notify microservice with uuid %s due to exception: %s',
                    s_id_1, '')
            post_patch.assert_has_calls([
                call('http://saddress1:1/foglamp/change',
                     data='{"category": "catname1", "items": null}',
                     headers={'content-type': 'application/json'})
            ])
        cm_get_patch.assert_called_once_with('catname1')
Esempio n. 5
0
    async def test_get_interest(self, client):
        Server._storage_client = MagicMock(StorageClientAsync)
        Server._configuration_manager = ConfigurationManager(
            Server._storage_client)
        Server._interest_registry = InterestRegistry(
            Server._configuration_manager)

        data = []
        category_name = 'test_Cat'
        muuid = '0c501cd3-c45a-439a-bec6-fc08d13f9699'
        reg_id = 'c6bbf3c8-f43c-4b0f-ac48-f597f510da0b'
        record = InterestRecord(reg_id, muuid, category_name)
        data.append(record)

        with patch.object(Server._interest_registry, 'get',
                          return_value=data) as patch_get_interest_reg:
            resp = await client.get('/foglamp/interest')
            assert 200 == resp.status
            r = await resp.text()
            json_response = json.loads(r)
            assert {
                'interests': [{
                    'category': category_name,
                    'microserviceId': muuid,
                    'registrationId': reg_id
                }]
            } == json_response
        args, kwargs = patch_get_interest_reg.call_args
        assert {} == kwargs
Esempio n. 6
0
    async def test_register_interest(self, client):
        Server._storage_client = MagicMock(StorageClientAsync)
        Server._configuration_manager = ConfigurationManager(
            Server._storage_client)
        Server._interest_registry = InterestRegistry(
            Server._configuration_manager)

        request_data = {
            "category": "COAP",
            "service": "c6bbf3c8-f43c-4b0f-ac48-f597f510da0b"
        }
        reg_id = 'a404852d-d91c-47bd-8860-d4ff81b6e8cb'
        with patch.object(Server._interest_registry,
                          'register',
                          return_value=reg_id) as patch_reg_interest_reg:
            resp = await client.post('/foglamp/interest',
                                     data=json.dumps(request_data))
            assert 200 == resp.status
            r = await resp.text()
            json_response = json.loads(r)
            assert {
                'id': reg_id,
                'message': 'Interest registered successfully'
            } == json_response
        args, kwargs = patch_reg_interest_reg.call_args
        assert (request_data['service'], request_data['category']) == args
Esempio n. 7
0
    async def test_unregister_interest(self, client):
        Server._storage_client = MagicMock(StorageClientAsync)
        Server._configuration_manager = ConfigurationManager(
            Server._storage_client)
        Server._interest_registry = InterestRegistry(
            Server._configuration_manager)

        data = []
        category_name = 'test_Cat'
        muuid = '0c501cd3-c45a-439a-bec6-fc08d13f9699'
        reg_id = 'c6bbf3c8-f43c-4b0f-ac48-f597f510da0b'
        record = InterestRecord(reg_id, muuid, category_name)
        data.append(record)

        with patch.object(Server._interest_registry, 'get',
                          return_value=data) as patch_get_interest_reg:
            with patch.object(Server._interest_registry,
                              'unregister',
                              return_value=[]) as patch_unregister_interest:
                resp = await client.delete(
                    '/foglamp/interest/{}'.format(reg_id))
                assert 200 == resp.status
                r = await resp.text()
                json_response = json.loads(r)
                assert {
                    'id': reg_id,
                    'message': 'Interest unregistered'
                } == json_response
            args, kwargs = patch_unregister_interest.call_args
            assert (reg_id, ) == args
        args1, kwargs1 = patch_get_interest_reg.call_args
        assert {'registration_id': reg_id} == kwargs1
    def test_get(self, reset_singleton):
        configuration_manager_mock = MagicMock(spec=ConfigurationManager)
        i_reg = InterestRegistry(configuration_manager_mock)

        # get when empty
        microservice_uuid = 'muuid'
        category_name = 'catname'
        with pytest.raises(interest_registry_exceptions.DoesNotExist) as excinfo:
            i_reg.get(microservice_uuid=microservice_uuid,
                      category_name=category_name)

        # get when there is a result (use patch on 'get')
        with patch.object(InterestRegistry, 'and_filter', return_value=[1]):
            ret_val = i_reg.get(
                microservice_uuid=microservice_uuid, category_name=category_name)
        assert ret_val is not None
        assert ret_val == [1]
 def test_constructor_no_configuration_manager_defined_no_configuration_manager_passed(
         self, reset_singleton):
     # first time initializing InterestRegistry without configuration manager
     # produces error
     with pytest.raises(TypeError) as excinfo:
         InterestRegistry()
     assert 'Must be a valid ConfigurationManager object' in str(
         excinfo.value)
Esempio n. 10
0
    def _expunge(cls, service_id, service_status):
        """ removes the service instance from action

        :param service_id: a uuid of registered service
        :param service_status: service status to be marked
        :return: service_id on successful deregistration
        """
        services = cls.get(idx=service_id)
        service_name = services[0]._name
        services[0]._status = service_status
        cls._remove_from_scheduler_records(service_name)

        # Remove interest registry records, if any
        interest_recs = InterestRegistry().get(microservice_uuid=service_id)
        for interest_rec in interest_recs:
            InterestRegistry().unregister(interest_rec._registration_id)

        return services[0]
 def test_constructor_no_configuration_manager_defined_configuration_manager_passed(
         self, reset_singleton):
     # first time initializing InterestRegistry with configuration manager
     # works
     configuration_manager_mock = MagicMock(spec=ConfigurationManager)
     i_reg = InterestRegistry(configuration_manager_mock)
     assert hasattr(i_reg, '_configuration_manager')
     assert isinstance(i_reg._configuration_manager, ConfigurationManager)
     assert hasattr(i_reg, '_registered_interests')
Esempio n. 12
0
 async def test_get_interest_exception(self, client, params, message, expected_kwargs):
     Server._storage_client = MagicMock(StorageClient)
     Server._configuration_manager = ConfigurationManager(Server._storage_client)
     Server._interest_registry = InterestRegistry(Server._configuration_manager)
     with patch.object(Server._interest_registry, 'get', side_effect=interest_registry_exceptions.DoesNotExist) as patch_get_interest_reg:
         resp = await client.get('/foglamp/interest{}'.format(params))
         assert 404 == resp.status
         assert message == resp.reason
     args, kwargs = patch_get_interest_reg.call_args
     assert expected_kwargs == kwargs
    def test_register(self, reset_singleton):
        configuration_manager_mock = MagicMock(spec=ConfigurationManager)
        i_reg = InterestRegistry(configuration_manager_mock)
        # register the first interest
        microservice_uuid = 'muuid'
        category_name = 'catname'
        ret_val = i_reg.register(microservice_uuid, category_name)
        assert ret_val is not None
        assert len(i_reg._registered_interests) is 1
        assert isinstance(i_reg._registered_interests[0], InterestRecord)
        assert i_reg._registered_interests[0]._registration_id is ret_val
        assert i_reg._registered_interests[0]._microservice_uuid is microservice_uuid
        assert i_reg._registered_interests[0]._category_name is category_name
        str_val = 'interest registration id={}: <microservice uuid={}, category_name={}>'.format(
            ret_val, microservice_uuid, category_name)
        assert str(i_reg._registered_interests[0]) == str_val

        # register an existing interest
        with pytest.raises(interest_registry_exceptions.ErrorInterestRegistrationAlreadyExists) as excinfo:
            ret_val = i_reg.register(microservice_uuid, category_name)
        assert ret_val is not None
        assert len(i_reg._registered_interests) is 1
        assert isinstance(i_reg._registered_interests[0], InterestRecord)
        assert i_reg._registered_interests[0]._registration_id is ret_val
        assert i_reg._registered_interests[0]._microservice_uuid is microservice_uuid
        assert i_reg._registered_interests[0]._category_name is category_name
        str_val = 'interest registration id={}: <microservice uuid={}, category_name={}>'.format(
            ret_val, microservice_uuid, category_name)
        assert str(i_reg._registered_interests[0]) == str_val

        # register a second interest
        category_name2 = 'catname2'
        ret_val = i_reg.register(microservice_uuid, category_name2)
        assert ret_val is not None
        assert len(i_reg._registered_interests) is 2
        assert isinstance(i_reg._registered_interests[1], InterestRecord)
        assert i_reg._registered_interests[1]._registration_id is ret_val
        assert i_reg._registered_interests[1]._microservice_uuid is microservice_uuid
        assert i_reg._registered_interests[1]._category_name is category_name2
        str_val = 'interest registration id={}: <microservice uuid={}, category_name={}>'.format(
            ret_val, microservice_uuid, category_name2)
        assert str(i_reg._registered_interests[1]) == str_val
Esempio n. 14
0
 async def test_get_interest_with_filter(self, client, params, expected_kwargs):
     Server._storage_client = MagicMock(StorageClient)
     Server._configuration_manager = ConfigurationManager(Server._storage_client)
     Server._interest_registry = InterestRegistry(Server._configuration_manager)
     with patch.object(Server._interest_registry, 'get', return_value=[]) as patch_get_interest_reg:
         resp = await client.get('/foglamp/interest{}'.format(params))
         assert 200 == resp.status
         r = await resp.text()
         json_response = json.loads(r)
         assert {'interests': []} == json_response
     args, kwargs = patch_get_interest_reg.call_args
     assert expected_kwargs == kwargs
Esempio n. 15
0
    async def test_bad_register_interest(self, client):
        Server._storage_client = MagicMock(StorageClient)
        Server._configuration_manager = ConfigurationManager(Server._storage_client)
        Server._interest_registry = InterestRegistry(Server._configuration_manager)

        request_data = {"category": "COAP", "service": "c6bbf3c8-f43c-4b0f-ac48-f597f510da0b"}
        with patch.object(Server._interest_registry, 'register', return_value=None) as patch_reg_interest_reg:
            resp = await client.post('/foglamp/interest', data=json.dumps(request_data))
            assert 400 == resp.status
            assert 'Interest by microservice_uuid {} for category_name {} could not be registered'.format(request_data['service'], request_data['category']) == resp.reason
        args, kwargs = patch_reg_interest_reg.call_args
        assert (request_data['service'], request_data['category']) == args
Esempio n. 16
0
    async def test_unregister_interest_exception(self, client):
        Server._storage_client = MagicMock(StorageClient)
        Server._configuration_manager = ConfigurationManager(Server._storage_client)
        Server._interest_registry = InterestRegistry(Server._configuration_manager)

        reg_id = 'c6bbf3c8-f43c-4b0f-ac48-f597f510da0b'
        with patch.object(Server._interest_registry, 'get', side_effect=interest_registry_exceptions.DoesNotExist) as patch_get_interest_reg:
            resp = await client.delete('/foglamp/interest/{}'.format(reg_id))
            assert 404 == resp.status
            assert 'InterestRecord with registration_id {} does not exist'.format(reg_id) == resp.reason
        args, kwargs = patch_get_interest_reg.call_args
        assert {'registration_id': reg_id} == kwargs
Esempio n. 17
0
    async def test_register_interest_exceptions(self, client):
        Server._storage_client = MagicMock(StorageClient)
        Server._configuration_manager = ConfigurationManager(Server._storage_client)
        Server._interest_registry = InterestRegistry(Server._configuration_manager)

        request_data = {"category": "COAP", "service": "c6bbf3c8-f43c-4b0f-ac48-f597f510da0b"}
        with patch.object(Server._interest_registry, 'register', side_effect=interest_registry_exceptions.ErrorInterestRegistrationAlreadyExists) as patch_reg_interest_reg:
            resp = await client.post('/foglamp/interest', data=json.dumps(request_data))
            assert 400 == resp.status
            assert 'An InterestRecord already exists by microservice_uuid {} for category_name {}'.format(request_data['service'], request_data['category']) == resp.reason
        args, kwargs = patch_reg_interest_reg.call_args
        assert (request_data['service'], request_data['category']) == args
Esempio n. 18
0
    async def test_run_no_intrests_in_cat(self, reset_state):
        storage_client_mock = MagicMock(spec=StorageClient)
        cfg_mgr = ConfigurationManager(storage_client_mock)

        s_id_1 = ServiceRegistry.register('sname1', 'Storage', 'saddress1', 1,
                                          1, 'http')
        s_id_2 = ServiceRegistry.register('sname2', 'Southbound', 'saddress2',
                                          2, 2, 'http')
        s_id_3 = ServiceRegistry.register('sname3', 'Southbound', 'saddress3',
                                          3, 3, 'http')
        i_reg = InterestRegistry(cfg_mgr)
        id_1_2 = i_reg.register(s_id_1, 'catname2')
        id_2_2 = i_reg.register(s_id_2, 'catname2')
        id_3_3 = i_reg.register(s_id_3, 'catname3')

        # used to mock client session context manager
        async def async_mock(return_value):
            return return_value

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

            async def __aenter__(self):
                client_response_mock = MagicMock(spec=aiohttp.ClientResponse)
                client_response_mock.text.side_effect = [async_mock(None)]
                status_mock = Mock()
                status_mock.side_effect = [200]
                client_response_mock.status = status_mock()
                return client_response_mock

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

        with patch.object(ConfigurationManager,
                          'get_category_all_items') as cm_get_patch:
            with patch.object(aiohttp.ClientSession, 'post') as post_patch:
                await cb.run('catname1')
        cm_get_patch.assert_not_called()
        post_patch.assert_not_called()
Esempio n. 19
0
    async def test_run_missing_service_record(self, reset_state):
        storage_client_mock = MagicMock(spec=StorageClient)
        cfg_mgr = ConfigurationManager(storage_client_mock)

        s_id_1 = ServiceRegistry.register('sname1', 'Storage', 'saddress1', 1,
                                          1, 'http')
        s_id_2 = ServiceRegistry.register('sname2', 'Southbound', 'saddress2',
                                          2, 2, 'http')
        s_id_3 = ServiceRegistry.register('sname3', 'Southbound', 'saddress3',
                                          3, 3, 'http')
        i_reg = InterestRegistry(cfg_mgr)
        id_fake_1 = i_reg.register('fakeid', 'catname1')
        id_1_1 = i_reg.register(s_id_1, 'catname1')
        id_1_2 = i_reg.register(s_id_1, 'catname2')
        id_2_1 = i_reg.register(s_id_2, 'catname1')
        id_2_2 = i_reg.register(s_id_2, 'catname2')
        id_3_3 = i_reg.register(s_id_3, 'catname3')

        # used to mock client session context manager
        async def async_mock(return_value):
            return return_value

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

            async def __aenter__(self):
                client_response_mock = MagicMock(spec=aiohttp.ClientResponse)
                client_response_mock.text.side_effect = [async_mock(None)]
                status_mock = Mock()
                status_mock.side_effect = [200]
                client_response_mock.status = status_mock()
                return client_response_mock

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

        with patch.object(ConfigurationManager,
                          'get_category_all_items',
                          return_value=async_mock(None)) as cm_get_patch:
            with patch.object(aiohttp.ClientSession,
                              'post',
                              return_value=AsyncSessionContextManagerMock()
                              ) as post_patch:
                with patch.object(cb._LOGGER, 'exception') as exception_patch:
                    await cb.run('catname1')
        cm_get_patch.assert_called_once_with('catname1')
        exception_patch.assert_called_once_with(
            'Unable to notify microservice with uuid %s as it is not found in the service registry',
            'fakeid')
        post_patch.assert_has_calls([
            call('http://saddress1:1/foglamp/change',
                 data='{"category": "catname1", "items": null}',
                 headers={'content-type': 'application/json'}),
            call('http://saddress2:2/foglamp/change',
                 data='{"category": "catname1", "items": null}',
                 headers={'content-type': 'application/json'})
        ])
    def test_get_with_and_filter(self, reset_singleton):
        configuration_manager_mock = MagicMock(spec=ConfigurationManager)
        i_reg = InterestRegistry(configuration_manager_mock)
        # register some interts
        id_1_1 = i_reg.register('muuid1', 'catname1')
        id_1_2 = i_reg.register('muuid1', 'catname2')
        id_2_1 = i_reg.register('muuid2', 'catname1')
        id_2_2 = i_reg.register('muuid2', 'catname2')
        id_3_3 = i_reg.register('muuid3', 'catname3')

        ret_val = i_reg.get(microservice_uuid='muuid1')
        assert len(ret_val) is 2
        for i in ret_val:
            assert isinstance(i, InterestRecord)
        assert ret_val[0]._registration_id is id_1_1
        assert ret_val[0]._microservice_uuid is 'muuid1'
        assert ret_val[0]._category_name is 'catname1'
        assert ret_val[1]._registration_id is id_1_2
        assert ret_val[1]._microservice_uuid is 'muuid1'
        assert ret_val[1]._category_name is 'catname2'

        ret_val = i_reg.get(category_name='catname2')
        assert len(ret_val) is 2
        for i in ret_val:
            assert isinstance(i, InterestRecord)
        assert ret_val[0]._registration_id is id_1_2
        assert ret_val[0]._microservice_uuid is 'muuid1'
        assert ret_val[0]._category_name is 'catname2'
        assert ret_val[1]._registration_id is id_2_2
        assert ret_val[1]._microservice_uuid is 'muuid2'
        assert ret_val[1]._category_name is 'catname2'

        ret_val = i_reg.get(category_name='catname2',
                            microservice_uuid='muuid2')
        assert len(ret_val) is 1
        for i in ret_val:
            assert isinstance(i, InterestRecord)
        assert ret_val[0]._registration_id is id_2_2
        assert ret_val[0]._microservice_uuid is 'muuid2'
        assert ret_val[0]._category_name is 'catname2'
    def test_unregister(self, reset_singleton):
        configuration_manager_mock = MagicMock(spec=ConfigurationManager)
        i_reg = InterestRegistry(configuration_manager_mock)
        # unregister when no items exists
        fake_uuid = 'bla'
        with pytest.raises(interest_registry_exceptions.DoesNotExist) as excinfo:
            ret_val = i_reg.unregister(fake_uuid)

        # register 2 interests, then unregister 1
        id_1_1 = i_reg.register('muuid1', 'catname1')
        id_1_2 = i_reg.register('muuid1', 'catname2')
        ret_val = i_reg.unregister(id_1_1)
        assert ret_val == id_1_1
        assert len(i_reg._registered_interests) is 1
        assert isinstance(i_reg._registered_interests[0], InterestRecord)
        assert i_reg._registered_interests[0]._registration_id is id_1_2
        assert i_reg._registered_interests[0]._microservice_uuid is 'muuid1'
        assert i_reg._registered_interests[0]._category_name is 'catname2'

        # unregister the second one
        ret_val = i_reg.unregister(id_1_2)
        assert ret_val == id_1_2
        assert len(i_reg._registered_interests) is 0
Esempio n. 22
0
    def _start_core(cls, loop=None):
        _logger.info("start core")

        try:
            host = cls._host

            core_app = cls._make_core_app()
            core_server, core_server_handler = cls._start_app(
                loop, core_app, host, 0)
            address, cls.core_management_port = core_server.sockets[
                0].getsockname()
            _logger.info('Management API started on http://%s:%s', address,
                         cls.core_management_port)
            # see http://<core_mgt_host>:<core_mgt_port>/foglamp/service for registered services

            _logger.info('Announce management API service')
            cls.management_announcer = ServiceAnnouncer(
                'FogLAMP-Core', '_foglamp_core._tcp', cls.core_management_port,
                ['The FogLAMP Core REST API'])

            # start storage
            loop.run_until_complete(cls._start_storage(loop))

            # get storage client
            loop.run_until_complete(cls._get_storage_client())

            # obtain configuration manager and interest registry
            cls._configuration_manager = ConfigurationManager(
                cls._storage_client)
            cls._interest_registry = InterestRegistry(
                cls._configuration_manager)

            # start scheduler
            # see scheduler.py start def FIXME
            # scheduler on start will wait for storage service registration
            loop.run_until_complete(cls._start_scheduler())

            # start monitor
            loop.run_until_complete(cls._start_service_monitor())

            service_app = cls._make_app()

            loop.run_until_complete(cls.rest_api_config())
            # print(cls.is_rest_server_tls_enabled, cls.rest_server_port)

            # ssl context
            ssl_ctx = None
            if not cls.is_rest_server_http_enabled:
                # ensure TLS 1.2 and SHA-256
                # handle expiry?
                ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
                cert, key = cls.get_certificates()
                _logger.info('Loading certificates %s and key %s', cert, key)
                ssl_ctx.load_cert_chain(cert, key)

            service_server, service_server_handler = cls._start_app(
                loop, service_app, host, cls.rest_server_port, ssl_ctx=ssl_ctx)
            address, service_server_port = service_server.sockets[
                0].getsockname()
            _logger.info(
                'REST API Server started on %s://%s:%s',
                'http' if cls.is_rest_server_http_enabled else 'https',
                address, service_server_port)

            cls.admin_announcer = ServiceAnnouncer(
                'FogLAMP', '_foglamp._tcp', service_server_port,
                ['The FogLAMP Admin REST API'])
            cls.user_announcer = ServiceAnnouncer(
                'FogLAMP', '_foglamp_app._tcp', service_server_port,
                ['The FogLAMP Application  REST API'])
            # register core
            # a service with 2 web server instance,
            # registering now only when service_port is ready to listen the request
            # TODO: if ssl then register with protocol https
            cls._register_core(host, cls.core_management_port,
                               service_server_port)
            print("(Press CTRL+C to quit)")

            try:
                loop.run_forever()
            except KeyboardInterrupt:
                pass
            finally:
                # graceful-shutdown
                # http://aiohttp.readthedocs.io/en/stable/web.html
                # TODO: FOGL-653 shutdown implementation
                # stop the scheduler
                loop.run_until_complete(cls._stop_scheduler())

                # stop monitor
                loop.run_until_complete(cls.stop_service_monitor())

                # stop the REST api (exposed on service port)
                service_server.close()
                loop.run_until_complete(service_server.wait_closed())
                loop.run_until_complete(service_app.shutdown())
                loop.run_until_complete(service_server_handler.shutdown(60.0))
                loop.run_until_complete(service_app.cleanup())

                # stop storage
                cls.stop_storage()

                # stop core management api
                core_server.close()
                loop.run_until_complete(core_server.wait_closed())
                loop.run_until_complete(core_app.shutdown())
                loop.run_until_complete(core_server_handler.shutdown(60.0))
                loop.run_until_complete(core_app.cleanup())

                loop.close()
        except (OSError, RuntimeError, TimeoutError) as e:
            sys.stderr.write('Error: ' + format(str(e)) + "\n")
            sys.exit(1)
        except Exception as e:
            sys.stderr.write('Error: ' + format(str(e)) + "\n")
            sys.exit(1)
Esempio n. 23
0
    async def test_run_good(self):
        storage_client_mock = MagicMock(spec=StorageClientAsync)
        cfg_mgr = ConfigurationManager(storage_client_mock)

        with patch.object(ServiceRegistry._logger, 'info') as log_info:
            s_id_1 = ServiceRegistry.register('sname1', 'Storage', 'saddress1',
                                              1, 1, 'http')
            s_id_2 = ServiceRegistry.register('sname2', 'Southbound',
                                              'saddress2', 2, 2, 'http')
            s_id_3 = ServiceRegistry.register('sname3', 'Southbound',
                                              'saddress3', 3, 3, 'http')
        assert 3 == log_info.call_count
        i_reg = InterestRegistry(cfg_mgr)
        i_reg.register(s_id_1, 'catname1')
        i_reg.register(s_id_1, 'catname2')
        i_reg.register(s_id_2, 'catname1')
        i_reg.register(s_id_2, 'catname2')
        i_reg.register(s_id_3, 'catname3')

        # used to mock client session context manager
        async def async_mock(return_value):
            return return_value

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

            async def __aenter__(self):
                client_response_mock = MagicMock(spec=aiohttp.ClientResponse)
                client_response_mock.text.side_effect = [async_mock(None)]
                status_mock = Mock()
                status_mock.side_effect = [200]
                client_response_mock.status = status_mock()
                return client_response_mock

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

        with patch.object(ConfigurationManager,
                          'get_category_all_items',
                          return_value=async_mock(None)) as cm_get_patch:
            with patch.object(aiohttp.ClientSession,
                              'post',
                              return_value=AsyncSessionContextManagerMock()
                              ) as post_patch:
                await cb.run('catname1')
            post_patch.assert_has_calls([
                call('http://saddress1:1/foglamp/change',
                     data='{"category": "catname1", "items": null}',
                     headers={'content-type': 'application/json'}),
                call('http://saddress2:2/foglamp/change',
                     data='{"category": "catname1", "items": null}',
                     headers={'content-type': 'application/json'})
            ])
        cm_get_patch.assert_called_once_with('catname1')

        with patch.object(ConfigurationManager,
                          'get_category_all_items',
                          return_value=async_mock(None)) as cm_get_patch:
            with patch.object(aiohttp.ClientSession,
                              'post',
                              return_value=AsyncSessionContextManagerMock()
                              ) as post_patch:
                await cb.run('catname2')
            post_patch.assert_has_calls([
                call('http://saddress1:1/foglamp/change',
                     data='{"category": "catname2", "items": null}',
                     headers={'content-type': 'application/json'}),
                call('http://saddress2:2/foglamp/change',
                     data='{"category": "catname2", "items": null}',
                     headers={'content-type': 'application/json'})
            ])
        cm_get_patch.assert_called_once_with('catname2')

        with patch.object(ConfigurationManager,
                          'get_category_all_items',
                          return_value=async_mock(None)) as cm_get_patch:
            with patch.object(aiohttp.ClientSession,
                              'post',
                              return_value=AsyncSessionContextManagerMock()
                              ) as post_patch:
                await cb.run('catname3')
            post_patch.assert_called_once_with(
                'http://saddress3:3/foglamp/change',
                data='{"category": "catname3", "items": null}',
                headers={'content-type': 'application/json'})
        cm_get_patch.assert_called_once_with('catname3')
Esempio n. 24
0
    def _start_core(cls, loop=None):
        _logger.info("start core")

        try:
            host = cls._host

            cls.core_app = cls._make_core_app()
            cls.core_server, cls.core_server_handler = cls._start_app(
                loop, cls.core_app, host, 0)
            address, cls.core_management_port = cls.core_server.sockets[
                0].getsockname()
            _logger.info('Management API started on http://%s:%s', address,
                         cls.core_management_port)
            # see http://<core_mgt_host>:<core_mgt_port>/foglamp/service for registered services
            # start storage
            loop.run_until_complete(cls._start_storage(loop))

            # get storage client
            loop.run_until_complete(cls._get_storage_client())

            # If readings table is empty, set last_object of all streams to 0
            total_count_payload = payload_builder.PayloadBuilder().AGGREGATE(
                ["count", "*"]).ALIAS("aggregate",
                                      ("*", "count", "count")).payload()
            result = loop.run_until_complete(
                cls._storage_client_async.query_tbl_with_payload(
                    'readings', total_count_payload))
            total_count = result['rows'][0]['count']
            if (total_count == 0):
                _logger.info(
                    "'foglamp.readings' table is empty, force reset of 'foglamp.streams' last_objects"
                )
                payload = payload_builder.PayloadBuilder().SET(
                    last_object=0, ts='now()').payload()
                loop.run_until_complete(
                    cls._storage_client_async.update_tbl("streams", payload))
            else:
                _logger.info(
                    "'foglamp.readings' has " + str(total_count) +
                    " rows, 'foglamp.streams' last_objects reset is not required"
                )

            # obtain configuration manager and interest registry
            cls._configuration_manager = ConfigurationManager(
                cls._storage_client_async)
            cls._interest_registry = InterestRegistry(
                cls._configuration_manager)

            # start scheduler
            # see scheduler.py start def FIXME
            # scheduler on start will wait for storage service registration
            loop.run_until_complete(cls._start_scheduler())

            # start monitor
            loop.run_until_complete(cls._start_service_monitor())

            loop.run_until_complete(cls.rest_api_config())
            cls.service_app = cls._make_app(auth_required=cls.is_auth_required)
            # ssl context
            ssl_ctx = None
            if not cls.is_rest_server_http_enabled:
                # ensure TLS 1.2 and SHA-256
                # handle expiry?
                ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
                cert, key = cls.get_certificates()
                _logger.info('Loading certificates %s and key %s', cert, key)
                ssl_ctx.load_cert_chain(cert, key)

            # Get the service data and advertise the management port of the core
            # to allow other microservices to find FogLAMP
            loop.run_until_complete(cls.service_config())
            _logger.info('Announce management API service')
            cls.management_announcer = ServiceAnnouncer(
                'core.{}'.format(cls._service_name), cls._MANAGEMENT_SERVICE,
                cls.core_management_port, ['The FogLAMP Core REST API'])

            cls.service_server, cls.service_server_handler = cls._start_app(
                loop,
                cls.service_app,
                host,
                cls.rest_server_port,
                ssl_ctx=ssl_ctx)
            address, service_server_port = cls.service_server.sockets[
                0].getsockname()

            # Write PID file with REST API details
            cls._write_pid(address, service_server_port)

            _logger.info(
                'REST API Server started on %s://%s:%s',
                'http' if cls.is_rest_server_http_enabled else 'https',
                address, service_server_port)

            # All services are up so now we can advertise the Admin and User REST API's
            cls.admin_announcer = ServiceAnnouncer(cls._service_name,
                                                   cls._ADMIN_API_SERVICE,
                                                   service_server_port,
                                                   [cls._service_description])
            cls.user_announcer = ServiceAnnouncer(cls._service_name,
                                                  cls._USER_API_SERVICE,
                                                  service_server_port,
                                                  [cls._service_description])
            # register core
            # a service with 2 web server instance,
            # registering now only when service_port is ready to listen the request
            # TODO: if ssl then register with protocol https
            cls._register_core(host, cls.core_management_port,
                               service_server_port)

            # Everything is complete in the startup sequence, write the audit log entry
            cls._audit = AuditLogger(cls._storage_client_async)
            loop.run_until_complete(cls._audit.information('START', None))

            loop.run_forever()

        except (OSError, RuntimeError, TimeoutError) as e:
            sys.stderr.write('Error: ' + format(str(e)) + "\n")
            sys.exit(1)
        except Exception as e:
            sys.stderr.write('Error: ' + format(str(e)) + "\n")
            sys.exit(1)