def test_registration_form(): service = Service( 'test_service', '/test/test/test', 'HTTP-SECURE-JSON', ) registration_form = forms.ServiceRegistrationForm( provided_service=service, provider_system=provider_system, secure='CERTIFICATE', metadata={'dummy': 'data'}, end_of_validity='dummy-date', version=0, ) valid_keys = { 'serviceDefinition', 'serviceUri', 'providerSystem', 'secure', 'interfaces', 'metadata', 'version', 'endOfValidity', } assert valid_keys == registration_form.dto.keys()
def handle_orchestration_response(service_orchestration_response: Mapping) \ -> List[Tuple[Service, ArrowheadSystem]]: """ Turns orchestration response into list of services """ orchestration_response_list = service_orchestration_response['response'] extracted_data = [] for orchestration_response in orchestration_response_list: service_dto = orchestration_response provider_dto = service_dto['provider'] service_definition = service_dto['service']['serviceDefinition'] service_uri = service_dto['serviceUri'] interface = service_dto['interfaces'][0]['interfaceName'] system_name = provider_dto['systemName'] address = provider_dto['address'] port = provider_dto['port'] service = Service( service_definition, service_uri, interface, ) system = ArrowheadSystem(system_name, address, port, '') extracted_data.append((service, system)) return extracted_data
def add_provided_service(self, service_definition: str = '', service_uri: str = '', interface: str = '', provided_service: Service = None, http_method: str = '', view_func: Optional[Callable] = None) -> None: """ Add service to provider system""" #TODO: This method does two thing at once. It adds a service from parameters, # and it adds an already created service. These functionalities should be # separated. Or maybe not? if not provided_service: provided_service = Service( service_definition, service_uri, interface,) if provided_service.service_definition not in self.provided_services.keys() and \ callable(view_func): # Register service with Flask app self.provided_services[provided_service.service_definition] = (provided_service, view_func) view_func = partial(view_func, request) self.app.add_url_rule(rule=f'/{provided_service.service_uri}', endpoint=provided_service.service_definition, methods=[http_method], view_func=view_func) else: # TODO: Add log message when service is trying to be overwritten pass
def provided_service( self, service_definition: str, service_uri: str, protocol: str, method: str, payload_format: str, access_policy: str, ) -> Callable: """ Decorator to add a provided provided_service to the provider. Useful during testing, because unlike the free :code:`provided_service` decorator this one does not require subclassing :code:`ArrowheadClient`. Args: service_definition: Service definition to be stored in the provided_service registry service_uri: The path to the provided_service protocol: method: HTTP method required to access the provided_service Example:: provider = SomeClient.create(...) @provider.provided_service( service_definition='list_reverser', service_uri='reverse', protocol='http', method='POST', payload_format='TEXT', access_policy='NOT_SECURE', ) async def reverse(input: List[str]): return list(reversed(input)) """ provided_service = Service( service_definition, service_uri, ServiceInterface.with_access_policy( protocol, access_policy, payload_format, ), access_policy, ) def wrapped_func(func): self.registration_rules.store( RegistrationRule( provided_service, self.system, method, func, )) return func return wrapped_func
def __init__(self, func: Callable): self.service_instance = Service.make( service_definition, service_uri, protocol, access_policy, payload_format, ) self.method = method self.service_definition = service_definition self.func = func
def query_result(self, query_response): query_data = query_response.read_json()['serviceQueryData'][0] service = Service( query_data['serviceDefinition']['serviceDefinition'], query_data['serviceUri'], query_data['interfaces'][0]['interfaceName'], query_data['secure'], query_data['metadata'], query_data['version'], ) system = ArrowheadSystem.from_dto(query_data['provider']) return service, system
def _extract_rule(core_service_tuple: CoreConfig, config: Dict, secure: bool) -> OrchestrationRule: secure_string = constants.Security.SECURE if secure else constants.Security.INSECURE access_policy = constants.AccessPolicy.CERTIFICATE if secure else constants.AccessPolicy.UNRESTRICTED interface = ServiceInterface(core_service_tuple.protocol, secure_string, core_service_tuple.payload) core_system = ArrowheadSystem(**config[core_service_tuple.system]) return OrchestrationRule( Service( core_service_tuple.service_definition, core_service_tuple.uri, interface, access_policy, ), core_system, core_service_tuple.method, )
def add_orchestration_rule( self, service_definition: str, method: str, protocol: str = '', access_policy: str = '', payload_format: str = '', # TODO: Should **kwargs just be orchestration_flags and preferred_providers? orchestration_flags: OrchestrationFlags = OrchestrationFlags.OVERRIDE_STORE, **kwargs, ) -> None: """ Add orchestration rule for provided_service definition Args: service_definition: Service definition that is looked up from the orchestrator. method: The HTTP method given in uppercase that is used to consume the provided_service. access_policy: Service access policy. """ requested_service = Service( service_definition, interface=ServiceInterface.with_access_policy( protocol, access_policy, payload_format, ), access_policy=access_policy ) orchestration_form = forms.OrchestrationForm.make( self.system, requested_service, orchestration_flags, **kwargs ) # TODO: Add an argument for arrowhead forms in consume_service, and one for the ssl-files orchestration_response = self.consume_service( CoreServices.ORCHESTRATION.service_definition, json=orchestration_form.dto(), cert=self.cert, ) rules = responses.process_orchestration(orchestration_response, method) for rule in rules: self.orchestration_rules.store(rule)
async def add_orchestration_rule( # type: ignore self, service_definition: str, method: str, protocol: str = '', access_policy: str = '', payload_format: str = '', orchestration_flags: OrchestrationFlags = OrchestrationFlags.OVERRIDE_STORE, **kwargs, ): """ Add orchestration rule for provided_service definition Args: service_definition: Service definition that is looked up from the orchestrator. method: The HTTP method given in uppercase that is used to consume the provided_service. access_policy: Service access policy. """ requested_service = Service.make( service_definition, protocol=protocol, access_policy=access_policy, payload_format=payload_format, ) orchestration_form = arrowhead_client.client.core_service_forms.client.OrchestrationForm.make( self.system, requested_service, orchestration_flags, **kwargs ) # TODO: Add an argument for arrowhead forms in consume_service, and one for the ssl-files orchestration_response = await self.consume_service( CoreServices.ORCHESTRATION.service_definition, json=orchestration_form.dto(), # cert=self.cert, ) rules = responses.process_orchestration(orchestration_response, method) for rule in rules: self.orchestration_rules.store(rule)
def access_policy_service(request): claims = request.param consumer_private_key, consumer_public_key = generate_keys() consumer_cert = generate_cert(claims['cid'], consumer_private_key, consumer_public_key) consumer_cert_string = consumer_cert.public_bytes( encoding=serialization.Encoding.PEM, ).decode() service_definition = claims['sid'] service_interface = claims['iid'] service = Service( service_definition, 'pytest/access', service_interface, ) return service, consumer_cert_string
def _initialize_event_subscription(self) -> None: for event_type, rule in self.event_subscription_rules.items(): fake_service = Service( service_definition=f'{event_type}-{rule.uuid}', service_uri=rule.notify_uri, interface=ServiceInterface.from_str('HTTP-SECURE-JSON'), ) fake_access_policy = get_access_policy( policy_name=constants.AccessPolicy.CERTIFICATE, provided_service=fake_service, privatekey=self.keyfile, authorization_key=self.auth_authentication_info) fake_registration_rule = RegistrationRule( provided_service=fake_service, provider_system=rule.subscriber_system, method='POST', access_policy=fake_access_policy, func=rule.callback, ) self.provider.add_provided_service(fake_registration_rule)
def _extract_service( query_data: client_forms.OrchestrationResponse) -> Service: """ Extracts provided_service data from test_core provided_service response """ # TODO: this code guarded against different versions of OrchestrationResponse, not sure why ''' if 'serviceDefinition' in query_data.dict(): service_definition_base = 'serviceDefinition' elif 'service' in query_data.dict(): service_definition_base = 'service' else: raise ValueError ''' service = Service( query_data.service.service_definition, query_data.service_uri, ServiceInterface.from_str(query_data.interfaces[0].interface_name), query_data.secure, query_data.metadata, query_data.version, ) return service
def process_service_query( query_response: Response) -> List[Tuple[Service, ArrowheadSystem]]: """ Handles provided_service query responses and returns a lists of services and systems """ # TODO: Status 400 is general for all core systems and should be put in the handler. if query_response.status_code == 400: raise errors.CoreServiceInputError( query_response.read_json()[constants.Misc.ERROR_MESSAGE]) query_response_ = client_forms.ServiceQueryResponse( **query_response.read_json()) service_and_system = [(Service( service_definition=query_result.service_definition.service_definition, service_uri=query_result.service_uri, interface=ServiceInterface.from_str( query_result.interfaces[0].interface_name), access_policy='', metadata=query_result.metadata, version=query_result.version, ), ArrowheadSystem(**query_result.provider.dict())) for query_result in query_response_.service_query_data] return service_and_system
def provided_service( self, service_definition: str, service_uri: str, interface: str, method: str, *func_args, **func_kwargs, ): """ Decorator to add a provided service to the provider. Args: service_definition: Service definition to be stored in the service registry service_uri: The path to the service interface: Arrowhead interface string(s) method: HTTP method required to access the service """ provided_service = Service( service_definition, service_uri, interface, ) def wrapped_func(func): self._provided_services[service_definition] = (provided_service, func) self.provider.add_provided_service(service_definition, service_uri, method=method, func=func, *func_args, **func_kwargs) return func return wrapped_func
from typing import Dict from arrowhead_client.service import Service #TODO: The service definition is repeated, this dict should be a custom class # where __getitem__() looks through a list of services. Or not, I'm not sure services: Dict[str, Service] = { 'register': Service( service_definition='register', service_uri='serviceregistry/register', interface='HTTP-SECURE-JSON', ), 'query': Service( service_definition='query', service_uri='serviceregistry/query', interface='HTTP-SECURE-JSON', ), 'unregister': Service( service_definition='unregister', service_uri='serviceregistry/unregister', interface='HTTP-SECURE-TEXT', ) }
setup_client = SyncClient.create( system_name='sysop', address='127.0.0.1', port=1337, keyfile='certificates/crypto/sysop.key', certfile='certificates/crypto/sysop.crt', cafile='certificates/crypto/sysop.ca' ) print('Setting up local cloud') setup_client.orchestration_rules.store( OrchestrationRule( Service( 'mgmt_register_service', 'serviceregistry/mgmt', ServiceInterface.from_str('HTTP-SECURE-JSON'), ), ArrowheadSystem( **default_config['service_registry'] ), 'POST', ) ) setup_client.orchestration_rules.store( OrchestrationRule( Service( 'mgmt_get_systems', 'serviceregistry/mgmt/systems', ServiceInterface('HTTP', 'SECURE', 'JSON'),
from typing import Dict from copy import deepcopy from arrowhead_client.service import Service _http_core_services: Dict[str, Service] = { 'register': Service( service_definition='register', service_uri='serviceregistry/register', interface='HTTP-SECURE-JSON', ), 'query': Service( service_definition='query', service_uri='serviceregistry/query', interface='HTTP-SECURE-JSON', ), 'unregister': Service( service_definition='unregister', service_uri='serviceregistry/unregister', interface='HTTP-SECURE-TEXT', ), 'orchestration-service': Service( service_definition='orchestration-service', service_uri='orchestrator/orchestration', interface='HTTP-SECURE-JSON', ) } def core_service(service_defintion: str) -> Service: core_service_instance = deepcopy(_http_core_services.get(service_defintion, None)) if not core_service_instance: raise ValueError(f'Core service \'{service_defintion}\' not found, ' f'available core services are {list(_http_core_services.keys())}')
from arrowhead_client.system import ArrowheadSystem from arrowhead_client.service import Service, ServiceInterface from arrowhead_client.rules import OrchestrationRule, OrchestrationRuleContainer provider_system = ArrowheadSystem.make('test', '127.0.0.1', 1337, '') consumed_service = Service( 'test', 'test', ServiceInterface('HTTP', 'SECURE', 'JSON'), metadata={'dummy': 'data'}, ) method = 'GET' authorization_token = 'token.token.token' def test_orchestration_rule(): rule = OrchestrationRule(consumed_service, provider_system, method, authorization_token) assert rule.service_definition == consumed_service.service_definition assert rule.protocol == consumed_service.interface.protocol assert rule.secure == consumed_service.interface.secure assert rule.payload_type == consumed_service.interface.payload assert rule.access_policy == consumed_service.access_policy assert rule.metadata == consumed_service.metadata assert rule.version == consumed_service.version assert rule.system_name == provider_system.system_name assert rule.endpoint == f'{provider_system.authority}/{consumed_service.service_uri}' assert rule.authentication_info == provider_system.authentication_info assert rule.method == method assert rule.authorization_token == authorization_token
from typing import Dict from arrowhead_client.service import Service services: Dict[str, Service] = { 'orchestration-service': Service( service_definition='orchestration-service', service_uri='orchestrator/orchestration', interface='HTTP-SECURE-JSON', ) }
from arrowhead_client.system import ArrowheadSystem from arrowhead_client.service import Service, ServiceInterface from arrowhead_client.constants import OrchestrationFlags import arrowhead_client.client.core_service_forms.client as forms requester_system = ArrowheadSystem.make('test_system', 'localhost', 0) provider_system = ArrowheadSystem.make('test_system', 'localhost', 0) provided_service = Service( service_definition='test_service', service_uri='/test/test/test', interface=ServiceInterface('HTTP', 'SECURE', 'JSON'), access_policy='CERTIFICATE', metadata={'dummy': 'data'}, version=0, ) def test_registration_form(): registration_form = forms.ServiceRegistrationForm.make( provided_service=provided_service, provider_system=provider_system, end_of_validity='dummy-date', ) valid_keys = { 'serviceDefinition', 'serviceUri', 'providerSystem', 'secure', 'interfaces', 'metadata',