Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e813f1d
fix: decode patched overrides into zeroed structs to avoid list corru…
johnduhart Jul 27, 2026
8393ba1
fix(api): add omitempty to optional nullable fields to stop webhook e…
johnduhart Jul 27, 2026
12d0379
fix(helm): sync bundled CRDs with generated manifests
johnduhart Jul 27, 2026
37bfb37
fix: use internal frontend for operator connections even with fronten…
johnduhart Jul 27, 2026
053d778
fix(status): clear ReconcileError condition on successful reconcile
johnduhart Jul 27, 2026
dd4a335
ci: verify chart bundled CRDs stay in sync with config/crd
johnduhart Jul 28, 2026
efd0f1d
feat: add support for Temporal Server v1.29, v1.30 and v1.31
Azerothian Jul 7, 2026
48e4109
fix dynamicconfig parsing of long integers
imilchev Jul 8, 2026
cf0fc7f
Preserve existing pod annotations/labels
bmorton May 7, 2026
56ee7ef
Linting fixes
bmorton May 7, 2026
34c4f60
FFix test setup since version is required
bmorton May 7, 2026
c278fab
fix(test): restore e2e cluster creation version to 1.24.3
johnduhart Jul 31, 2026
73258e0
fix(version): forbid retracted releases v1.26.0 and v1.26.1
johnduhart Jul 31, 2026
1eb6277
ci: migrate golangci-lint to v2.12.2
johnduhart Jul 31, 2026
0b441e0
fix(api): make SQLPasswordCommandSpec.Timeout a pointer
johnduhart Jul 31, 2026
574d0cd
chore(deps): bump controller-runtime to v0.23.3
johnduhart Jul 31, 2026
00303b7
fix(persistence): correct the Temporal >= 1.30 Elasticsearch schema s…
johnduhart Aug 3, 2026
db11ec0
fix(meta): remove operator-managed pod metadata when the spec stops a…
johnduhart Aug 3, 2026
84a6df6
fix(config): keep exponent-form and 64-bit dynamic config integers as…
johnduhart Aug 3, 2026
13923d7
fix(version): suggest an upgrade target that is not itself broken
johnduhart Aug 3, 2026
4f97d7e
fix(webhooks): use the corrected broken-release suggestion, warn on p…
johnduhart Aug 3, 2026
867cb7f
refactor: single source for the server config file path
johnduhart Aug 3, 2026
078c2e6
docs: correct the CHANGELOG defaults and document the CRD schema change
johnduhart Aug 3, 2026
c89423e
ci: run golangci-lint without its analysis cache
johnduhart Aug 3, 2026
1325b16
build: raise the e2e timeout and prefer podman for local container ta…
johnduhart Aug 4, 2026
2edc9d6
test(e2e): run every persistence case, and revive the Elasticsearch one
johnduhart Aug 4, 2026
2591f87
test(version): cover admin-tools tags for 1.29, 1.30 and 1.31
johnduhart Aug 4, 2026
34d814a
test(e2e): make the workflow assertion retry, and hold mysql8 at 1.28.1
johnduhart Aug 4, 2026
b222842
Merge branch 'main' into feat/johnduhart-customizations
linvald Aug 28, 2026
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
27 changes: 25 additions & 2 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ defaults:
shell: bash

env:
GOLANG_CI_VERSION: v1.64.8
GOLANG_CI_VERSION: v2.12.2

jobs:
license:
Expand All @@ -31,9 +31,21 @@ jobs:
go-version-file: 'go.mod'
cache: false
- name: lint
uses: golangci/golangci-lint-action@v6
uses: golangci/golangci-lint-action@v9
with:
version: ${{ env.GOLANG_CI_VERSION }}
# A restored analysis cache produces incorrect results. Two runs of
# this workflow over a byte-identical main.go disagreed: the first,
# which populated the cache, reported no issues; the second, which
# restored it, reported the two SA1019 //nolint directives in main.go
# as unused. Removing those directives and running cold shows SA1019
# firing at both sites, so the directives are used and the cached
# verdict was wrong. It fails in the other direction too — a warm
# cache locally reported "0 issues" on a tree that genuinely had one.
#
# Correct lint results matter more than the ~1 minute the cache saves
# (the cached run still took 130s), so every run starts cold.
skip-cache: true
build:
name: Build operator
runs-on: 'ubuntu-latest'
Expand All @@ -56,3 +68,14 @@ jobs:
check-latest: true
- name: test
run: make test
chart-crds:
name: Check chart CRDs are in sync
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version-file: 'go.mod'
check-latest: true
- name: verify
run: make verify-chart-crds
291 changes: 164 additions & 127 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -1,133 +1,170 @@
version: "2"
run:
timeout: 10m
go: "1.22"
# Language version is derived from go.mod. Do not pin it here: a stale pin
# silently holds linters to older semantics than the module actually targets.
allow-parallel-runners: true

linters:
disable-all: true
default: none
enable:
- asasalint
- asciicheck
- bidichk
- bodyclose
- containedctx
- dogsled
- dupword
- durationcheck
- errcheck
- errchkjson
- copyloopvar
- ginkgolinter
- goconst
- gocritic
- godot
- gofmt
- goimports
- goprintffuncname
- gosec
- gosimple
- govet
- importas
- ineffassign
- misspell
- nakedret
- nilerr
- noctx
- nolintlint
- nosprintfhostport
- prealloc
- predeclared
- revive
- rowserrcheck
- staticcheck
- stylecheck
- typecheck
- unconvert
- unused
- usestdlibvars
- whitespace
- unparam

linters-settings:
ginkgolinter:
# Suppress the wrong length assertion warning.
suppress-len-assertion: false
# Suppress the wrong nil assertion warning.
suppress-nil-assertion: false
# Suppress the wrong error assertion warning.
suppress-err-assertion: true
stylecheck:
checks: ["all", "-ST1000", "-ST1020"]
importas:
no-unaliased: true
alias:
# Kubernetes
- pkg: k8s.io/api/core/v1
alias: corev1
- pkg: k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1
alias: apiextensionsv1
- pkg: k8s.io/apimachinery/pkg/apis/meta/v1
alias: metav1
- pkg: k8s.io/apimachinery/pkg/api/errors
alias: apierrors
- pkg: k8s.io/apimachinery/pkg/util/errors
alias: kerrors
- pkg: k8s.io/api/apps/v1
alias: appsv1
- pkg: k8s.io/api/batch/v1
alias: batchv1
- pkg: k8s.io/api/networking/v1
alias: networkingv1
# Cert Manager
- pkg: github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1
alias: certmanagerv1
# Prometheus Operator
- pkg: github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1
alias: monitoringv1
# Istio
- pkg: istio.io/client-go/pkg/apis/networking/v1beta1
alias: istionetworkingv1beta1
- pkg: istio.io/client-go/pkg/apis/security/v1beta1
alias: istiosecurityv1beta1
- pkg: istio.io/api/security/v1beta1
alias: istioapisecurityv1beta1
- pkg: istio.io/api/type/v1beta1
alias: istioapiv1beta1
# Controller Runtime
- pkg: sigs.k8s.io/controller-runtime
alias: ctrl
nolintlint:
allow-unused: false
require-specific: true
revive:
rules:
- name: blank-imports
- name: context-as-argument
- name: context-keys-type
- name: error-return
- name: error-strings
- name: error-naming
- name: if-return
- name: increment-decrement
- name: var-naming
- name: var-declaration
- name: range
- name: receiver-naming
- name: time-naming
- name: unexported-return
- name: indent-error-flow
- name: errorf
- name: empty-block
- name: superfluous-else
- name: unreachable-code
- name: redefines-builtin-id
- name: bool-literal-in-expr
- name: constant-logical-expr
- name: exported
- name: unused-parameter
- name: package-comments
- asasalint
- asciicheck
- bidichk
- bodyclose
- containedctx
- copyloopvar
- dogsled
- dupword
- durationcheck
- errcheck
- errchkjson
- ginkgolinter
- goconst
- gocritic
- godot
- goprintffuncname
- gosec
- govet
- importas
- ineffassign
- misspell
- nakedret
- nilerr
- noctx
- nolintlint
- nosprintfhostport
- prealloc
- predeclared
- revive
- rowserrcheck
- staticcheck
- unconvert
- unparam
- unused
- usestdlibvars
- whitespace
settings:
goconst:
# Table-driven tests legitimately repeat short literals ("test", "secret",
# "password") across cases; hoisting those into constants makes the tables
# harder to read, not easier.
#
# This restores v1's signal rather than suppressing it. Evidence: the v1
# config carried no test exclusions at all (only zz_generated), and the
# lint job was green on upstream main 1398896 with v1.64.8 — while the
# files this would newly flag (internal/resource/persistence/utils_test.go,
# pkg/status/status_test.go, pkg/kubernetes/overrides_test.go, ...) all
# already existed at that commit. So v1's goconst was not reporting them,
# and without this setting the v2 migration would add ~70 findings that
# have nothing to do with any behaviour change.
ignore-tests: true
govet:
disable:
# Reports "cannot inline: type parameter inference is not yet supported"
# on generic calls such as slices.Contains. That is the analyzer
# describing its own limitation, not a defect in our code, and it only
# started firing once the module moved to go 1.26.
- inline
ginkgolinter:
suppress-len-assertion: false
suppress-nil-assertion: false
suppress-err-assertion: true
importas:
alias:
- pkg: k8s.io/api/core/v1
alias: corev1
- pkg: k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1
alias: apiextensionsv1
- pkg: k8s.io/apimachinery/pkg/apis/meta/v1
alias: metav1
- pkg: k8s.io/apimachinery/pkg/api/errors
alias: apierrors
- pkg: k8s.io/apimachinery/pkg/util/errors
alias: kerrors
- pkg: k8s.io/api/apps/v1
alias: appsv1
- pkg: k8s.io/api/batch/v1
alias: batchv1
- pkg: k8s.io/api/networking/v1
alias: networkingv1
- pkg: github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1
alias: certmanagerv1
- pkg: github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1
alias: monitoringv1
- pkg: istio.io/client-go/pkg/apis/networking/v1beta1
alias: istionetworkingv1beta1
- pkg: istio.io/client-go/pkg/apis/security/v1beta1
alias: istiosecurityv1beta1
- pkg: istio.io/api/security/v1beta1
alias: istioapisecurityv1beta1
- pkg: istio.io/api/type/v1beta1
alias: istioapiv1beta1
- pkg: sigs.k8s.io/controller-runtime
alias: ctrl
no-unaliased: true
nolintlint:
require-specific: true
allow-unused: false
revive:
rules:
- name: blank-imports
- name: context-as-argument
- name: context-keys-type
- name: error-return
- name: error-strings
- name: error-naming
- name: if-return
- name: increment-decrement
- name: var-naming
- name: var-declaration
- name: range
- name: receiver-naming
- name: time-naming
- name: unexported-return
- name: indent-error-flow
- name: errorf
- name: empty-block
- name: superfluous-else
- name: unreachable-code
- name: redefines-builtin-id
- name: bool-literal-in-expr
- name: constant-logical-expr
- name: exported
- name: unused-parameter
- name: package-comments
staticcheck:
# v1 applied this list to `stylecheck`, where "all" meant the ST* checks.
# v2 merged gosimple/stylecheck/typecheck into staticcheck, so "all" now
# also pulls in the QF* ("quickfix") suggestions, which v1 never ran.
# Excluding QF* keeps the enabled set equivalent to the pre-migration one.
checks:
- all
- -ST1000
- -ST1020
- -QF1001
- -QF1008
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- zz_generated.*\.go$
- third_party$
- builtin$
- examples$
issues:
max-same-issues: 0
max-issues-per-linter: 0
exclude-files:
- "zz_generated.*\\.go$"
max-same-issues: 0
formatters:
enable:
- gofmt
- goimports
exclusions:
generated: lax
paths:
- zz_generated.*\.go$
- third_party$
- builtin$
- examples$
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,30 @@

All notable changes to this project are documented in this file.

## Unreleased

Improvements:
- Add support for Temporal Server v1.29.x. Temporal v1.29 introduces only dynamic-config changes (task-queue fairness, task-queue config API), which are already supported through the cluster `dynamicConfig` field.
- Add support for Temporal Server v1.30.x. (The defaults and supported range moved on again with v1.31 support below; see that entry for the values this release actually ships.)
- Temporal v1.30 removed `dockerize`/`auto-setup` from the `temporalio/server` image and moved config-template rendering into the server binary (embedded sprig engine). For clusters running `>= 1.30`, the operator now emits config templates with the `# enable-template` header and sprig `{{ env "NAME" }}` placeholders (instead of the dockerize `{{ .Env.NAME }}` syntax), sets `TEMPORAL_SERVER_CONFIG_FILE_PATH`, and selects the service to start through the new `TEMPORAL_SERVICES` environment variable (the legacy `SERVICES` variable is still set for backward compatibility).
- Temporal v1.30 also removed `curl` and `jq` from the `temporalio/admin-tools` image, which broke the operator's Elasticsearch visibility setup scripts. For clusters `>= 1.30` the operator now drives ES visibility setup/upgrade through the `temporal-elasticsearch-tool` shipped in the image (`setup-schema`, `create-index`, `update-schema`), analogous to `temporal-sql-tool`. Its embedded index template applies all built-in search attributes automatically. The MTLS sidecar-shutdown step now uses `wget` instead of `curl` on `>= 1.30`. Clusters `< 1.30` keep the previous `curl`-based scripts.
- Broken releases: `v1.30.0` has no published GitHub release upstream (silently skipped) and is now rejected; use `v1.30.1+`.
- Add support for Temporal Server v1.31.x. The default Temporal version is now `1.31.1`, the default Temporal UI version is now `2.49.1`, and the supported version range is extended to `< 1.32.0`.
- New `sql.passwordCommand` field on datastores (Temporal >= 1.31): resolves the datastore password by running an external command, e.g. to generate a short-lived cloud IAM auth token (AWS RDS / GCP Cloud SQL). Mutually exclusive with `passwordSecretRef`; validated by the webhook. The password is wired both into the server config (native support) and into the persistence schema-setup jobs, where the generated `temporal-sql-tool` invocation resolves it through a shell command substitution.

**Known limitation:** the schema-setup jobs run the command inside the `admin-tools` image, and their pod spec is fully operator-owned — there is no volume or container override through which a helper binary could be supplied. The command must therefore already exist in that image. If it does not, the server pods resolve the password correctly but schema setup fails with a password-authentication error. The webhook emits an admission warning to this effect. Extending the schema jobs with pod-level overrides is tracked separately.
- Elasticsearch visibility on `>= 1.31` uses the `temporal-elasticsearch-tool` path introduced for `>= 1.30` (see the 1.30 entry); its embedded index template applies all built-in search attributes up to v14 (including `TemporalExternalPayloadSizeBytes`/`TemporalExternalPayloadCount`) automatically.

Fixes:
- Preserve externally-added pod-template labels and annotations (e.g. `kubectl.kubernetes.io/restartedAt` from `kubectl rollout restart`) across reconciles, while still removing operator-managed ones when the spec stops asking for them. Disabling a feature now actually clears its metadata: previously, clearing `spec.mTLS` left `sidecar.istio.io/inject: "true"` behind and istio kept injecting sidecars, and turning off `spec.metrics` left the `prometheus.io/*` scrape annotations in place.
- `spec.version` values that are marked broken no longer suggest another broken release as the upgrade target (`1.26.0` previously suggested `1.26.1`, which is also rejected).
- Dynamic config integers written in exponent form (e.g. `1e9`) are no longer emitted in scientific notation, which Temporal's file-based dynamic config client rejects for settings expecting an integer. Large integers no longer truncate on 32-bit builds.

Updates:
- Bump `go.temporal.io/server` to v1.31.1, `go.temporal.io/api` to v1.62.8, `go.temporal.io/sdk` to v1.41.1.
- Bump `controller-gen` to v0.21.0 (v0.16.3 cannot be built with Go 1.26). **This changes the published CRD schema for two pre-existing fields:** `cassandra.consistency` and `cassandra.serialConsistency` are now `type: string` instead of `type: integer`. The previous schema was self-contradictory — it declared `type: integer` alongside string enum values (`ANY`, `ONE`, `LOCAL_QUORUM`, ...), so no value could ever validate. `type: string` matches the JSON form these fields have always had, since `gocql.Consistency` implements `encoding.TextMarshaler`. No spec change is required of users.
- Bump `controller-runtime` to v0.23.3 (pairs with client-go v0.35) and migrate `golangci-lint` to v2.

## 0.12.2

**Release date:** 2023-04-02
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build the manager binary
FROM --platform=${BUILDPLATFORM} golang:1.24.6 AS builder
FROM --platform=${BUILDPLATFORM} golang:1.26.4 AS builder

ARG TARGETPLATFORM
ARG BUILDPLATFORM
Expand Down
Loading
Loading