What is a feature?
A feature is an installable piece of software that can be dragged into a node group or cluster in the design studio.
What is a route?
A route is a connection between two features. Routes are drawn so that features can communicate with one another. In the example below, the reason why filebeatmqtt feature has a route to elasticsearch is that it stores events there. Therefore, elasticsearch feature needs to be aware of an incoming connection and configure itself for it. See example 1 below:
What is an internal route?
An internal route is one between two features in the architecture. One of the features is the ingress feature and the other one is the egress feature.
In example 1 above, filebeatmqtt is the egress feature and elasticsearch is the ingress feature.
The code snippets below show manifest.yaml files of the participating features. These show ingresses and egresses that make it possible to draw the line as in example 1.
# a snippet from elasticsearch manifest.yaml
id: elasticsearch
ingresses:
- id: ingress-cluster-elasticsearch
name: Internal ingress to elasticsearch
isExternal: False
default: True
# a snippet from filebeatmqtt manifest.yaml
id: filebeatmqtt
connections:
- id: egress-elasticsearch
description: Egress to elasticsearch
featureReference: elasticsearch
a very important fact is that the ingress feature is not aware of the name of the egress feature. On the other hand, the egress feature is aware of what feature it connects to. See featureReference property on filebeatmqtt manifest.yaml
What is an external route?
an external route is a connection from outside of the architecture into a feature in the architecture
there is only one feature participating in the route. That is the ingress feature.
Ingress definition deep dive:
id: string | unique ingress name, name must be same as patch name
name: string | human readable name of ingress to be displayed in UI
isExternal: boolean | defines if the ingress is meant to be used with connections from outside of the architecture
default: boolean | defines if the ingress should be chosen by the UI if there is more than 1 ingress with same isExternal flag
Egress definition deep dive
id: string | unique connection name, name must be same as patch name
name: string | human readable name of connection to be displayed in UI
featureReference: string | must be equal to the name of the ingress feature
Patching files
Every *egress|ingress uses a corresponding .json file with the same name as the name of the ingress|egress. For example, given this ingress in manifest.yaml:
ingresses:
- id: ingress-influxdb-docker
name: Docker ingress to influxdb
isExternal: False
default: True
a file with name ingress-influxdb-docker.json must exist in routing directory, like so:
influxdb_docker
└── 2.5.1
├── container
│ ├── docker
│ │ └── docker-compose.yaml
│ ├── library
│ │ └── routingConfig.json
│ ├── routing
│ │ └── ingress-influxdb-docker.json <<--- here it is
│ └── schemas
│ ├── ui.schema.json
│ └── ui.schema.midlayer.json
└── manifest.yaml
Patch file specification
As stated above, every ingress | egress has a json patch file. The object in the file has three properties:
externalVariables
files
returns
Examples
managementstudio feature has an external ingress
- id: ingress-external-managementstudio
name: External ingress to managementstudio
isExternal: True
default: True
The patch file is:
{
"externalVariables": [],
"files": {
"values.yaml": [
{
"title": "Enable external connection ingress to Management Studio",
"comparison": [
{
"type": "always"
}
],
"operations": [
{
"op": "add",
"path": "/self/grafana/ingress/enabled",
"value": true
}
]
}
]
}
}
This can be interpreted as:
do not use any external variables
on the values.yaml file perform one operation. The operation toggles grafana/ingress/enabled flag from false to true. The self references the values.yaml file.
return nothing
mosquitto-docker feature has an internal ingress
- id: ingress-mosquitto-docker
name: Ingress to mosquitto_docker
isExternal: False
default: True
The patch file is:
{
"externalVariables": [],
"files": {},
"returns": {
"servicePort": {
"file": "routingConfig.json",
"path": "/self/SERVICE_PORT"
},
"serviceProtocol": {
"file": "routingConfig.json",
"path": "/self/PROTOCOL"
}
}
}
This can be interpreted as:
do not use any externalVariables
return
{
"servicePort": "property SERVICE_PORT from file routingConfig.json",
"serviceProtocol": "property PROTOCOL from file routingConfig.json"
}
Why do we need return values?
An internal route has two participating features, ingress feature and egress feature. The ingress feature is the one that takes priority and is the “owner” of the connection. The ingress feature tells the egress feature what parameters it should use to connect to it. This is where the return values come in place. Let’s take a concrete example and make a route from modbus2mqtt to mosquitto-docker.
User drags mosquitto-docker into a nodegroup.
User changes the port on mosquitto-docker in the UI like so:
3. User drags `modbus2mqtt` and drags a line from it to `mosquitto-docker`
That brings us to the conclusion that only the mosquitto-docker feature is aware of the port number and it should propagate that to the egress feature, i.e modbus2mqtt. That is done with return values.
How is this example processed?
mosquitto-docker's uiSchema.midlayer.json is processed first to save the port number the user has entered in the UI. It will patch two files: docker-compose.yaml and routingConfig.json
{
"Service Port": {
"docker-compose.yaml": [
{
"title": "Set servicePort",
"comparison": [
{
"type": "always"
}
],
"operations": [
{
"op": "textReplacement",
"path": "/self/services/mosquitto/ports/0",
"from": "/externalVariables/userInput",
"variableName": "SERVICE_PORT"
}
]
}
],
"routingConfig.json": [
{
"title": "Set servicePort",
"comparison": [
{
"type": "always"
}
],
"operations": [
{
"op": "copy",
"path": "/self/SERVICE_PORT",
"from": "/externalVariables/userInput"
}
]
}
]
}
}
mosquitto-docker's ingress-mosquitto-docker.json is processed. It doesn’t edit any files. It reads routingConfig.json file and assigns servicePort property to externalVariables:
{
"externalVariables": [],
"files": {},
"returns": {
"servicePort": {
"file": "routingConfig.json",
"path": "/self/SERVICE_PORT"
}
}
}
modbus2mqtt 's egress-mosquitto-docker.json is processed. It reads the servicePort from externalVariables and sets its value to commonconfig.json:
{
"externalVariables": [
"servicePort"
],
"files": {
"commonconfig.json": [
{
"title": "Route to filebeatmqtt",
"comparison": [
{
"type": "always"
}
],
"operations": [
{
"op": "copy",
"path": "/self/Mqtt/Port",
"from": "/externalVariables/servicePort"
}
]
}
]
}
}
The example above shows that ingresses are processed first and they return externalVariables that are fed into egress features.
Helmchart features and routing
It is impossible to predict routing properties for helmchart features without running helmchart template command. Let’s take this example:
User changes attributes on elasticsearch in the UI.
These changes are applied on values.yaml file with uiSchema.midlayer.json
If one of the properties changed is Enable security then we are not able to predict ingress properties locally, and therefore helm template command must be run:
helm template --release-name "elasticsearch" --values="{path/to/values.yaml}" oci://europe-north1-docker.pkg.dev/pratexo-public-5b5a/helm-charts/elasticsearch
That requires routing.yaml template to be present in elasticsearch helmchart.\
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "common.names.fullname" . }}-pratexo-routing
labels: {{- include "common.labels.standard" . | nindent 4 }}
data:
serviceName: {{ include "elasticsearch.coordinating.fullname" . }}
servicePort: {{ .Values.coordinating.service.port | quote }}
certificates: {{ include "elasticsearch.coordinating.fullname" . }}-crt
secrets: {{ template "common.names.fullname" . }}
security: {{ .Values.security.enabled | quote }}
username: {{ .Values.security.elasticUsername | quote }}
The data returned from the helm template command becomes an external variable named ingressConfig that is then fed into egress features as described in previous examples.
{
"externalVariables": [
"ingressConfig"
],
"files": {
"values.yaml": [
{
"title": "Set serviceName elasticsearch",
"comparison": [
{
"type": "always"
}
],
"operations": [
{
"op": "copy",
"path": "/self/elasticsearch/port",
"from": "/externalVariables/ingressConfig/servicePort"
}
]
}
]
}
}
Was this article helpful?
That’s Great!
Thank you for your feedback
Sorry! We couldn't be helpful
Thank you for your feedback
Feedback sent
We appreciate your effort and will try to fix the article