Config

Config - Shared

Configuration types shared across both Clients and Services.

class intersect_sdk_common.config.ControlPlaneConfig(protocol: Literal['mqtt5.0', 'amqp0.9.1'], username: Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1)])], password: Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1)])], host: Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1)])] = '127.0.0.1', port: Annotated[int, Gt(gt=0)] | None = None, is_root: bool = True)

Configuration for interacting with a broker.

host: Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1)])] = '127.0.0.1'

127.0.0.1)

Type:

Broker hostname (default

is_root: bool = True

Whether or not the broker credentials are for connecting as a root user.

This should be True IF:
  • You are a Core Service

  • You are an SDK Client or Service, but your message broker is hosted locally.

This should be False IF:
  • You are an SDK Client or Service, and the broker you’re connected to is remote.

This is important for specific implementations; the Registry Service configures queues for microservices, but Core Services configure their own queues themselves.

password: Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1)])]

Password credentials for broker connection.

port: Annotated[int, Gt(gt=0)] | None = None

Broker port. List of common ports:

  • 1883 (MQTT)

  • 4222 (NATS default port)

  • 5222 (XMPP)

  • 5223 (XMPP over TLS)

  • 5671 (AMQP over TLS)

  • 5672 (AMQP)

  • 7400 (DDS Discovery)

  • 7401 (DDS User traffic)

  • 8883 (MQTT over TLS)

  • 61613 (RabbitMQ STOMP - WARNING: ephemeral port)

NOTE: INTERSECT currently only supports AMQP and MQTT.

protocol: Literal['mqtt5.0', 'amqp0.9.1']

The protocol of the broker you’d like to use (i.e. AMQP, MQTT…)

username: Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1)])]

Username credentials for broker connection.

intersect_sdk_common.config.ControlProvider

The type of broker we connect to.

alias of Literal[‘mqtt5.0’, ‘amqp0.9.1’]

class intersect_sdk_common.config.DataStoreConfig(username: Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1)])], password: Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1)])], host: Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1)])] = '127.0.0.1', port: Annotated[int, Gt(gt=0)] | None = None)

Configuration for interacting with a data store.

host: Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1)])] = '127.0.0.1'

127.0.0.1)

Type:

Data store hostname (default

password: Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1)])]

Password credentials for data store connection.

port: Annotated[int, Gt(gt=0)] | None = None

Data store port

username: Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1)])]

Username credentials for data store connection.

class intersect_sdk_common.config.DataStoreConfigMap(minio: list[DataStoreConfig] = <factory>)

Configurations for any data stores the application should talk to.

get_missing_data_store_types() set[IntersectDataHandler]

Return a set of IntersectDataHandlers which will not be permitted, due to a configuration type missing.

If all data configurations exist, returns an empty set

minio: list[DataStoreConfig]

minio configurations

intersect_sdk_common.config.HIERARCHY_REGEX = '^[a-z]((?!--)[a-z0-9-]){2,62}$'

The hierarchy regex needs to be fairly restricted due to the number of different systems we want to be compatible with. The rules:

  • Only allow unreserved characters (alphanumeric and .-~_): https://datatracker.ietf.org/doc/html/rfc3986#section-2.3

  • Require lowercase letters to avoid incompatibilities with case-insensitive systems.

  • MinIO has been found to forbid _ and ~ characters

  • MinIO requires an alphanumeric character at the start of the string

  • No adjacent non-alphanumeric characters allowed

  • Range should be from 3-63 characters

The following commit tracks several issues with MINIO: https://code.ornl.gov/intersect/additive-manufacturing/ros-intersect-adapter/-/commit/fa71b791be0ccf1a5884910b5be3b5239cf9896f

class intersect_sdk_common.config.HierarchyConfig(*, service: Annotated[str, _PydanticGeneralMetadata(pattern='^[a-z]((?!--)[a-z0-9-]){2,62}$')], subsystem: Annotated[str | None, _PydanticGeneralMetadata(pattern='^[a-z]((?!--)[a-z0-9-]){2,62}$')] = None, system: Annotated[str, _PydanticGeneralMetadata(pattern='^[a-z]((?!--)[a-z0-9-]){2,62}$')], facility: Annotated[str, _PydanticGeneralMetadata(pattern='^[a-z]((?!--)[a-z0-9-]){2,62}$')], organization: Annotated[str, _PydanticGeneralMetadata(pattern='^[a-z]((?!--)[a-z0-9-]){2,62}$')])

Configuration for registering this service in a system-of-system architecture.

facility: Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(pattern='^[a-z]((?!--)[a-z0-9-]){2,62}$')])]

Name of the facility (an ORNL institutional designation, i.e. ‘neutrons’) (NOT abbreviated, should be unique within an organization)

hierarchy_string(join_str: str = '') str

Get the full hierarchy string. This is mostly used internally, but if you’re developing a client, it could potentially be helpful.

Params

join_str: String used to separate different hierarchy parts in the full string (default: empty string).

Returns:

Single string, which will contain all system-of-system parts. For optional parts not configured (i.e. - no subsystem), they will be represented by a “-” character.

organization: Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(pattern='^[a-z]((?!--)[a-z0-9-]){2,62}$')])]

Name of the organization (i.e. ‘ornl’) (NOT abbreviated) (should be unique in an INTERSECT cluster)

service: Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(pattern='^[a-z]((?!--)[a-z0-9-]){2,62}$')])]

The name of this application - should be unique within an INTERSECT system

subsystem: str | None

An associated subsystem / service-grouping of the system (should be unique within an INTERSECT system)

system: Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(pattern='^[a-z]((?!--)[a-z0-9-]){2,62}$')])]

Name of the “system”, could also be thought of as a “device” (should be unique within a facility)

Config - Service

Service specific configuration types.

class intersect_sdk.config.service.IntersectServiceConfig(*, hierarchy: ~intersect_sdk_common.config.HierarchyConfig, brokers: ~typing.Annotated[list[~intersect_sdk_common.config.ControlPlaneConfig], ~annotated_types.MinLen(min_length=1)], data_stores: ~intersect_sdk_common.config.DataStoreConfigMap = <factory>, status_interval: ~typing.Annotated[float, ~annotated_types.Ge(ge=30.0), ~annotated_types.Lt(lt=1500.0), ~annotated_types.Gt(gt=0)] = 300.0)

The user-provided configuration needed to integrate with INTERSECT.

brokers: Annotated[list[ControlPlaneConfig], FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1)])]

Configurations for any message brokers the application should attach to

use literal “discovery” string to discover brokers, use list of brokers otherwise

data_stores: DataStoreConfigMap, FieldInfo(annotation=NoneType, required=False, default_factory=<lambda>)]

Configurations for any data stores the application should talk to

hierarchy: HierarchyConfig

Configuration of the System-of-System representation

status_interval: Annotated[float, Gt(gt=0)]

This value must be greater than 30 seconds but less than 25 minutes, as every 30 minutes the resource service will check to get the last reply time of the adapter, and will automatically mark the adapter as having an unknown lifecycle status if the adapter has not made some kind of response. (We give 5 minutes as a potential time buffer.)

Type:

How often to send status messages through the broker (seconds) (default

Config - Client

Client specific configuration types.

final class intersect_sdk.config.client.IntersectClientConfig(*, brokers: ~typing.Annotated[list[~intersect_sdk_common.config.ControlPlaneConfig], ~annotated_types.MinLen(min_length=1)], data_stores: ~intersect_sdk_common.config.DataStoreConfigMap = <factory>, initial_message_event_config: ~intersect_sdk.client_callback_definitions.IntersectClientCallback, resend_initial_messages_on_secondary_startup: bool = False, terminate_after_initial_messages: bool = False, system: str = 'tmp-', facility: str = 'tmp-', organization: str = 'tmp-')

The user-provided configuration needed to integrate with INTERSECT as a client.

brokers: Annotated[list[ControlPlaneConfig], FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1)])]

Configurations for any message brokers the application should attach to

use literal “discovery” string to discover brokers, use list of brokers otherwise

data_stores: DataStoreConfigMap, FieldInfo(annotation=NoneType, required=False, default_factory=<lambda>)]

Configurations for any data stores the application should talk to

facility: Annotated[str, FieldInfo(annotation=NoneType, required=False, default='tmp-')]

Name of the facility (an ORNL institutional designation, i.e. ‘neutrons’) (NOT abbreviated, should be unique within an organization)

initial_message_event_config: IntersectClientCallback

configuration for: 1) the initial messages you want to send out 2) the initial events you want to listen to

Note that at LEAST one of these should be non-empty.

organization: Annotated[str, FieldInfo(annotation=NoneType, required=False, default='tmp-')]

Name of the organization (i.e. ‘ornl’) (NOT abbreviated) (should be unique in an INTERSECT cluster)

resend_initial_messages_on_secondary_startup: bool

if set to True, resend the initial messages if the client is restarted

(default: False)

system: Annotated[str, FieldInfo(annotation=NoneType, required=False, default='tmp-')]

Name of the “system”, could also be thought of as a “device” (should be unique within a facility)

terminate_after_initial_messages: bool

if set to True, will never enter the pub/sub loop and will never wait for responses from the services

(default: False)