@yarkivaev/scada 2.3.114 → 2.3.116
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +109 -0
- package/charts/scada/Chart.yaml +2 -2
- package/charts/scada/templates/_helpers.tpl +12 -4
- package/charts/scada/templates/clickhouse.yaml +3 -3
- package/charts/scada/templates/collector.yaml +2 -2
- package/charts/scada/templates/namespace.yaml +6 -0
- package/charts/scada/templates/postgres.yaml +3 -3
- package/charts/scada/templates/processes.yaml +88 -0
- package/charts/scada/templates/rabbitmq-config.yaml +91 -0
- package/charts/scada/templates/rabbitmq.yaml +54 -113
- package/charts/scada/templates/site-server.yaml +5 -3
- package/charts/scada/templates/supervisor-sink.yaml +4 -2
- package/charts/scada/values.schema.json +22 -0
- package/charts/scada/values.yaml +21 -0
- package/index.js +3 -0
- package/package.json +8 -3
- package/src/application/deploy/collectorProcesses.js +43 -0
- package/src/application/deploy/expandFlows.js +21 -10
- package/src/application/deploy/publishedStreams.js +30 -0
- package/src/application/deploy/releaseEdges.js +13 -16
- package/src/application/deploy/releaseNodes.js +13 -0
- package/src/application/deploy/releaseValues.js +4 -15
- package/src/application/deploy/releases.js +3 -1
- package/src/application/deploy/subscriptions.js +20 -0
- package/src/infrastructure/deploy/executeRelease.js +102 -0
- package/src/infrastructure/ingest/durableConsume.js +2 -169
- package/src/infrastructure/ingest/modbus/silentStreams.js +9 -11
- package/src/infrastructure/ingest/silentOpenWatch.js +5 -42
- package/src/infrastructure/ingest/telemetry/amqpMetricsIngest.js +7 -18
- package/src/infrastructure/ingest/telemetry/amqpMqttRelay.js +8 -17
- package/src/infrastructure/messaging/rabbitmq/definitions.js +24 -0
- package/src/infrastructure/messaging/rabbitmq/reconcile.js +104 -0
- package/src/infrastructure/opcua/config.js +38 -0
- package/src/infrastructure/opcua/endpoint.js +80 -0
- package/src/infrastructure/opcua/index.js +10 -0
- package/src/infrastructure/opcua/session.js +60 -0
- package/src/infrastructure/opcua/source.js +35 -0
- package/src/infrastructure/opcua/subscriptionHealth.js +28 -0
- package/src/infrastructure/operators/operatorsSync.js +5 -29
- package/src/infrastructure/persistence/clickhouse/streamHub.js +21 -15
- package/src/infrastructure/persistence/metricsSensor.js +9 -6
- package/src/infrastructure/sync/operationSyncIngest.js +4 -16
package/README.md
CHANGED
|
@@ -269,6 +269,30 @@ Opaque operation `kind` strings and generic ports (`latestForMachine`, list/upse
|
|
|
269
269
|
| Export ports `Query` / `Stream` / `Sink` / `Job` | Export jobs + destination adapters |
|
|
270
270
|
| ClickHouse + PG adapters | Plant wiring (`sokolPlant` / `edgePlant`) |
|
|
271
271
|
|
|
272
|
+
### Stream transport ownership
|
|
273
|
+
|
|
274
|
+
`@yarkivaev/source-to-sink` owns reusable Node.js sources, sinks and transport
|
|
275
|
+
lifecycle: serial input, Modbus polling,
|
|
276
|
+
MQTT/STOMP messaging, AMQP consumption and confirmed publishing, and serialized
|
|
277
|
+
periodic ticks. SCADA composes these primitives with generic codecs, domain ports
|
|
278
|
+
and persistence adapters. Plant packages supply source mappings, payload formats,
|
|
279
|
+
queries, routing and plant-specific behavior.
|
|
280
|
+
|
|
281
|
+
The SCADA AMQP telemetry, MQTT relay and operation-sync pipelines use
|
|
282
|
+
`amqpSource`. It acknowledges after collector acceptance, requeues failures by
|
|
283
|
+
default, and avoids settling explicitly acknowledged or rejected deliveries twice.
|
|
284
|
+
Shutdown cancels consumption, drains accepted work and settlements, then closes
|
|
285
|
+
the channel and connection. Reconnect and restart wait for that drain.
|
|
286
|
+
`durableConsume` remains a compatibility facade over the shared AMQP session.
|
|
287
|
+
Collectors that batch records acknowledge acceptance into that collector; this is
|
|
288
|
+
not a guarantee that a later batch has already reached persistent storage.
|
|
289
|
+
|
|
290
|
+
`intervalSource` schedules operator-cache synchronization, stale-open-segment
|
|
291
|
+
sweeps, silent-stream reconciliation, PostgreSQL metric streams and the shared
|
|
292
|
+
ClickHouse stream hub. Polls do not overlap; metric streams await subscribers
|
|
293
|
+
before advancing their cursors. HTTP keepalive timers and domain coalescing
|
|
294
|
+
windows remain owned by their respective adapters and domain policies.
|
|
295
|
+
|
|
272
296
|
Depend on a pinned version (`"@yarkivaev/scada": "…#v2.3.46"`), not a local path, in downstream packages.
|
|
273
297
|
|
|
274
298
|
## CI/CD
|
|
@@ -286,3 +310,88 @@ The scada chart declares the queue and applies an ingest-only dead-letter policy
|
|
|
286
310
|
without changing existing queue arguments. The profile `env` is passed to both
|
|
287
311
|
site-server and supervisor-sink. DLQ records retain the original body and RabbitMQ
|
|
288
312
|
`x-death` metadata for inspection and deliberate replay; they are not auto-expired.
|
|
313
|
+
|
|
314
|
+
### Deploy a node with named processes
|
|
315
|
+
|
|
316
|
+
A profile can expose deployment coordinates in `target`, set
|
|
317
|
+
`apps.scada.site.enabled` and `apps.scada.sink.enabled` independently, and
|
|
318
|
+
provide RabbitMQ chart settings in `modules.message_bus.chart`. The
|
|
319
|
+
`releases(document, cluster)` projection returns the target and chart values.
|
|
320
|
+
The default profile still renders the existing site and sink.
|
|
321
|
+
|
|
322
|
+
`subscriptions(expandedDocument, sourceId)` returns the outgoing server
|
|
323
|
+
subscriptions as `{ from, to, name, api? }`. It combines sender `fan_out` and
|
|
324
|
+
receiver `fan_in` declarations, keeping each expanded stream path and any
|
|
325
|
+
explicit service selected by the receiver. Declaring the same subscription on
|
|
326
|
+
both sides produces a single row.
|
|
327
|
+
|
|
328
|
+
Use `collectorProcesses(machines, describe, project)` to derive workloads from
|
|
329
|
+
the selected server's source rows. For each row, `describe(row)` returns a
|
|
330
|
+
process name, command and optional environment and resources. Rows with the
|
|
331
|
+
same name must describe the same process. `project(descriptor, rows)` converts
|
|
332
|
+
its sources into adapter-specific environment variables and host devices. Process
|
|
333
|
+
order follows the first occurrence of each name in the source rows.
|
|
334
|
+
The packaged `charts/scada` chart renders the resulting `processes` as
|
|
335
|
+
named Deployments. A configured broker claim name selects a standalone PVC.
|
|
336
|
+
The default storage mode uses StatefulSet claim templates.
|
|
337
|
+
|
|
338
|
+
`executeRelease(plan, action)` renders the chart or runs check, diff, adopt
|
|
339
|
+
and apply against the explicitly supplied Kubernetes context and namespace.
|
|
340
|
+
During `adopt`, the legacy client-side manager migrates the resources first.
|
|
341
|
+
The release's server-side manager then applies the same rendered manifest before
|
|
342
|
+
the executor waits for the workloads. This restores declared fields that a
|
|
343
|
+
legacy three-way merge can drop, such as an environment entry whose name was
|
|
344
|
+
duplicated in the old last-applied annotation. Each apply gets its own server
|
|
345
|
+
dry-run. `check-adoption` previews the client-side phase only. The server-side
|
|
346
|
+
phase must run against the migrated state. An ownership conflict stops adoption
|
|
347
|
+
before rollout waits and the afterReady hook. Resolve the field ownership and
|
|
348
|
+
rerun `apply` after the client-side migration has completed.
|
|
349
|
+
A caller can supply prerequisites, rollout resources and an afterReady hook.
|
|
350
|
+
The RabbitMQ definitions builder and management reconciler are exported as
|
|
351
|
+
`@yarkivaev/scada/rabbitmq/definitions` and `@yarkivaev/scada/rabbitmq/reconcile`.
|
|
352
|
+
The caller supplies the vhost, connection settings and ownership policy for
|
|
353
|
+
retired routes. Reconciliation retains stored queues.
|
|
354
|
+
|
|
355
|
+
### Collect multiple OPC UA endpoints
|
|
356
|
+
|
|
357
|
+
`@yarkivaev/scada/opcua` exports `opcuaConnections(connections, publish, options)`
|
|
358
|
+
and `validateConnections(connections)`. The same entry point exports
|
|
359
|
+
`opcuaSource(connections, collector, options)` for source-to-sink composition;
|
|
360
|
+
the collector accepts `{ channel, value }`. SCADA owns the OPC UA runtime and
|
|
361
|
+
its `node-opcua` dependency; source-to-sink contains no OPC UA implementation.
|
|
362
|
+
Offline deployment planners should import
|
|
363
|
+
`validateConnections` from `@yarkivaev/scada/opcua/config`; this entry point never
|
|
364
|
+
loads the network library or its startup diagnostics. Each connection has a unique `url`,
|
|
365
|
+
positive `publishMs` and `heartbeatMs`, and `channels` with explicit, unique
|
|
366
|
+
`nodeId` values. Additional channel metadata is opaque to this library.
|
|
367
|
+
|
|
368
|
+
```js
|
|
369
|
+
import opcuaConnections from '@yarkivaev/scada/opcua';
|
|
370
|
+
|
|
371
|
+
const collector = opcuaConnections([
|
|
372
|
+
{ url: 'opc.tcp://192.0.2.10:4840', publishMs: 100, heartbeatMs: 1000,
|
|
373
|
+
channels: [{ nodeId: 'ns=1;s=temperature', topic: 'line/temperature' }] }
|
|
374
|
+
], (channel, value) => publish(channel.topic, value));
|
|
375
|
+
await collector.start();
|
|
376
|
+
// On process shutdown:
|
|
377
|
+
await collector.stop();
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Each endpoint owns its client, session and subscription. An unavailable endpoint
|
|
381
|
+
retries independently while others continue. Start schedules these workers; it
|
|
382
|
+
does not wait for every server to be available. Samples are delivered only with
|
|
383
|
+
Good quality, both on change and through serialized fresh heartbeat reads.
|
|
384
|
+
The caller owns value conversion, routing, timestamps and destination transport.
|
|
385
|
+
Options `retryMs`, `connectTimeoutMs` and `requestTimeoutMs` bound retry timing and
|
|
386
|
+
network requests; `onError(error, connection)` receives connection diagnostics.
|
|
387
|
+
Do not replicate a collector with the same sources to distribute load: assign
|
|
388
|
+
disjoint source sets to separate instances instead.
|
|
389
|
+
|
|
390
|
+
A release can replace old collectors using
|
|
391
|
+
`retirements: [{ workload: 'deployment/old-reader', selector: 'app=old-reader' }]`.
|
|
392
|
+
For apply/adopt, the executor validates the new manifests first, foreground-deletes
|
|
393
|
+
only these explicit Deployments, and verifies that no selected old pods remain
|
|
394
|
+
before applying the replacement. This trades a collection gap for no overlap.
|
|
395
|
+
The caller must bind each selector to its old Deployment; no namespace-wide prune
|
|
396
|
+
is performed. Render/check/diff do not delete anything. An optional process `image`
|
|
397
|
+
overrides the release image, so unrelated collectors can retain their pinned runtime.
|
package/charts/scada/Chart.yaml
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
{{- define "scada.prefix" -}}
|
|
2
|
+
{{- default .Release.Name .Values.prefix -}}
|
|
3
|
+
{{- end }}
|
|
4
|
+
|
|
1
5
|
{{- define "scada.labels" -}}
|
|
2
6
|
app.kubernetes.io/name: scada
|
|
3
7
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
|
@@ -69,7 +73,7 @@ volumeMode: Filesystem
|
|
|
69
73
|
{{- end }}
|
|
70
74
|
{{- if .Values.rabbitmq.enabled }}
|
|
71
75
|
- name: STOMP_URL
|
|
72
|
-
value: {{ printf "stomp://%s-rabbitmq:61613" .
|
|
76
|
+
value: {{ printf "stomp://%s-rabbitmq:61613" (include "scada.prefix" .) | quote }}
|
|
73
77
|
- name: STOMP_LOGIN
|
|
74
78
|
value: guest
|
|
75
79
|
- name: STOMP_PASSCODE
|
|
@@ -77,12 +81,16 @@ volumeMode: Filesystem
|
|
|
77
81
|
- name: STOMP_HOST
|
|
78
82
|
value: /
|
|
79
83
|
- name: AMQP_URL
|
|
80
|
-
value: {{ printf "amqp://guest:guest@%s-rabbitmq:5672" .
|
|
84
|
+
value: {{ printf "amqp://guest:guest@%s-rabbitmq:5672" (include "scada.prefix" .) | quote }}
|
|
81
85
|
{{- end }}
|
|
82
86
|
{{- if .Values.clickhouse.enabled }}
|
|
83
87
|
- name: CLICKHOUSE_HOST
|
|
84
|
-
value: {{ printf "%s-clickhouse" .
|
|
88
|
+
value: {{ printf "%s-clickhouse" (include "scada.prefix" .) | quote }}
|
|
85
89
|
- name: CLICKHOUSE_URL
|
|
86
|
-
value: {{ printf "http://%s-clickhouse:8123" .
|
|
90
|
+
value: {{ printf "http://%s-clickhouse:8123" (include "scada.prefix" .) | quote }}
|
|
87
91
|
{{- end }}
|
|
88
92
|
{{- end }}
|
|
93
|
+
|
|
94
|
+
{{- define "scada.brokerConfigName" -}}
|
|
95
|
+
{{- default (printf "%s-rabbitmq" (include "scada.prefix" .)) .Values.rabbitmq.configName -}}
|
|
96
|
+
{{- end }}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
apiVersion: v1
|
|
3
3
|
kind: Service
|
|
4
4
|
metadata:
|
|
5
|
-
name: {{ .
|
|
5
|
+
name: {{ include "scada.prefix" . }}-clickhouse
|
|
6
6
|
namespace: {{ .Release.Namespace }}
|
|
7
7
|
labels:
|
|
8
8
|
{{- include "scada.labels" . | nindent 4 }}
|
|
@@ -24,13 +24,13 @@ spec:
|
|
|
24
24
|
apiVersion: apps/v1
|
|
25
25
|
kind: StatefulSet
|
|
26
26
|
metadata:
|
|
27
|
-
name: {{ .
|
|
27
|
+
name: {{ include "scada.prefix" . }}-clickhouse
|
|
28
28
|
namespace: {{ .Release.Namespace }}
|
|
29
29
|
labels:
|
|
30
30
|
{{- include "scada.labels" . | nindent 4 }}
|
|
31
31
|
app: clickhouse
|
|
32
32
|
spec:
|
|
33
|
-
serviceName: {{ .
|
|
33
|
+
serviceName: {{ include "scada.prefix" . }}-clickhouse
|
|
34
34
|
replicas: 1
|
|
35
35
|
selector:
|
|
36
36
|
matchLabels:
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
apiVersion: apps/v1
|
|
54
54
|
kind: Deployment
|
|
55
55
|
metadata:
|
|
56
|
-
name: {{
|
|
56
|
+
name: {{ include "scada.prefix" $ }}-collector-{{ $slug }}
|
|
57
57
|
namespace: {{ $.Release.Namespace }}
|
|
58
58
|
labels:
|
|
59
59
|
{{- include "scada.labels" $ | nindent 4 }}
|
|
@@ -97,7 +97,7 @@ spec:
|
|
|
97
97
|
value: {{ $maps | toJson | quote }}
|
|
98
98
|
{{- if $.Values.rabbitmq.enabled }}
|
|
99
99
|
- name: MQTT_URL
|
|
100
|
-
value: {{ printf "mqtt://%s-rabbitmq:1883"
|
|
100
|
+
value: {{ printf "mqtt://%s-rabbitmq:1883" (include "scada.prefix" $) | quote }}
|
|
101
101
|
{{- end }}
|
|
102
102
|
resources:
|
|
103
103
|
{{- toYaml $.Values.resources | nindent 12 }}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
apiVersion: v1
|
|
3
3
|
kind: Service
|
|
4
4
|
metadata:
|
|
5
|
-
name: {{ .
|
|
5
|
+
name: {{ include "scada.prefix" . }}-postgres
|
|
6
6
|
namespace: {{ .Release.Namespace }}
|
|
7
7
|
labels:
|
|
8
8
|
{{- include "scada.labels" . | nindent 4 }}
|
|
@@ -18,13 +18,13 @@ spec:
|
|
|
18
18
|
apiVersion: apps/v1
|
|
19
19
|
kind: StatefulSet
|
|
20
20
|
metadata:
|
|
21
|
-
name: {{ .
|
|
21
|
+
name: {{ include "scada.prefix" . }}-postgres
|
|
22
22
|
namespace: {{ .Release.Namespace }}
|
|
23
23
|
labels:
|
|
24
24
|
{{- include "scada.labels" . | nindent 4 }}
|
|
25
25
|
app: postgres
|
|
26
26
|
spec:
|
|
27
|
-
serviceName: {{ .
|
|
27
|
+
serviceName: {{ include "scada.prefix" . }}-postgres
|
|
28
28
|
replicas: 1
|
|
29
29
|
selector:
|
|
30
30
|
matchLabels:
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{{- $names := dict }}
|
|
2
|
+
{{- $devices := dict }}
|
|
3
|
+
{{- range .Values.processes }}
|
|
4
|
+
{{- $name := required "process name is required" .name }}
|
|
5
|
+
{{- if hasKey $names $name }}
|
|
6
|
+
{{- fail (printf "duplicate process name %s" $name) }}
|
|
7
|
+
{{- end }}
|
|
8
|
+
{{- $_ := set $names $name true }}
|
|
9
|
+
{{- range .hostDevices }}
|
|
10
|
+
{{- if hasKey $devices . }}
|
|
11
|
+
{{- fail (printf "processes %s and %s both claim %s" $name (get $devices .) .) }}
|
|
12
|
+
{{- end }}
|
|
13
|
+
{{- $_ := set $devices . $name }}
|
|
14
|
+
{{- end }}
|
|
15
|
+
---
|
|
16
|
+
apiVersion: apps/v1
|
|
17
|
+
kind: Deployment
|
|
18
|
+
metadata:
|
|
19
|
+
name: {{ include "scada.prefix" $ }}-{{ $name }}
|
|
20
|
+
namespace: {{ $.Release.Namespace }}
|
|
21
|
+
labels:
|
|
22
|
+
{{- include "scada.labels" $ | nindent 4 }}
|
|
23
|
+
app: {{ $name }}
|
|
24
|
+
{{- with $.Values.workloadLabels }}
|
|
25
|
+
{{- toYaml . | nindent 4 }}
|
|
26
|
+
{{- end }}
|
|
27
|
+
spec:
|
|
28
|
+
replicas: 1
|
|
29
|
+
strategy:
|
|
30
|
+
type: Recreate
|
|
31
|
+
rollingUpdate: null
|
|
32
|
+
selector:
|
|
33
|
+
matchLabels:
|
|
34
|
+
{{- include "scada.match" (dict "app" $name "ctx" $) | nindent 6 }}
|
|
35
|
+
template:
|
|
36
|
+
metadata:
|
|
37
|
+
labels:
|
|
38
|
+
{{- include "scada.labels" $ | nindent 8 }}
|
|
39
|
+
app: {{ $name }}
|
|
40
|
+
{{- with $.Values.workloadLabels }}
|
|
41
|
+
{{- toYaml . | nindent 8 }}
|
|
42
|
+
{{- end }}
|
|
43
|
+
{{- if and $.Values.rabbitmq.enabled $.Values.rabbitmq.rolloutOnConfigChange }}
|
|
44
|
+
annotations:
|
|
45
|
+
checksum/broker: {{ include (print $.Template.BasePath "/rabbitmq-config.yaml") $ | sha256sum }}
|
|
46
|
+
{{- end }}
|
|
47
|
+
spec:
|
|
48
|
+
{{- with $.Values.pullSecret }}
|
|
49
|
+
imagePullSecrets:
|
|
50
|
+
- name: {{ . }}
|
|
51
|
+
{{- end }}
|
|
52
|
+
{{- with .podSecurityContext }}
|
|
53
|
+
securityContext:
|
|
54
|
+
{{- toYaml . | nindent 8 }}
|
|
55
|
+
{{- end }}
|
|
56
|
+
containers:
|
|
57
|
+
- name: {{ $name }}
|
|
58
|
+
image: {{ required "process image is required" (default $.Values.image .image) | quote }}
|
|
59
|
+
imagePullPolicy: IfNotPresent
|
|
60
|
+
command: {{ required "process command is required" .command | toJson }}
|
|
61
|
+
{{- if .hostDevices }}
|
|
62
|
+
securityContext:
|
|
63
|
+
privileged: true
|
|
64
|
+
volumeMounts:
|
|
65
|
+
{{- range $index, $path := .hostDevices }}
|
|
66
|
+
- name: serial-{{ add1 $index }}
|
|
67
|
+
mountPath: {{ $path | quote }}
|
|
68
|
+
{{- end }}
|
|
69
|
+
{{- end }}
|
|
70
|
+
{{- with .env }}
|
|
71
|
+
env:
|
|
72
|
+
{{- range $key, $value := . }}
|
|
73
|
+
- name: {{ $key }}
|
|
74
|
+
value: {{ $value | quote }}
|
|
75
|
+
{{- end }}
|
|
76
|
+
{{- end }}
|
|
77
|
+
resources:
|
|
78
|
+
{{- toYaml (default $.Values.resources .resources) | nindent 12 }}
|
|
79
|
+
{{- with .hostDevices }}
|
|
80
|
+
volumes:
|
|
81
|
+
{{- range $index, $path := . }}
|
|
82
|
+
- name: serial-{{ add1 $index }}
|
|
83
|
+
hostPath:
|
|
84
|
+
path: {{ $path | quote }}
|
|
85
|
+
type: CharDevice
|
|
86
|
+
{{- end }}
|
|
87
|
+
{{- end }}
|
|
88
|
+
{{- end }}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{{- if .Values.rabbitmq.enabled }}
|
|
2
|
+
{{- $ingest := list -}}
|
|
3
|
+
{{- $outgoing := list -}}
|
|
4
|
+
{{- range .Values.collectors }}
|
|
5
|
+
{{- if .path }}
|
|
6
|
+
{{- $ingest = append $ingest (include "scada.routingKey" .path | trim) -}}
|
|
7
|
+
{{- end }}
|
|
8
|
+
{{- end }}
|
|
9
|
+
{{- range $item := concat (.Values.buses | default (list)) (.Values.bus | default (list)) }}
|
|
10
|
+
{{- range $name := ($item.names | default (list)) }}
|
|
11
|
+
{{- $routed := include "scada.routingKey" $name | trim -}}
|
|
12
|
+
{{- $ingest = append $ingest $routed -}}
|
|
13
|
+
{{- $outgoing = append $outgoing $routed -}}
|
|
14
|
+
{{- end }}
|
|
15
|
+
{{- end }}
|
|
16
|
+
{{- $outgoing = $outgoing | uniq -}}
|
|
17
|
+
{{- if $ingest }}
|
|
18
|
+
{{- $ingest = $ingest | uniq -}}
|
|
19
|
+
{{- else }}
|
|
20
|
+
{{- $ingest = list "#" -}}
|
|
21
|
+
{{- end }}
|
|
22
|
+
{{- $exchange := list
|
|
23
|
+
(dict "name" "scada.alerts" "vhost" "/" "type" "topic" "durable" true "auto_delete" false)
|
|
24
|
+
(dict "name" "scada.segments" "vhost" "/" "type" "topic" "durable" true "auto_delete" false)
|
|
25
|
+
(dict "name" "scada.telemetry" "vhost" "/" "type" "topic" "durable" true "auto_delete" false)
|
|
26
|
+
(dict "name" "scada.operations" "vhost" "/" "type" "topic" "durable" true "auto_delete" false)
|
|
27
|
+
(dict "name" "scada.user_decisions" "vhost" "/" "type" "topic" "durable" true "auto_delete" false)
|
|
28
|
+
-}}
|
|
29
|
+
{{- $queue := list
|
|
30
|
+
(dict "name" "scada.segments.ingest" "vhost" "/" "durable" true "auto_delete" false)
|
|
31
|
+
(dict "name" "scada.telemetry.ingest" "vhost" "/" "durable" true "auto_delete" false)
|
|
32
|
+
(dict "name" "scada.operations.ingest" "vhost" "/" "durable" true "auto_delete" false)
|
|
33
|
+
(dict "name" "scada.user_decisions" "vhost" "/" "durable" true "auto_delete" false)
|
|
34
|
+
-}}
|
|
35
|
+
{{- if $outgoing }}
|
|
36
|
+
{{- $queue = append $queue (dict "name" "scada.telemetry.outbox" "vhost" "/" "durable" true "auto_delete" false) -}}
|
|
37
|
+
{{- end }}
|
|
38
|
+
{{- $policies := list -}}
|
|
39
|
+
{{- with .Values.rabbitmq.deadLetter }}
|
|
40
|
+
{{- $queue = append $queue (dict "name" .queue "vhost" "/" "durable" true "auto_delete" false) -}}
|
|
41
|
+
{{- $policies = append $policies (dict "name" "ingest-dlq" "vhost" "/" "pattern" "^scada\\.(segments|operations|telemetry)\\.ingest$" "apply-to" "queues" "priority" 10 "definition" (dict "dead-letter-exchange" "" "dead-letter-routing-key" .queue)) -}}
|
|
42
|
+
{{- end }}
|
|
43
|
+
{{- $binding := list -}}
|
|
44
|
+
{{- range $key := $ingest }}
|
|
45
|
+
{{- $binding = append $binding (dict "source" "scada.telemetry" "vhost" "/" "destination" "scada.telemetry.ingest" "destination_type" "queue" "routing_key" $key) -}}
|
|
46
|
+
{{- end }}
|
|
47
|
+
{{- range $pair := (list
|
|
48
|
+
(dict "source" "scada.operations" "destination" "scada.operations.ingest")
|
|
49
|
+
(dict "source" "scada.segments" "destination" "scada.segments.ingest")
|
|
50
|
+
(dict "source" "scada.user_decisions" "destination" "scada.user_decisions")) }}
|
|
51
|
+
{{- $binding = append $binding (dict "source" $pair.source "vhost" "/" "destination" $pair.destination "destination_type" "queue" "routing_key" "#") -}}
|
|
52
|
+
{{- end }}
|
|
53
|
+
{{- range $key := $outgoing }}
|
|
54
|
+
{{- $binding = append $binding (dict "source" "scada.telemetry" "vhost" "/" "destination" "scada.telemetry.outbox" "destination_type" "queue" "routing_key" $key) -}}
|
|
55
|
+
{{- end }}
|
|
56
|
+
{{- $definitions := dict
|
|
57
|
+
"vhosts" (list (dict "name" "/"))
|
|
58
|
+
"users" (list (dict "name" "guest" "password" "guest" "tags" (list "administrator")))
|
|
59
|
+
"permissions" (list (dict "user" "guest" "vhost" "/" "configure" ".*" "write" ".*" "read" ".*"))
|
|
60
|
+
"exchanges" $exchange
|
|
61
|
+
"queues" $queue
|
|
62
|
+
"policies" $policies
|
|
63
|
+
"bindings" $binding
|
|
64
|
+
-}}
|
|
65
|
+
apiVersion: v1
|
|
66
|
+
kind: ConfigMap
|
|
67
|
+
metadata:
|
|
68
|
+
name: {{ include "scada.brokerConfigName" . }}
|
|
69
|
+
namespace: {{ .Release.Namespace }}
|
|
70
|
+
labels:
|
|
71
|
+
{{- include "scada.labels" . | nindent 4 }}
|
|
72
|
+
app: rabbitmq
|
|
73
|
+
data:
|
|
74
|
+
enabled_plugins: |
|
|
75
|
+
[{{ join ", " .Values.rabbitmq.plugins }}].
|
|
76
|
+
rabbitmq.conf: |
|
|
77
|
+
load_definitions = /etc/rabbitmq/definitions.json
|
|
78
|
+
mqtt.listeners.tcp.default = 1883
|
|
79
|
+
mqtt.allow_anonymous = true
|
|
80
|
+
mqtt.vhost = /
|
|
81
|
+
mqtt.exchange = scada.telemetry
|
|
82
|
+
{{- range $key, $value := .Values.rabbitmq.extraConfig }}
|
|
83
|
+
{{ $key }} = {{ $value }}
|
|
84
|
+
{{- end }}
|
|
85
|
+
definitions.json: |
|
|
86
|
+
{{- if ne .Values.rabbitmq.definitions nil }}
|
|
87
|
+
{{ .Values.rabbitmq.definitions | toPrettyJson | nindent 4 }}
|
|
88
|
+
{{- else }}
|
|
89
|
+
{{ $definitions | toPrettyJson | nindent 4 }}
|
|
90
|
+
{{- end }}
|
|
91
|
+
{{- end }}
|
|
@@ -1,91 +1,8 @@
|
|
|
1
1
|
{{- if .Values.rabbitmq.enabled }}
|
|
2
|
-
{{- $ingest := list -}}
|
|
3
|
-
{{- $outgoing := list -}}
|
|
4
|
-
{{- range .Values.collectors }}
|
|
5
|
-
{{- if .path }}
|
|
6
|
-
{{- $ingest = append $ingest (include "scada.routingKey" .path | trim) -}}
|
|
7
|
-
{{- end }}
|
|
8
|
-
{{- end }}
|
|
9
|
-
{{- range $item := concat (.Values.buses | default (list)) (.Values.bus | default (list)) }}
|
|
10
|
-
{{- range $name := ($item.names | default (list)) }}
|
|
11
|
-
{{- $routed := include "scada.routingKey" $name | trim -}}
|
|
12
|
-
{{- $ingest = append $ingest $routed -}}
|
|
13
|
-
{{- $outgoing = append $outgoing $routed -}}
|
|
14
|
-
{{- end }}
|
|
15
|
-
{{- end }}
|
|
16
|
-
{{- $outgoing = $outgoing | uniq -}}
|
|
17
|
-
{{- if $ingest }}
|
|
18
|
-
{{- $ingest = $ingest | uniq -}}
|
|
19
|
-
{{- else }}
|
|
20
|
-
{{- $ingest = list "#" -}}
|
|
21
|
-
{{- end }}
|
|
22
|
-
{{- $exchange := list
|
|
23
|
-
(dict "name" "scada.alerts" "vhost" "/" "type" "topic" "durable" true "auto_delete" false)
|
|
24
|
-
(dict "name" "scada.segments" "vhost" "/" "type" "topic" "durable" true "auto_delete" false)
|
|
25
|
-
(dict "name" "scada.telemetry" "vhost" "/" "type" "topic" "durable" true "auto_delete" false)
|
|
26
|
-
(dict "name" "scada.operations" "vhost" "/" "type" "topic" "durable" true "auto_delete" false)
|
|
27
|
-
(dict "name" "scada.user_decisions" "vhost" "/" "type" "topic" "durable" true "auto_delete" false)
|
|
28
|
-
-}}
|
|
29
|
-
{{- $queue := list
|
|
30
|
-
(dict "name" "scada.segments.ingest" "vhost" "/" "durable" true "auto_delete" false)
|
|
31
|
-
(dict "name" "scada.telemetry.ingest" "vhost" "/" "durable" true "auto_delete" false)
|
|
32
|
-
(dict "name" "scada.operations.ingest" "vhost" "/" "durable" true "auto_delete" false)
|
|
33
|
-
(dict "name" "scada.user_decisions" "vhost" "/" "durable" true "auto_delete" false)
|
|
34
|
-
-}}
|
|
35
|
-
{{- if $outgoing }}
|
|
36
|
-
{{- $queue = append $queue (dict "name" "scada.telemetry.outbox" "vhost" "/" "durable" true "auto_delete" false) -}}
|
|
37
|
-
{{- end }}
|
|
38
|
-
{{- $policies := list -}}
|
|
39
|
-
{{- with .Values.rabbitmq.deadLetter }}
|
|
40
|
-
{{- $queue = append $queue (dict "name" .queue "vhost" "/" "durable" true "auto_delete" false) -}}
|
|
41
|
-
{{- $policies = append $policies (dict "name" "ingest-dlq" "vhost" "/" "pattern" "^scada\\.(segments|operations|telemetry)\\.ingest$" "apply-to" "queues" "priority" 10 "definition" (dict "dead-letter-exchange" "" "dead-letter-routing-key" .queue)) -}}
|
|
42
|
-
{{- end }}
|
|
43
|
-
{{- $binding := list -}}
|
|
44
|
-
{{- range $key := $ingest }}
|
|
45
|
-
{{- $binding = append $binding (dict "source" "scada.telemetry" "vhost" "/" "destination" "scada.telemetry.ingest" "destination_type" "queue" "routing_key" $key) -}}
|
|
46
|
-
{{- end }}
|
|
47
|
-
{{- range $pair := (list
|
|
48
|
-
(dict "source" "scada.operations" "destination" "scada.operations.ingest")
|
|
49
|
-
(dict "source" "scada.segments" "destination" "scada.segments.ingest")
|
|
50
|
-
(dict "source" "scada.user_decisions" "destination" "scada.user_decisions")) }}
|
|
51
|
-
{{- $binding = append $binding (dict "source" $pair.source "vhost" "/" "destination" $pair.destination "destination_type" "queue" "routing_key" "#") -}}
|
|
52
|
-
{{- end }}
|
|
53
|
-
{{- range $key := $outgoing }}
|
|
54
|
-
{{- $binding = append $binding (dict "source" "scada.telemetry" "vhost" "/" "destination" "scada.telemetry.outbox" "destination_type" "queue" "routing_key" $key) -}}
|
|
55
|
-
{{- end }}
|
|
56
|
-
{{- $definitions := dict
|
|
57
|
-
"vhosts" (list (dict "name" "/"))
|
|
58
|
-
"users" (list (dict "name" "guest" "password" "guest" "tags" (list "administrator")))
|
|
59
|
-
"permissions" (list (dict "user" "guest" "vhost" "/" "configure" ".*" "write" ".*" "read" ".*"))
|
|
60
|
-
"exchanges" $exchange
|
|
61
|
-
"queues" $queue
|
|
62
|
-
"policies" $policies
|
|
63
|
-
"bindings" $binding
|
|
64
|
-
-}}
|
|
65
|
-
apiVersion: v1
|
|
66
|
-
kind: ConfigMap
|
|
67
|
-
metadata:
|
|
68
|
-
name: {{ .Release.Name }}-rabbitmq
|
|
69
|
-
namespace: {{ .Release.Namespace }}
|
|
70
|
-
labels:
|
|
71
|
-
{{- include "scada.labels" . | nindent 4 }}
|
|
72
|
-
app: rabbitmq
|
|
73
|
-
data:
|
|
74
|
-
enabled_plugins: |
|
|
75
|
-
[rabbitmq_stomp, rabbitmq_mqtt, rabbitmq_management].
|
|
76
|
-
rabbitmq.conf: |
|
|
77
|
-
load_definitions = /etc/rabbitmq/definitions.json
|
|
78
|
-
mqtt.listeners.tcp.default = 1883
|
|
79
|
-
mqtt.allow_anonymous = true
|
|
80
|
-
mqtt.vhost = /
|
|
81
|
-
mqtt.exchange = scada.telemetry
|
|
82
|
-
definitions.json: |
|
|
83
|
-
{{ $definitions | toPrettyJson | nindent 4 }}
|
|
84
|
-
---
|
|
85
2
|
apiVersion: v1
|
|
86
3
|
kind: Service
|
|
87
4
|
metadata:
|
|
88
|
-
name: {{ .
|
|
5
|
+
name: {{ include "scada.prefix" . }}-rabbitmq
|
|
89
6
|
namespace: {{ .Release.Namespace }}
|
|
90
7
|
labels:
|
|
91
8
|
{{- include "scada.labels" . | nindent 4 }}
|
|
@@ -94,46 +11,30 @@ spec:
|
|
|
94
11
|
{{- $svc := .Values.rabbitmq.service | default dict }}
|
|
95
12
|
type: {{ $svc.type | default "ClusterIP" }}
|
|
96
13
|
ports:
|
|
97
|
-
- name
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
{{
|
|
101
|
-
{{-
|
|
102
|
-
nodePort: {{ .
|
|
103
|
-
{{- end }}
|
|
104
|
-
{{- end }}
|
|
105
|
-
- name: mqtt
|
|
106
|
-
port: 1883
|
|
107
|
-
targetPort: mqtt
|
|
108
|
-
- name: stomp
|
|
109
|
-
port: 61613
|
|
110
|
-
targetPort: stomp
|
|
111
|
-
{{- with $svc.nodePorts }}
|
|
112
|
-
{{- if .stomp }}
|
|
113
|
-
nodePort: {{ .stomp }}
|
|
114
|
-
{{- end }}
|
|
115
|
-
{{- end }}
|
|
116
|
-
- name: management
|
|
117
|
-
port: 15672
|
|
118
|
-
targetPort: management
|
|
119
|
-
{{- with $svc.nodePorts }}
|
|
120
|
-
{{- if .management }}
|
|
121
|
-
nodePort: {{ .management }}
|
|
122
|
-
{{- end }}
|
|
14
|
+
{{- range $entry := list (dict "name" "amqp" "port" 5672) (dict "name" "mqtt" "port" 1883) (dict "name" "stomp" "port" 61613) (dict "name" "management" "port" 15672) }}
|
|
15
|
+
- name: {{ $entry.name }}
|
|
16
|
+
port: {{ $entry.port }}
|
|
17
|
+
targetPort: {{ ternary $entry.port $entry.name ($svc.numericTargetPorts | default false) }}
|
|
18
|
+
{{- with get ($svc.nodePorts | default dict) $entry.name }}
|
|
19
|
+
nodePort: {{ . }}
|
|
123
20
|
{{- end }}
|
|
21
|
+
{{- end }}
|
|
124
22
|
selector:
|
|
125
23
|
{{- include "scada.match" (dict "app" "rabbitmq" "ctx" .) | nindent 4 }}
|
|
126
24
|
---
|
|
127
25
|
apiVersion: apps/v1
|
|
128
26
|
kind: StatefulSet
|
|
129
27
|
metadata:
|
|
130
|
-
name: {{ .
|
|
28
|
+
name: {{ include "scada.prefix" . }}-rabbitmq
|
|
131
29
|
namespace: {{ .Release.Namespace }}
|
|
132
30
|
labels:
|
|
133
31
|
{{- include "scada.labels" . | nindent 4 }}
|
|
134
32
|
app: rabbitmq
|
|
33
|
+
{{- with .Values.workloadLabels }}
|
|
34
|
+
{{- toYaml . | nindent 4 }}
|
|
35
|
+
{{- end }}
|
|
135
36
|
spec:
|
|
136
|
-
serviceName: {{ .
|
|
37
|
+
serviceName: {{ include "scada.prefix" . }}-rabbitmq
|
|
137
38
|
replicas: 1
|
|
138
39
|
selector:
|
|
139
40
|
matchLabels:
|
|
@@ -143,10 +44,24 @@ spec:
|
|
|
143
44
|
labels:
|
|
144
45
|
{{- include "scada.labels" . | nindent 8 }}
|
|
145
46
|
{{- include "scada.match" (dict "app" "rabbitmq" "ctx" .) | nindent 8 }}
|
|
47
|
+
{{- with .Values.workloadLabels }}
|
|
48
|
+
{{- toYaml . | nindent 8 }}
|
|
49
|
+
{{- end }}
|
|
50
|
+
{{- if .Values.rabbitmq.rolloutOnConfigChange }}
|
|
51
|
+
annotations:
|
|
52
|
+
checksum/config: {{ include (print $.Template.BasePath "/rabbitmq-config.yaml") . | sha256sum }}
|
|
53
|
+
{{- end }}
|
|
146
54
|
spec:
|
|
55
|
+
{{- with .Values.pullSecret }}
|
|
56
|
+
imagePullSecrets:
|
|
57
|
+
- name: {{ . }}
|
|
58
|
+
{{- end }}
|
|
147
59
|
containers:
|
|
148
60
|
- name: rabbitmq
|
|
149
61
|
image: {{ .Values.rabbitmq.image | quote }}
|
|
62
|
+
{{- with .Values.rabbitmq.imagePullPolicy }}
|
|
63
|
+
imagePullPolicy: {{ . }}
|
|
64
|
+
{{- end }}
|
|
150
65
|
ports:
|
|
151
66
|
- name: amqp
|
|
152
67
|
containerPort: 5672
|
|
@@ -156,6 +71,18 @@ spec:
|
|
|
156
71
|
containerPort: 61613
|
|
157
72
|
- name: management
|
|
158
73
|
containerPort: 15672
|
|
74
|
+
{{- with .Values.rabbitmq.readinessProbe }}
|
|
75
|
+
readinessProbe:
|
|
76
|
+
{{- toYaml . | nindent 12 }}
|
|
77
|
+
{{- end }}
|
|
78
|
+
{{- with .Values.rabbitmq.livenessProbe }}
|
|
79
|
+
livenessProbe:
|
|
80
|
+
{{- toYaml . | nindent 12 }}
|
|
81
|
+
{{- end }}
|
|
82
|
+
{{- with .Values.rabbitmq.resources }}
|
|
83
|
+
resources:
|
|
84
|
+
{{- toYaml . | nindent 12 }}
|
|
85
|
+
{{- end }}
|
|
159
86
|
volumeMounts:
|
|
160
87
|
- name: config
|
|
161
88
|
mountPath: /etc/rabbitmq/enabled_plugins
|
|
@@ -171,10 +98,24 @@ spec:
|
|
|
171
98
|
volumes:
|
|
172
99
|
- name: config
|
|
173
100
|
configMap:
|
|
174
|
-
name: {{ .
|
|
101
|
+
name: {{ include "scada.brokerConfigName" . }}
|
|
102
|
+
{{- with .Values.rabbitmq.claimName }}
|
|
103
|
+
- name: data
|
|
104
|
+
persistentVolumeClaim:
|
|
105
|
+
claimName: {{ . }}
|
|
106
|
+
---
|
|
107
|
+
apiVersion: v1
|
|
108
|
+
kind: PersistentVolumeClaim
|
|
109
|
+
metadata:
|
|
110
|
+
name: {{ . }}
|
|
111
|
+
namespace: {{ $.Release.Namespace }}
|
|
112
|
+
spec:
|
|
113
|
+
{{- include "scada.claim" (dict "size" $.Values.rabbitmq.storage "class" $.Values.rabbitmq.storageClass) | nindent 2 }}
|
|
114
|
+
{{- else }}
|
|
175
115
|
volumeClaimTemplates:
|
|
176
116
|
- metadata:
|
|
177
117
|
name: data
|
|
178
118
|
spec:
|
|
179
119
|
{{- include "scada.claim" (dict "size" .Values.rabbitmq.storage "class" .Values.rabbitmq.storageClass) | nindent 8 }}
|
|
180
120
|
{{- end }}
|
|
121
|
+
{{- end }}
|