Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,22 @@ Please choose versions by [Semantic Versioning](http://semver.org/).
* MINOR version when you add functionality in a backwards-compatible manner, and
* PATCH version when you make backwards-compatible bug fixes.

## Unreleased
- BREAKING(helm): replace the single `controller:` values block with a `controllers:` list so multiple per-vault controllers (e.g. openclaw + personal) install from one release; each entry renders `agent-task-controller-<name>` StatefulSet + Service + Secret. Chart 0.2.0 → 0.3.0.
- **Migration (0.2.0 → 0.3.0):** `controllers:` defaults to `[]` (empty), so an existing install that set `controller.enabled: true` renders ZERO controllers until migrated. Move the old block into a one-item list and add a `name`:
```yaml
# before (0.2.0) # after (0.3.0)
controller: controllers:
enabled: true - name: main # NEW: names the objects
vaultName: myvault enabled: true
kafkaBrokers: ... vaultName: myvault
... kafkaBrokers: ...
...
```
- **Object rename:** the StatefulSet/Service/Secret/ServiceAccount are now `agent-task-controller-<name>` (were `agent-task-controller`). External RBAC, NetworkPolicies, or tooling that referenced the old fixed name must be updated to the new per-name form. On the quant crossover use `--take-ownership`; the old kubectl-managed objects already carry per-vault names so no rename is needed there.
- helm(agents): make per-agent `volumeMountPath`/`volumeClaim`/PVC and `resources` optional (a stateless agent that declares no `volumeMountPath` gets no PVC), and add an optional `secretName` override (for agents whose existing Secret name differs from the agent name). Lets a cluster reference existing (e.g. teamvault-managed) Secrets by leaving `secretEnv` empty.
- helm(recurring-task-creator): add `recurringTaskCreator.affinity` and `recurringTaskCreator.pullSecrets` overrides (fall back to the globals) — recurring often pins a different node pool / pull secret than the executor + controllers.

## v0.74.1
- Add `helm/README.md`: third-party install guide — prerequisites, `helm install` from the OCI registry, full values reference, a "generic cluster" divergence section (no keel/mirror/TeamVault/Strimzi), and the two-chart (core + maintainer) story.

Expand Down
2 changes: 1 addition & 1 deletion helm/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: agent
description: bborbe agent framework — event-driven, Kafka-based, K8s-native task platform (controller, executor, and example agents)
type: application
# Chart version — bumped on chart changes, independent of appVersion.
version: 0.2.0
version: 0.3.0
# Default image tag for the framework components when values don't override.
appVersion: "0.3.1"
home: https://github.com/bborbe/agent
Expand Down
16 changes: 0 additions & 16 deletions helm/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,8 @@ helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" }}
{{- printf "%s/%s:%s" .Values.image.registry .Values.executor.image.repository $tag -}}
{{- end -}}

{{/* Controller image ref: registry/repository:tag, tag defaulting to appVersion. */}}
{{- define "agent.controller.image" -}}
{{- $tag := .Values.controller.image.tag | default .Chart.AppVersion -}}
{{- printf "%s/%s:%s" .Values.image.registry .Values.controller.image.repository $tag -}}
{{- end -}}

{{/* Recurring-task-creator image ref: registry/repository:tag, tag defaulting to appVersion. */}}
{{- define "agent.recurringTaskCreator.image" -}}
{{- $tag := .Values.recurringTaskCreator.image.tag | default .Chart.AppVersion -}}
{{- printf "%s/%s:%s" .Values.image.registry .Values.recurringTaskCreator.image.repository $tag -}}
{{- end -}}

{{/* Controller GIT_REST_URL: explicit value wins; otherwise derive from vaultName
as the in-cluster obsidian git-rest service URL. */}}
{{- define "agent.controller.gitRestUrl" -}}
{{- if .Values.controller.gitRestUrl -}}
{{- .Values.controller.gitRestUrl -}}
{{- else -}}
{{- printf "http://vault-obsidian-%s:9090" (required "controller.vaultName is required" .Values.controller.vaultName) -}}
{{- end -}}
{{- end -}}
15 changes: 12 additions & 3 deletions helm/templates/agents.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ spec:
priorityClassName: {{ $agent.name }}
image: {{ printf "%s/%s:%s" $.Values.image.registry $agent.image ($agent.tag | default $.Chart.AppVersion) | quote }}
heartbeat: {{ $agent.heartbeat | quote }}
secretName: {{ $agent.name }}
volumeClaim: {{ $agent.name }}
secretName: {{ $agent.secretName | default $agent.name }}
{{- if $agent.volumeMountPath }}
volumeClaim: {{ $agent.volumeClaim | default $agent.name }}
volumeMountPath: {{ $agent.volumeMountPath | quote }}
{{- end }}
{{- with $agent.env }}
env:
{{- toYaml . | nindent 4 }}
Expand Down Expand Up @@ -46,19 +48,26 @@ data:
{{ $k }}: {{ $v | b64enc }}
{{- end }}
{{- end }}
{{- if $agent.volumeMountPath }}
---
# PVC only when the agent mounts a volume (some agents — e.g. a stateless
# backtest runner — declare no volumeMountPath and get no claim).
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ $agent.name }}
name: {{ $agent.volumeClaim | default $agent.name }}
namespace: {{ include "agent.namespace" $ }}
labels:
{{- include "agent.labels" $ | nindent 4 }}
spec:
accessModes: [ReadWriteOnce]
{{- with $agent.storageClassName }}
storageClassName: {{ . }}
{{- end }}
resources:
requests:
storage: {{ $agent.storageSize | default "1Gi" }}
{{- end }}
---
# PriorityClass is cluster-scoped (no namespace). Named per-agent so the
# ResourceQuota below can cap concurrent pods of exactly this agent.
Expand Down
17 changes: 10 additions & 7 deletions helm/templates/controller-secret.yaml
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
{{- if and .Values.controller.enabled (not .Values.controller.existingSecret) (or .Values.controller.sentry.dsn .Values.controller.gatewaySecret) }}
{{- range $c := .Values.controllers }}
{{- if and $c.enabled (not $c.existingSecret) (or ($c.sentry | default dict).dsn $c.gatewaySecret) }}
---
# Created only when no existingSecret is referenced AND at least one secret value
# is set. Quant resolves the Sentry DSN + gateway secret from teamvault and passes
# them via --set-string; a generic install sets them directly or points
# controller.existingSecret at a Secret managed outside the chart.
# controllers[].existingSecret at a Secret managed outside the chart.
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: agent-task-controller
namespace: {{ include "agent.namespace" . }}
name: agent-task-controller-{{ $c.name }}
namespace: {{ include "agent.namespace" $ }}
labels:
{{- include "agent.labels" . | nindent 4 }}
{{- include "agent.labels" $ | nindent 4 }}
data:
sentry-dsn: {{ .Values.controller.sentry.dsn | b64enc | quote }}
gateway-secret: {{ .Values.controller.gatewaySecret | b64enc | quote }}
sentry-dsn: {{ ($c.sentry | default dict).dsn | b64enc | quote }}
gateway-secret: {{ $c.gatewaySecret | b64enc | quote }}
{{- end }}
{{- end }}
15 changes: 9 additions & 6 deletions helm/templates/controller-service.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
{{- if .Values.controller.enabled }}
{{- range $c := .Values.controllers }}
{{- if $c.enabled }}
---
apiVersion: v1
kind: Service
metadata:
name: agent-task-controller
namespace: {{ include "agent.namespace" . }}
name: agent-task-controller-{{ $c.name }}
namespace: {{ include "agent.namespace" $ }}
labels:
app: agent-task-controller
{{- include "agent.labels" . | nindent 4 }}
app: agent-task-controller-{{ $c.name }}
{{- include "agent.labels" $ | nindent 4 }}
annotations:
admin/port: '9090'
admin/path: ''
Expand All @@ -15,5 +17,6 @@ spec:
- name: http
port: 9090
selector:
app: agent-task-controller
app: agent-task-controller-{{ $c.name }}
{{- end }}
{{- end }}
73 changes: 40 additions & 33 deletions helm/templates/controller-statefulset.yaml
Original file line number Diff line number Diff line change
@@ -1,98 +1,104 @@
{{- if .Values.controller.enabled }}
{{- range $c := .Values.controllers }}
{{- if $c.enabled }}
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: agent-task-controller
namespace: {{ include "agent.namespace" . }}
name: agent-task-controller-{{ $c.name }}
namespace: {{ include "agent.namespace" $ }}
labels:
app: agent-task-controller
{{- include "agent.labels" . | nindent 4 }}
app: agent-task-controller-{{ $c.name }}
{{- include "agent.labels" $ | nindent 4 }}
annotations:
{{- if .Values.keel.enabled }}
{{- if $.Values.keel.enabled }}
keel.sh/policy: force
keel.sh/trigger: poll
keel.sh/match-tag: "true"
keel.sh/pollSchedule: {{ .Values.keel.pollSchedule | quote }}
keel.sh/pollSchedule: {{ $.Values.keel.pollSchedule | quote }}
{{- end }}
{{- with .Values.rolloutNonce }}
{{- with $.Values.rolloutNonce }}
random: {{ . | quote }}
{{- end }}
spec:
replicas: 1
serviceName: agent-task-controller
serviceName: agent-task-controller-{{ $c.name }}
updateStrategy:
type: RollingUpdate
selector:
matchLabels:
app: agent-task-controller
app: agent-task-controller-{{ $c.name }}
template:
metadata:
annotations:
prometheus.io/path: /metrics
prometheus.io/port: "9090"
prometheus.io/scheme: http
prometheus.io/scrape: "true"
{{- with .Values.rolloutNonce }}
{{- with $.Values.rolloutNonce }}
random: {{ . | quote }}
{{- end }}
labels:
app: agent-task-controller
app: agent-task-controller-{{ $c.name }}
spec:
{{- with .Values.controller.podSecurityContext }}
{{- with $c.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
{{- with $.Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: service
image: {{ include "agent.controller.image" . | quote }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- with .Values.controller.securityContext }}
image: {{ printf "%s/%s:%s" $.Values.image.registry (($c.image | default dict).repository | default "bborbe/agent-task-controller") (($c.image | default dict).tag | default $.Chart.AppVersion) | quote }}
imagePullPolicy: {{ $.Values.image.pullPolicy }}
{{- with $c.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
args:
- -v={{ .Values.controller.logLevel }}
- -v={{ $c.logLevel }}
env:
- name: LISTEN
value: ':9090'
- name: SENTRY_DSN
valueFrom:
secretKeyRef:
name: {{ .Values.controller.existingSecret | default "agent-task-controller" }}
name: {{ $c.existingSecret | default (printf "agent-task-controller-%s" $c.name) }}
key: sentry-dsn
- name: GATEWAY_SECRET
valueFrom:
secretKeyRef:
name: {{ .Values.controller.existingSecret | default "agent-task-controller" }}
name: {{ $c.existingSecret | default (printf "agent-task-controller-%s" $c.name) }}
key: gateway-secret
{{- with .Values.controller.sentry.proxy }}
{{- with ($c.sentry | default dict).proxy }}
- name: SENTRY_PROXY
value: {{ . | quote }}
{{- end }}
- name: BRANCH
value: {{ .Values.controller.branch | quote }}
value: {{ $c.branch | quote }}
- name: TOPIC_PREFIX
value: {{ .Values.controller.topicPrefix | quote }}
value: {{ $c.topicPrefix | quote }}
- name: KAFKA_BROKERS
value: {{ required "controller.kafkaBrokers is required" .Values.controller.kafkaBrokers | quote }}
value: {{ required "controllers[].kafkaBrokers is required" $c.kafkaBrokers | quote }}
# GIT_REST_URL: explicit controllers[].gitRestUrl wins; otherwise
# derived as http://vault-obsidian-<vaultName>:9090 — a quant service
# naming convention. On any cluster whose git-rest Service is named
# differently, set controllers[].gitRestUrl explicitly (see values.yaml).
- name: GIT_REST_URL
value: {{ include "agent.controller.gitRestUrl" . | quote }}
value: {{ $c.gitRestUrl | default (printf "http://vault-obsidian-%s:9090" (required "controllers[].vaultName is required" $c.vaultName)) | quote }}
- name: VAULT_NAME
value: {{ required "controller.vaultName is required" .Values.controller.vaultName | quote }}
value: {{ required "controllers[].vaultName is required" $c.vaultName | quote }}
- name: POLL_INTERVAL
value: {{ .Values.controller.pollInterval | default "60s" | quote }}
value: {{ $c.pollInterval | default "60s" | quote }}
- name: TASK_DIR
value: {{ .Values.controller.taskDir | quote }}
value: {{ $c.taskDir | quote }}
- name: DATA_DIR
value: '/data/bolt'
- name: NO_SYNC
value: "false"
- name: AUTO_INJECT_TASK_IDENTIFIER
value: {{ .Values.controller.autoInjectTaskIdentifier | quote }}
value: {{ $c.autoInjectTaskIdentifier | quote }}
- name: NAMESPACE
valueFrom:
fieldRef:
Expand All @@ -117,11 +123,11 @@ spec:
initialDelaySeconds: 5
timeoutSeconds: 5
resources:
{{- toYaml .Values.controller.resources | nindent 12 }}
{{- toYaml $c.resources | nindent 12 }}
volumeMounts:
- name: datadir
mountPath: /data
{{- with .Values.image.pullSecrets }}
{{- with $.Values.image.pullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
Expand All @@ -130,12 +136,13 @@ spec:
name: datadir
spec:
accessModes: [ReadWriteOnce]
{{- with .Values.controller.storage.storageClassName }}
{{- with ($c.storage | default dict).storageClassName }}
# Omitted when empty so the cluster's DEFAULT StorageClass is used;
# an explicit "" would instead disable dynamic provisioning.
storageClassName: {{ . }}
{{- end }}
resources:
requests:
storage: {{ .Values.controller.storage.size }}
storage: {{ ($c.storage | default dict).size | default "1Gi" }}
{{- end }}
{{- end }}
4 changes: 2 additions & 2 deletions helm/templates/recurring-task-creator-statefulset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ spec:
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
{{- with (.Values.recurringTaskCreator.affinity | default .Values.affinity) }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
Expand Down Expand Up @@ -175,7 +175,7 @@ spec:
volumes:
- name: tmp
emptyDir: {}
{{- with .Values.image.pullSecrets }}
{{- with (.Values.recurringTaskCreator.pullSecrets | default .Values.image.pullSecrets) }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
Expand Down
Loading