Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
adc593b
added support to start a digitalpy application from barebones
naman108 Nov 30, 2023
6eb95d2
expanded service management support and added initial network impl
naman108 Dec 3, 2023
7d0c492
updated gitignore
naman108 Dec 3, 2023
0ac70ea
Refactor code and remove unused methods and print statements, and imp…
naman108 Dec 19, 2023
29e371d
added builder
naman108 Dec 20, 2023
fea842f
Implemented object_id parse method
naman108 Dec 22, 2023
73cbc58
updated linting and state management for default facade
naman108 Dec 22, 2023
c9caba7
implemented domain component in digitalpy
naman108 Dec 22, 2023
f9b9879
implemented NetworkClient
naman108 Dec 22, 2023
339bebf
renamed configuration to model configuration
naman108 Dec 22, 2023
fb37c06
updated linting
naman108 Dec 22, 2023
9139c31
updated tracing and initial testing framework
naman108 Dec 22, 2023
0e62f39
updated xml serialization controller to support standard nodes
naman108 Dec 22, 2023
ab04a93
added service stop support and default service status
naman108 Dec 22, 2023
0a52007
updated deps and version
naman108 Dec 22, 2023
7e793b1
updated facade names to remove startup error messages
naman108 Dec 22, 2023
6040eb3
added request format method
naman108 Dec 22, 2023
5968be3
added broker receive response method
naman108 Dec 23, 2023
8b85343
improved docs and linting
naman108 Dec 23, 2023
19bb615
added intial test implementation
naman108 Dec 23, 2023
2abf4f9
implemented simple health management
naman108 Dec 23, 2023
f80cf30
Add service health functionality
naman108 Dec 23, 2023
f554315
Merge pull request #52 from FreeTAKTeam/health_checking
naman108 Dec 23, 2023
e3f3303
fixed health check to prevent checking off services
naman108 Dec 23, 2023
e944ee3
Refactor get_all_service_health method to use dictionary items() method
naman108 Dec 23, 2023
2f261bf
Refactor service management component and configuration module
naman108 Dec 27, 2023
57ea549
Refactor DigitalPyService class and add missing docstrings
naman108 Dec 27, 2023
c4e3916
Add network handling to DigitalPyService
naman108 Dec 27, 2023
90790b2
Refactor ServiceManagementSenderController to improve code readabilit…
naman108 Dec 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,5 @@ dmypy.json

# Pyre type checker
.pyre/
digitalpy/core/network/impl/stream_tcp_test.py
digitalpy/core/IAM/persistence/connections.json
4 changes: 2 additions & 2 deletions digitalpy/core/IAM/controllers/iam_users_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@

from digitalpy.core.main.controller import Controller
from digitalpy.core.domain.node import Node
from digitalpy.core.domain.domain.network_client import NetworkClient
from digitalpy.core.zmanager.request import Request
from digitalpy.core.zmanager.response import Response
from digitalpy.core.zmanager.action_mapper import ActionMapper
from digitalpy.core.digipy_configuration.configuration import Configuration

from ..configuration.iam_constants import COMPONENT_NAME, CONNECTIONS_PERSISTENCE
from ..model.connection import Connection

class IAMUsersController(Controller):
def __init__(self, request: Request, response: Response, action_mapper: ActionMapper, configuration: Configuration):
super().__init__(request, response, action_mapper, configuration)

def connection(self, logger, connection: Connection, **kargs):
def connection(self, logger, connection: NetworkClient, **kargs):
"""handle the case of a connection connection to any digitalpy service

Args:
Expand Down
4 changes: 2 additions & 2 deletions digitalpy/core/IAM/model/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
class Connection(Node):
def __init__(self, node_type = "connection", oid=None) -> None:
super().__init__(node_type, oid=oid)
self._service_id = None
self._protocol = None
self._service_id: str = None
self._protocol: str = None

@property
def service_id(self):
Expand Down
68 changes: 67 additions & 1 deletion digitalpy/core/action_mapping.ini
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,14 @@ __class = digitalpy.core.zmanager.impl.default_request.DefaultRequest
[ActionMapper]
; this is the default action mapper
__class = digitalpy.core.zmanager.impl.async_action_mapper.AsyncActionMapper
routing_subscriber_address = tcp://127.0.0.1:19030
routing_publisher_address = tcp://127.0.0.1:19031

[AsyncActionMapper]
; this is a static reference to the async action mapper and should not be changed
__class = digitalpy.core.zmanager.impl.async_action_mapper.AsyncActionMapper
routing_subscriber_address = tcp://127.0.0.1:19030
routing_publisher_address = tcp://127.0.0.1:19031

[SyncActionMapper]
; this is a static reference to the sync action mapper and should not be changed
Expand All @@ -51,11 +55,73 @@ __class = digitalpy.core.impl.default_file_logger.DefaultFileLogger
[CotRouter]
__class = FreeTAKServer.components.core.COT_Router.cot_router_facade.CotRouter

; the subject configuration
[Subject]
__class = digitalpy.core.zmanager.subject.Subject
frontend_pull_address = tcp://127.0.0.1:19030
frontend_pub_address = tcp://127.0.0.1:19031
backend_address = tcp://127.0.0.1:19031
worker_count = 3

; the integration manager configuration
[IntegrationManager]
__class = digitalpy.core.zmanager.integration_manager.IntegrationManager

integration_manager_puller_protocol = tcp
integration_manager_puller_address = 127.0.0.1
integration_manager_puller_port = 19033
integration_manager_publisher_protocol = tcp
integration_manager_publisher_address = 127.0.0.1
integration_manager_publisher_port = 19034

; the routing worker configuration
[RoutingWorker]
__class = digitalpy.core.zmanager.impl.default_routing_worker.DefaultRoutingWorker
server_address = tcp://127.0.0.1:19031
integration_manager_address = tcp://127.0.0.1:19033

; the service manager configuration
[ServiceManager]
__class = digitalpy.core.service_management.controllers.service_management_main.ServiceManagementMain
subject_address = 127.0.0.1
subject_port = 19030
subject_protocol = tcp
integration_manager_address = 127.0.0.1
integration_manager_port = 19034
integration_manager_protocol = tcp
service_id = service_manager

; the service configuration values
[Service]
subject_address = 127.0.0.1
subject_port = 19030
subject_protocol = tcp
integration_manager_address = 127.0.0.1
integration_manager_port = 19034
integration_manager_protocol = tcp

; the service manager process controller class
[ServiceManagerProcessController]
__class = digitalpy.core.service_management.controllers.service_management_process_controller.ServiceManagementProcessController

; the default tcp_network
[TCPNetwork]
__class = digitalpy.core.network.impl.network_tcp.TCPNetwork
client = DefaultClient

[DefaultClient]
__class = digitalpy.core.domain.domain.network_client.NetworkClient

; the default tracer exporter
[TracerExporter]
__class = opentelemetry.sdk.trace.export.ConsoleSpanExporter
;__class = FreeTAKServer.components.core.abstract_component.telemetry_exporter.ZMQExporter
;host = 127.0.0.1
;port = 40033

; the processor mechanism for the tracer controller
[TracerProcessor]
__class = opentelemetry.sdk.trace.export.BatchSpanProcessor

; the exporter mechanism for the tracer controller
[TracingProvider]
__class = digitalpy.core.telemetry.impl.opentel_tracing_provider.OpenTelTracingProvider
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import importlib
import os
from pathlib import PurePath
from typing import List
from typing import Dict, List
import pkg_resources

from digitalpy.core.main.registration_handler import RegistrationHandler
Expand All @@ -22,10 +22,12 @@
class ComponentRegistrationHandler(RegistrationHandler):
"""this class is used to manage component registration"""

registered_components = {}
registered_components: Dict[str, DefaultFacade] = {}

pending_components = {}

component_index: Dict[str, Configuration] = {}

@staticmethod
def clear():
ComponentRegistrationHandler.registered_components = {}
Expand Down Expand Up @@ -109,16 +111,17 @@ def register_component(
return False

@staticmethod
def save_component(facade, component_name: str):
def save_component(facade: DefaultFacade, component_name: str):
ComponentRegistrationHandler.registered_components[component_name] = facade
ComponentRegistrationHandler.component_index[component_name] = facade.get_manifest()

@staticmethod
def register_pending(component_name, config):
for facade_instance in ComponentRegistrationHandler.pending_components.pop(component_name, []):
facade_instance.register(config)

@staticmethod
def validate_manifest(manifest: Configuration, component_name: str, component_facade) -> bool:
def validate_manifest(manifest: Configuration, component_name: str, component_facade) -> tuple[bool, bool]:
#TODO: determine better way to inform the caller that the manifest is invalid
"""validate that the component is compatible with the current digitalpy version

Expand All @@ -130,7 +133,7 @@ def validate_manifest(manifest: Configuration, component_name: str, component_fa
ValueError: raised if the manifest section is missing from the manifest configuration

Returns:
bool: whether the component is compatible with the current digitalpy installation
tuple[bool, bool]: whether the component is compatible with the current digitalpy installation and whether the component has any pending dependencies
"""
# retrieve the current digitalpy version based on the setup.py
digitalpy_version = pkg_resources.require(DIGITALPY)[0].version
Expand All @@ -148,7 +151,7 @@ def validate_manifest(manifest: Configuration, component_name: str, component_fa

# validate the component name matches the name specified in the manifest
if component_name != section[NAME]:
return False
return False, False

# iterate the delimited version number and compare it to the digitalpy version
for i in range(len(section[REQUIRED_ALFA_VERSION].split(VERSION_DELIMITER))):
Expand All @@ -159,23 +162,23 @@ def validate_manifest(manifest: Configuration, component_name: str, component_fa
elif int(digitalpy_version_number)==int(section[REQUIRED_ALFA_VERSION].split(VERSION_DELIMITER)[i]):
continue
else:
return False
return False, False

# dont approve the manifest if the component has already been registered
if (
component_name in ComponentRegistrationHandler.registered_components
and section[VERSION]
!= ComponentRegistrationHandler.registered_components[component_name][VERSION]
):
return False
return False, False

# dont approve the manifest if a component with the same name but a different ID already exists
if (
component_name in ComponentRegistrationHandler.registered_components
and ComponentRegistrationHandler.registered_components[component_name][ID]
!= section[ID]
):
return False
return False, False

pending = False

Expand Down
47 changes: 36 additions & 11 deletions digitalpy/core/component_management/impl/default_facade.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
# pylint: disable=unused-argument
"""This is the default facade module. It is used to create a facade for a component. It is a simple example of a DigitalPyFacade.
"""
from types import ModuleType
from digitalpy.core.main.controller import Controller
from digitalpy.core.domain.node import Node
from digitalpy.core.parsing.load_configuration import LoadConfiguration
from digitalpy.core.digipy_configuration.impl.inifile_configuration import InifileConfiguration
from digitalpy.core.zmanager.impl.default_action_mapper import DefaultActionMapper
from digitalpy.core.zmanager.request import Request
from digitalpy.core.zmanager.response import Response
from digitalpy.core.main.object_factory import ObjectFactory
from digitalpy.core.main.log_manager import LogManager
from digitalpy.core.main.impl.default_file_logger import DefaultFileLogger
from digitalpy.core.main.controller import Controller
from digitalpy.core.digipy_configuration.configuration import Configuration

from digitalpy.core.telemetry.tracer import Tracer


Expand All @@ -19,11 +26,11 @@ def __init__(
log_file_path,
component_name=None,
type_mapping=None,
action_mapper: DefaultActionMapper = None,
base=object,
request=None,
response=None,
configuration=None,
action_mapper: DefaultActionMapper = None, # type: ignore
base=ModuleType,
request: Request = None, # type: ignore
response: Response = None, # type: ignore
configuration: Configuration = None, # type: ignore
configuration_path_template=None,
tracing_provider_instance=None,
manifest_path=None,
Expand Down Expand Up @@ -75,7 +82,7 @@ def __init__(
self.component_name
)
else:
self.tracer = None
self.tracer = None # type: ignore
# load the manifest file as a configuration
if manifest_path is not None:
self.manifest = InifileConfiguration("")
Expand All @@ -95,16 +102,19 @@ def __init__(
else:
self.config_loader = None

self.injected_values = {"logger": self.logger, "config_loader": self.config_loader, "tracer": self.tracer}
self.injected_values = {
"logger": self.logger, "config_loader": self.config_loader, "tracer": self.tracer}

def initialize(self, request, response):
super().initialize(request, response)
self.request.set_sender(self.__class__.__name__)

def execute(self, method):
def execute(self, method=None) -> None:
self.request.set_value("logger", self.logger)
self.request.set_value("config_loader", self.config_loader)
self.request.set_value("tracer", self.tracer)
if not method:
return
try:
if hasattr(self, method):
# pass all request values as keyword arguments
Expand All @@ -127,6 +137,7 @@ def public(func):
facade methods being called directly. it's role is to
inject internal attributes into the wrapped function which
would generally be injected by the execute method"""

def wrapper(self, *args, **kwargs):
# ensure that required values are passed by to controller
# methods even if method isnt called through .execute method
Expand All @@ -151,7 +162,7 @@ def register(self, config: InifileConfiguration, **kwargs):
internal_config.add_configuration(self.internal_action_mapping_path)
ObjectFactory.register_instance(
f"{self.component_name.lower()}actionmapper",
self.base.ActionMapper(
self.base.ActionMapper( # type: ignore
ObjectFactory.get_instance("event_manager"),
internal_config,
),
Expand All @@ -178,7 +189,8 @@ def _register_type_mapping(self):
request.set_action("RegisterHumanToMachineMapping")
# reverse the mapping and save the reversed mapping
request.set_value(
"human_to_machine_mapping", {k: v for v, k in self.type_mapping.items()}
"human_to_machine_mapping", {
k: v for v, k in self.type_mapping.items()}
)

actionmapper = ObjectFactory.get_instance("SyncActionMapper")
Expand All @@ -187,3 +199,16 @@ def _register_type_mapping(self):

def accept_visitor(self, node: Node, visitor, **kwargs):
return node.accept_visitor(visitor)

def __setstate__(self, state: dict) -> None:
from .. import base
self.__dict__ = state
if "base" in state:
self.base = base

def __getstate__(self) -> dict:
tmp = self.__dict__
set_base = tmp.get("base", None)
if set_base is not None:
tmp["base"] = True
return tmp

This file was deleted.

Loading