Repository navigation
Expand file tree
/
Copy pathvalues.yaml
More file actions
1259 lines (1213 loc) · 54.1 KB
/
Copy pathvalues.yaml
File metadata and controls
1259 lines (1213 loc) · 54.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
acs:
# -- The organisation where ACS is being deployed
organisation: AMRC
# -- The base URL that services will be served from
baseUrl: factoryplus.myorganisation.com
# -- Whether or not services should be served over HTTPS
secure: true
letsEncrypt:
# -- Whether or not to use Let's Encrypt to automatically generate
# certificates for the services
enabled: false
# -- The email address to use for Let's Encrypt
email: ''
# -- Whether or not to use the staging environment for Let's Encrypt
staging: false
# -- A list of additional DNS names to use for the certificate
additionalDnsNames: []
# -- The name of the secret holding the wildcard certificate for the
# above domain. It will be used for every service unless that service
# specifies its own tlsSecretName.
tlsSecretName: factoryplus-tls
cacheMaxAge: 300
# -- Image pull secrets for container images
imagePullSecrets: []
# The default registry for ACS images. This can be overridden for
# individual images if necessary.
defaultRegistry: ghcr.io/amrc-factoryplus
# -- An optional tag that will force images to use this version
# regardless of the version in the Helm chart. Each component can
# further override this value by setting the `tag` property in its
# own section. Deployments from a Git checkout must set this value.
#defaultTag: ''
# The default pullPolicy.
defaultPullPolicy: IfNotPresent
# -- How long Kerberos clients wait for the KDC before giving up and
# letting Kubernetes restart them. The KDC runs three initContainers
# and attaches an RWO volume before it listens, so on a cold boot
# every service in the stack races it. attempts * interval is the
# total grace period; the default is five minutes.
kdcWait:
attempts: 60
interval: 5
# -- tcpSocket probes for services that listen on a port. The startup
# grace (failureThreshold * periodSeconds) has to cover the slowest
# legitimate start in the stack, which is a ConfigDB schema migration,
# or the liveness probe will restart a service that was going to come
# up on its own.
probes:
startup:
periodSeconds: 10
failureThreshold: 30
readiness:
periodSeconds: 10
failureThreshold: 3
liveness:
periodSeconds: 20
failureThreshold: 3
# -- Configure which schemas are loaded into the ConfigDB
schemas:
load: true
image:
registry: ghcr.io
repository: amrc-factoryplus/acs-schemas
tag: v1.6.0
coredns:
# -- An option to enable the redirecting of external URL's back
# to the internal Traefik service. This is done through a config map
# override to coredns in the kube-system namespace. The override rewrites
# queries matching .*.<baseURL> to acs-traefik.<namespace>.svc.cluster.local,
# ensuring correct internal service resolution. ACS deployments without
# external DNS should enable this.
traefikRedirect:
enabled: false
identity:
# -- Whether or not to enable the Identity component
enabled: true
# -- The Kerberos realm for this Factory+ deployment.
realm: FACTORYPLUS.MYORGANISATION.COM
# -- Kerberos UPNs to grant kadmin access. This needs to be list of
# objects with 'principal', 'permission' and (optionally)
# 'restrictions' properties; see the kadmin documentation for their
# meaning.
kadminUsers: []
# -- Enable support for cross-realm authentication
crossRealm: [ ]
# crossRealm:
# - realm: MYOTHERREALM.COM
# domain: myotherrealm.com
# otherDomains:
# - myotherrealm.org
# - myotherrealm.net
identity:
image:
# -- The repository of the Identity component
repository: acs-identity
# If this is set to true, the kdb-init container will not set up the
# KDB but will sit and wait. This can be used to halt startup of the
# KDC until a restore from backup can be performed. Be aware that
# this will halt startup of the KDC every time the pod starts until
# the setting is changed.
manualInit: false
krbKeysOperator:
# -- A comma-separated list of namespaces that the KerberosKey Operator should watch for
# KerberosKey resources in, in addition to the release namespace and `addon-*` (every
# `addon-<name>` namespace is always watched so optional add-on services get their identity
# provisioned with no core-side configuration). Entries may be glob patterns.
namespaces: ""
image:
# -- The repository of the KerberosKey Operator
repository: acs-krb-keys-operator
auth:
# -- Whether or not to enable the Authorisation component
enabled: true
image:
# -- The repository of the Authorisation component
repository: acs-auth
verbosity: "ALL,!service,!token,!query"
directory:
# -- Whether or not to enable the Directory component
enabled: true
image:
# -- The repository of the Directory component
repository: acs-directory
# -- Debug log tags for the Directory web API and MQTT components,
# passed to them as the VERBOSE environment variable.
# This is a comma-separated list of tags (the word printed at the
# start of each log line). "ALL" or "1" turns on every tag, "!tag"
# turns one off again, and "" turns off all debug logging. The default
# turns off the tags that dump a payload on every operation: "query"
# (every SQL statement with its parameters), "acl" (the full ACL on
# every permission check) and "notify-msg" (every notify request and
# update, with the full body). Errors and warnings do not use these
# tags, so they still appear. Set this to "1" to log everything, for
# example while debugging.
verbosity: "ALL,!query,!acl,!notify-msg"
# -- Exit (so Kubernetes restarts the pod) if the MQTT client has had
# no connection to the broker, and has made no attempt to connect, for
# this many seconds. This catches a client that has stopped trying,
# which otherwise leaves the service running with no MQTT connection
# until someone restarts it. A client that keeps retrying while the
# broker is down is not restarted. Set it to 0 to disable the check.
mqttWatchdogTimeout: 300
configdb:
# -- Whether or not to enable the Configuration Store component
enabled: true
image:
# -- The repository of the Configuration Store component
repository: acs-configdb
# -- Debug log tags for the ConfigDB web API, passed to it as the
# VERBOSE environment variable.
# This is a comma-separated list of tags (the word printed at the
# start of each log line). "ALL" or "1" turns on every tag, "!tag"
# turns one off again, and "" turns off all debug logging. The default
# turns off the tags that dump a payload on every operation: "query"
# (every SQL statement with its parameters), "acl" (the full ACL on
# every permission check) and "notify-msg" (every notify request and
# update, with the full body). Errors and warnings do not use these
# tags, so they still appear. Set this to "1" to log everything, for
# example while debugging.
verbosity: "ALL,!query,!acl,!notify-msg"
# -- Exit (so Kubernetes restarts the pod) if the MQTT client has had
# no connection to the broker, and has made no attempt to connect, for
# this many seconds. This catches a client that has stopped trying,
# which otherwise leaves the service running with no MQTT connection
# until someone restarts it. A client that keeps retrying while the
# broker is down is not restarted. Set it to 0 to disable the check.
mqttWatchdogTimeout: 300
bodyLimit: 100kb
# -- Resource requests and limits for the `webapi` container. The
# default is empty, which leaves the pod BestEffort: first in line for
# the kernel OOM killer and for eviction under node memory pressure.
# Set a memory request to make it Burstable, and a memory limit to cap
# it. Size the limit above the normal working set, because a limit that
# is too low turns memory pressure into a restart loop. With about
# 40,000 devices ConfigDB used about 0.9 GiB at rest and 1.5 GiB while
# i3X ran its first sync; a 2 GiB limit was too low (the heap ran out
# during client reconnects).
# For example:
# resources:
# requests:
# memory: 1Gi
# limits:
# memory: 4Gi
resources: {}
# -- Minimum time in ms between the class member and subclass lookups
# that ConfigDB runs for notify watchers when classes change. During a
# bulk import this stops every watched class being looked up again on
# every object create. A change can reach watchers up to this long
# after it is made. 0 looks up again on every change.
classLookupInterval: 1000
backup:
# -- Whether to run a pg_dump of the ConfigDB before every helm upgrade
enabled: true
# -- Number of backups to retain
retention: 5
# -- Size of the PVC for storing backups
storageSize: 1Gi
metadb:
enabled: false
asConfigDB: false
image:
repository: acs-metadb
files:
enabled: true
image:
repository: acs-files
bodyLimit: 3gb
storage: 20Gi
monitor:
enabled: true
image:
repository: acs-monitor
verbosity: "ALL,!service,!token"
# -- Exit (so Kubernetes restarts the pod) if the MQTT client has had
# no connection to the broker, and has made no attempt to connect, for
# this many seconds. This catches a client that has stopped trying,
# which otherwise leaves the service running with no MQTT connection
# until someone restarts it. A client that keeps retrying while the
# broker is down is not restarted. Set it to 0 to disable the check.
mqttWatchdogTimeout: 300
dataAccess:
enabled: true
image:
repository: acs-data-access
verbosity: "ALL,!service,!token"
# The coverage summary: hourly and daily data-arrival counts per device
# that timelines read instead of counting raw data. See
# docs/services/data-access.md#coverage-summary. Each setting is
# passed to Data Access as the COVERAGE_* variable named below.
coverage:
# -- (COVERAGE_ENABLED) Keep the coverage summary. false turns off
# its bucket and task provisioning, the backfill, the daily repair
# and coverage reads; timelines then count raw data.
enabled: true
# -- (COVERAGE_BACKFILL) Summarise the history already in InfluxDB,
# one day at a time from today backwards. false skips it.
backfill: true
# -- (COVERAGE_PAUSE_MS) Minimum pause between backfill or repair
# days, in milliseconds. The pause is also at least as long as the
# day took. Raise it to make the backfill gentler on InfluxDB.
pauseMs: 1000
# -- (COVERAGE_BACKFILL_EMPTY_DAYS) The backfill stops after this
# many days in a row with no raw data below the oldest data it has
# found. Raise it if your history has a longer gap.
backfillEmptyDays: 365
# -- (COVERAGE_BACKFILL_FROM) An ISO date-time the backfill stops at.
# When set, the backfill walks down to it whatever gaps it meets.
# Empty: stop after `backfillEmptyDays` empty days.
backfillFrom: ""
# -- (COVERAGE_TIMEOUT_MS) Time allowed for one backfill or repair
# query, in milliseconds. Data Access then closes the connection, so
# InfluxDB can cancel the query.
timeoutMs: 600000
# -- (COVERAGE_REPAIR_DAYS) Full days the daily repair recounts at
# 03:00 Europe/London. 0 turns the repair off.
repairDays: 7
# -- (COVERAGE_REBUILD) Any new value starts the backfill again from
# today, once per value. Empty: no rebuild.
rebuild: ""
openid:
# -- Whether or not to deploy the Keycloak OIDC server
enabled: true
# -- Realm name created in Keycloak. Must match the realm used in
# the Grafana OAuth ConfigMap (deploy/templates/grafana/grafana-ini.yaml).
realm: factory_plus
# -- Keycloak login theme set on the realm. The "factory-plus" theme
# ships in the acs-keycloak image and renders ACS-branded login,
# logout and error pages. Set to "" (empty) to keep Keycloak's stock
# keycloak.v2 theme, or set to a different name if you've baked a
# custom theme into your own Keycloak image.
loginTheme: factory-plus
# -- Kerberos realms trusted for cross-realm login. A user from a
# listed realm can sign in without an administrator hand-creating a
# Factory+ principal for them first: once their home KDC accepts the
# password, the SPI writes their Kerberos identity here and they
# appear in the ACL editor with no permissions until granted some.
#
# This requires cross-realm Kerberos trust to already exist - the
# realm and its KDC must be listed in krb5.conf on this cluster.
# Listing a realm here does not create that trust.
#
# RECOMMENDED: list the realm and nothing else, as shown below. The
# user's principal UUID is then derived from their UPN (UUIDv5), which
# means every cluster derives the same UUID for the same person with
# no coordination, no grant to obtain, no outbound call at login, and
# no dependency on the far cluster being reachable. It also lets an
# admin pre-grant: compute the UUID and attach permissions before the
# user has ever logged in, so their first login works properly instead
# of landing with nothing. To compute one:
#
# python3 -c "import uuid; print(uuid.uuid5(uuid.UUID(
# 'cb3714c4-c85c-482a-987b-408293aa141e'), 'me1ago@AMRC-FP.SHEF.AC.UK'))"
#
# (Realm in CAPITALS, username as the person types it, usually lower
# case. See the SPI README for the exact rule.)
#
# `authUrl` is the alternative, and only worth it when you specifically
# need this cluster to reuse the principal UUID the user already has on
# their home cluster. The cost is real: you must get a principal created
# for THIS cluster's sv1openid on the home cluster and have it granted
# ReadKrb there, which is Wildcard-only and confers blanket read and
# enumeration of the home cluster's entire identity table. Logins then
# also depend on that cluster being reachable.
#
# Pick one and stay: this is close to a one-way door. If you start
# without an authUrl and add one later, users who already logged in
# keep their derived UUID while new users get home-derived ones, split
# by when each first signed in. Converging afterwards means re-pointing
# identity records by hand.
#
# Default empty: no realm is trusted and the feature is inert.
trustedRealms: []
# - realm: AMRC-FP.SHEF.AC.UK
# # - realm: PARTNER.EXAMPLE.ORG
# # authUrl: https://auth.partner.example.org
image:
# -- Custom Keycloak image with the Factory+ User Storage SPI baked
# in (built from acs-keycloak/Dockerfile). To run upstream Keycloak
# without the SPI, override repository to "keycloak/keycloak" and
# registry to "quay.io" - but the SPI federation provider won't load.
repository: acs-keycloak
# tlsSecretName: <override> # optional, falls back to acs.tlsSecretName
# -- The service-setup component loads ACS-specific configuration into
# the ACS services when the Helm chart is deployed or upgraded.
serviceSetup:
enabled: true
image:
repository: acs-service-setup
# This section overrides the classes etc. installed into the ConfigDB
config:
# Git repos to create in the on-prem server. These may be
# automatically mirrored from external repos, or populated by the
# service setup job.
repoMirror:
helm:
name: Edge Helm charts
pull: {}
# Helm charts to deploy to the edge; these default to the charts
# created automatically but can be overridden to customise
helmChart:
# Chart to deploy an edge cluster
#cluster: null
# Stable UUIDs for the Grafana role groups in F+. These groups are
# created by service-setup (see lib/grafana-groups.js) as subclasses
# of Class.Principal. To grant a user a Grafana role, an admin adds
# their principal to one of these groups via the F+ ACL editor;
# the SPI's fp_groups claim picks this up on next login (within
# cache TTL) and Grafana's role_attribute_path translates it to
# the matching Grafana role.
#
# Customise per deployment if needed, but DO NOT change once a
# production cluster has grants attached - the UUIDs are referenced
# by the F+ ACL data which doesn't migrate when UUIDs change.
grafanaPermissions:
admin: "7b553965-0987-4ffb-bf9a-afac8bc13707"
editor: "e5f9fe18-da63-49d3-bee5-7950eeb3e053"
# OIDC clients to provision in Keycloak. Each entry generates a
# LocalSecret holding the client_secret in keycloak-clients/<key>.
# Every client automatically gets the fp_principal_uuid and
# fp_groups protocol mappers attached - JWT consumers read F+
# identity directly from the token. Per-client Keycloak roles are
# no longer used; permissions are driven from F+ ACLs via
# fp_groups.
#
# By default the client's URLs are derived from the entry name and
# acs.baseUrl: rootUrl/baseUrl/webOrigins all become
# `<proto>://<name>.<acs.baseUrl>`, redirectUris becomes
# `<root><redirectPath>`, and post.logout.redirect.uris becomes
# `<root>`. For applications served at a different host, override
# any of the following per-client fields - the values flow
# straight through to Keycloak and replace the auto-derived
# defaults so removals also work:
# rootUrl (string)
# baseUrl (string)
# redirectUris (list of full URLs)
# webOrigins (list of origins)
# postLogoutRedirectUris (list of full URLs)
#
# Machine-to-machine clients: set `serviceAccountsEnabled: true` to
# enable the OAuth client-credentials grant (Keycloak "service
# account") so an unattended consumer - a kiosk, a scheduled job -
# can exchange the generated client_secret for tokens with no
# human login. Such clients are necessarily confidential (ignored
# if publicClient is set) and should also set
# `standardFlowEnabled: false`: they have no browser flow, so no
# redirect URIs are ever exercised.
#
# service-setup automatically creates an F+ Principal for each
# service-account client ("Service account: <name>" in the ACL
# editor) and stamps its UUID into the client's tokens as
# fp_principal_uuid, so the account can be granted F+ permissions
# (e.g. MQTT read for a visualiser wall) like any other principal.
# A fresh service account holds NO grants: an unattended display
# will authenticate but see nothing until an admin grants its
# principal the relevant permissions. Example:
# polyptic-kiosk:
# enabled: true
# name: Polyptic kiosk
# serviceAccountsEnabled: true
# standardFlowEnabled: false
#
# `accessTokenLifespan` (seconds) overrides the realm's access-token
# lifespan (default 300s) for one client. A kiosk JWT is re-presented
# on every request by the consuming app (e.g. Grafana url_login), so
# an unattended display dies at token expiry: give such clients a
# long lifespan (e.g. 2592000 = 30 days) and let the consumer refresh
# before expiry. Leave unset everywhere a human signs in.
openidClients:
grafana:
enabled: true
name: Grafana
redirectPath: /login/generic_oauth
# Browser SPA doing Authorization Code + PKCE; public because a
# client secret cannot be kept in a browser. The visualiser also
# honours a `?auth_token=<JWT>` query parameter (like Grafana's
# url_login) for unattended kiosk displays; mint such tokens from
# a service-account client with a long accessTokenLifespan.
visualiser:
enabled: true
name: ACS Visualiser
publicClient: true
# Postman / curl / scripted-API client. Public (no client secret)
# so it can be configured directly in Postman without keeping a
# secret out of source control; PKCE S256 is enforced by
# service-setup so the grant is still secure. Authorization Code
# is for human users (Postman opens a browser to log in). Device
# Authorization (RFC 8628) is for headless CLIs. ROPC stays off:
# it's deprecated in OAuth 2.1 and unnecessary.
acs-cli:
enabled: true
name: ACS CLI
publicClient: true
standardFlowEnabled: true
deviceAuthorizationFlowEnabled: true
directAccessGrantsEnabled: false
redirectUris:
- https://oauth.pstmn.io/v1/callback
- http://localhost/*
- http://127.0.0.1/*
webOrigins:
- https://oauth.pstmn.io
postLogoutRedirectUris:
- https://oauth.pstmn.io/v1/callback
edgeHelm:
enabled: true
image:
repository: edge-helm-charts
repoPath: shared/helm
mqtt:
# -- Whether or not to enable the MQTT component
enabled: true
image:
# -- The repository of the MQTT component
repository: acs-mqtt
# -- Possible values are either 1 to enable all possible debugging, or a comma-separated list of debug tags (the tags printed before the log lines). No logging is specified as an empty string.
verbosity: 0
# -- Extra JVM options for the HiveMQ broker, passed as JAVA_OPTS.
# Without a heap limit the JVM sizes its heap from the node's memory
# (25% by default, 4 GB on a 16 GB node) and rarely gives memory back,
# so the broker grows to whatever peak it has seen. With a 512 MB
# heap the broker runs at about 800 MB resident under a large
# Sparkplug fleet (~44k devices). Set to "" to use the JVM default.
javaOpts: "-Xmx512m"
# -- Kubernetes resources for the broker container, for example
# `{ requests: { memory: 1Gi }, limits: { memory: 1536Mi } }`. Allow
# about 300 MB above the heap limit for non-heap memory. Empty by
# default.
resources: {}
unsIngesters:
sparkplug:
enabled: true
image:
# -- The repository of the MQTT component
repository: uns-ingester-sparkplug
# -- The minimum log level that the historian will log messages at (One of 'fatal', 'error', 'warn', 'info', 'debug', 'trace' or 'silent'.)
logLevel: info
verbosity: 0
# -- Exit (so Kubernetes restarts the pod) if no Sparkplug message has
# been received for this many seconds, once data has started to
# flow. This catches an ingester that stops receiving data and does
# not recover, for example after a broker or KDC restart. Any
# Sparkplug message counts, including births, deaths and STATE. The
# check arms on the first message, so a site with no traffic at all
# does not restart. A gap in traffic longer than this after data has
# flowed does cause a restart: raise the value on sites with long
# quiet periods, or set it to 0 to disable the check.
stallTimeout: 600
# -- Exit (so Kubernetes restarts the pod) if the MQTT client has not
# been connected to the broker with a granted subscription for this
# many seconds, counted from startup or from when the connection or
# subscription was lost. This catches a client that never connects,
# or stops reconnecting, even on a site with no traffic. A connected
# and subscribed client is healthy however quiet the broker is. The
# default allows for a broker and KDC restart during an upgrade. Set
# it to 0 to disable the check.
connectTimeout: 300
visualiser:
enabled: true
image:
# -- The repository of the MQTT component
repository: acs-visualiser
idleFade:
# -- Seconds a device can go without sending a BIRTH or DATA before
# it starts to fade. Edge Agents only publish when a value changes,
# so a faded device has been quiet, not necessarily broken.
after: 120
# -- Seconds a device takes to fade fully once it has started.
duration: 600
# -- Opacity of a fully faded device, from 0 to 1. Set it to 1 to
# turn fading off.
opacity: 0.4
cmdesc:
# -- Whether or not to enable the Commands component
enabled: true
image:
# -- The repository of the Commands component
repository: acs-cmdesc
# -- Possible values are either 1 to enable all possible debugging, or a comma-separated list of debug tags (the tags printed before the log lines). No logging is specified as an empty string.
verbosity: 1
# -- Exit (so Kubernetes restarts the pod) if the MQTT client has had
# no connection to the broker, and has made no attempt to connect, for
# this many seconds. This catches a client that has stopped trying,
# which otherwise leaves the service running with no MQTT connection
# until someone restarts it. A client that keeps retrying while the
# broker is down is not restarted. Set it to 0 to disable the check.
mqttWatchdogTimeout: 300
historians:
uns:
enabled: false
# -- The minimum log level that the historian will log messages at (One of 'fatal', 'error', 'warn', 'info', 'debug', 'trace' or 'silent'.)
logLevel: info
# -- The number of messages to batch together before sending to InfluxDB
batchSize: 5000
# -- Send all buffered messages after this amount of time has elapsed if the buffer is not full (in milliseconds)
flushInterval: 10000
# -- Exit (so Kubernetes restarts the pod) if no UNS message has been
# received for this many seconds, once data has started to flow.
# This catches a historian that stops receiving data and does not
# recover, for example after a broker or KDC restart. Any message
# under UNS/v1/ counts. The check arms on the first message, so a
# site with no traffic at all does not restart. A gap in traffic
# longer than this after data has flowed does cause a restart: raise
# the value on sites with long quiet periods, or set it to 0 to
# disable the check.
stallTimeout: 600
# -- Exit (so Kubernetes restarts the pod) if the MQTT client has not
# been connected to the broker with a granted subscription for this
# many seconds, counted from startup or from when the connection or
# subscription was lost. This catches a client that never connects,
# or stops reconnecting, even on a site with no traffic. A connected
# and subscribed client is healthy however quiet the broker is. The
# default allows for a broker and KDC restart during an upgrade. Set
# it to 0 to disable the check.
connectTimeout: 300
image:
# -- The repository of the UNS Historian component
repository: historian-uns
sparkplug:
enabled: true
# -- The minimum log level that the historian will log messages at (One of 'fatal', 'error', 'warn', 'info', 'debug', 'trace' or 'silent'.)
logLevel: info
# -- The number of messages to batch together before sending to InfluxDB
batchSize: 5000
# -- Send all buffered messages after this amount of time has elapsed if the buffer is not full (in milliseconds)
flushInterval: 10000
# -- Exit (so Kubernetes restarts the pod) if no Sparkplug message has
# been received for this many seconds, once data has started to
# flow. This catches a historian that stops receiving data and does
# not recover, for example after a broker or KDC restart. Any
# Sparkplug message counts, including births, deaths and STATE. The
# check arms on the first message, so a site with no traffic at all
# does not restart. A gap in traffic longer than this after data has
# flowed does cause a restart: raise the value on sites with long
# quiet periods, or set it to 0 to disable the check.
stallTimeout: 600
# -- Exit (so Kubernetes restarts the pod) if the MQTT client has not
# been connected to the broker with a granted subscription for this
# many seconds, counted from startup or from when the connection or
# subscription was lost. This catches a client that never connects,
# or stops reconnecting, even on a site with no traffic. A connected
# and subscribed client is healthy however quiet the broker is. The
# default allows for a broker and KDC restart during an upgrade. Set
# it to 0 to disable the check.
connectTimeout: 300
image:
# -- The repository of the Warehouse component
repository: historian-sparkplug
git:
# -- Whether or not to enable the Git component
enabled: true
image:
# -- The repository of the Git component
repository: acs-git
# -- Possible values are either 1 to enable all possible debugging, or a comma-separated list of debug tags (the tags printed before the log lines). No logging is specified as an empty string.
verbosity: "ALL,!service,!token"
# -- Exit (so Kubernetes restarts the pod) if the MQTT client has had
# no connection to the broker, and has made no attempt to connect, for
# this many seconds. This catches a client that has stopped trying,
# which otherwise leaves the service running with no MQTT connection
# until someone restarts it. A client that keeps retrying while the
# broker is down is not restarted. Set it to 0 to disable the check.
mqttWatchdogTimeout: 300
clusterManager:
# -- Whether or not to enable the Cluster Manager component
enabled: true
image:
# -- The repository of the Clusters component
repository: acs-cluster-manager
verbosity: "ALL,!service,!token"
i3x:
# -- Whether or not to enable the i3X service
enabled: true
image:
# -- The repository of the i3X service
repository: acs-i3x
# -- Passed to the service as LOG_LEVEL. The current i3X code does not
# read it; use `verbosity` below to control the i3X logs.
logLevel: info
# -- Debug log tags for the i3X service, passed to it as the VERBOSE
# environment variable.
# This is a comma-separated list of tags (the word printed at the
# start of each log line). "ALL" or "1" turns on every tag, "!tag"
# turns one off again, and "" turns off all debug logging. The default
# turns off the tags that dump a payload on every operation: "query"
# (every SQL statement with its parameters), "acl" (the full ACL on
# every permission check) and "notify-msg" (every notify request and
# update, with the full body). Errors and warnings do not use these
# tags, so they still appear. Set this to "1" to log everything, for
# example while debugging.
verbosity: "ALL,!query,!acl,!notify-msg"
# -- Resource requests and limits for the `i3x` container. The
# default is empty, which leaves the pod BestEffort: first in line for
# the kernel OOM killer and for eviction under node memory pressure.
# Set a memory request to make it Burstable, and a memory limit to cap
# it. Size the limit above the normal working set, because a limit that
# is too low turns memory pressure into a restart loop. With MCP off and
# the default maxHeapMB, i3X used about 370 MiB during its first sync of
# about 40,000 devices and about 280 MiB at 74,000 devices in testing.
# With MCP on, allow several GiB.
# For example:
# resources:
# requests:
# memory: 512Mi
# limits:
# memory: 1Gi
resources: {}
# -- Override the i3X namespace URI (defaults to https://<baseUrl>/i3x)
# namespaceUri: https://example.com/i3x
# i3X keeps its namespace (the object tree) and the last value of
# each metric in a SQLite database at /data/i3x.db. The database is
# a cache of ConfigDB and the UNS, so losing it costs only a full
# sync from ConfigDB on the next start.
persistence:
# -- Keep the database on a PersistentVolumeClaim (ReadWriteOnce),
# so a restart serves the stored tree at once and fetches only the
# configs that changed. The Deployment then stops the old pod before
# starting the new one (RollingUpdate with maxSurge 0), like the Recreate
# strategy. When false the database is on an emptyDir and every
# start syncs from scratch.
enabled: true
# -- Size of the PersistentVolumeClaim. At 74,000 devices the
# database is about 2 GB, and its write-ahead log can reach about
# 1.5 GB more during a burst of new UNS metrics.
size: 10Gi
# -- StorageClass for the claim. Empty uses the cluster default.
storageClass: ""
mcp:
# -- Serve the MCP endpoint (/mcp) and build the search index it
# uses. Off by default: the index costs about 47 KB of memory per
# device. When off, /mcp answers 404.
enabled: false
# -- Cap on the i3X JavaScript heap in MiB (--max-old-space-size).
# The object tree and values live in SQLite, so the heap stays small
# (about 75 MiB at 74,000 devices). Without a cap V8 lets the heap
# grow between collections during a cold sync (about 550 MiB RSS at
# 74,000 devices, against about 320 MiB with a 256 MiB cap). Only
# applied while MCP is off: the MCP search index needs several GB at
# fleet scale. Set to 0 for no cap.
maxHeapMB: 384
# After a restart or an MQTT reconnect, i3X catches up its stored
# values from InfluxDB (the points written while it was not listening)
# instead of clearing them and reading every value again.
catchUp:
# -- Ms to allow for the historian's write delay and for device
# clocks behind i3X's. i3X waits this long after connecting before
# it reads InfluxDB, and reads from this long before the values were
# last current. Keep it above the historians' flushInterval.
marginMs: 60000
# -- Longest gap, in ms, to catch up; after a longer one the values
# are cleared and read again. At most 30 days. Keep it below the
# InfluxDB bucket's retention.
maxGapMs: 86400000
# -- Ms between refreshes of the values i3X keeps from InfluxDB,
# while connected: the same query over the time since the last
# refresh. Devices that do not publish to the UNS change only there.
refreshMs: 300000
# -- Exit (so Kubernetes restarts the pod) if no UNS message has been
# received for this many seconds, once data has started to flow.
# This catches an i3X whose live values stop updating and do not
# recover, for example after a broker or KDC restart. Any message
# under UNS/v1/ counts. The check arms on the first message, so a
# site with no traffic at all does not restart. A gap in traffic
# longer than this after data has flowed does cause a restart, which
# also drops i3X subscriptions: raise the value on sites with long
# quiet periods, or set it to 0 to disable the check.
stallTimeout: 600
# -- Exit (so Kubernetes restarts the pod) if the MQTT client has not
# been connected to the broker with a granted subscription for this
# many seconds, counted from startup or from when the connection or
# subscription was lost. This catches a client that never connects,
# or stops reconnecting, even on a site with no traffic. A connected
# and subscribed client is healthy however quiet the broker is. The
# default allows for a broker and KDC restart during an upgrade. Set
# it to 0 to disable the check.
connectTimeout: 300
admin:
# -- Whether or not to enable the Admin component
enabled: true
image:
# -- The repository of the Admin component
repository: acs-admin
shell:
image:
repository: acs-krb-utils
# XXX This should probably be included in acs-krb-utils
curl:
image:
registry: docker.io
repository: appropriate/curl
tag: latest
kubectl:
image:
registry: docker.io
repository: alpine/kubectl
tag: 1.33.4
postgres:
# -- Whether or not to enable Postgres
enabled: true
# Postgres image to use. DO NOT change major version on an
# existing installation without being prepared to handle database
# dump/restore manually.
image:
registry: docker.io/library
repository: postgres
tag: 16.1
# Kubegres doesn't support setting pullPolicy
kubegres:
kubeProxy:
image:
registry: registry.k8s.io
repository: kubebuilder/kube-rbac-proxy
tag: v0.13.0
kubegres:
image:
registry: docker.io
repository: reactivetechio/kubegres
tag: 1.16
traefik:
enabled: true
ports:
mqtt:
port: 1883
expose: false
exposedPort: 1883
protocol: TCP
mqttsecure:
port: 8883
expose: true
exposedPort: 8883
protocol: TCP
kdc:
port: 8888
expose: true
exposedPort: 88
protocol: TCP
kpasswd:
port: 8464
expose: true
exposedPort: 464
protocol: TCP
kadmin:
port: 8749
expose: true
exposedPort: 749
protocol: TCP
additionalArguments:
- --metrics.prometheus=true
- --serverstransport.insecureskipverify=true
ingressRoute:
dashboard:
enabled: false
# -- [AZURE] Enable the below section to expose your instance of Factory+/ACS over the internet, replacing the <Value>
# -- tags with the details of your pre-configured load balancer.
service:
spec:
loadBalancerIP: <External IP address here>
annotations:
service.beta.kubernetes.io/azure-load-balancer-resource-group: <Load Balancer Resource Group here>
providers:
kubernetesCRD:
allowCrossNamespace: true
logs:
general:
level: DEBUG
grafana:
deploymentStrategy:
type: Recreate
image:
# v13 migrates dashboards to a new schema ON FIRST USE and the migration
# is one-way — see "Grafana upgraded from v10 to v13" in the release
# notes before downgrading this on an existing installation.
# Not 13.x. Grafana 13 deleted the sqlstore migration that adds
# playlist.created_at/updated_at (present 10.2.0 - 12.4.x) while
# still running a unified-storage playlist migration whose SQL
# requires those columns, so any database created before 10.2.0 -
# including every ACS v5.1.0 site, which shipped Grafana 10.0.1 -
# cannot start under 13. 12.4.x still ships the migration, adds the
# columns through Grafana's own framework, and then completes the
# unified-storage migration itself, recording it in
# unifiedstorage_migration_log. A later move to 13 is then safe,
# because 13 skips the migration on that log row.
tag: 12.4.5
enabled: true
persistence:
enabled: true
annotations:
"helm.sh/resource-policy": "keep"
envFromSecret: influxdb-auth
admin:
existingSecret: grafana-admin-user
grafana.ini:
server:
root_url: "$__file{/etc/acs-config/root_url}"
auth:
# Hide the local username/password form: F+ via Keycloak is the
# only intended login path.
#
# There is NO query-parameter escape hatch. With this set,
# registration.go does not register the form client at all, so no
# interactive or API password login exists -- the local admin in
# Secret grafana-admin-user cannot log in while this is true.
# To break glass (Keycloak down, no F+ login possible), override
# the value and restart the pod:
# grafana:
# grafana.ini:
# auth:
# disable_login_form: false
disable_login_form: true
oauth_auto_login: false
# Required for OAuth to be able to claim an existing Grafana
# user at all - without this flag, pkg/services/authn/clients/
# oauth.go leaves lookupParams.Email AND lookupParams.Login
# both nil, so lookupByOneOf finds nothing, Grafana drops into
# createUser, and the create collides with the existing row's
# email/login uniqueness check ("user already exists"). The
# "insecure" wording refers to providers that don't verify
# emails - ours is our own Keycloak federating F+ Auth, and
# the FactoryPlusUserAdapter already stamps email_verified=true
# because the email is derived from a kerberos-authoritative
# F+ Principal record.
#
# This MUST live under `auth`, not `auth.generic_oauth`: Grafana
# reads it with a hardcoded section literal --
# KeyValue("auth", "oauth_allow_insecure_email_lookup")
# -- and the grafana subchart renders every top-level grafana.ini
# key as its own ini section, so nesting it under
# auth.generic_oauth emits [auth.generic_oauth] where the flag is
# silently ignored and defaults back to false.
oauth_allow_insecure_email_lookup: true
auth.basic:
enabled: false
auth.generic_oauth:
enabled: true
name: "Factory+"
allow_sign_up: true
client_id: grafana
client_secret: $__file{/etc/secrets/auth_generic_oauth/grafana}
scopes: openid profile email
# F+ has no email field; the kerberos UPN (delivered as the
# `preferred_username` claim by Keycloak) is the closest thing.
# Pointing email_attribute_path at it stops Grafana falling back
# to the GitHub-style /emails endpoint (which Keycloak doesn't
# expose and which 404s).
email_attribute_path: preferred_username
auth_url: $__file{/etc/acs-config/auth_url}
token_url: $__file{/etc/acs-config/token_url}
api_url: $__file{/etc/acs-config/api_url}
signout_redirect_url: $__file{/etc/acs-config/signout_redirect_url}
# role_attribute_path is templated into the acs-grafana-config
# ConfigMap by deploy/templates/grafana/grafana-ini.yaml so the
# F+ permission UUIDs from serviceSetup.config.grafanaPermissions
# can be interpolated. Reading via $__file picks up the rendered
# value.
role_attribute_path: $__file{/etc/acs-config/role_attribute_path}
# Grafana applies role_attribute_path on every OAuth login. By
# default it will not *demote* an existing user; with strict
# mode the JMESPath result is authoritative each login, so
# revoking Grafana.Perm.* in F+ downgrades on next login rather
# than letting the 60s SPI cache staleness become permanent.
role_attribute_strict: true
# Keep folders and dashboards on legacy storage on every site, not
# just the big ones. Grafana 12.4.x auto-migrates them into unified
# storage when a site has fewer dashboards than
# DefaultAutoMigrationThreshold (10, setting_unified_storage.go), and
# that migration is one-way. ACS provisions five dashboards, so
# without this a fresh install silently takes a migration that an
# established site does not, splitting the estate into two storage
# modes on a row count - and leaving CI exercising a different path
# from production. A threshold of 1 is below any real dashboard
# count, so shouldAutoMigrate is false everywhere.
unified_storage.folders.folder.grafana.app:
autoMigrationThreshold: 1
unified_storage.dashboards.dashboard.grafana.app:
autoMigrationThreshold: 1
extraConfigmapMounts:
- name: acs-grafana-config
mountPath: /etc/acs-config
configMap: acs-grafana-config
readOnly: true
# The grafana subchart (6.52.4) calls `tpl` on `.subPath` and
# errors when the field is missing rather than honouring its
# `default ""` fallback. Empty string keeps the mount un-subpath'd.
subPath: ""
extraSecretMounts:
- name: keycloak-client-grafana
secretName: keycloak-clients
defaultMode: 0440
mountPath: /etc/secrets/auth_generic_oauth
readOnly: true
items:
- key: grafana
path: grafana
sidecar:
datasources:
enabled: true
label: grafana_datasource
initDatasources: true
dashboards:
enabled: true
provider:
folder: 'Factory+'
disableDelete: true
searchNamespace: ALL
influxdb2:
enabled: true
# InfluxDB holds the historian data and is on the critical path for
# every dashboard. With no resource requests at all it is BestEffort,
# which puts it first in line for the kernel OOM killer and first to
# be evicted when a node comes under memory pressure - and when it
# goes, the historians exit on the failed write and take a while to
# come back. Requesting resources moves it to Burstable so it is not
# the first thing sacrificed.
#
# Requests only. InfluxDB's memory use scales with series cardinality,
# so a limit that is comfortable on one site will OOM another; set
# limits per site if you want a ceiling, but note that a limit which
# is too low turns node pressure into a guaranteed restart loop.
resources:
requests:
cpu: 250m
memory: 1Gi
adminUser:
organization: default
existingSecret: influxdb-auth
initScripts:
enabled: true
scripts: