Compare commits

...
17 Commits
Author SHA1 Message Date
KilianandClaude Opus 5.5 17dd600872 feat(hub): make analysis thumbnail regeneration opt-in (0.163.0) (#197)
Add kerberospipeline.analysis.thumbnailRegeneration.enabled (default
false), passed to pipe-analysis as THUMBNAIL_REGENERATION_ENABLED. When
enabled, analysis regenerates thumbnails from the first frame of a
classified moving object, adding one thumbnail job per classified
recording. Requires an analysis image that reads the flag.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:22:29 +02:00
KilianandClaude Opus 5.5 4880dc1197 feat(hub): allow defining the classification catalog inline in values (0.162.0) (#196)
Restore the optional classificationCatalog values key removed in 0.155.0.
A nonempty list ({key, label, icon?}, unique keys) replaces the bundled
defaults in the chart's classification-catalog ConfigMap, so Hub API and
the bundled catalogs/classifications.json share it. Omitted or null keeps
the defaults; [] is rejected. Combining it with classificationCatalogEnabled:
false, classificationCatalogExistingConfigMap or a classifications.json
replacement fails rendering.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 15:24:00 +02:00
KilianandClaude Opus 5.5 805dfe405b feat(hub): add frontend Google Places API selector (0.161.0) (#195)
Add kerberoshub.frontend.googlemaps.placesApi, rendered as
GOOGLEMAPS_PLACES_API on the hub-frontend and hub-frontend-demo
deployments. Defaults to "legacy" so existing keys keep working; "new"
switches address autocomplete to Places API (New) with the same apikey.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 15:14:23 +02:00
Kilian e861dbecc3 Merge pull request #194 from kerberos-io/feat/workflow-label-triggers
feat(hub): device system tags and system-tag global workflows (0.160.0)
2026-10-16 13:57:39 +02:00
Kilian BouteandClaude Opus 5.5 a35e701cb2 feat(hub): align the system tag catalog with the chart's catalog conventions
- Catalog entries use the Hub shared choice catalog format (key, label) plus
  an optional description, as catalogs/classifications.json does.
- values.schema.json now validates deviceTags (enabled boolean; entries with
  a stored-form key, a label, an optional description; no unknown keys), so
  mistakes fail like other values; templates keep the uniqueness and
  workflow cross-checks.
- The catalog stays inline in values (Helm checks workflow systemTags against
  it) but reaches hub-api like the classification catalog: the
  device-system-tags ConfigMap mounted at /etc/kerberos/device-tags, named by
  DEVICE_SYSTEM_TAGS_FILE, with a checksum annotation. The DEVICE_SYSTEM_TAGS
  JSON env var is gone (hub-api#672 reads the file).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 08:24:21 +00:00
Kilian BouteandClaude Opus 5.5 7cddafbe93 feat(hub): harden the system tag gate for workflow definitions
The engine reads JSON keys case-insensitively and ignores unknown ones, so
the previous exact-path checks could be bypassed (SystemTags, nested or
shared conditions, nested stage needs) and a typo (systemTag:, trigger:)
silently removed a workflow's device scope.

- While deviceTags.system.enabled is false, any mention of system tags in a
  definition (case-insensitive, any depth) fails rendering.
- Definitions may only use id, enabled, triggers and stages, and triggers
  only the models.WorkflowTrigger fields, spelled exactly.
- deviceTags.system.enabled must be a boolean; the string "false" enabled it.

Production's definitions still render.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 08:07:41 +00:00
Kilian BouteandClaude Opus 5.5 5c6198eff2 feat(hub): rename device labels to typed device tags (system tags)
Root deviceLabelsEnabled/deviceLabels become deviceTags.system.enabled and
deviceTags.system.catalog, leaving room for more tag types. hub-api gets
DEVICE_SYSTEM_TAGS, and workflow triggers select devices with systemTags
(condition path device.systemTags). Matches uug-ai/models#284.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 08:47:47 +00:00
Kilian BouteandClaude Opus 5.5 f2ab8c8505 feat(hub): gate device labels with a root deviceLabelsEnabled flag
Replace kerberoshub.workflows.labelTriggers (and hub-workflows'
WORKFLOW_LABEL_TRIGGERS_ENABLED) with one deployment-wide switch next to
the catalog. While it is off, hub-api gets an empty catalog and rendering
fails on any workflow that selects devices by label (trigger labels or
device.labels conditions).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 08:12:52 +00:00
Kilian BouteandClaude Opus 5.5 7472d44683 feat(hub): add the device label catalog
Root deviceLabels is the deployment's device label catalog: the only
labels owners can assign to devices (value, name, description). It is
rendered as DEVICE_LABELS on hub-api; empty (the default) disables
device labels.

Labels are a device concept, so the catalog lives at the root next to
the classification catalog; workflows only refer to it. Rendering fails
when a catalog value is invalid or duplicated, or when a workflow
trigger selects a label that is not in the catalog, so a typo cannot
silently match no device. labelTriggers stays the separate trust switch
for global workflows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 07:47:14 +00:00
Kilian BouteandClaude Opus 5.5 004377e69d feat(hub): allow label-scoped global workflows (0.160.0)
Add kerberoshub.workflows.labelTriggers (default false), rendered as
WORKFLOW_LABEL_TRIGGERS_ENABLED on hub-workflows. It lets global workflow
definitions select devices across organisations by owner-set device
label (trigger `labels`); the engine refuses such definitions until it
is enabled. Owners set labels, so enable it only where owners are
trusted administrators (self-hosted), never on multi-tenant SaaS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 07:16:11 +00:00
KilianandClaude Opus 5.5 664c587300 feat(hub): make the dominant color stage opt-in (#193)
* feat(hub): make the dominant color stage opt-in

Add kerberospipeline.dominantColor.enabled (default false). It gates the
pipe-dominantcolor deployment and is projected to pipe-analysis as
DOMINANTCOLOR_ENABLED, so the producer and consumer follow one value.

Requires a hub-pipeline-analysis image that reads DOMINANTCOLOR_ENABLED:
older images always publish to kcloud-dominantcolor-queue.fifo, which
would back up once the consumer is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(hub): bump analysis to v1.8.22 for DOMINANTCOLOR_ENABLED

v1.8.22 is the first hub-pipeline-analysis release that reads the flag
(uug-ai/hub-pipeline-analysis#114). Chart version moves to 0.159.0 since
0.158.0 was taken on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:52:23 +02:00
KilianandClaude Opus 5.5 c538f3da0b feat(hub): add frontend day overview feature flag (0.158.0) (#192)
Add kerberoshub.frontend.features.dayOverview.enabled, rendered as
FEATURE_DAY_OVERVIEW_ENABLED on the hub-frontend and hub-frontend-demo
deployments. Defaults to "true" so the Day overview page stays visible.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:35:36 +02:00
KilianandClaude Opus 5.5 40b17c5c37 feat(hub): make sprite and thumbnail prefetch count configurable (#191)
Add kerberospipeline.{sprite,thumbnail}.prefetchCount, rendered as
RABBITMQ_PREFETCH_COUNT only when greater than 0, and bump the images to
the releases that read it (sprite v1.1.21, thumbnail v1.3.15).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 13:17:45 +02:00
KilianandClaude Opus 5.5 d7551babe1 feat(hub): expose OpenTelemetry trace sampler settings (#190)
Add opentelemetry.sampler.type / opentelemetry.sampler.arg, rendered as
OTEL_TRACES_SAMPLER / OTEL_TRACES_SAMPLER_ARG on every workload that already
receives OTEL_EXPORTER_OTLP_ENDPOINT (hub-api, hub-workflows and the pipe-*
services) via a shared hub.opentelemetry.samplerEnv helper. Both are empty by
default, so rendered manifests are unchanged and services keep the SDK
default of sampling every trace.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:23:25 +02:00
Cédric Verstraeten 7b43295a18 Merge pull request #189 from kerberos-io/fix/hub-api-cors-origins
fix/hub-api-cors-origins
2026-10-10 13:24:20 +02:00
Cédric VerstraetenandCopilot 2de3a6f7c3 Allow additional Hub API CORS origins
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-10 11:14:38 +00:00
Cédric Verstraeten 8441ed7825 Add DB cache options to hub analysis pipeline
Adds `kerberospipeline.analysis.dbCache.enabled` (default false) and `dbCache.ttl` (default "5m") values. These are passed to the analysis deployment as DB_CACHE_ENABLED and DB_CACHE_TTL env vars to cache hot-path MongoDB lookups (site vault per device) in memory. Site changes apply after at most one TTL, and each replica caches separately. Documented in the chart README and values.yaml.
2026-10-10 13:03:30 +02:00
28 changed files with 477 additions and 46 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.155.0
version: 0.163.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
+89 -21
View File
@@ -76,7 +76,7 @@ The inline examples use the following order, leaving gaps of ten:
Enable the annotation in each service's existing environment values section.
No separate example values file is required. These annotations do not change
image tags or enable disabled services such as sprite.
image tags or enable disabled services such as sprite or dominantColor.
Deploy the compatible analysis bridge before replying workers, and select the
fixed counting release; waves do not enforce minimum compatible image versions.
The chart's default image tags are not a compatibility-tested rollout bundle.
@@ -99,6 +99,51 @@ workflow engine. These deployment-global, ops-managed workflows are read-only
through the API; manage them in Helm values. There are no per-project on/off
overrides.
To run a global workflow on specific devices across organisations, select them
by system tag. Enable `deviceTags.system` and define the tags in its catalog;
owners assign them to devices in Hub (only catalog tags can be assigned):
```yaml
deviceTags:
system:
enabled: true
catalog:
- key: anpr-pilot
label: ANPR pilot
description: Runs licence plate recognition on this camera
kerberoshub:
workflows:
definitions:
anpr-pilot:
id: "6720f3a1c2d4e5f60718293a"
enabled: true
triggers:
- type: automatic
systemTags: ["anpr-pilot"]
stages:
- operation: anpr
```
Every tag a trigger selects must be in the catalog; otherwise rendering fails,
so a typo cannot silently match no device. Because owners set system tags, any
owner could enroll devices into such a workflow, so `deviceTags.system.enabled`
is `false` by default. When it is on, the catalog is rendered into the
`device-system-tags` ConfigMap and mounted into Hub API
(`DEVICE_SYSTEM_TAGS_FILE`), like the classification catalog. While it is off,
Hub API gets no catalog (system tags cannot be set) and rendering fails on any workflow that mentions system
tags anywhere (trigger `systemTags`, or a `device.systemTags` condition at any
depth, in any key casing). Enable it only on deployments whose owners are
trusted administrators (self-hosted), never on multi-tenant SaaS.
The engine reads keys case-insensitively and ignores unknown ones, so a typo
could silently widen a workflow to every device. Workflow definitions may
therefore only use the keys `id`, `enabled`, `triggers` and `stages`, and
triggers only the trigger fields the engine knows, spelled exactly; anything
else fails rendering. System-tag workflows also need a hub-workflows image
that understands `systemTags` (uug-ai/hub-workflows#87 or later): an older
engine drops the field and would run the workflow on every device.
Supply an explicit, stable `id` for new definitions:
```yaml
@@ -223,6 +268,8 @@ kerberospipeline:
| `opentelemetry.enabled` | Enable or disable OpenTelemetry instrumentation. | `false` |
| `opentelemetry.routingEnabled` | Enable or disable OpenTelemetry routing/export behavior. | `false` |
| `opentelemetry.collector.endpoint` | OpenTelemetry collector endpoint used for trace export. | `"http://otel-collector:4317"` |
| `opentelemetry.sampler.type` | Trace sampler, exported as `OTEL_TRACES_SAMPLER` (e.g. `parentbased_traceidratio`). Empty keeps the SDK default (sample everything). | `""` |
| `opentelemetry.sampler.arg` | Sampler argument, exported as `OTEL_TRACES_SAMPLER_ARG` (e.g. `"0.1"` for ~10% of traces). | `""` |
| `openai.enabled` | Enable or disable OpenAI-backed semantic features. | `false` |
| `openai.apikey` | OpenAI API key used when OpenAI integration is enabled. | `"xxx"` |
| `kerberosvault.uri` | The default Kerberos Vault uri (you can add multiple within the app), by default `'https://api.storage.yourdomain.com'` | `"https://api.vault.yourdomain.com"` |
@@ -267,6 +314,7 @@ kerberospipeline:
| `kerberoshub.api.jwtSecret` | A secret that is for generating JWT tokens. | `"this-is-a-secret-please-change-to-random-string"` |
| `kerberoshub.api.schema` | The protocol to serve the Kerberos Hub API, `'http'` or `'https'`. | `"https"` |
| `kerberoshub.api.url` | The Kerberos Hub API ingress to access the API. | `"api.yourdomain.com"` |
| `kerberoshub.api.corsAllowedOrigins` | Additional complete HTTP(S) origins allowed to call the Hub API. Configured frontend origins remain allowed automatically. | `[]` |
| `kerberoshub.api.disableAgentHeartbeat` | Temporarily stop serving the polled `GET /devices` list (hub-api returns `204` without database reads). Devices still load once through `/session/bootstrap`; online/offline status stops refreshing. | `false` |
| `kerberoshub.api.mediaProxy.enabled` | Serve media through hub-api (`/media/proxy`) instead of handing out Vault/storage URLs, hiding the storage endpoint from clients. | `false` |
| `kerberoshub.api.mediaProxy.publicUrl` | Public hub-api base URL used in proxied media URLs. Defaults to `{schema}://{url}`. | `""` |
@@ -329,6 +377,7 @@ kerberospipeline:
| `kerberoshub.frontend.sentry.url` | No longer used. | `"https://xxx@sentry.io/xxx"` |
| `kerberoshub.frontend.stripe.publicKey` | Public key for `kerberoshub.frontend.stripe`. | `""` |
| `kerberoshub.frontend.googlemaps.apikey` | Within Kerberos Hub frontend a couple of maps are being used, the google maps is leveraged for that. | `"xxxx"` |
| `kerberoshub.frontend.googlemaps.placesApi` | Google Places API used for address autocomplete with the same `apikey`: `"legacy"` (Places API) or `"new"` (Places API (New), required for keys that cannot enable the legacy Places API). | `"legacy"` |
| `kerberoshub.frontend.zendesk.url` | No longer used. | `"yourdomain.zendesk.com"` |
| `kerberoshub.frontend.posthog.key` | The API key retrieved from the Posthog instance. | `"xxx"` |
| `kerberoshub.frontend.posthog.url` | Posthog's endpoint (http/https). | `"https://posthog.domain.com"` |
@@ -355,6 +404,7 @@ kerberospipeline:
| `kerberoshub.frontend.features.i18n.defaultLanguage` | Default language code used by the front-end (e.g. `en`, `nl`, `pl`, `tr`, `fr`, `sv`, `de`). | `"en"` |
| `kerberoshub.frontend.features.workflows.enabled` | Enable or disable the workflows feature in the frontend. | `"false"` |
| `kerberoshub.frontend.features.audit.enabled` | Enable or disable the owner/admin Audit events page and navigation link. | `"true"` |
| `kerberoshub.frontend.features.dayOverview.enabled` | Enable or disable the Day overview page and navigation menu. Role page permissions still apply. | `"true"` |
| `kerberoshub.frontend.features.organisations.enabled` | Enable or disable the organisation feature family, including projects. When empty, child groups apply independently. | `""` |
| `kerberoshub.frontend.features.organisations.switcherEnabled` | Enable or disable the organisation dropdown and switching. The current organisation remains visible when disabled. | `"false"` |
| `kerberoshub.frontend.features.organisations.creationEnabled` | Enable or disable organisation creation. Requires organisation switching to be enabled. | `"false"` |
@@ -542,8 +592,12 @@ kerberospipeline:
| `kerberospipeline.analysis.tag` | The Docker image tag/version. | `"v1.7.8"` |
| `kerberospipeline.analysis.replicas` | Number of replicas for `kerberospipeline.analysis`. | `1` |
| `kerberospipeline.analysis.logLevel` | Log verbosity level for `kerberospipeline.analysis`. | `"info"` |
| `kerberospipeline.analysis.thumbnailRegeneration.enabled` | Regenerate thumbnails from the first frame of a classified moving object (`THUMBNAIL_REGENERATION_ENABLED`). Adds one thumbnail job per classified recording. Requires an analysis image that reads the flag. | `false` |
| `kerberospipeline.analysis.dbCache.enabled` | Cache hot-path MongoDB lookups (site vault per device) in memory. Site changes apply after at most one TTL. | `false` |
| `kerberospipeline.analysis.dbCache.ttl` | Lifetime of a cached lookup, as a Go duration (e.g. `"30s"`, `"5m"`). | `"5m"` |
| `kerberospipeline.analysis.resources.requests.memory` | Memory request for `kerberospipeline.analysis`. | `"10Mi"` |
| `kerberospipeline.analysis.resources.requests.cpu` | CPU request for `kerberospipeline.analysis`. | `"10m"` |
| `kerberospipeline.dominantColor.enabled` | Deploy `pipe-dominantcolor` and let the analysis stage schedule it (`DOMINANTCOLOR_ENABLED`). Requires an analysis image that reads the flag. | `false` |
| `kerberospipeline.dominantColor.repository` | The dominant color microservices is computing a top 3 color histogram. | `"ghcr.io/uug-ai/hub-pipeline-dominantcolors"` |
| `kerberospipeline.dominantColor.pullPolicy` | The Docker registry pull policy. | `"IfNotPresent"` |
| `kerberospipeline.dominantColor.tag` | The Docker image tag/version. | `"v2.0.2"` |
@@ -557,6 +611,8 @@ kerberospipeline:
| `kerberospipeline.thumbnail.pullPolicy` | The Docker registry pull policy. | `"IfNotPresent"` |
| `kerberospipeline.thumbnail.tag` | The Docker image tag/version. | `"v1.3.4"` |
| `kerberospipeline.thumbnail.replicas` | Number of replicas for `kerberospipeline.thumbnail`. | `2` |
| `kerberospipeline.thumbnail.prefetchCount` | Max unacknowledged RabbitMQ messages per pod (`RABBITMQ_PREFETCH_COUNT`); `0` keeps the service default of 5. Requires hub-pipeline-thumbnail ≥ v1.3.15. | `0` |
| `kerberospipeline.sprite.prefetchCount` | Max unacknowledged RabbitMQ messages per pod (`RABBITMQ_PREFETCH_COUNT`); `0` keeps the service default of 5. Requires hub-pipeline-sprite ≥ v1.1.21. | `0` |
| `kerberospipeline.thumbnail.logLevel` | Log verbosity level for `kerberospipeline.thumbnail`. | `"info"` |
| `kerberospipeline.thumbnail.quality` | Configuration value for `kerberospipeline.thumbnail.quality`. | `"1"` |
| `kerberospipeline.thumbnail.width` | Configuration value for `kerberospipeline.thumbnail.width`. | `"600"` |
@@ -664,19 +720,37 @@ Within the Kerberos Hub front-end you'll see the option to filter through classi
The default shared classification list lives in
[`templates/configMaps/catalogs/classifications.yaml`](templates/configMaps/catalogs/classifications.yaml),
independently of workflow contracts. The chart uses this bundled definition
unless a deployer provides a ConfigMap override. Each entry contains the stable classifier output
unless a deployer defines the catalog inline or provides a ConfigMap override. Each entry contains the stable classifier output
`key`, the user-facing `label`, and an `icon` key. Hub API exposes this catalog
to alerts and filters. When the mounted catalog is unavailable, compatible Hub
API versions fall back to the legacy `settings` document and then the built-in
classification list. Set `classificationCatalogEnabled: false` to omit the
ConfigMap and make Hub API use that fallback directly.
Starting with chart **0.155.0**, the inline `classificationCatalog` values key is
removed. Supplying it fails validation, including `null` and `[]`; it is never
silently ignored or replaced with bundled defaults.
The simplest way to customize the catalog is to define the complete list inline
in your values (restored in chart **0.162.0** after its removal in 0.155.0):
To customize the catalog, create a ConfigMap in the release namespace containing
the complete JSON array, then use the per-file replacement interface:
```yaml
classificationCatalog:
- key: car
label: Car
icon: car
- key: forklift
label: Forklift
```
The list replaces the bundled defaults entirely (entries are not merged) and is
rendered into the chart's `classification-catalog` ConfigMap, so Hub API and the
bundled `catalogs/classifications.json` of workflow packaging use the same list
and a change rolls the API pod. Each entry needs a `key` and `label`, `icon` is
optional, and keys must be unique. Omitting the key (or `null`) keeps the bundled
defaults; `[]` is rejected, so use `classificationCatalogEnabled: false` for the
API fallback. An inline list cannot be combined with
`classificationCatalogEnabled: false`, `classificationCatalogExistingConfigMap` or
a per-file catalog replacement.
Alternatively, create a ConfigMap in the release namespace containing the complete
JSON array, then use the per-file replacement interface:
```yaml
classificationCatalogEnabled: true
@@ -691,13 +765,8 @@ workflowConfiguration:
replace: true
```
To migrate, copy the existing list exactly (preserving keys, labels and icons)
into the ConfigMap's JSON data, remove `classificationCatalog` from every values
overlay and command-line override, and deploy the ConfigMap before the chart
upgrade. A `null` value is not a migration: remove the key. The bundled list
remains the default when no override is configured. If an old `[]` intentionally
selected the API's runtime fallback, use `classificationCatalogEnabled: false`
and configure workflow packaging without bundled defaults instead.
Deploy that ConfigMap before the chart upgrade. The bundled list remains the
default when no override is configured.
The existing `classificationCatalogExistingConfigMap: hub-classification-catalog`
option remains supported, including for deployments without workflow packaging.
@@ -1042,12 +1111,12 @@ not owned by workflows. A library may ship a catalog without implementing an API
**effective** classification list under `/etc/kerberos/configuration`, using
the directory layout above. The projected volume reuses the existing
classification ConfigMap, including `classificationCatalogExistingConfigMap`
overrides or explicit per-file replacements, rather
overrides, an inline `classificationCatalog` or explicit per-file replacements, rather
than storing another copy in the workflow ConfigMap.
The default classification ConfigMap name, mount path, `CLASSIFICATION_CATALOG_FILE`
and API endpoint remain unchanged. Inline `classificationCatalog` values,
including `[]` and `null`, are rejected from chart 0.155.0 onward. The current API
and API endpoint remain unchanged. An inline `classificationCatalog` list is
rendered into that ConfigMap; `[]` is rejected. The current API
still falls back to settings/built-in values for an empty/invalid mounted catalog. The preparatory
bundle does not reproduce that runtime fallback and must not be treated as a
resolved API catalog. The Start-specific loader shares the existing classification
@@ -1134,10 +1203,9 @@ A replacement for `catalogs/classifications.json` also supplies the standalone
classification API. Both mounts use that ConfigMap and key, even when its key
is not named `classifications.json`. The chart does not generate or checksum the
replaced ConfigMap. To avoid two competing sources, do not combine this
replacement with a nonempty `classificationCatalogExistingConfigMap`. That
existing ConfigMap option remains supported when no per-file catalog replacement
is configured. The retired inline `classificationCatalog` key is rejected
regardless of the selected configuration.
replacement with a nonempty `classificationCatalogExistingConfigMap` or an inline
`classificationCatalog`. Those options remain supported when no per-file catalog
replacement is configured.
`classificationCatalogEnabled` must remain true when including defaults.
This is whole-file replacement, not field-level YAML merging or catalog-entry
@@ -1,7 +1,6 @@
# Create these ConfigMaps in the release namespace before deploying the chart.
# Keys contain complete contracts/catalogs; they are not merged with chart data.
# Remove the retired classificationCatalog key from every values overlay.
# Do not also set classificationCatalogExistingConfigMap.
# Do not also set classificationCatalog or classificationCatalogExistingConfigMap.
classificationCatalogEnabled: true
workflowConfiguration:
enabled: true
+11 -3
View File
@@ -22,9 +22,6 @@
{{/* Normalize both interfaces without changing the caller's values. */}}
{{- define "hub.workflowConfiguration.settings" -}}
{{- if hasKey .Values "classificationCatalog" -}}
{{- fail "classificationCatalog is no longer supported; remove the values key and place the complete catalog in a ConfigMap, then use workflowConfiguration.configMaps with path: catalogs/classifications.json and replace: true" -}}
{{- end -}}
{{- $config := .Values.workflowConfiguration | default dict -}}
{{- $unified := or (hasKey $config "includeDefaults") (hasKey $config "configMaps") -}}
{{- $legacy := or (hasKey $config "existingConfigMap") (hasKey $config "items") (hasKey $config "extraConfigMaps") -}}
@@ -78,6 +75,17 @@
{{- fail "a classifications.json replacement cannot be combined with classificationCatalogExistingConfigMap; choose one override mechanism" -}}
{{- end -}}
{{- end -}}
{{- if not (kindIs "invalid" .Values.classificationCatalog) -}}
{{- if not .Values.classificationCatalogEnabled -}}
{{- fail "classificationCatalog requires classificationCatalogEnabled; remove the inline list to use the API fallback" -}}
{{- end -}}
{{- if .Values.classificationCatalogExistingConfigMap -}}
{{- fail "classificationCatalog cannot be combined with classificationCatalogExistingConfigMap; choose one override mechanism" -}}
{{- end -}}
{{- if hasKey $replacements "catalogs/classifications.json" -}}
{{- fail "classificationCatalog cannot be combined with a classifications.json replacement; choose one override mechanism" -}}
{{- end -}}
{{- end -}}
{{- dict "enabled" $enabled "includeDefaults" $includeDefaults "configMaps" $normalizedSources "replacements" $replacements | toYaml -}}
{{- end -}}
+51
View File
@@ -0,0 +1,51 @@
{{/*
The system tag catalog (deviceTags.system.catalog) uses the Hub shared choice
catalog format: {key, label, description?}. values.schema.json validates each
entry (key in stored device tag form, models.NormalizeDeviceTags: 1-64
characters of a-z, 0-9, ".", "_", ":" and "-", starting and ending with a
letter or digit) and that enabled is a boolean; keys must also be unique.
*/}}
{{- define "kerberoshub.deviceTags.system.validate" -}}
{{- $seen := dict -}}
{{- range $tag := (include "kerberoshub.deviceTags.system.catalog" . | fromJsonArray) -}}
{{- $key := toString $tag.key -}}
{{- if hasKey $seen $key -}}
{{- fail (printf "deviceTags.system.catalog: duplicate key %q" $key) -}}
{{- end -}}
{{- $_ := set $seen $key true -}}
{{- end -}}
{{- end -}}
{{/*
The configured system tag catalog as a JSON array, whether or not system tags
are enabled (missing values read as empty).
*/}}
{{- define "kerberoshub.deviceTags.system.catalog" -}}
{{- $deviceTags := .Values.deviceTags | default dict -}}
{{- $system := $deviceTags.system | default dict -}}
{{- $system.catalog | default list | toJson -}}
{{- end -}}
{{/*
Whether system tags are enabled (deviceTags.system.enabled): "true" or "".
*/}}
{{- define "kerberoshub.deviceTags.system.enabled" -}}
{{- $deviceTags := .Values.deviceTags | default dict -}}
{{- $system := $deviceTags.system | default dict -}}
{{- if and (kindIs "bool" $system.enabled) $system.enabled -}}true{{- end -}}
{{- end -}}
{{/*
The system tag catalog file hub-api reads (DEVICE_SYSTEM_TAGS_FILE), rendered
from deviceTags.system.catalog into the device-system-tags ConfigMap.
*/}}
{{- define "kerberoshub.deviceTags.system.json" -}}
{{- include "kerberoshub.deviceTags.system.validate" . -}}
{{- $tags := list -}}
{{- range $tag := (include "kerberoshub.deviceTags.system.catalog" . | fromJsonArray) -}}
{{- $entry := dict "key" $tag.key "label" $tag.label -}}
{{- with $tag.description }}{{- $_ := set $entry "description" . -}}{{- end }}
{{- $tags = append $tags $entry -}}
{{- end -}}
{{- $tags | toJson -}}
{{- end -}}
+17 -1
View File
@@ -81,4 +81,20 @@ Usage: {{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-api") | nin
- name: mongodb-tls
mountPath: {{ .Values.mongodb.tls.mountPath }}
readOnly: true
{{- end -}}
{{- end -}}
{{/*
OpenTelemetry sampler env entries, rendered only when configured. The OTel SDKs
read these natively; unset keeps the SDK default (parentbased_always_on).
Usage: {{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
*/}}
{{- define "hub.opentelemetry.samplerEnv" -}}
{{- with .Values.opentelemetry.sampler.type }}
- name: OTEL_TRACES_SAMPLER
value: {{ . | quote }}
{{- end }}
{{- with .Values.opentelemetry.sampler.arg }}
- name: OTEL_TRACES_SAMPLER_ARG
value: {{ . | quote }}
{{- end }}
{{- end -}}
@@ -11,6 +11,28 @@
{"key": "cell phone", "label": "Cell phone", "icon": "cell phone"}
]
{{- end -}}
{{/*
The effective chart-rendered catalog: the inline classificationCatalog values
list when set, otherwise the bundled defaults above. values.schema.json
validates each entry ({key, label, icon?}); keys must also be unique.
*/}}
{{- define "hub.classificationCatalog.json" -}}
{{- if kindIs "invalid" .Values.classificationCatalog -}}
{{- include "hub.classificationCatalog.defaults" . | mustFromJson | toJson -}}
{{- else if and (kindIs "slice" .Values.classificationCatalog) .Values.classificationCatalog -}}
{{- $seen := dict -}}
{{- range $entry := .Values.classificationCatalog -}}
{{- $key := toString $entry.key -}}
{{- if hasKey $seen $key -}}
{{- fail (printf "classificationCatalog: duplicate key %q" $key) -}}
{{- end -}}
{{- $_ := set $seen $key true -}}
{{- end -}}
{{- .Values.classificationCatalog | toJson -}}
{{- else -}}
{{- fail "classificationCatalog must be omitted (bundled defaults) or a nonempty list; to use the API fallback set classificationCatalogEnabled: false" -}}
{{- end -}}
{{- end -}}
{{- $config := include "hub.workflowConfiguration.settings" . | fromYaml -}}
{{- if and .Values.classificationCatalogEnabled (not .Values.classificationCatalogExistingConfigMap) (not (hasKey $config.replacements "catalogs/classifications.json")) }}
apiVersion: v1
@@ -20,5 +42,5 @@ metadata:
namespace: {{ .Release.Namespace }}
data:
classifications.json: |-
{{- include "hub.classificationCatalog.defaults" . | mustFromJson | toPrettyJson | nindent 4 }}
{{- include "hub.classificationCatalog.json" . | mustFromJson | toPrettyJson | nindent 4 }}
{{- end -}}
@@ -0,0 +1,12 @@
{{- if include "kerberoshub.deviceTags.system.enabled" . }}
apiVersion: v1
kind: ConfigMap
metadata:
name: device-system-tags
namespace: {{ .Release.Namespace }}
data:
# Rendered from deviceTags.system.catalog; hub-api reads it through
# DEVICE_SYSTEM_TAGS_FILE.
system-tags.json: |-
{{- include "kerberoshub.deviceTags.system.json" . | mustFromJson | toPrettyJson | nindent 4 }}
{{- end -}}
+26 -2
View File
@@ -125,6 +125,9 @@ spec:
{{- if and .Values.classificationCatalogEnabled (not .Values.classificationCatalogExistingConfigMap) (not $catalogReplacement) }}
checksum/classification-catalog: {{ include (print $.Template.BasePath "/configMaps/catalogs/classifications.yaml") . | sha256sum }}
{{- end }}
{{- if include "kerberoshub.deviceTags.system.enabled" . }}
checksum/device-system-tags: {{ include (print $.Template.BasePath "/configMaps/catalogs/device-system-tags.yaml") . | sha256sum }}
{{- end }}
{{- if and $workflowConfiguration.enabled $workflowConfiguration.includeDefaults (not (hasKey $workflowConfiguration.replacements "workflow-contracts/start.yaml")) }}
checksum/workflow-configuration: {{ include (print $.Template.BasePath "/configMaps/workflow-contracts/start.yaml") . | sha256sum }}
{{- end }}
@@ -147,7 +150,8 @@ spec:
{{- $serverTLS := .Values.kerberoshub.api.serverTLS }}
{{- $mongodbTLS := .Values.mongodb.tls }}
{{- $classificationCatalogEnabled := .Values.classificationCatalogEnabled }}
{{- if or $workflowConfiguration.enabled $classificationCatalogEnabled .Values.kerberoshub.api.volumes (and $serverTLS.enabled $serverTLS.secretName) (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
{{- $deviceSystemTagsEnabled := include "kerberoshub.deviceTags.system.enabled" . }}
{{- if or $workflowConfiguration.enabled $classificationCatalogEnabled $deviceSystemTagsEnabled .Values.kerberoshub.api.volumes (and $serverTLS.enabled $serverTLS.secretName) (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumes:
{{- if $workflowConfiguration.enabled }}
- name: workflow-configuration
@@ -200,6 +204,11 @@ spec:
path: classifications.json
{{- end }}
{{- end }}
{{- if $deviceSystemTagsEnabled }}
- name: device-system-tags
configMap:
name: device-system-tags
{{- end }}
{{- with .Values.kerberoshub.api.volumes }}
{{- toYaml . | nindent 8 }}
{{- end }}
@@ -227,7 +236,7 @@ spec:
ports:
- containerPort: 80
name: http
{{- if or $workflowConfiguration.enabled $classificationCatalogEnabled .Values.kerberoshub.api.volumeMounts (and $serverTLS.enabled $serverTLS.secretName) (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
{{- if or $workflowConfiguration.enabled $classificationCatalogEnabled $deviceSystemTagsEnabled .Values.kerberoshub.api.volumeMounts (and $serverTLS.enabled $serverTLS.secretName) (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumeMounts:
{{- if $workflowConfiguration.enabled }}
- name: workflow-configuration
@@ -239,6 +248,11 @@ spec:
mountPath: /etc/kerberos/classifications
readOnly: true
{{- end }}
{{- if $deviceSystemTagsEnabled }}
- name: device-system-tags
mountPath: /etc/kerberos/device-tags
readOnly: true
{{- end }}
{{- with .Values.kerberoshub.api.volumeMounts}}
{{- toYaml . | nindent 12 }}
{{- end }}
@@ -261,6 +275,12 @@ spec:
- name: CLASSIFICATION_CATALOG_FILE
value: /etc/kerberos/classifications/classifications.json
{{- end }}
{{- if $deviceSystemTagsEnabled }}
# System tag catalog (deviceTags.system.catalog): the only system
# tags owners can assign. Unset (disabled) disables system tags.
- name: DEVICE_SYSTEM_TAGS_FILE
value: /etc/kerberos/device-tags/system-tags.json
{{- end }}
- name: ENVIRONMENT
value: "{{ .Values.environment }}"
- name: READ_ONLY
@@ -290,6 +310,9 @@ spec:
{{- if and .Values.kerberoshub.frontend.demoEnabled .Values.kerberoshub.frontend.demoUrl }}
{{- $corsOrigins = append $corsOrigins (printf "%s://%s" .Values.kerberoshub.frontend.schema .Values.kerberoshub.frontend.demoUrl) }}
{{- end }}
{{- range .Values.kerberoshub.api.corsAllowedOrigins }}
{{- $corsOrigins = append $corsOrigins . }}
{{- end }}
- name: CORS_ALLOWED_ORIGINS
value: {{ join "," $corsOrigins | quote }}
{{ if .Values.isPrivate }}
@@ -574,5 +597,6 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 12 }}
{{- end }}
{{- end }}
@@ -192,6 +192,8 @@ spec:
# Google maps for using and displaying cameras, sites on a map
- name: GOOGLEMAPS_KEY
value: "{{ .Values.kerberoshub.frontend.googlemaps.apikey }}"
- name: GOOGLEMAPS_PLACES_API
value: "{{ .Values.kerberoshub.frontend.googlemaps.placesApi }}"
# features > chart
- name: CHART_COLORS
@@ -235,6 +237,8 @@ spec:
value: "{{ .Values.kerberoshub.frontend.features.workflows.enabled }}"
- name: FEATURE_AUDIT_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.audit.enabled }}"
- name: FEATURE_DAY_OVERVIEW_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.dayOverview.enabled }}"
- name: FEATURE_DEVICE_ANALYTICS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.devices.analyticsEnabled }}"
- name: FEATURE_DASHBOARD_SITES_FULLSCREEN_ENABLED
@@ -275,6 +275,8 @@ spec:
# Google maps for using and displaying cameras, sites on a map
- name: GOOGLEMAPS_KEY
value: "{{ .Values.kerberoshub.frontend.googlemaps.apikey }}"
- name: GOOGLEMAPS_PLACES_API
value: "{{ .Values.kerberoshub.frontend.googlemaps.placesApi }}"
# Zendesk for support
- name: ZENDESK_URL
@@ -314,6 +316,8 @@ spec:
value: "{{ .Values.kerberoshub.frontend.features.workflows.enabled }}"
- name: FEATURE_AUDIT_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.audit.enabled }}"
- name: FEATURE_DAY_OVERVIEW_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.dayOverview.enabled }}"
- name: FEATURE_DEVICE_ANALYTICS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.devices.analyticsEnabled }}"
- name: FEATURE_DASHBOARD_SITES_FULLSCREEN_ENABLED
@@ -21,6 +21,64 @@ workflow later cannot silently alias another workflow's runs or references.
{{- end -}}
{{- $_ := set $identities $id $name -}}
{{- end -}}
{{- include "kerberoshub.workflows.validateSystemTags" . -}}
{{- end -}}
{{/*
Guard the definitions that can select devices by system tag. The engine reads
JSON keys case-insensitively and ignores unknown ones, so a misspelled or
re-cased key silently changes what a definition selects (a dropped
systemTags scope makes a global workflow run on every device). Therefore:
- definitions and triggers may only use the keys the engine knows, spelled
exactly (definition: id, enabled, triggers, stages; trigger: the
models.WorkflowTrigger fields);
- while deviceTags.system.enabled is false, no definition may mention system
tags anywhere (trigger systemTags, or a device.systemTags condition at any
depth, in triggers, shared conditions or stage needs), matched
case-insensitively on the whole definition;
- every system tag a trigger selects must be in deviceTags.system.catalog,
so a typo fails rendering instead of never matching a device.
Disabled definitions are checked too, so enabling one cannot fail later.
*/}}
{{- define "kerberoshub.workflows.validateSystemTags" -}}
{{- include "kerberoshub.deviceTags.system.validate" . -}}
{{- $catalog := dict -}}
{{- range $tag := (include "kerberoshub.deviceTags.system.catalog" . | fromJsonArray) -}}
{{- $_ := set $catalog (toString $tag.key) true -}}
{{- end -}}
{{- $enabled := include "kerberoshub.deviceTags.system.enabled" . -}}
{{- $definitionKeys := list "id" "enabled" "triggers" "stages" -}}
{{- $triggerKeys := list "type" "edgeId" "sharedConditions" "devices" "siteIds" "groupIds" "systemTags" "classifications" "conditionMode" "conditions" "weeklySchedule" "surfaces" -}}
{{- range $name, $wf := .Values.kerberoshub.workflows.definitions -}}
{{- if $wf -}}
{{- if not (kindIs "map" $wf) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q] must be an object" $name) -}}
{{- end -}}
{{- if and (not $enabled) (contains "systemtags" (lower (toJson $wf))) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q] selects devices by system tag (systemTags or a device.systemTags condition), but deviceTags.system.enabled is false" $name) -}}
{{- end -}}
{{- range $key, $_ := $wf -}}
{{- if not (has $key $definitionKeys) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q]: unknown key %q (allowed: %s). Keys are case-sensitive; a misspelled key would be ignored" $name $key (join ", " $definitionKeys)) -}}
{{- end -}}
{{- end -}}
{{- range $i, $trigger := ($wf.triggers | default list) -}}
{{- if not (kindIs "map" $trigger) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q].triggers[%d] must be an object" $name $i) -}}
{{- end -}}
{{- range $key, $_ := $trigger -}}
{{- if not (has $key $triggerKeys) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q].triggers[%d]: unknown key %q (allowed: %s). Keys are case-sensitive; a misspelled key would be ignored and widen the trigger" $name $i $key (join ", " $triggerKeys)) -}}
{{- end -}}
{{- end -}}
{{- range $tag := ($trigger.systemTags | default list) -}}
{{- if not (hasKey $catalog (toString $tag)) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q].triggers[%d].systemTags: %q is not in deviceTags.system.catalog; add it to the system tag catalog" $name $i (toString $tag)) -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
@@ -115,6 +115,7 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
@@ -121,6 +121,20 @@ spec:
# Sprites
- name: SPRITE_ENABLED
value: "{{ .Values.kerberospipeline.sprite.enabled }}"
# Dominant colors
- name: DOMINANTCOLOR_ENABLED
value: "{{ .Values.kerberospipeline.dominantColor.enabled }}"
# Thumbnail regeneration from classified frames (opt-in)
- name: THUMBNAIL_REGENERATION_ENABLED
value: {{ .Values.kerberospipeline.analysis.thumbnailRegeneration.enabled | default false | quote }}
# In-memory cache for hot-path MongoDB lookups
- name: DB_CACHE_ENABLED
value: {{ .Values.kerberospipeline.analysis.dbCache.enabled | default false | quote }}
- name: DB_CACHE_TTL
value: {{ .Values.kerberospipeline.analysis.dbCache.ttl | default "5m" | quote }}
{{- if .Values.opentelemetry.enabled }}
# Open Telemetry tracing
@@ -130,6 +144,7 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
@@ -89,6 +89,7 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
@@ -1,4 +1,4 @@
{{- if or (eq .Values.mode "all") (eq .Values.mode "pipeline") -}}
{{- if and (or (eq .Values.mode "all") (eq .Values.mode "pipeline")) (eq .Values.kerberospipeline.dominantColor.enabled true) -}}
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -89,6 +89,7 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
@@ -110,6 +110,7 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
@@ -142,6 +142,7 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
@@ -131,6 +131,7 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
@@ -130,6 +130,7 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
@@ -176,6 +176,7 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
@@ -104,6 +104,7 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
@@ -87,6 +87,10 @@ spec:
value: "{{ .Values.rabbitmq.username }}"
- name: RABBITMQ_PASSWORD
value: "{{ .Values.rabbitmq.password }}"
{{- with .Values.kerberospipeline.sprite.prefetchCount }}
- name: RABBITMQ_PREFETCH_COUNT
value: {{ . | quote }}
{{- end }}
# There is an option to store the sprites in a storage provider in Kerberos Vault.
- name: VAULT_SPRITE_ENABLED
@@ -112,6 +116,7 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
@@ -106,6 +106,7 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
@@ -87,6 +87,10 @@ spec:
value: "{{ .Values.rabbitmq.username }}"
- name: RABBITMQ_PASSWORD
value: "{{ .Values.rabbitmq.password }}"
{{- with .Values.kerberospipeline.thumbnail.prefetchCount }}
- name: RABBITMQ_PREFETCH_COUNT
value: {{ . | quote }}
{{- end }}
# Thumbnail generation
- name: THUMBNAIL_QUALITY
@@ -115,6 +119,7 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
+64 -2
View File
@@ -8,8 +8,70 @@
"pattern": "^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"
},
"classificationCatalog": {
"not": {},
"description": "Removed in 0.155.0. Store the complete catalog in a ConfigMap and use workflowConfiguration.configMaps with replace: true at catalogs/classifications.json."
"type": ["array", "null"],
"minItems": 1,
"description": "Optional inline classification catalog in the Hub shared choice catalog format; replaces the bundled defaults in the chart's classification-catalog ConfigMap. Omit (or null) for the bundled defaults. Keys must be unique (checked when rendering).",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["key", "label"],
"properties": {
"key": {"type": "string", "minLength": 1},
"label": {"type": "string", "minLength": 1},
"icon": {"type": "string", "minLength": 1}
}
}
},
"deviceTags": {
"type": "object",
"additionalProperties": false,
"properties": {
"system": {
"type": "object",
"additionalProperties": false,
"properties": {
"enabled": {
"type": "boolean",
"description": "Owners may assign system tags and global workflows may select devices by them. Only for deployments whose owners are trusted (self-hosted)."
},
"catalog": {
"type": "array",
"description": "The system tags owners can assign, in the Hub shared choice catalog format (key, label) plus an optional description. Keys must be unique (checked when rendering).",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["key", "label"],
"properties": {
"key": {
"type": "string",
"maxLength": 64,
"pattern": "^[a-z0-9]([a-z0-9._:-]*[a-z0-9])?$"
},
"label": {"type": "string", "minLength": 1},
"description": {"type": "string"}
}
}
}
}
}
}
},
"kerberoshub": {
"type": "object",
"properties": {
"api": {
"type": "object",
"properties": {
"corsAllowedOrigins": {
"type": "array",
"items": {
"type": "string",
"pattern": "^https?://[^/?#]+$"
}
}
}
}
}
},
"workflowConfiguration": {
"type": "object",
+75 -7
View File
@@ -82,8 +82,39 @@ classificationCatalogEnabled: true
# When set, do not create a catalog ConfigMap; this replaces bundled defaults.
classificationCatalogExistingConfigMap: ""
# Defaults live in templates/configMaps/catalogs/classifications.yaml.
# Inline classificationCatalog values are no longer accepted (including null/[]).
# Use a ConfigMap item with path: catalogs/classifications.json and replace: true.
# Optionally define the complete catalog inline instead; it replaces the
# defaults in the chart's classification-catalog ConfigMap (and so the bundled
# catalogs/classifications.json). Entries are {key, label, icon?} with unique
# keys. Do not combine it with classificationCatalogExistingConfigMap or a
# catalogs/classifications.json replacement in workflowConfiguration.
# classificationCatalog:
# - key: car
# label: Car
# icon: car
# Device tags, grouped by type. System tags are defined here and assigned by
# owners (a multi-select on the device page); global workflows select devices
# across organisations by system tag (`systemTags` in a trigger). Owners set
# them, so any owner could enroll devices into such a workflow: enable only
# where owners are the deployment's administrators (self-hosted), never on
# multi-tenant SaaS. While disabled, hub-api gets an empty catalog (system tags
# cannot be set) and rendering fails on workflows that select devices by
# system tag.
deviceTags:
system:
enabled: false # a boolean (true/false), not a string
# The only system tags owners can assign, in the Hub shared choice catalog
# format (as catalogs/classifications.json) plus an optional description.
# Rendered into the device-system-tags ConfigMap for hub-api.
# key stored tag: 1-64 characters of a-z, 0-9, ".", "_", ":" or
# "-", starting and ending with a letter or digit; unique.
# label display name.
# description optional help text shown with the tag.
# Workflow trigger systemTags must exist here; otherwise rendering fails.
catalog: []
# - key: anpr-pilot
# label: ANPR pilot
# description: Runs licence plate recognition on this camera
# Configuration packaging only: consuming contracts requires a compatible
# API/frontend. Enabling this mounts files but does not register stage workers.
@@ -97,7 +128,7 @@ workflowConfiguration:
# Replacement requires includeDefaults: true and a known bundled destination path.
# Unmarked collisions and repeated custom destinations are rejected.
# Replacing catalogs/classifications.json also supplies the classification API:
# do not combine it with classificationCatalogExistingConfigMap.
# do not combine it with classificationCatalogExistingConfigMap or classificationCatalog.
# Legacy existingConfigMap/items/extraConfigMaps remain supported, but cannot
# be mixed with includeDefaults/configMaps. Both interfaces are omitted here
# so Helm's default merging does not introduce a false mixed configuration.
@@ -178,6 +209,17 @@ opentelemetry:
# the collector terminates TLS. A scheme-less value defaults to TLS and
# fails against a plaintext collector ("server gave HTTP response to HTTPS client").
endpoint: "http://otel-collector:4318"
# Trace sampling, passed to the services as OTEL_TRACES_SAMPLER and
# OTEL_TRACES_SAMPLER_ARG. Leave empty to keep the SDK default, which records
# every trace. Example: keep ~10% of traces, and follow the parent's decision
# for spans that continue an upstream trace:
# type: "parentbased_traceidratio"
# arg: "0.1"
# Supported types: always_on, always_off, traceidratio, parentbased_always_on,
# parentbased_always_off, parentbased_traceidratio.
sampler:
type: ""
arg: ""
############################################
# OpenAI configuration (semantic search)
#
@@ -294,6 +336,9 @@ kerberoshub:
jwtSecret: "this-is-a-secret-please-change-to-random-string" # change to a random value, this is for generating JWT tokens.
schema: "https"
url: "api.yourdomain.com"
# Additional complete HTTP(S) origins allowed to call the Hub API.
# The configured frontend origins remain allowed automatically.
corsAllowedOrigins: []
# Temporarily stop serving the polled GET /devices list: hub-api answers 204
# without querying MongoDB. The frontend still loads devices once through
# /session/bootstrap, but device online/offline status stops refreshing.
@@ -537,6 +582,9 @@ kerberoshub:
# Audit events are visible to owner/admin users when enabled.
audit:
enabled: "true" # Enable or disable the Audit events page and navigation link 'true' or 'false'
# Day overview page and its navigation menu; role page permissions still apply.
dayOverview:
enabled: "true" # Enable or disable the Day overview page and navigation menu 'true' or 'false'
# Organisation controls remain visible as a read-only current organisation when switching is disabled.
organisations:
enabled: "" # Enable or disable the organisation feature family, including projects; when empty, child groups apply independently
@@ -661,6 +709,7 @@ kerberoshub:
publicKey: ""
googlemaps: # Google maps is used inside the application to visualise cameras and sites.
apikey: "xxxx"
placesApi: "legacy" # Places API for address autocomplete: "legacy" (default) or "new" for keys with Places API (New) enabled. Uses the same apikey.
zendesk: # We can use different support tools, for now we use Zendesk but others can be integrated
url: "yourdomain.zendesk.com"
posthog: # Posthog is used for auditing and user interaction logging
@@ -822,7 +871,9 @@ kerberoshub:
# triggers how a run OPENS. Omit for a single bare automatic trigger
# (opens for every recording); the per-stage `needs` then decide
# which stages FIRE. Narrow with device/schedule triggers, e.g.
# `- {type: automatic, devices: [{key: <device-key>}]}`.
# `- {type: automatic, devices: [{key: <device-key>}]}`, or by
# device label across organisations, e.g.
# `- {type: automatic, systemTags: [anpr-pilot]}` (see deviceTags).
# stages the executable stages, each {operation, dispatch?, needs?,
# needsMode?}. dispatch is "always" (default) or "conditional";
# a conditional stage's `needs` are upstream dependencies, each
@@ -1215,7 +1266,7 @@ kerberospipeline:
# deploymentAnnotations:
# argocd.argoproj.io/sync-wave: "40"
pullPolicy: IfNotPresent
tag: "v1.8.5"
tag: "v1.8.22"
replicas: 1 # Number of pods for the service.
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
# Optional extra volumes / volumeMounts for this deployment (empty = none).
@@ -1226,11 +1277,26 @@ kerberospipeline:
# - name: extra
# mountPath: /data
logLevel: "info" # possible values: trace, debug, info, warn, error
# Opt-in: after classification, re-enqueue the recording on the thumbnail
# queue to regenerate its thumbnail from the first frame of a tracked moving
# object (THUMBNAIL_REGENERATION_ENABLED). Adds one thumbnail job per
# classified recording; size pipe-thumbnail accordingly before enabling.
thumbnailRegeneration:
enabled: false
# In-memory cache for hot-path MongoDB lookups (site vault per device).
# Site changes apply after at most one TTL; each replica caches separately.
dbCache:
enabled: false
ttl: "5m" # Go duration, e.g. "30s", "5m"
resources:
requests:
memory: 10Mi
cpu: 10m
dominantColor:
# Opt-in: deploys pipe-dominantcolor and tells the analysis stage to schedule
# it (DOMINANTCOLOR_ENABLED). Requires an analysis image that reads the flag;
# older images always publish to the dominantcolor queue.
enabled: false # Enable or disable dominant color extraction 'true' or 'false'
repository: ghcr.io/uug-ai/hub-pipeline-dominantcolors
deploymentAnnotations: {}
# deploymentAnnotations:
@@ -1260,8 +1326,9 @@ kerberospipeline:
# deploymentAnnotations:
# argocd.argoproj.io/sync-wave: "50"
pullPolicy: IfNotPresent
tag: "v1.3.10"
tag: "v1.3.15"
replicas: 2 # Number of pods for the service.
prefetchCount: 0 # Max unacknowledged RabbitMQ messages per pod; 0 = service default (5).
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
# Optional extra volumes / volumeMounts for this deployment (empty = none).
#volumes:
@@ -1311,8 +1378,9 @@ kerberospipeline:
# argocd.argoproj.io/sync-wave: "50"
repository: ghcr.io/uug-ai/hub-pipeline-sprite
pullPolicy: IfNotPresent
tag: "v1.1.16"
tag: "v1.1.21"
replicas: 5 # Number of pods for the service.
prefetchCount: 0 # Max unacknowledged RabbitMQ messages per pod; 0 = service default (5).
topologySpreadConstraints: [] # Optional pod topology spread constraints (empty = none).
# Optional extra volumes / volumeMounts for this deployment (empty = none).
#volumes:
@@ -51,21 +51,21 @@ expected="$(printf '%s\n' \
'pipe-counting 50' 'pipe-sequence 60' 'pipe-monitor 70' | sort)"
for mode in all pipeline; do
default_render="$(helm template hub "$CHART_DIR" --set "mode=$mode" --set kerberospipeline.sprite.enabled=true)"
default_render="$(helm template hub "$CHART_DIR" --set "mode=$mode" --set kerberospipeline.sprite.enabled=true --set kerberospipeline.dominantColor.enabled=true)"
assert_waves "$default_render" ""
if printf '%s\n' "$default_render" | grep -q '^ annotations: null'; then
echo "Empty annotations must be omitted" >&2
exit 1
fi
configured_render="$(helm template hub "$CHART_DIR" "${WAVE_FLAGS[@]}" --set "mode=$mode" --set kerberospipeline.sprite.enabled=true)"
configured_render="$(helm template hub "$CHART_DIR" "${WAVE_FLAGS[@]}" --set "mode=$mode" --set kerberospipeline.sprite.enabled=true --set kerberospipeline.dominantColor.enabled=true)"
assert_waves "$configured_render" "$expected"
echo "OK ($mode): defaults opt out; per-service values assign all ten Deployment waves"
done
disabled_sprite="$(helm template hub "$CHART_DIR" "${WAVE_FLAGS[@]}" --set mode=pipeline)"
assert_waves "$disabled_sprite" "$(printf '%s\n' "$expected" | grep -v '^pipe-sprite ')"
disabled_optional="$(helm template hub "$CHART_DIR" "${WAVE_FLAGS[@]}" --set mode=pipeline)"
assert_waves "$disabled_optional" "$(printf '%s\n' "$expected" | grep -v -e '^pipe-sprite ' -e '^pipe-dominantcolor ')"
ui_render="$(helm template hub "$CHART_DIR" "${WAVE_FLAGS[@]}" --set mode=ui --set kerberospipeline.sprite.enabled=true)"
ui_render="$(helm template hub "$CHART_DIR" "${WAVE_FLAGS[@]}" --set mode=ui --set kerberospipeline.sprite.enabled=true --set kerberospipeline.dominantColor.enabled=true)"
assert_waves "$ui_render" ""
# Exercise zero/negative strings and an unrelated annotation on the same map.