mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-10 06:24:09 +09:00
56dd6c2e413db2ede4e46f76ff384776d2002e0e
4571
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
56dd6c2e41 |
fix(fluxcd): refuse a flux-plunger drain deadline that leaves no time
A drain deadline of zero or less is already spent when the drain
starts, so flux-plunger would exit holding every uninstall fence
without listing one. The chart could produce one: its 40-second floor
was a literal, so raising the manager's stop bound or the margin before
SIGKILL, which the drain subtraction is already tied to, would leave the
floor rendering a non-positive deadline. The binary now refuses such a
flag at startup, before it reaches for a cluster, and the chart's floor
and the timings the README and the values comment state are held to
the same constants.
A whole number of a million seconds or more printed in exponent form
and was refused as a fraction; the range is now checked first, so it
gets the range message.
Assisted-by: LLM
Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io>
(cherry picked from commit
|
||
|
|
021040795b |
fix(fluxcd): keep Helm uninstall working during flux-plunger recovery
flux-plunger recovers a "has no deployed releases" HelmRelease by
briefly suspending it, deleting the stale storage Secret and
unsuspending. helm-controller v1.5.x skips the uninstall and drops its
finalizer when it handles a delete on a suspended HelmRelease, and it
wakes on the same delete event flux-plunger does, so a delete inside
that window orphaned the release's DataVolume, PVCs, RBAC and storage
Secret. Lifting the suspension on the delete event cannot win that race
reliably.
Hold the release with a flux-plunger finalizer while it is suspended.
The finalizer is applied together with the suspension in one server-side
apply. On a delete flux-plunger lifts its suspension and keeps the
finalizer, helm-controller reconciles the unsuspended generation and
runs the uninstall, and flux-plunger removes the finalizer once
helm-controller's own is gone and that generation is observed. This
holds whichever controller handles the delete first. A completed
recovery lifts the suspension and the finalizer together, and a
terminating release never begins recovery.
Decide ownership of a suspension by which field manager owns
spec.suspend in metadata.managedFields rather than by an annotation. The
apiserver transfers the field away the moment an operator, cozyhr resume
or a backup controller writes a different value to it, so a later
suspension is never misread as flux-plunger's, and one set through the
shared flux-client-side-apply manager (platform migrations, the tenant
delete hook, a manual kubectl apply) is never claimed. A release deleted
under another manager's suspension is left to that manager's decision.
Acquire applies without forcing first and, on a conflict, re-fetches and
forces only if spec.suspend is still false: a backup controller owns the
field at false through a dynamic-client Update, which a non-forced apply
can never take, while true is an active suspension to leave alone. Every
apply is preconditioned on the resourceVersion and uid of the read that
decided on it. Without the resourceVersion, the unforced apply of true
over a foreign true is accepted as shared ownership, a window the
optimistic-locked merge patch this replaces had closed, and lifting the
suspension and the finalizer from a release read as live would delete it
without an uninstall if helm-controller had meanwhile handled a delete.
Without the uid, an apply to a release that has gone would create an
empty one. The apply carries only spec.suspend and the finalizer, so it
cannot leak the required spec.interval.
Read the release, every re-check and the storage Secret list from the
apiserver rather than the informer cache. A lagging cache would let the
processed-version guard delete the revision below the one just
reclaimed, and the ClusterRole grants secrets get and list but not the
watch an informer needs.
Emit a Warning when flux-plunger holds a suspension it failed to clear,
and Normal events when it leaves an external suspension alone or defers
a recovery. An external suspension on a release flux-plunger has
recovered before is a Warning instead: it is most likely one an earlier
flux-plunger left under the shared manager, which nothing lifts unless
an operator does. A release deleted under another manager's suspension
is a Normal event when that was a migration's choice, and a Warning when
the release carries flux-plunger's processed-version annotation, since
then the skipped uninstall is an accident.
Keep a single writer with leader election. A second process able to act
under the same field manager could clear a suspension the first is still
recovering, and no rollout strategy prevents one: the next pod starts as
soon as the old one is terminating, and an eviction or a node drain
replaces a pod the same way. The old pod keeps its Lease, unreleased,
through its stop and drain, and the Lease outlasts both, so the next pod
acts only after the old one is done; the price is that a new pod waits
for the Lease to run out. The strategy sets maxSurge 0 with
maxUnavailable 1 and stays RollingUpdate because existing installs carry
the apiserver-defaulted rollingUpdate block and helm-controller applies
server-side, where type Recreate over it is rejected on upgrade.
Give the finalizer a way out when flux-plunger itself goes. Once the
manager has stopped, within a bounded time, and with it every reconcile,
flux-plunger drains its finalizers under a deadline that, with the stop,
fits inside the pod's termination grace period. A stop that overran its
bound is drained too and still reported, and only a pod that led drains.
The drain writes its events straight to the apiserver, since the
manager's recorder stops with the manager. A recovery in progress is
aborted, the suspension and the finalizer lifted together for the next
flux-plunger to start again, and a release being deleted has the
suspension lifted and keeps the finalizer until helm-controller has run
the uninstall. A release helm-controller does not handle in time keeps
it. The waiting lives in the controller, where the envtest suites hold
it against a real apiserver's generations and finalizers, rather than in
a shell script against a model of them.
A pre-delete hook on the chart is the backstop for what the drain could
not finish, so uninstalling the component never leaves a release that
tenant teardown waits on forever. It stops flux-plunger, waits out its
grace period, then lifts any remaining suspension and finalizer without
waiting again, naming each release it lets go of before helm-controller
uninstalled it. It lifts a suspension only where flux-plunger alone
holds it, with a JSON patch preconditioned on the resourceVersion and
uid it read: kubectl apply --server-side on a release last written by a
client-side apply moves that apply's fields to the applying manager and
strips every one the body leaves out. The Job's deadline sits under the
300s helm-controller gives a pre-delete hook by default. A Deployment
that cannot be stopped or a listing that never succeeds ends the hook
before any finalizer is touched, and a finalizer it cannot remove ends
it after the sweep; either way it exits non-zero: a failed pre-delete
hook leaves the release untouched and helm-controller retries the
uninstall, hook included, from a state it can still converge from, where
exiting 0 would remove the component and strand the finalizer. A
flux-plunger pod still present after its grace period, typically one
stuck Terminating on a NotReady node, is only reported, since failing on
it would fail every retry until the node returns; because it may still
be setting finalizers, they are listed again after the sweep and any
found fails the hook. The Job runs once, since helm-controller's retry
is the one that starts afresh, and is kept after success so that its
report stays readable; helm.sh/hook-output-log-policy would make
helm-controller call a nil output writer (fluxcd/helm-controller#1562).
A delete still held after ten minutes raises a Warning, and the held
state is re-checked on a timer instead of only on helm-controller's next
status write. The chart README documents the finalizer and how to clear
it.
Run the envtest suites on every pull request through a new make target
that fetches a kube-apiserver and etcd with a pinned setup-envtest and
takes the HelmRelease CRD from the in-tree Flux manifests: the unit
tests drive a fake client, and everything the finalizer rests on (apply
preconditions, the finalizer set-merge, real managedFields) only holds
against a real apiserver. CI caches those binaries, and the target uses
them without asking the release index, so a pull request does not depend
on their sources being reachable; the control plane gets a longer start
timeout because it starts beside the other test goals.
Assisted-by: LLM
Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io>
(cherry picked from commit
|
||
|
|
38d6ac7efb |
feat(redis): expose min-replicas-to-write and min-replicas-max-lag (#4848)
## What this PR does Adds two optional values to the Redis app, `minReplicasToWrite` and `minReplicasMaxLag`, rendered as `min-replicas-to-write` and `min-replicas-max-lag` in the RedisFailover `spec.redis.customConfig`. Both are unset by default, so the rendered config and behaviour are unchanged for existing instances. Replication is asynchronous, so a master that is isolated from its replicas keeps accepting writes until Sentinel fails over, and those writes are lost. With `minReplicasToWrite: 1` the isolated master stops accepting them after `minReplicasMaxLag` seconds, which bounds the loss. Trade-off: with the default `replicas: 2` there is a single replica, so the master also refuses writes whenever that replica is down (node drain, restart, upgrade). Users who turn this on accept lower write availability for a bounded loss window. Includes helm-unittest cases and the regenerated schema, README, Go types and ApplicationDefinition. ### Screenshots ### Downstream repositories - [ ] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [x] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: https://github.com/cozystack/terraform-provider-cozystack/issues/68 - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note feat(redis): add optional minReplicasToWrite and minReplicasMaxLag values to bound writes lost on failover; unset by default ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added optional Redis settings to require a minimum number of replicas to acknowledge writes and to set the maximum age of those acknowledgements. * Invalid settings are rejected: the required replica count must be nonnegative and below the configured replica count, and the acknowledgement age must be at least 1 when a replica requirement is set. Replication remains asynchronous, so these settings do not eliminate potential write loss during failover. * **Documentation** * Documented the settings, defaults, validation, and behavior in Redis configuration guidance. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
95c2d85b5b |
fix(etcd): leave compaction to etcd and pass the real quota to defrag (#4873)
## What this PR does The hourly defrag CronJob ran `etcd-defrag` with its defaults, and two of them do not fit the cluster the chart creates. - `--compaction` (default `true`) compacts to the latest revision before every defrag. The EtcdCluster already compacts itself (`autoCompactionMode: periodic`, `autoCompactionRetention: 5m`), so the extra compaction either fails with `mvcc: required revision has been compacted` when nothing was written since the last auto-compaction, which is what every defrag Job log shows on our clusters, or, on a busy cluster, drops the history the retention keeps for watchers to resume from. - `--etcd-storage-quota-bytes` defaults to 2 GiB, so `dbQuotaUsage` in the defrag rule is measured against 2 GiB rather than the `quotaBackendBytes` the chart sets (95% of `size`, about 3.8 GiB for the default `4Gi`). The CronJob now passes `--compaction=false` and the chart's own quota through the existing `calculateQuotaBackendBytes` helper. The new unit tests check both arguments and that the defrag quota equals the EtcdCluster's `quotaBackendBytes` for a non-default size. Without the template change all three fail. The same templates are on `release-1.6` and the change applies there cleanly. ### Screenshots Not a UI change. ### Downstream repositories - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: The diff is two template arguments and a unit test in `packages/extra/etcd`, with no change to values, schema, defaults or package names, so nothing in the trigger map applies. ### Release note ```release-note fix(etcd): the defrag job no longer compacts on top of etcd's periodic auto-compaction, and it evaluates its 80% quota threshold against the cluster's real quotaBackendBytes instead of 2 GiB. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Improvements** * The etcd defragmentation job now uses the cluster’s configured backend storage quota and skips compaction before defragmenting. This keeps the defragmentation operation aligned with the cluster’s storage settings. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
8be7fb2e66 |
feat(redis): expose min-replicas-to-write and min-replicas-max-lag
Lets an operator bound the writes lost when an isolated Redis master is failed over: the master refuses writes while fewer replicas than configured are connected and recent. Both values are unset by default, so the rendered Redis config is unchanged. Redis treats 0 in either directive as disabling the check, so the chart refuses minReplicasMaxLag 0 next to a replica requirement instead of silently turning the protection off. Negative values are refused by the schema (minimum 0), since Redis rejects them at CONFIG SET and the operator would stop healing the Sentinels of that instance. A requirement of replicas or more is refused at render: a master with replicas pods has replicas-1 replicas, so it would refuse every write for good. Assisted-by: LLM Signed-off-by: Yasar Rahman <yasar.rehman@gmail.com> |
||
|
|
33ca8b67bb |
feat(redis): run Sentinel on the same image as the Redis pods (#4831)
## What this PR does
The Redis application pins its Sentinels to `redis:6.2.6-alpine`
(`packages/apps/redis/templates/redisfailover.yaml`), while the data
pods run the version selected by `version` (`redis:8.4.0` for `v8`,
`redis:7.4.7` for `v7`). The pin was added in
|
||
|
|
fe59a6bf91 |
fix(etcd): leave compaction to etcd and pass the real quota to defrag
The hourly defrag CronJob runs etcd-defrag with its defaults, which compact to the latest revision before defragmenting. Every cluster already compacts itself with a periodic five-minute retention, so the second compaction either fails with "required revision has been compacted" when nothing was written since, or drops the history that retention keeps for watchers to resume from. The same defaults evaluate dbQuotaUsage in the defrag rule against 2 GiB rather than the quotaBackendBytes the cluster runs with, so the 80 percent threshold fires at a different database size than intended. Assisted-by: LLM Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com> |
||
|
|
9a348eeb50 |
fix(kubernetes): delete orphaned resources in new post-delete job (#3856)
## What this PR does When tenant deletes the kubernetes cluster, 3 resources are orphaned and leftover in the tenant namespace. - jobs/<name>-oidc-bootstrap - secrets/<name>-talos-ca - secrets/<name>-talos-tls-cert This PR adds a new "step 7" in existing `packages/apps/kubernetes/templates/delete.yaml` in order to delete these orphaned resources manually. ### Downstream repositories - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: ### Release note ```release-note fix(kubernetes): Fixed the `<name>-talos-ca` and `<name>-talos-tls-cert` Secrets and the `<name>-oidc-bootstrap` Job being left in the tenant namespace after a Kubernetes cluster is deleted. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Kubernetes release cleanup now removes the Talos CA and TLS certificates before their associated Secrets, and also removes the OIDC bootstrap Job. * The final cleanup report now includes best-effort failures from Step 7, alongside failures from Steps 3, 5, and 6. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
76a4af95c0 |
docs(monitoring): correct the release name the OIDC comment, guide and test fixture encode (#3468)
## What this PR does
The Grafana OIDC `clientId`, audience-scope name, client-secret name and
users-Job name are all derived from the Monitoring release name. In a
running cluster that release is always `monitoring-system`: the tenant
chart's outer HelmRelease `monitoring` points at `extra/monitoring`,
whose `templates/helmrelease.yaml` creates the inner HelmRelease `{{
.Release.Name }}-system` that carries `system/monitoring` and renders
OIDC. There is no release named `monitoring` that renders OIDC.
Three places encoded a release named `monitoring` (i.e.
`<ns>-monitoring`, where a cluster renders `<ns>-monitoring-system`),
per #3338:
- `packages/system/monitoring/templates/_helpers.tpl` header comment —
both example lines were wrong. The per-tenant release is
`monitoring-system`, and the platform Grafana lives in the `tenant-root`
namespace, not `cozy-monitoring`. (`cozy-monitoring` only hosts the
ExternalName services that redirect to the platform stack the root
tenant hosts in `tenant-root` — see
`packages/system/cozystack-basics/templates/monitoring-external-services.yaml`.)
- `docs/oidc-grafana.md` — placed the platform release in
`cozy-monitoring`; it lives in `tenant-root`. It also named the
per-tenant release `monitoring`; that is `monitoring-system` too, so
both instances now read `monitoring-system` and differ only by
namespace.
- `packages/system/monitoring/tests/oidc_test.yaml` — the suite pinned
`release.name: monitoring`, so its clientId / audience-scope /
client-secret / users-Job assertions pinned names no cluster renders.
Both fixtures are set to `monitoring-system` and the derived expected
values updated to what a cluster actually renders.
Nothing changes at runtime — the templates are self-consistent whatever
the release is called; this only aligns the descriptions and the test
fixture with reality.
Out of scope here (from the issue, left for a maintainer decision):
- Confirming/removing the apparently-dead `cozystack.monitoring`
PackageSource in `packages/core/platform/sources/monitoring.yaml` (issue
item 3) — removing a source is a call I can't safely make.
- Re-checking Detail B of #3259 against the corrected topology (issue
item 4).
Verification, rebased on current main: `helm unittest -f
'tests/oidc_test.yaml' packages/system/monitoring` — 39/39 pass; the
whole monitoring chart passes as well. After setting the fixtures I
updated only the assertions helm-unittest reported as newly diverging.
Disclosure: prepared with AI assistance; I reviewed the change and
verified the release-name topology against the source files cited above.
### Screenshots
N/A — no UI changes.
### Downstream repositories
Walked the trigger map in `docs/agents/contributing.md` against the
diff, file by file. The three changed paths are a `system/monitoring`
chart `_helpers.tpl` comment, the repo-internal `docs/oidc-grafana.md`,
and a chart test fixture. None match a listed trigger: no change under
`packages/apps/` or `packages/extra/`, no
`packages/core/platform/values.yaml`, and no
variant/bundle/component/release-asset/Talos/tooling change. So no
downstream repository is mechanically affected. (The website's own OIDC
page referenced in cozystack/website#597 is a separate artifact the
reporter is already engaged with, outside this repo's trigger map.)
- [x] No downstream repository is affected by this change
### Release note
```release-note
docs(monitoring): correct the release name (`monitoring-system`) and platform namespace (`tenant-root`) encoded in the Grafana OIDC helper comment, the OIDC guide, and the chart test fixture.
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Documentation**
- Clarified that both platform and tenant Grafana instances use the
`monitoring-system` release name. The platform instance runs in
`tenant-root`, while tenant instances run in their respective tenant
namespaces.
- Updated the OIDC integration guidance to reflect the platform
namespace and tenant release naming.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
||
|
|
4295930989 |
feat(dashboard): show categories brought by tapped repositories in the sidebars (#4741)
## What this PR does The marketplace and console sidebars render a fixed category list, `["IaaS", "PaaS", "NaaS"]`, and drop every other `spec.dashboard.category`. A repository tapped with `cozypkg` that brings its own category is reachable only at the bottom of the full application list, and its installed applications get no console section at all. Both sidebars now follow `groupByCategory`, the order the marketplace page already uses: IaaS, PaaS, NaaS first, then any other category alphabetically. `Administration` stays in the Admin portal, as before. Unknown categories get the generic grid icon. The note in `docs/agents/contributing.md` that described the hardcoded list is removed, since it no longer holds. Tests: two new cases in `sidebar-sections.test.tsx` (a tapped `Paleocomputing` category appears after the built-in ones in both sidebars, `Administration` stays out). Both fail on the previous code. The console suite (448 tests), `pnpm typecheck` and `eslint` on the changed files pass. ### Screenshots Same cluster and tenant, a repository tapped that brings the `Paleocomputing` category. Before, marketplace: the category is only reachable at the bottom of the full list.  After, marketplace: the category gets its own filter.  Before, console: no section for the tapped applications.  After, console: installed applications of that category get their own section.  ### Downstream repositories Walked the trigger map against the diff: it touches only the console sidebar code and a note in `docs/agents/contributing.md`. No package, values schema, CRD, installer value or `ApplicationDefinition` field changes. The website page on `ApplicationDefinition` does not restrict `spec.dashboard.category` values, and `external-apps-example` uses `PaaS`, which keeps working as before. - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note feat(dashboard): categories brought by tapped repositories now appear in the marketplace and console sidebars, after IaaS, PaaS and NaaS, instead of only in the full application list. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Marketplace and Console sidebars now show application categories beyond the built-in options, including custom categories. Categories appear in the order provided by the application grouping. * The Administration category remains excluded from both sidebars. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
b7708fb285 |
docs(monitoring): correct the release name the OIDC comment, guide and test fixture encode
The naming block in _helpers.tpl, the guide's opening paragraph and the oidc test fixture all describe the per-tenant Grafana as the release `monitoring`. Both instances are released as `monitoring-system` by the monitoring application and differ only by namespace: the platform one in `tenant-root`, a per-tenant one in each tenant namespace. Assisted-by: LLM Signed-off-by: youdie006 <youdie006@users.noreply.github.com> |
||
|
|
904bc38fc3 |
fix(kubernetes): delete the Talos PKI and oidc-bootstrap Job on uninstall
cert-manager runs with enableCertificateOwnerRef: false, so the <release>-talos-ca and <release>-talos-tls-cert Secrets carry no ownerReference to their Certificates and outlive the release, keeping the CA private key of a cluster that no longer exists. A new cluster created under the same name then adopts that stale CA instead of issuing its own trust root. The <release>-oidc-bootstrap Job is a hook whose only delete policy is before-hook-creation. Hooks are not part of the release manifest, so uninstall never removes it. The pre-delete hook deletes the two Certificates before their Secrets, because deleting a Secret while its Certificate exists makes cert-manager re-issue it. It runs after the TenantControlPlane is gone, since the control plane's CSR signer mounts the CA. The Role grants each delete by resourceName only. Assisted-by: LLM Signed-off-by: Ray Low <crossrt@gmail.com> |
||
|
|
9a88afe6ca |
feat(redis): run Sentinel on the same image as the Redis pods
The Sentinels were left on redis:6.2.6-alpine when the operator moved to the freshworks-oss fork, so that its new compiled-in default could not move them on upgrade. 6.2 is end of life, and every instance now runs a Sentinel one or two major versions behind the Redis it monitors. The rollback risk behind that pin, a newer engine rewriting dump.rdb in a format the older one cannot load, does not apply to Sentinel. It stores no RDB or AOF, only sentinel.conf on an emptyDir that the config-copy init container rewrites from the operator's ConfigMap on every start, so moving back to an older image starts from a clean config. Taking the image from the same version map as the data pods also means one image per node instead of two. The e2e comment that relied on busybox's timeout exit code in the Sentinel container is updated, since that container now carries coreutils. Signed-off-by: Yasar Rahman <yasar.rehman@gmail.com> Assisted-by: LLM |
||
|
|
df2e1c33e1 |
feat(kubernetes-nodes): build the Proxmox worker template from the pool's Talos values (#4742)
## What this PR does
A `substrate: proxmox` pool clones its workers from a VM template the
chart never sees: capmox selects it by `proxmox.templateTags`, and the
pool's `talos.*` values reach only the installer written into the worker
machineconfig. Nothing in the repository says which image that template
has to carry, and the image an operator reaches for is the wrong one:
- The release asset `nocloud-amd64.raw.xz` is built from
`packages/core/talos/images/talos/profiles/nocloud.yaml`, the bare-metal
node image. Its `zfs` extension starts `ext-zfs-service`, which waits
for `/dev/zfs`. A VM never has it, so `startAllServices` never finishes,
and Talos fails the boot sequence and reboots the guest each time the
boot timeout runs out. On our v1.13.6 stand that was every ~70 minutes,
visible in the tenant only as `SandboxChanged` on every Pod (218 cilium
restarts in 12 days); from the Proxmox side the VM never restarts. The
same profile also follows the host nodes' Talos (v1.14.2 since
|
||
|
|
1d813c9445 |
fix(backups): refuse concurrent restores and skip the CNPG purge only for this restore's Cluster (#4754)
## What this PR does Fixes #3322. An in-place Postgres (CNPG) restore decided whether to skip deleting the live `Cluster` by comparing its `creationTimestamp` with the RestoreJob's `StartedAt`. The timestamp says the Cluster is new, not which restore rendered it, so two cases let a restore skip its purge and report `Succeeded` on data from another restore: 1. Two RestoreJobs into the same application at once. The second sees the Cluster the first produced, created after its own `StartedAt`, and skips its purge. 2. The live Cluster is deleted while the restore waits for the WAL archive. The still-active HelmRelease re-renders it from the previous restore's values, again created after `StartedAt`. ### Refuse a restore into an application another restore holds The RestoreJob controller now refuses, for every driver, a RestoreJob that has not started yet when another unfinished RestoreJob in the namespace writes into the same application and goes first. The refused job fails with reason `ConcurrentRestore`, and its message names the job that goes first. It fails instead of waiting, so the application is never restored a second time later, after the first restore, by a job its author may no longer expect to run. A started restore goes before one that has not started. Between two that have not, the older goes first, by creation time and then by name; creation times have one-second precision, so two jobs created in the same second are ordered by name. A running restore is never failed by a newer one. The target application is resolved by `restoreJobTarget`, the same helper the BackupJob hold uses, so a Velero restore into another namespace does not collide with an in-place one. The gate lists RestoreJobs through the manager's API reader, not the informer cache. A job reconciled before the cache holds its peer's `StartedAt` would otherwise see that peer as not started and, on a same-second name tie, proceed alongside it. The controller runs a single worker, so a peer's `StartedAt` written by an earlier reconcile is already on the API server when the next job reads it; `SetupWithManager` now sets `MaxConcurrentReconciles: 1` explicitly, since the guarantee depends on it. ### Skip the CNPG purge only for this restore's Cluster The restore patch already sets `bootstrap.newServerName` to `restoredServerName(cluster, RestoreJob UID)`, a value unique to each RestoreJob. The postgres chart now annotates the `Cluster` with it as `postgres.cozystack.io/restored-server-name`. The annotation is rendered even when the barman plugin is not; the plugin's `serverName` also carries the value, but the plugin renders only with chart-level S3 coordinates. The driver skips the purge only when the annotation names this RestoreJob. A Cluster produced by a concurrent restore, or re-rendered from an earlier restore's values, carries another value and is purged. The mark lives on the rendered Cluster rather than in RestoreJob status. That keeps it valid in the case the skip exists for: the purge succeeded, but the `TargetPurged` status write failed. A UID recorded in status was rejected in the code for exactly that reason. A Cluster rendered by a chart that predates the annotation has none and keeps the creation-time check, so a restore in flight across an upgrade behaves as before. ### Tests - `TestRestoreAhead` covers order, a started job going first, the name tie-break, finished and terminating jobs, other applications, retargeted restores and a Velero restore into another namespace. - `TestReconcileRestore_ConcurrentRestoreIsRefused` checks that the newer job fails with `ConcurrentRestore` and the running one is left alone. - `TestReconcileRestore_ConcurrentRestoreReadsPastTheCache` gives the cache a stale, not-started peer and the API reader the started one, and requires the job to fail with `ConcurrentRestore`. - `TestCNPGClusterFreshlyRecovered` adds both cases from the issue: a Cluster marked by another restore and created after `StartedAt` must be purged. The timestamp-only cases are kept for the unmarked fallback. - `TestReconcileCNPGRestore_RepeatInPlacePurgesStaleRecoveryCluster` gains two reconcile-level cases. One purges a Cluster that another restore marked, even though it was created after `StartedAt`. The other runs a full purge, takes the mark from the `bootstrap.newServerName` the restore patch wrote, drops `TargetPurged` as a lost status write would, and requires a Cluster carrying that mark to survive, although it predates `StartedAt`. That pins the purge decision to the value the chart actually renders. - `packages/apps/postgres/tests/restore_mark_test.yaml` checks that the annotation is rendered with and without the barman plugin, and is absent on a Cluster that was never restored. Each new test was checked against the code it guards: disabling the gate call, listing through the cache, flipping the started-job precedence, ignoring the annotation, or deriving the expected mark from the app name instead of the cluster name each turns one red. `go test ./internal/backupcontroller/...` and `helm unittest packages/apps/postgres` (152 tests) pass. The restore flow was not run against a live cluster. `docs/operations/backup-classes.md` documents the one-restore-at-a-time rule and the annotation. ### Screenshots N/A — no UI changes. ### Downstream repositories Walked the trigger map in `docs/agents/contributing.md` against the diff: Go changes in `internal/backupcontroller` (no CRD or API type change), one annotation added to the postgres chart's Cluster (no `values.yaml` or `values.schema.json` change), and a docs paragraph. No package is added or renamed, no platform values, ApplicationDefinition, RestoreJob CRD, metric, label or namespace changes, so no trigger is reached. - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note fix(backups): a RestoreJob now fails with reason ConcurrentRestore when another unfinished RestoreJob is already restoring the same application, instead of running alongside it; create it again once the first restore has finished. An in-place Postgres restore now skips deleting the live Cluster only when that Cluster was rendered for this RestoreJob, identified by the new postgres.cozystack.io/restored-server-name annotation, so it no longer reports Succeeded on data from a concurrent or earlier restore. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Restores targeting the same application are now handled one at a time. A competing restore is refused rather than queued, with started restores taking priority. * PostgreSQL now calculates a default `shared_buffers` value when the memory limit is below 512 MiB, while respecting explicitly configured values. * **Bug Fixes** * Recovery clusters are more reliably distinguished from manual recoveries and clusters created by other restores, reducing the risk of purging the wrong cluster. * **Documentation** * Clarified restore ordering and how recovery-cluster cleanup is determined. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
05cfb63044 |
feat(keycloak): expose zone placement for Keycloak and the database proxy (#4606)
## What this PR does Neither the Keycloak StatefulSet nor the `keycloak-kms-proxy` Deployment exposes any placement, so the scheduler is free to put both replicas of each in one failure domain. For Keycloak this is worse than it looks: a StatefulSet does not replace a pod stuck on an unreachable node, so losing that domain takes every Keycloak replica with it for as long as the domain stays lost. This exposes placement for both, with empty defaults so nothing changes unless an installation opts in: - `affinity` and `topologySpreadConstraints` for the Keycloak StatefulSet; - `encryption.affinity` and `encryption.topologySpreadConstraints` for the proxy; - a `PodDisruptionBudget` (`maxUnavailable: 1`) for the proxy when `encryption.replicas > 1`, so a drain cannot take both replicas at once. The `values.yaml` example spreads one replica per zone with `whenUnsatisfiable: DoNotSchedule` and `nodeTaintsPolicy: Honor`. The taint policy matters for a zone loss: kube-scheduler already ignores terminating pods when it counts the spread (`countPodsMatchSelector` in `pkg/scheduler/framework/plugins/podtopologyspread/common.go`, "Bypass terminating Pod"), but with the default `nodeTaintsPolicy: Ignore` the lost zone's nodes still count as a domain holding zero pods, so a replacement pod could not be placed on the surviving zone without violating `maxSkew`. With `Honor`, nodes carrying the `node.kubernetes.io/unreachable` NoSchedule taint drop out of the count and the replacement schedules. `ScheduleAnyway` was tried first in a live deployment and did not spread the proxy replicas on rollout. Found during a site-isolation drill in which both Keycloak pods and both proxy replicas had drifted into one zone. Tests: new `tests/placement_test.yaml` (defaults render no placement; set values render as given; PDB only for more than one proxy replica); `helm unittest` passes 87/87; the default render is unchanged apart from a randomly generated secret. ### Screenshots Not applicable, no UI changes. ### Downstream repositories Walked the trigger map in `docs/agents/contributing.md` against the diff: it touches only `packages/system/keycloak` (templates, values, tests) — no app under `packages/apps` or `packages/extra`, no platform values, CRD, `hack/` tooling, commit convention or PR template. - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note feat(keycloak): expose affinity and topologySpreadConstraints for Keycloak and the keycloak-kms-proxy, and add a PodDisruptionBudget for the proxy when it runs more than one replica. Defaults are unchanged. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added optional node affinity and topology spread settings for Keycloak, its KMS proxy, and the database to control pod placement. * Database-specific topology spread settings take precedence over cluster-wide settings; constraints without a selector are scoped to the database cluster. * Added a disruption budget for the KMS proxy when running multiple replicas, allowing up to one pod to be unavailable. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
f093273736 |
feat(redis): size the Sentinel pods separately from Redis (#4832)
## What this PR does
The Redis application renders `spec.sentinel.resources` from the same
`resources`/`resourcesPreset` pair as the Redis pods. Every instance
runs three Sentinels, so it reserves three extra copies of a Redis
replica's memory for processes that hold only their configuration and
the failover state. The dataset that drives the Redis sizing never
reaches a Sentinel.
On our Cozystack v1.6.4 staging cluster, an HA Redis on `t1.nano`
reserves 3 x 128Mi for its Sentinels. The VPA recommender
(recommendation mode only) gives an uncapped target of 16Mi for the
`sentinel` container. On a `u1.small` instance the same three Sentinels
would reserve 3 x 4Gi.
This PR adds an optional `sentinel` block with the same two keys the top
level has:
```yaml
resourcesPreset: u1.small
sentinel:
resources:
cpu: 100m
memory: 64Mi
# resourcesPreset: t1.nano
```
Resolution rules:
- `sentinel` empty (the default): the Sentinels keep the Redis sizing
(`resources` + `resourcesPreset`). Existing instances therefore render
exactly as before and an upgrade does not roll their Sentinels.
- `sentinel.resourcesPreset` set: the Sentinels use that preset.
Explicit top-level `resources` are not carried over, since they were
sized for the dataset.
- `sentinel.resources` set: it wins. Any key it leaves out is filled
from `sentinel.resourcesPreset`, which falls back to `resourcesPreset`.
- The Sentinel `WorkloadMonitor` label
`workloads.cozystack.io/resource-preset` now carries the preset the
Sentinels actually use. The Redis `WorkloadMonitor` is unchanged.
Changes:
- `values.yaml`: new `Sentinel parameters` section (`@typedef Sentinel`,
`@param {Sentinel} [sentinel]`, default `{}`), reusing the existing
`Resources` and `ResourcesPreset` types so the enum and quantity
validation is the same as the top-level pair.
- `templates/redisfailover.yaml`: computes the Sentinel preset and
resources once and uses them for `spec.sentinel.resources` and the
Sentinel `WorkloadMonitor` label.
- `README.md`: generated table rows plus a short hand-written `sentinel`
section next to `resources and resourcesPreset`.
- Generated: `values.schema.json`, `api/apps/v1alpha1/redis/types.go`
(new `Sentinel` struct, `ConfigSpec.Sentinel`),
`api/apps/v1alpha1/redis/zz_generated.deepcopy.go`,
`packages/system/redis-rd/cozyrds/redis.yaml`.
- `tests/sentinel_resources_test.yaml`: 10 helm-unittest cases covering
the rules above and an unknown preset being refused.
I chose not to change the default sizing. A smaller default (for example
a fixed small preset for Sentinel) would save more for everyone, but it
would also roll every instance's Sentinels and change what tenants are
billed for on upgrade. If maintainers prefer that, it is a one-line
follow-up on top of this change.
Testing done:
- `make generate` in `packages/apps/redis` with cozyvalues-gen v1.7.0
(the version `pre-commit.yml` installs); regenerated files committed.
- Deepcopy: `controller-gen object` v0.16.4 on `api/apps/v1alpha1` (the
last step of `hack/update-codegen.sh`), only the redis package changed;
`go build ./...` and `go vet ./redis/` pass in that module, `go mod
tidy` leaves no diff. I could not run the full root `make generate` on
my machine: code-generator v0.37.1 fails to parse the Go 1.27.1 standard
library (`math/rand/v2: method must have no type parameters`), which is
a host toolchain problem unrelated to this change. CI's `codegen-drift`
job should confirm.
- `make test` in `packages/apps/redis` (helm-unittest v1.1.2): 58
passed. With the template change reverted, 4 of the new cases fail (the
ones that set `sentinel.*`); the cases that pin today's behaviour pass
both ways.
- Rendered output with no `sentinel` block is identical to `main` (all
documents except the random-password Secret) for the defaults,
`resourcesPreset=u1.small`, and explicit `resources` (cpu 1, memory
2Gi).
Backwards compatibility: purely additive. The field is optional with an
empty default, existing instances render unchanged, and nothing rolls on
upgrade. Clients that do not know the field are unaffected.
### Screenshots
Not a UI change. The dashboard form gets a `sentinel` object from the
schema like other nested parameters (e.g. `tls`).
### Downstream repositories
- [ ] No downstream repository is affected by this change
- [ ] [cozystack/website](https://github.com/cozystack/website) -
follow-up:
- [ ]
[cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack)
- follow-up:
- [ ]
[cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack)
- follow-up:
- [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up:
- [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up:
- [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) -
follow-up:
- [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) -
follow-up:
- [ ]
[cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server)
- follow-up:
- [ ]
[cozystack/external-apps-example](https://github.com/cozystack/external-apps-example)
- follow-up:
- [ ] [cozystack/examples](https://github.com/cozystack/examples) -
follow-up:
- [ ] [cozystack/community](https://github.com/cozystack/community) -
follow-up:
Trigger map walked against the diff: this adds a field to
`values.schema.json`, so `cozystack/terraform-provider-cozystack` needs
to model `sentinel.resources` / `sentinel.resourcesPreset` in its Redis
resource. I will open that issue once this PR has a number and link it
here; a draft is in `FOLLOWUP-terraform-provider-redis-sentinel.md`. The
website page for `redis` is regenerated from `README.md` by the release
bot (`redis` is in the website `APPS` list), so no manual follow-up
there. Nothing else in the map is touched.
### Release note
```release-note
feat(redis): new optional `sentinel.resources` and `sentinel.resourcesPreset` parameters size the three Sentinel pods independently of the Redis pods. When unset, Sentinels keep the Redis sizing as before, so existing instances are unchanged.
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added independent CPU and memory resource settings and sizing presets
for Redis Sentinel pods.
* When Sentinel-specific settings aren’t provided, Sentinel pods inherit
Redis resource settings. Unspecified Sentinel resource values can use
the Sentinel preset, which defaults to the Redis preset.
* Added configuration documentation and validation for Sentinel resource
settings.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
||
|
|
bbd39c94a4 |
feat(kubernetes-nodes): build the Proxmox worker template from the pool's Talos values
A proxmox pool clones its workers from a VM template the chart never sees, and nothing said which Talos image that template has to carry. The one an operator reaches for, the platform release's nocloud-amd64.raw.xz, is the bare-metal node image: its zfs extension's service waits for a /dev/zfs no VM has, the boot sequence never completes, and Talos reboots every worker each time the boot timeout runs out, about every 70 minutes on v1.13. It also follows the host nodes' Talos version, not the pool's talos.version that the installer in the worker machineconfig names. The chart's default schematic has a trap of its own: its qemu-guest-agent service waits the same way for the agent's virtio port, which Proxmox adds only to a VM with the agent enabled. hack/proxmox-talos-template.sh builds the template from the chart's talos.schematicID and talos.version in the nocloud flavour with the agent enabled, refuses a tag set another template already carries, because capmox then finds two and clones neither, and prints the templateTags that select it. Assisted-by: LLM Signed-off-by: Marian Koreniuk <moriarti@cp.if.ua> |
||
|
|
08ee470f6a |
fix(postgres)!: refuse plaintext sessions on external instances (#4847)
## What this PR does CloudNativePG offers TLS on an external Postgres but does not require it. Its built-in last `pg_hba` rule is `host all all all`, which matches TLS and non-TLS connections alike, so a client outside the cluster that connects with `sslmode=disable` gets an unencrypted session. The chart's `tls.enabled` only decides whether the external hostname goes into the certificate, so it cannot prevent this. This is #4619. When `external: true`, the chart now renders `spec.postgresql.pg_hba`: ```yaml pg_hba: - hostssl all all all scram-sha-256 # md5 on PostgreSQL 13, matching CloudNativePG's default rule - host all all all reject ``` CloudNativePG puts user rules after its fixed rules (`local` peer, `streaming_replica` and pooler `cert`) and before its default `host all all all` rule, and PostgreSQL uses the first matching rule, so the two lines above make remote sessions TLS-only without touching replication or the metrics exporter. See the CloudNativePG [`pg_hba` section](https://cloudnative-pg.io/documentation/current/postgresql_conf/#the-pg_hba-section) and the [template](https://github.com/cloudnative-pg/cloudnative-pg/blob/v1.30.0/pkg/postgres/configuration.go) for v1.30.0, the operator version the platform ships. A new tri-state `tls.required` follows the same pattern as `tls.enabled`: when omitted it follows `external`, `false` opts out, `true` requires TLS on an in-cluster instance too. The issue is silent on a switch; I added one because the change is breaking and a tenant with a client that cannot do TLS needs a way back that does not mean patching the operator's resources. In-cluster clients: the pod network cannot be told apart from an external client (the external Service uses `externalTrafficPolicy: Local`, so the source IP is the client's), so the rules apply to every remote client. The chart's init job connects to `<release>-rw` with libpq's default `sslmode=prefer`, which already negotiates TLS, as do the backup and monitoring paths that run inside the pod over the Unix socket. Only clients that disable TLS explicitly are refused. In-cluster instances with `external: false` are unchanged. Changes: - `templates/_tls.tpl`: `postgres.tls.required` helper. - `templates/db.yaml`: renders `spec.postgresql.pg_hba` when required. - `values.yaml`: `tls.required`, with the generated `values.schema.json`, `README.md`, `api/apps/v1alpha1/postgresql/types.go` and `packages/system/postgres-rd/cozyrds/postgres.yaml`. The `Required` deepcopy block in `zz_generated.deepcopy.go` is controller-gen v0.16.4 output. - `README.md`: new "Refusing plaintext sessions" paragraph. - `tests/pg_hba_test.yaml`: 10 helm-unittest cases. Backwards compatibility: breaking for existing external instances whose clients connect without TLS. The rules apply on the next reconcile. They are refused until the client enables TLS or the instance sets `tls.required: false`. Testing done: - `make generate` in `packages/apps/postgres` with cozyvalues-gen v1.7.0; regenerated files committed. - `helm unittest .` in `packages/apps/postgres`: 206 passed (25 suites), 10 of them new. I did not run it against a live cluster, so the `pg_hba` ordering is taken from the operator source and docs rather than observed. ### Screenshots Not a UI change. The dashboard form gets a `tls.required` toggle from the schema. ### Downstream repositories I walked the trigger map against the diff and left every box empty so a human decides. The nearest hit is the website's managed-apps reference page for postgres, which a stable-tag bot regenerates from `README.md`; the Terraform provider's postgres schema may also want the new `tls.required` field. - [ ] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note fix(postgres)!: an external Postgres now refuses sessions that are not encrypted. The chart renders `hostssl` rules for all users and databases with scram-sha-256 (md5 on PostgreSQL 13, matching CloudNativePG's default rule) and rejects plain `host` connections, so a client using `sslmode=disable` is refused. The new `tls.required` value follows `external` by default; set it to `false` to keep accepting plaintext sessions. ``` Fixes #4619 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a `tls.required` setting for PostgreSQL instances. By default, TLS is required for external instances and optional for others. You can override this behavior to require encrypted connections for both external and in-cluster clients, or allow plaintext connections for external instances. Rendering fails if TLS is required while PostgreSQL SSL is disabled. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
f0e3e17493 |
feat(kubernetes-nodes): let CDI trust a self-hosted Talos image factory (#3797)
## What this PR does Adds `talos.imageFactoryCA` to the `kubernetes-nodes` chart, so CDI can verify a Talos Image Factory served with a certificate from an internal CA. Fixes #3796. ### The gap `talos.imageFactoryURL` is documented for self-hosted factories and mirrors in air-gapped, rate-limited or flaky-egress environments. Such an endpoint is normally served by the organisation's own CA, and CDI, which trusts only its system store, refuses the import with `x509: certificate signed by unknown authority`. The DataVolume never completes and no worker joins. `DataVolume.spec.source.http.certConfigMap` exists for exactly this, but the worker DataVolume in `templates/nodegroup.yaml` renders `url` alone and no value reaches that field. ### The change One optional value on the existing `talos` group of a `KubernetesNodes` pool: ```yaml talos: imageFactoryURL: "https://factory.example.com" imageFactoryCA: | -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- ``` When set on an HTTP import path (the default and `osImage.factory`), the chart renders a ConfigMap `<release>-talos-factory-ca` in the release namespace and points the DataVolume's `source.http.certConfigMap` at it. A pool on `osImage.builtin` clones a golden image, builds no HTTP source and gets no ConfigMap. Empty, the default, renders nothing: `helm template` with the field unset is byte-identical to `main`, so existing pools keep their KubevirtMachineTemplate name. Setting the CA changes that name, so the pool rolls once. CDI appends the bundle to the system pool rather than replacing it (`x509.SystemCertPool()` followed by `AppendCertsFromPEM` in `pkg/importer/http-datasource.go`), so a publicly trusted endpoint keeps verifying. The PEM is taken inline rather than as a ConfigMap name because `certConfigMap` must live in the DataVolume's namespace, and the dashboard offers no way to create that object by hand. ### Fail-closed guards The value lands verbatim in a ConfigMap that anything able to read the namespace can read, so it must be complete PEM certificate blocks and nothing else, and must never carry private key material. That includes the realistic accident of `cat ca.pem key.pem` pasted into the field. The rules now live in one shared helper, `cozy-lib.tls.validateCACert`, which `cozy-lib.tls.caCertSecret` also calls instead of keeping its own copy. The regexes are unchanged; the failure message names the caller's field. ### Testing - `packages/apps/kubernetes-nodes/tests/talos_image_factory_ca_test.yaml`, 13 cases: unset renders nothing, set renders the ConfigMap and a matching `certConfigMap`, whitespace-only counts as unset, multi-certificate chains, the builtin path, and each guard on the input that trips it. - `packages/tests/cozy-lib-tests/tests/tls_validatecacert_test.yaml`, 6 cases for the shared helper, plus the existing `caCertSecret` tests updated for the new message. - `make generate` in the package: regenerated `values.schema.json`, `README.md`, `api/apps/v1alpha1/kubernetesnodes/types.go` and the `kubernetes-nodes-rd` definition are committed. Not yet exercised end to end against a live internal factory. ### Not in this PR `packages/apps/vm-disk/templates/dv.yaml` renders `source.http.url` with the same gap. Left for a follow-up if this shape is accepted. ### Screenshots Not a UI change. ### Downstream repositories - [ ] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [x] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: cozystack/terraform-provider-cozystack#31 (the field belongs to the `kubernetes_nodes` model) - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: Walked the trigger map against the diff: - **terraform-provider-cozystack**: ticked. The diff adds a field to `packages/apps/kubernetes-nodes/values.schema.json`, which the trigger map names directly. Filed as an issue there. - **website**: not ticked. No package is added, renamed or removed, and the reference page is regenerated from the package `README.md`, which is regenerated and committed here. - Every other repository: no path in the trigger map is touched. ### Release note ```release-note feat(kubernetes-nodes): add `talos.imageFactoryCA` so CDI can verify a self-hosted Talos Image Factory served with a certificate from an internal CA. Previously the worker image import failed with `x509: certificate signed by unknown authority`. Set the CA in PEM form and the chart wires it into the worker DataVolume; leave it empty and nothing changes. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added an optional setting for providing PEM certificate authorities trusted when importing worker OS images over HTTPS. This supports the default image source and factory images, allowing imports from endpoints that use certificates not already trusted by the system. * Certificate authorities are provided as PEM certificate blocks; when configured, they are used for HTTPS image imports. The setting defaults to empty and has no effect on pools using built-in OS images. * **Bug Fixes** * Invalid certificate input, including private keys, is rejected. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
dde75d6cf5 |
feat(keycloak): expose zone placement for the keycloak-db instances
The Keycloak StatefulSet and the database proxy can already be spread across failure domains, but the CloudNativePG Cluster behind them could only follow the cluster-wide topology constraint, with no way to pick zones for this database alone. With both instances in one zone, losing that zone loses the database and every login with it. Add database.affinity (CloudNativePG shape) and database.topologySpreadConstraints, with empty defaults so nothing changes unless an installation opts in. The cnpg.io/cluster label selector is added to constraints that carry none, and the constraints replace the cluster-wide ones for this database when set. Assisted-by: LLM Signed-off-by: Andrei Kvapil <kvapss@gmail.com> |
||
|
|
faf8a250ba |
fix: typo in monitoring-agents values.yaml (#4799)
<!-- Thank you for making a contribution! Here are some tips for you: - Use Conventional Commits for the PR title: `type(scope): description` - Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore - Scopes are not an exhaustive list — pick the most specific scope for the change and extend the list when a genuinely new area appears. Examples: - System components: dashboard, platform, operator, cilium, kube-ovn, linstor, fluxcd, cluster-api - Managed apps: postgres, mariadb, redis, kafka, clickhouse, virtual-machine, kubernetes - Development and maintenance: api, hack, tests, ci, docs, maintenance - Breaking changes: append `!` after type/scope (`feat(api)!: ...`) or add a `BREAKING CHANGE:` footer - If it's a work in progress, consider creating this PR as a draft. - Don't hesistate to ask for opinion and review in the community chats, even if it's still a draft. - Add the label `kind/backport` if it's a bugfix that needs to be backported to a previous version. --> ## What this PR does Fixes a typo in monitoring-agents values.yaml. ### Screenshots <!-- REQUIRED for UI changes: attach screenshots or screen recordings demonstrating the visual impact of your changes. PRs with UI changes without screenshots will not be merged. --> ### Downstream repositories <!-- Cozystack is upstream for repositories that are NOT kept in sync with it automatically, and nothing in CI compares the two sides, so a change here can break them silently. Which change forces what, and which file to touch, is the trigger map in docs/agents/contributing.md under "Downstream Repositories". Walk it before you tick anything. IF YOU ARE AN AI AGENT OR AN LLM, THIS IS PART OF THE TASK, NOT A FORM TO FILL IN: 1. Walk the trigger map against the actual diff of this PR, file by file. Do not decide from the PR title or from your memory of what you changed. 2. For every repository you tick, open the follow-up PR there and link it on the same line. A ticked box with no link claims work that does not exist, which is worse than an empty box. Search that repository for an open PR or issue covering it first, and link that instead of filing a duplicate. 3. When the follow-up is out of scope, or needs a decision that is not yours to make, open an issue in that repository instead, link that, and say so in the PR body. Do not push a speculative PR into another repository just to fill a line here. 4. Do not tick "No downstream repository is affected" to make the checklist go away. If you are unsure, leave every box empty and say so in the PR body, so a human decides. --> - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note <!-- Write a release note: - Explain what has changed internally and for users. - Start with the same `type(scope):` prefix as in the PR title - Follow the guidelines at https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md. --> ```release-note ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Corrected the namespace metadata field used for event streams. Event metadata is now labeled consistently, helping downstream tools identify the namespace associated with each event. This fixes an incorrect field name in the event output configuration without changing other event stream behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
e4e991e837 |
fix(backups): skip the CNPG restore purge only for this restore's Cluster
The in-place CNPG restore skips deleting the live Cluster when it carries bootstrap.recovery and was created after the RestoreJob started, taking that as "this restore's own purge and re-render produced it". The timestamp does not say which restore rendered the Cluster. A Cluster deleted while the restore waits for the WAL archive is re-rendered by the still-active HelmRelease from the previous restore's values and is created after StartedAt too; the restore then skipped its purge and reported Succeeded on the previous restore's data. The restore patch already sets bootstrap.newServerName to restoredServerName(cluster, RestoreJob UID). The chart now annotates the Cluster with it as postgres.cozystack.io/restored-server-name, whether or not it renders the barman plugin that also carries the value, and the purge is skipped only when the annotation names this RestoreJob. The mark lives on the rendered Cluster rather than in RestoreJob status, so it still covers the failed status write the skip exists for. A Cluster rendered by a chart that predates the annotation keeps the creation-time check. Fixes #3322 Assisted-by: LLM Signed-off-by: Andrey Kolkov <androndo@gmail.com> |
||
|
|
bcde187858 |
fix(dashboard): small Console fixes from the #3828 triage (#3837)
## What this PR does Six small Console fixes from the #3828 triage. Each one is small and most of the code sits in `apps/console/src`, so they go together in one PR. `Fixes #3105`: sizes between 1Ki and 1Mi printed as a raw byte count. `humanizeBytes` had branches for Ti, Gi and Mi and then fell through to bytes. It now has a Ki branch with the same `toFixed(0)` as the Mi branch. The `1023B` case still holds, and the test covers 1Ki and 512Ki. `Fixes #3106`: the tenant picker showed on admin pages where the tenant changes nothing. It is now hidden on the cluster-scoped admin pages only: Capacity, Backup classes, External IPs and Modules. The rest of `/admin` mounts the same tenant-scoped pages as `/console`, and those take their namespace from the tenant context, so the picker stays there. `/admin/tenants` keeps it too, because its rows come from the picker-filtered tenant list. `Fixes #3107`: both capacity drill-downs showed one generic error, so a permission failure looked like a broken page. Both now use the `error instanceof K8sApiError && error.status === 403` check that `ClusterStorageSection` already uses, with a test for the forbidden case and one for a generic error on each page. `Fixes #3102`: an immutable leaf was not restored when the YAML edit dropped its parent object. `overlayPath` stopped as soon as the submitted body had nothing at a path segment. It now creates `{}` for the missing parent, but only when the target there is undefined or null and the original really has the leaf to restore. So a scalar or an explicit null the user put there survives. A wildcard with more path under it does not rebuild a deleted parent, since that would put back entries the user removed. The test uses foundationdb's `storage.storageClass`, which is a shipped path of this shape. `Fixes #3135`: a blocked submit did not scroll to the field that blocked it. Plain `focusOnFirstError` crashes here, because RJSF's built-in handler reads `form.elements` and this form is `tagName="div"`. So the form passes a small handler that finds the field by its generated id and scrolls it into view. The ids come from one shared definition, and the widgets that had none now carry it: the `DynamicOptionsWidget` select, which every `x-cozystack-options` field uses, and the `SourceField` controls. The nested form that `AdditionalPropertiesField` mounts per map entry continues the outer id namespace instead of restarting at `root`, so fields like `nodeGroups.*.instanceType` resolve. A map key with a dot in it, such as a mariadb user `john.doe`, resolves by trying both readings of the dotted error path. `Fixes #3108`: `cilium`, `coredns` and `verticalPodAutoscaler` have only `valuesOverride` and no `enabled`, so they rendered as plain groups next to the toggleable addons and looked like a switch that failed to appear. Setting `<addon>.enabled: true` in the YAML editor is accepted, because the schema sets no `additionalProperties`, and the API stores the field and echoes it back. Nothing reads it. The three addons are not the same case. `cilium` and `coredns` are always installed. `verticalPodAutoscaler` has no switch of its own and is installed and removed together with `addons.monitoringAgents.enabled`. The three are now marked in `values.yaml` with a new `x-cozystack-no-enable-switch` schema keyword, and the form renders them with a note that there is no enable switch and an `enabled` field in YAML does nothing. The per-addon reason goes into the schema description, which the form renders and which regenerates into the README, the Go types and the ApplicationDefinition. The generated files are regenerated with cozyvalues-gen v1.7.0, the version CI pins, and the pre-commit check passes. The console typecheck and tests pass in CI. ### Screenshots ##### Ki formatting <img width="1182" height="184" alt="image" src="https://github.com/user-attachments/assets/62662265-4f77-455d-b90e-85e417684bb9" /> ##### Admin without tenant picker <img width="1440" height="245" alt="image" src="https://github.com/user-attachments/assets/99aff4f3-fda9-4c4c-8cf8-0c1eb01fb973" /> ##### Capacity 403 error <img width="1232" height="270" alt="image" src="https://github.com/user-attachments/assets/f4e4b328-ee5e-4516-b78f-9b5084b6bbc8" /> <img width="1232" height="944" alt="image" src="https://github.com/user-attachments/assets/142e438e-f538-436e-aae8-dfb79ec747e8" /> ##### Validation focus <img width="1166" height="135" alt="image" src="https://github.com/user-attachments/assets/89abb73b-a624-406f-9736-3bf38bb8a923" /> ##### Addon lifecycle <img width="1166" height="591" alt="image" src="https://github.com/user-attachments/assets/14a95891-84d1-4073-a009-bc0eab94f114" /> ### Downstream repositories I walked the trigger map in `docs/agents/contributing.md` against the diff, file by file. This PR changes field descriptions, adds the `x-cozystack-no-enable-switch` schema keyword on three addon objects, and changes the console. No field is added, removed or renamed, and no default, version enum, `kind`, `plural`, `release.prefix`, output Secret or Service changes, so none of the terraform provider triggers fire. No package is added or removed, and nothing changes in `packages/core/platform/values.yaml`, the variants, `hack/` or the node prerequisites. cozyvalues-gen itself is unchanged, since the keyword goes through its generic `@x-*` passthrough. The kubernetes reference page on the website regenerates from `README.md` on a stable tag, which is automated rather than a follow-up. - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note fix(dashboard): Ki-range sizes now render as Ki instead of raw bytes, the tenant picker is hidden on cluster-scoped admin pages, capacity drill-downs distinguish a permission error from a broken page, an immutable field whose parent object is absent is now applied, a blocked submit scrolls to the field that blocked it including fields inside maps and the source and dropdown widgets, and the cluster addons with no enable switch now say so instead of showing a toggle that never appears ``` |
||
|
|
1b0a5a2829 |
fix(velero): bump velero-plugin-for-aws to v1.14.4 so backups work on R2 (#4834)
## What this PR does Bumps the `velero-plugin-for-aws` init container in `packages/system/velero/values.yaml` from `v1.14.1` to `v1.14.4`, and updates the pin in `tests/velero_test.yaml`. `v1.14.1` sets `x-amz-tagging` on every `PutObject`, even when the BackupStorageLocation configures no tags, in which case the header is empty. Cloudflare R2 rejects that with `501 NotImplemented: Header 'x-amz-tagging' with value '' not implemented`. Velero then cannot upload backup metadata, so every Velero backup to an R2-backed location fails. That includes Cozystack's own `cozy-default` BackupStorageLocation when the platform backup bucket is on R2. Upstream fixed this in v1.14.3: velero-plugin-for-aws#309 (a backport of #299, "Only set PutObject Tagging when tags are configured"). `v1.14.4` is the current patch release of the 1.14 line. Its only change on top of v1.14.3 is CVE dependency bumps (#336). v1.14.3 itself also carries #310 (SSE-C presigned URLs), #313 (no amz-checksum encapsulation when `checksumAlgorithm=""`) and CVE/Go bumps. The plugin's compatibility table lists `v1.14.x` for Velero `v1.18.x`, which is what the chart ships (`velero:v1.18.1`), so this stays inside the supported pairing. Testing done: - `make test` in `packages/system/velero` (helm-unittest v1.1.2): 7 passed, with the existing init-container pin assertion moved to `v1.14.4`. - `helm template` renders `velero/velero-plugin-for-aws:v1.14.4` as `initContainers[0]` of the `velero` Deployment. - On a Cozystack v1.6.4 staging cluster with the backup bucket on Cloudflare R2: before the bump, Velero backups failed on the empty `x-amz-tagging` header. After pinning the same plugin image through a Package values override (`docker.io/velero/velero-plugin-for-aws:v1.14.4@sha256:c85a7fa803569e3128c33e4f5766f84ab156c8d171c9f1dd2715581d45ce98fa`), all of our volume backup and restore drills pass. That covers CSI snapshots with the Kopia data mover to R2, and incremental backups confirmed. Backwards compatibility: same plugin minor line and the same Velero version. The init container image changes, so the `velero` Deployment rolls once on upgrade. Users who never set `tagging` on a location now get no tagging header at all; users who do set it get the same header as before. The reference stays in the existing shape (tag only, no digest), like the current `v1.14.1` line. If you'd rather pin third-party init containers by digest, the v1.14.4 multi-arch index digest is `sha256:c85a7fa803569e3128c33e4f5766f84ab156c8d171c9f1dd2715581d45ce98fa`. ### Screenshots Not a UI change. ### Downstream repositories - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: Trigger map walked against the diff: a third-party image tag in a system package values file and its test; no app schema, platform values, names or tooling. Fixes #4852 ### Release note ```release-note fix(velero): velero-plugin-for-aws is bumped from v1.14.1 to v1.14.4, which no longer sends an empty x-amz-tagging header, so Velero backups work against S3-compatible stores that reject it, such as Cloudflare R2. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Updates** * Updated the AWS backup plugin used by Velero to version 1.14.4. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
cd1345e661 |
fix(redis): re-send the Sentinel auth-pass when the operator resets a Sentinel (#4833)
Fixes #4851 ## What this PR does Adds a downstream patch to the redis-operator image (`packages/system/redis-operator/images/redis-operator/patches/unauthenticated-sentinel.diff`) so that a Sentinel which lost its `auth-pass` is repaired by the operator instead of being reset forever. ### The failure After a node power cycle on a Cozystack v1.6.4 cluster (3 nodes, Talos, HA Redis with `authEnabled: true`), the Sentinel pod on that node came back monitoring the correct master address, but with no `auth-pass`. The master answered it with `NOAUTH`, it reported the master as `s_down,disconnected`, and `SENTINEL CKQUORUM mymaster` on it returned `NOQUORUM 1 usable Sentinels`. The operator logged `mismatch number of sentinels in memory. resetting` on every resync and sent `SENTINEL RESET *`. That does not touch `auth-pass`, so the Sentinel never recovered on its own: the instance keeps running with two working Sentinels out of three until someone deletes that pod. One more failure then leaves Sentinel without a majority. The mechanism, which I reproduced locally with Redis 8.6.2 (script and output in #4851): 1. The pod restarts in place (same pod, same IP), so the `sentinel-config-copy` init container writes the operator's initial `sentinel.conf` again: `sentinel monitor mymaster 127.0.0.1 6379 2` and no `auth-pass`. 2. The other Sentinels still know that address and keep sending their hello messages to it directly. A failover has raised the config epoch, so the restarted Sentinel adopts the current master address from a peer (`+config-update-from sentinel ... +switch-master mymaster 127.0.0.1 ... <current master>`) before the operator looks at it. 3. `CheckAndHeal` then finds the right address in `CheckSentinelMonitor` and skips `NewSentinelMonitor`, the only call that sends `SENTINEL SET <master> auth-pass`. 4. `INFO sentinel` reports `status=sdown`, so `CheckSentinelNumberInMemory` fails and `RestoreSentinel` sends `SENTINEL RESET *`. The reset keeps the empty `auth-pass`, and the cycle repeats. The same code is on `main`: freshworks-oss v3.3.5 sets `auth-pass` only in `MonitorRedisWithPort`, and none of the three patches Cozystack carries touch this path. ### The change `RestoreSentinel` sends `SENTINEL SET <master> auth-pass <password>` right after `SENTINEL RESET *` when the RedisFailover has auth enabled. It uses the same password `NewSentinelMonitor` uses (`k8s.GetRedisPassword`), the same TLS config, and the same master name (`rf.MasterName()`, so `disableMyMaster` is respected). - It only runs on the unhealthy path. `RestoreSentinel` is called only when a Sentinel's view is already wrong: its sentinel or replica count does not match, or its status is not `ok`. A healthy Sentinel is never touched. - It does not disturb a working Sentinel. `SENTINEL SET auth-pass` drops the Sentinel's links to the monitored instances, but the `RESET` just before it has already done that. - Without auth, `GetRedisPassword` returns an empty string and nothing is sent, so the behaviour is exactly as before. - Bootstrap mode goes through the same function and gets the same password `NewSentinelMonitorWithPort` already sends there. Patch contents: a `SetSentinelAuthPass` method on `service/redis.Client`, its mockery-style mock, the two-step `RestoreSentinel`, and `TestRestoreSentinel` (5 cases: auth off, auth on, reset error, unreadable Secret, `SET` error). The file name sorts after `tls.diff` on purpose: the patch is written on top of it (same functions, new `tlsConfig` parameters), and the Dockerfile applies `patches/*.diff` in glob order. If you prefer numbered patch names, I can rename it. Like `tls.diff`, this belongs upstream too: the same fix is open as freshworks-oss/redis-operator#90. This carried patch can be dropped once a release containing it is vendored here. ### Why not a quorum-checking liveness or readiness probe The RedisFailover CRD does allow `spec.sentinel.customLivenessProbe` / `customReadinessProbe`, so a `SENTINEL CKQUORUM` probe could be set from the chart. I looked at that first and decided against it: - A liveness restart does not repair this. It restarts the container, not the pod. `sentinel.conf` lives on an `emptyDir` that survives a container restart, and only the init container rewrites it, on pod start. The restarted Sentinel reads the same file without `auth-pass` and fails again, so the probe would restart it in a loop. - `CKQUORUM` does not reliably detect it. In the local reproduction the broken Sentinel still answered `OK 3 usable Sentinels`, because its peers reach it directly. On the cluster it answered `NOQUORUM`. What does show the problem every time is `status=sdown` in `INFO sentinel`, which the operator already reads. - It hurts in real outages. With two of three nodes down, a quorum-based liveness probe would restart the last Sentinel, and a quorum-based readiness probe would empty the `rfs-` Service, at the moment clients most need it. The operator already detects this state and already runs a repair for it. The repair just did not include the password. ### Testing done - Applied the four patches to a fresh v3.3.5 tarball in Dockerfile order (`git apply patches/*.diff`). Then ran the Dockerfile's test step: `go test .` and `go vet -tags integration .` in every directory the patches touch, all 11 pass. Also ran `GOOS=linux GOARCH=amd64 go build ./cmd/redisoperator`. I could not run `make image` because Docker was not available on my machine. - `TestRestoreSentinel` fails on 3 of its 5 cases without the `heal.go` change and passes with it. The existing `operator/redisfailover/...` and `service/redis` tests pass unchanged. - End-to-end against real Sentinels (Redis 8.6.2, local): master + replica with `requirepass`, three Sentinels configured the way the operator configures them, a `SENTINEL FAILOVER`, then one Sentinel restarted on the same port with the operator's initial config. Result: that Sentinel switched to the new master from a peer's hello and sat in `status=sdown`, `flags s_down,master,disconnected`. `SENTINEL RESET *` alone left it in `sdown`. The patched `service/redis` client (`ResetSentinel` then `SetSentinelAuthPass`) brought it to `status=ok,...,slaves=1,sentinels=3`. - The mock was written in the format mockery v2.45.0 generates; v2.45.0 itself does not build with Go 1.26+ (`golang.org/x/tools` v0.17.0), so I could not regenerate it mechanically. Backwards compatibility: no API or chart change. The operator image has to be rebuilt to pick up the patch, like the existing patches (the image digest in `packages/system/redis-operator/values.yaml` is stamped by the build). Instances without auth are unaffected. ### Screenshots Not a UI change. ### Downstream repositories - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: Trigger map walked against the diff: one new file under `packages/system/redis-operator/images/redis-operator/patches/`; no values, schema, CRD, name or tooling change. ### Release note ```release-note fix(redis): the redis-operator now re-sends the Redis password to a Sentinel it resets, so a Sentinel that restarted in place (for example after a node reboot) and lost its auth-pass recovers on the next check instead of staying down until its pod is deleted. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Sentinel recovery now restores the Redis authentication password after a successful reset when a password is configured. * Recovery stops if the reset fails and reports errors encountered while retrieving or applying the password. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
525814d399 |
fix: typo in monitoring-agents values.yaml
Signed-off-by: gireassen <80508012+gireassen@users.noreply.github.com> |
||
|
|
68cd1028bd |
feat(kubernetes-nodes): let CDI trust a self-hosted Talos image factory
talos.imageFactoryURL is documented for self-hosted factories and mirrors in air-gapped, rate-limited or flaky-egress environments. Such an endpoint is normally served with a certificate from an internal CA, and CDI — which trusts only its system store — refuses the import with "x509: certificate signed by unknown authority". The DataVolume never completes, no worker joins, and the release sits in install until it times out. DataVolume.spec.source.http.certConfigMap exists for exactly this, but the chart rendered source.http.url alone and no value reached the field. Add an optional talos.imageFactoryCA taking the CA in PEM form. When set, the chart renders it into a ConfigMap in the release namespace — CDI requires certConfigMap to sit alongside the DataVolume — and references it from the worker DataVolume on the HTTP import path; a pool cloning a golden image via osImage.builtin builds no source.http and renders neither. When empty, nothing is rendered and the output is byte-for-byte what it was. CDI appends the bundle to the system pool rather than replacing it, so a release pulling from a publicly-trusted endpoint keeps verifying either way. The value is emitted verbatim into a ConfigMap readable by anything that can read the namespace, so the render fails closed on private key material and on anything that is not complete PEM certificate blocks. Those guards live in a new validate-only cozy-lib.tls.validateCACert helper that takes the caller's field name for its messages, and cozy-lib.tls.caCertSecret is refactored onto it, so the check exists in exactly one place. Assisted-by: LLM Signed-off-by: Fedor Batonogov <fedor@batonogov.ru> |
||
|
|
8580a9d46d |
feat(redis): size the Sentinel pods separately from Redis
Every Sentinel pod gets the Redis pods' resources, so the three Sentinels of an instance reserve three times a Redis replica's memory while holding only their configuration and the failover state. On a t1.nano instance that is 3 x 128Mi while the VPA recommender's uncapped target for a Sentinel container is 16Mi, and the waste grows with every larger preset, because the dataset that drives the Redis sizing never reaches a Sentinel. sentinel.resources and sentinel.resourcesPreset follow the convention of the top-level pair, and sentinel.resourcesPreset falls back to resourcesPreset. Explicit Redis resources are not carried over once the sentinel block sets either key, since they were sized for the dataset. An empty sentinel.resources map counts as unset, as an empty top-level resources does. An empty sentinel block keeps today's sizing, so existing instances render unchanged and an upgrade does not roll their Sentinels. The Sentinel WorkloadMonitor reports the preset the Sentinels actually use. Signed-off-by: Yasar Rahman <yasar.rehman@gmail.com> Assisted-by: LLM |
||
|
|
f6f879cf38 |
fix(postgres)!: refuse plaintext sessions on external instances
CloudNativePG offers TLS but its built-in last pg_hba rule, host all all all, also accepts plaintext, so a client outside the cluster that connects with sslmode=disable gets an unencrypted session. tls.enabled only decides whether the external hostname goes into the certificate and cannot prevent this. When external is true the chart now renders spec.postgresql.pg_hba with hostssl all all all scram-sha-256 followed by host all all all reject. CloudNativePG places user rules after its fixed rules and before its default rule, and the first match wins, so only TLS sessions are accepted. The pod network cannot be told apart from an external client, so in-cluster clients are held to the same rule; libpq's default sslmode=prefer already negotiates TLS. The new tri-state tls.required follows external when omitted. Setting it to false keeps accepting plaintext on an external instance and true requires TLS on an in-cluster one. The hostssl rule uses the same password method as CloudNativePG's own default rule (md5 before PostgreSQL 14, scram-sha-256 from 14), so existing md5 verifiers keep working on PostgreSQL 13. Rendering fails when postgresql.parameters.ssl is off while TLS is required, since hostssl would never match and every remote session would be refused. BREAKING CHANGE: external clients that connect without TLS are refused after the upgrade. Set tls.required to false to keep accepting them. Assisted-by: LLM Signed-off-by: Yasar Rahman <yasar.rehman@gmail.com> |
||
|
|
f4bde9e50d |
fix(backups): delete the original PVC of an in-place VM restore without keepOriginalPVC (#4672)
<!-- Thank you for making a contribution! Here are some tips for you:
- Use Conventional Commits for the PR title: `type(scope): description`
- Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore
- Scopes are not an exhaustive list — pick the most specific scope for
the change and extend the list when a genuinely new area appears.
Examples:
- System components: dashboard, platform, operator, cilium, kube-ovn,
linstor, fluxcd, cluster-api
- Managed apps: postgres, mariadb, redis, kafka, clickhouse,
virtual-machine, kubernetes
- Development and maintenance: api, hack, tests, ci, docs, maintenance
- Breaking changes: append `!` after type/scope (`feat(api)!: ...`) or
add a `BREAKING CHANGE:` footer
- If it's a work in progress, consider creating this PR as a draft.
- Don't hesistate to ask for opinion and review in the community chats,
even if it's still a draft.
- Add the label `kind/backport` if it's a bugfix that needs to be
backported to a previous version.
-->
## What this PR does
An in-place VMInstance restore with `keepOriginalPVC: false` reports
`Succeeded` without restoring the disks, and leaves every disk it
touched unable to come back. `prepareForRestore` deletes each DataVolume
with Orphan propagation and leaves the PVC in place, on the assumption,
stated in the `deleteDataVolume` comment, that Velero overwrites it.
Velero does not overwrite a PVC. Its CSI restore action returns early
for a claim that already exists, so no DataDownload is ever created, and
with `existingResourcePolicy: update` the merge patch it attempts
instead is rejected because a bound claim's spec is immutable. All that
reaches the claim is the labels-only fallback patch, which also drops
the `cdi.kubevirt.io/allowClaimAdoption` annotation the resource
modifier added.
The claim left behind then blocks the disk for good. Orphan propagation
has removed its owner reference to the DataVolume, and it lacks the
`cdi.kubevirt.io/storage.populatedFor` annotation that
kubevirt-velero-plugin writes on the backed-up copy, so when the
HelmRelease resumes, the CDI webhook refuses the DataVolume it creates
with `Destination PVC <ns>/<name> already exists`, on every reconcile.
Deleting the disk through the API leaves the PVC behind, and a new disk
of the same name fails the same way.
Observed on a v1.6.3 cluster, for a VMInstance restore with
`keepOriginalPVC: false` whose disk was attached to the VM. The Velero
log for the restore, trimmed:
```text
level=info msg="Retrieved per-restore resource modifiers from configmap cozy-velero/restore-modifiers-..."
level=warning msg="PVC already exists and ExistingVolumeDataPolicy is not in-place restore. Skip restore this PVC." Action=PVCCSIRestoreItemAction PVC=tenant-datalab/vm-disk-e2edisk
level=info msg="Applying resource modifier patch on tenant-datalab/vm-disk-e2edisk"
level=warning msg="patch attempt failed for /v1, Kind=PersistentVolumeClaim tenant-datalab/vm-disk-e2edisk: PersistentVolumeClaim \"vm-disk-e2edisk\" is invalid: spec: Forbidden: spec is immutable after creation except resources.requests and volumeAttributesClassName for bound claims"
level=info msg="backup/restore labels successfully updated for PersistentVolumeClaim tenant-datalab/vm-disk-e2edisk"
```
`velero restore describe --details` lists the PVC as `(failed)` and the
Restore is `Completed` with two warnings. Afterwards the claim had its
original creation timestamp and UID, no owner reference, no
`allowClaimAdoption`, no `populatedFor`, and the disk's HelmRelease was
`Ready=False` with the webhook error above. That cluster runs a Velero
build from `main`, whose wording is quoted above; the released v1.17.1
and v1.18.3 return early at the same point with `PVC already exists.
Skip restore this PVC.` (`pkg/restore/actions/csi/pvc_action.go`).
The fix deletes the PVC when `keepOriginalPVC` is false, only once its
DataVolume is confirmed gone so that CDI cannot recreate it, and holds
the Velero Restore until the claim has actually disappeared. A claim
still mounted stays `Terminating` behind `kubernetes.io/pvc-protection`,
and creating the Restore then would hit the same existing-claim path.
Velero then creates the PVC from the backup, the data mover fills it,
and the recreated DataVolume adopts it through `populatedFor`. A failed
deletion now fails the RestoreJob instead of letting it report
`Succeeded` over the old data. Before
|
||
|
|
a2e10312de |
fix(platform): stop treating a failed ConfigMap read as a fresh cluster (#4792)
## What this PR does A single failed API read at the start of the platform migration Job could skip every pending migration and still end green. `run-migrations.sh` checked whether the `cozystack-version` ConfigMap exists with a silenced `kubectl get` and looked only at the exit code. A timeout, a dropped connection or an apiserver restart during the upgrade all counted as "no ConfigMap", so the script stamped the target version and exited 0. The hook Job is rendered only when that ConfigMap already exists, so in practice an error was the only way into this branch. Now the script creates the ConfigMap only when it is really missing. The check uses `--ignore-not-found --output name`: kubectl drops NotFound and nothing else, so empty output means a genuine NotFound. Any other error keeps a non-zero exit, `set -e` aborts the script, and the Job retries the pod. The rest of the script already works this way: the read of the stamped version aborts on error, and the stamp runs under `pipefail`. The tests cover both branches. A new case in `hack/run-migrations.bats` makes the existence check fail with a connection error and expects a non-zero exit, no migration run and the stamp left where it was. It fails against the old check. The fake kubectl returns empty output for a missing ConfigMap only when `--ignore-not-found` is passed, as real kubectl does, so dropping the flag breaks the existing "no ConfigMap" case. No migration is added, so `targetVersion` stays. The script ships in the migrations image, and the release build restamps that image's digest as usual. Several older migrations have the same problem in a smaller form. They check for an object with `kubectl get ... >/dev/null 2>&1` and skip their own work when the check fails, for example migrations 31, 32, 36, 48, 50 and 51. A transient error there skips one migration's work, not all of them. Editing migrations that already shipped has its own risk, so I'd track that separately. Closes #4579 ### Screenshots Not a UI change. ### Downstream repositories - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note fix(platform): a transient API error while the platform migration Job checks for the cozystack-version ConfigMap now fails the pod so the Job retries, instead of stamping the target version and silently skipping every pending migration. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Migration checks now distinguish a missing version record from an error while checking for it. When the check fails, the pod stops instead of treating the record as missing and proceeding with migrations. * Added coverage for TLS-handshake timeouts during the check, confirming that migrations do not run and the stamped version remains unchanged. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
be2387323b |
feat(gateway)!: reserve a passthrough listener's name by the spec alone (#4638)
## What this PR does This keeps the TLS-passthrough services on port 443 of the tenant Gateway and makes the passthrough rules hold on Cilium 1.20.2. It is stacked on #3343 and has to land with it (stack #4717). On 1.20, upstream Cilium marks an HTTPS-terminate listener and a TLS-passthrough listener on one port `Conflicted` when their hostnames overlap, and drops both from Envoy. That took `*.<apex>` and the `api`, `vm-exportproxy` and `cdi-uploadproxy` passthrough listeners down together on every tenant Gateway in `dns01` and `existingSecret` mode (#3912). #3343 now ships a patched operator that conflicts the pair only when the hostnames are equal, so the layout stays as it is on main: one Gateway, one address, everything on 443. What remains is the equal-hostname case and the cleanup that 1.20 allows. Under `http01`, a name a passthrough listener answers is now reserved by the spec alone. Before, the controller dropped the terminate listener for such a name only once a TLSRoute was attached to the passthrough listener and its backend Service resolved, which copied how Cilium builds filter chains. Without a working TLSRoute, an HTTPRoute on `api.<apex>` kept its terminate listener next to `tls-api`, and on 1.20 that equal-hostname pair takes both listeners down. Now such an HTTPRoute gets no listener and no certificate, TLSRoute or not. If all its hostnames are reserved it reads `Accepted=False` with `NoMatchingListenerHostname`. If it also claims a free hostname it stays `Accepted` and is served there. The backend lookup, its Service and ReferenceGrant watches and their RBAC rules are gone. Other changes: - `tlsPassthroughListeners` is accepted under `dns01` and `existingSecret`. The old refusal relied on 1.19.5 serving all ports from one Envoy listener; 1.20 splits ports whose SNI overlaps. - A TenantGateway reads `Ready=False` with reason `GatewayClassUnsupported` when its GatewayClass lists features in `status.supportedFeatures` but not `TLSRoute`, while it renders passthrough listeners. A class that lists nothing is not judged. Cilium 1.20.2 lists `TLSRoute`. - Comments, the README and one error message no longer describe Cilium 1.19.5 as the shipped release. - The gateway chart writes `tlsPassthroughServices` on the publishing tenant only, behind the same `gateway.enabled` switch and `publishing.exposedServices` filter as the platform TLSRoutes. Before, every tenant Gateway got the three passthrough listeners with nothing routed to them, and the reservation above would have taken those names from a child tenant's own HTTPRoutes. The uniform `allowedRoutes.kinds` on port 443 from #3087 stays. The Cilium bug behind it is fixed since 1.19.6, but several tests pin it, so removing it is a separate cleanup. ### Upgrade notes Only the publishing tenant keeps the `api`, `vm-exportproxy` and `cdi-uploadproxy` passthrough listeners. That is `tenant-root` unless `publishing.ingressName` says otherwise, and only for names in `publishing.exposedServices` while `gateway.enabled` is on. Other tenants lose these listeners on upgrade. Nothing shipped was attached to them, so a child tenant's own HTTPRoute on `api.<child-apex>` keeps its listener and certificate. Two narrow cases do change. On the publishing tenant under `http01`, an HTTPRoute on an exposed passthrough name loses its listener and certificate when the platform TLSRoute for that name forwards nowhere (the owning package is not installed, or its backends do not resolve). A TLSRoute attached by hand to a child tenant's `tls-*` listener loses its parent. To keep that listener, merge-patch `tlsPassthroughServices` into the tenant's `TenantGateway` after the upgrade. From then on the chart does not render the key there, and later upgrades leave the patch alone. `dns01` and `existingSecret` do not change: the wildcard listener still covers such a name, and the passthrough listener answers it by its exact name. Tested locally: Go tests for the controller, `go vet`, helm-unittest for `extra/gateway` and `cozystack-controller`, `make generate` and `make manifests` with no diff. The gateway e2e scenario checks that a child tenant renders no passthrough listener. It then declares `tls-api` and a passthrough listener on a native port on that tenant, checks that the tenant stays Ready with no route behind either, and checks the reservation against `tls-api`. Unit tests catch a regression in either change. In e2e, dropping the reservation turns the gateway suite red, and dropping the chart scoping does not, because CI never sets `gateway.enabled` (#4846). The controller was not run on a live cluster; the operator patch it depends on was, see #3343. ### Downstream repositories - [ ] No downstream repository is affected by this change - [x] [cozystack/website](https://github.com/cozystack/website) - follow-up: https://github.com/cozystack/website/issues/725 - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note feat(gateway)!: the tenant Gateway renders the api, vm-exportproxy and cdi-uploadproxy passthrough listeners only on the publishing tenant, for the names publishing.exposedServices lists while gateway.enabled is on. Under certMode http01 a name a TLS-passthrough listener answers no longer gets an HTTPS listener on 443, with or without a TLSRoute behind it. On the publishing tenant, an HTTPRoute on such a name whose TLSRoute forwards nowhere loses its listener and certificate. A TLSRoute attached by hand to a tls-* listener of another tenant loses its parent. An HTTPRoute with some reserved and some free hostnames used to be rejected whole; it is now Accepted and its free hostnames get a listener and a certificate. tlsPassthroughListeners is accepted under dns01 and existingSecret. A TenantGateway whose GatewayClass does not list TLSRoute in its supported features reads Ready=False while it renders passthrough listeners. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * TLS passthrough listeners are supported with HTTP-01, DNS-01, and existing-secret certificate modes. Edge-terminated Gateways remain unsupported. * Declaring a passthrough hostname reserves it from HTTPS termination and certificate creation, even when no route is attached. * Passthrough listeners are rendered only for exposed services on the enabled publishing Gateway. * **Bug Fixes** * Gateways that declare passthrough listeners but explicitly lack TLSRoute support are now reported as not ready. * Routes targeting a hostname served by a passthrough listener on a different Gateway are correctly withdrawn. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
d9689bd6e7 |
fix(gateway): stop describing Cilium 1.19.5 as the shipped release
With Cilium at 1.20.2 the tenant gateway comments, README and one status message still explained behaviour as that of "the pin" at 1.19.5. Several of those claims no longer hold: a Gateway with two routed passthrough ports now gets an Envoy listener per port, Cilium judges a route's kinds against the listener the route names, and the shipped operator accepts an HTTPS and a passthrough listener on one port when the passthrough hostname is strictly narrower. Behaviour that is unchanged is re-anchored on the 1.20.2 source, behaviour that is gone is stated as history, and the refusal of one hostname on two passthrough ports no longer blames a Cilium limitation the shipped release does not have. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
ad3f15d4f3 |
feat(gateway)!: reserve a passthrough listener's name by the spec alone
The TenantGateway controller withheld the HTTPS-terminate listener for a name a passthrough listener answers only once a TLSRoute was attached there and resolved a backend, mirroring how Cilium builds its filter chains. That kept a served endpoint up on Cilium 1.19.5, but it tied every route's status to one implementation's translator and needed Service and ReferenceGrant watches to land the deferred decision. The shipped operator accepts a wildcard terminate listener beside a narrower passthrough listener on 443 and keeps conflicting every other overlap. A terminate listener for the passthrough name itself is not narrower, so on 443 the rule now protects the dataplane outright; on a native port Gateway API would serve the pair, and the rule holds as a policy that keeps a platform name with its passthrough listener. Reading it off the spec makes the outcome the same on every implementation. Under http01 an HTTPRoute claiming such a name gets no listener and no certificate whether or not a TLSRoute is attached. A route whose every hostname is reserved reads Accepted=False with NoMatchingListenerHostname; one that also claims a free hostname stays Accepted and is served there, as Gateway API accepts a route whose hostnames intersect at least one listener. dns01 and existingSecret are unchanged: their wildcard listener still covers such a name, and the passthrough listener answers it by its exact server name. The chart writes the passthrough services on the publishing tenant alone, so the names reserved by default are the ones the platform publishes there through its own TLSRoutes. The shape an upgrade changes is an HTTPRoute on such a name whose platform TLSRoute forwards nowhere, because it never attached (the package owning the service is not installed) or because none of its backends resolve: that route kept a terminate listener and now gets none. The backend resolution, its watches and the RBAC rules that served them go away. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
d76bd1f263 |
fix(mariadb): mount the chart's my.cnf under a .cnf name
mariadb-operator up to v0.0.27 mounted the referenced ConfigMap key as
/etc/mysql/conf.d/my.cnf whatever the key was called. Since v0.0.28 the
file takes the key's own name, so the chart's key "config" became
/etc/mysql/conf.d/config, and the server's !includedir reads only *.cnf
files from that directory. Every setting in the chart's my.cnf has been
ignored since that operator bump: instances run on stock defaults,
including a 128M InnoDB buffer pool inside the 128Mi default limit.
Renaming the key restores the file as intended. Existing instances roll
their pods once, since the projected volume in the pod template changes,
and come back with the chart's settings in effect, including sql-mode
and innodb_flush_log_at_trx_commit, not only the resource sizing.
Fixes:
|
||
|
|
83aaa65ed1 |
fix(velero): bump velero-plugin-for-aws to v1.14.4 so backups work on R2
velero-plugin-for-aws v1.14.1 sets x-amz-tagging on every PutObject,
empty when the BackupStorageLocation configures no tags. Cloudflare R2
answers that with 501 NotImplemented ("Header 'x-amz-tagging' with value
'' not implemented"), so Velero cannot write backup metadata and every
backup to an R2 location fails, the cozy-default location included when
the platform bucket is on R2.
The plugin sends the header only when tags are configured since v1.14.3
(velero-plugin-for-aws#309, a backport of #299). v1.14.4 is the current
patch release of the 1.14 line, which upstream lists as the one
compatible with Velero 1.18, and adds only CVE dependency bumps on top
of v1.14.3.
Signed-off-by: Yasar Rahman <yasar.rehman@gmail.com>
Assisted-by: LLM
|
||
|
|
8bfd4e5f5e |
fix(redis): re-send the Sentinel auth-pass when the operator resets a Sentinel
A Sentinel that restarts on the same pod IP, as after a node reboot, comes back with the operator's initial sentinel.conf, which monitors a 127.0.0.1 placeholder and carries no auth-pass. Its peers still know that address and keep publishing hello messages to it, and once a failover has raised the config epoch the restarted Sentinel adopts the current master address from them before the operator looks at it. The operator then finds the right master address and skips NewSentinelMonitor, the only call that sends SENTINEL SET auth-pass. The master answers that Sentinel with NOAUTH, it reports the master as s_down, and the operator's resulting SENTINEL RESET on every check keeps the empty auth-pass, so the instance runs with one Sentinel fewer until someone deletes the pod. RestoreSentinel now sends the RedisFailover's password with SENTINEL SET auth-pass after the reset. It runs only when the Sentinel already looks unhealthy, and the reset has just dropped its links, so a Sentinel that had the password loses nothing. Without auth there is nothing to send. The patch file sorts after tls.diff because it is written on top of it; the Dockerfile applies patches/*.diff in glob order. Signed-off-by: Yasar Rahman <yasar.rehman@gmail.com> Assisted-by: LLM |
||
|
|
f61e13fdef |
fix(cilium): size the agent memory limit for its BPF maps (#4803)
## What this PR does This raises the cilium-agent memory limit from 4Gi to 24Gi. The 4Gi limit from #3495 has no room for the agent's BPF maps. On nodes with roughly a terabyte of RAM or more, the agent is OOM-killed on every start after a reboot, and the node loses pod networking. The maps grow with node RAM. Cilium sizes its CT, NAT, neighbor and socket rev-NAT maps as a share of total RAM (`bpf-map-dynamic-size-ratio`, 0.0025 by default), and caps each map at 16Mi entries. These are LRU hash maps, so the kernel preallocates them in full. Since Linux 5.11 that memory is charged to the memcg of the process that creates the maps, which is the agent container. This is also why the upgrade itself works. A map reused from bpffs stays charged to the cgroup that created it. The failure shows up on the first reboot after the upgrade, when the maps are recreated inside the limited cgroup. Policy maps don't belong on that list. The issue and the upstream chart's configmap comment both say the ratio sizes them, but at this version they are LPM tries sized by `bpf.policyMapMax`, and they allocate per entry. One DaemonSet serves every node, so the limit can't follow node RAM. The map sizes are capped, though, so a fixed limit can cover any node. With every map at 16Mi entries for both IPv4 and IPv6, the maps take just under 20Gi of kernel memory. Add the 4Gi the agent already had and you get 24Gi. The request stays at 256Mi. The limit doesn't reserve memory, and the pod cgroup still gets `memory.max`, which is what #3495 was after. What it costs is the leak backstop. The agent is now stopped at 24Gi minus its own map memory, so on most nodes a leak in its heap is no longer caught before the node feels it. If someone prefers a tighter backstop over IPv6 headroom, they can lower `cilium.resources.limits.memory` in the networking component values. About 13Gi still covers the IPv4-only map ceiling. I didn't pin the map sizes (`bpf.ctTcpMax`, `bpf.natMax` and so on). No single value works for every node. A value small enough for a 16Gi node cuts the conntrack capacity of a 1.5TiB node many times over. A pinned size also differs from what almost every node above ~14Gi of RAM runs today, so the agent would recreate those maps on upgrade and drop their conntrack and NAT state. A lower ratio has the same problem and doesn't lower the ceiling. The new test keeps the ratio at its default and the sizes unpinned, so changing either has to be deliberate. The figures are computed, not measured. I read the sizing code at cilium 1.19.5 (`pkg/option/config.go`), and 1.20.2, which #3343 moves to, has the same code. Memory comes from that formula plus the kernel hash map layout: a 48-byte element header, the key and value rounded up to 8 bytes, and a 16-byte bucket per power of two of `max_entries`. By that math the IPv4 maps alone pass 4Gi at roughly a terabyte of RAM. Bucket rounding moves the exact point, so I wouldn't read more precision into it. For the 1.5TiB node in the report, the issue's 3.9GiB is the agent's own budget (0.25% of RAM), and the kernel's actual charge comes out higher. Follow-ups, not in this PR: - Operators who want smaller maps on large nodes can size them per node with a `CiliumNodeConfig` selected by node label. This needs a documentation note. - The reporter's `bpftool` measurement of the real map memory is still pending. That is the measured check for the numbers above. The cilium helm-unittest suite passes on this branch, and also with this change applied over the 1.20.2 chart from #3343. Each new assertion fails when its value changes: the limit, the CT, NAT and neighbor sizes, the socket rev-NAT size set through `extraConfig`, and the ratio. Closes #4800 ### Screenshots Not a UI change. ### Downstream repositories - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: The diff changes only `packages/system/cilium/values.yaml` and its test. None of the trigger-map entries apply: no app, schema, platform value, variant, release asset or tooling changes, and no website page documents the agent limit. ### Release note ```release-note fix(cilium): raise the cilium-agent memory limit from 4Gi to 24Gi so it covers the agent's BPF maps, which cilium sizes from node RAM. On nodes with around a terabyte of RAM or more, the 4Gi limit got the agent OOM-killed on every start after a reboot, leaving the node without pod networking. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Increased the Cilium agent memory limit to 24 GiB. * Updated validation for BPF map sizing: checks the dynamic size ratio and confirms that specific map-size settings are absent. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
52f09d1aed |
fix(gateway)!: render passthrough services only where platform routes attach
The chart wrote the tlsPassthroughServices default onto every non-edge tenant's TenantGateway, so every tenant Gateway carried tls-api, tls-vm-exportproxy and tls-cdi-uploadproxy. The TLSRoutes that serve those names are platform routes: the packages owning the services render one per name in publishing.exposedServices while gateway.enabled is on, parented to the publishing tenant's Gateway alone. Everywhere else no shipped route attached to the listeners, and a passthrough listener holds its name whether or not anything is routed through it. The chart now writes the field only on the publishing tenant, with the same gateway.enabled switch and the same exposedServices filter those routes use, so a listener exists exactly where a platform route can attach. A TLSRoute attached by hand to one of those listeners on another tenant loses its parent. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
bdca165f4c |
feat(gateway): report a GatewayClass that does not serve TLSRoute
A GatewayClass lists the features it serves in status.supportedFeatures, and TLS passthrough is TLSRoute. On a class that leaves it out the passthrough listeners are accepted and serve nothing, so the TenantGateway now reads Ready=False/GatewayClassUnsupported naming the class instead of Ready. A class that lists no features at all is not judged: implementations predating the field leave it empty. The class writes that list after it is accepted and may change it when its controller is upgraded, so a GatewayClass event requeues the TenantGateways on it. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
d624049a3a |
feat(gateway): allow tlsPassthroughListeners under dns01 and existingSecret
The refusal existed because Cilium 1.19.5 served every Gateway port from one Envoy listener matched by SNI alone, so the "*.<apex>" terminate listener of the wildcard modes and a passthrough listener under the apex could reach each other's backend. The shipped Cilium 1.20.2 gives each port its own Envoy listener when SNI overlaps across ports, and Gateway API treats listeners on different ports as compatible, so the pair is served as declared. edge still refuses the field: it renders no TLS listener for an entry to bind to. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
e1319b5a6c |
docs(cilium): say the SNAT backport is dropped by hand
The patch header cited a commit of cilium/cilium#49232, an open PR whose branch is force-pushed, so the commit is reachable from no ref. Cite the PR alone. It also read as if the build would flag the patch once upstream carries the fix. It does not: a fix that lands in another place leaves this patch applying cleanly as a second early return, so the drop is a manual step. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
1bfa64f83a |
fix(cilium): keep per-type xDS while the 1.20 upgrade rolls
The 1.20 chart renders envoy-xds-mode "ads" and an adsConfig bootstrap for cilium-envoy unless xdsMode or upgradeCompatibility says otherwise. A 1.19 agent never registers the aggregated discovery service, and a 1.20 agent in ADS mode registers nothing else. The agent and envoy DaemonSets roll independently, so on every node where their versions differ envoy gets no configuration until both pods are replaced, and Gateway traffic stops on all nodes at once during the upgrade. Pin xdsMode to split, the per-type xDS both versions serve and the agent's own default when the key is absent. Moving to ADS is a separate step once every node runs 1.20. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
5b92ca3fc8 |
fix(cilium): serve HTTPS and passthrough on one port from one listener
When a Gateway needs per-port Envoy listeners, the operator emits one listener per HTTPS port and, with two or more passthrough ports, one per passthrough port, all named listener-<port>. A port carrying both gets two listeners with one name, and the agent skips the whole CiliumEnvoyConfig, so every listener of the Gateway stops serving while its status stays green. With one passthrough port the port is instead mapped to two listeners in the CEC services. A tenant Gateway with HTTPS and passthrough on 443 plus a passthrough listener on a native port reaches the first case. The patch puts the passthrough filter chains of such a port on its HTTPS listener and leaves the port out of the passthrough listeners and service mappings. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
cebf9f1e1e |
feat(cilium): accept wildcard HTTPS beside specific TLS passthrough
Cilium 1.19.6 and later mark an HTTPS-terminate listener and a TLS passthrough listener on the same port Conflicted whenever their hostnames intersect, and 1.20 drops both from Envoy. That rejects *.<apex> HTTPS next to api.<apex> passthrough on 443, which a tenant Gateway with one address needs. Envoy selects the most specific server_names match before the transport protocol, so the pair maps every SNI to exactly one filter chain. The operator is rebuilt from the upstream tag with a patch that accepts the pair when the passthrough hostname is strictly narrower than the HTTPS one, and keeps every other overlap conflicted. The asymmetry is needed because passthrough chains take their server_names from the attached TLSRoutes: under a passthrough wildcard a route may claim the HTTPS listener's exact name, and two chains with one match make Envoy refuse the whole listener. The binary replaces the one in the upstream operator-generic image, and the builder runs the patched packages' tests, so a tag bump that breaks the patch fails the build. make update re-pins both upstream images by the digests the vendored chart carries, the builder by upstream's own Go toolchain, and the source archive by its checksum. The image ref sits under operator.image.override: committed as the upstream operator the rebuild starts from, so a tree rendered without a build still pulls an image that exists, and stamped by make image. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
aa804aaa83 |
fix(dashboard): allow editing free-form objects in application forms (#4682)
## What this PR does Free-form object fields, such as NATS `config.merge` and `config.resolver`, get a JSON editor. The form keeps nested objects, arrays and primitive values. Input that is not a JSON object stays visible, and schema validation blocks the create or update request until it is fixed. A JSON object that fails the schema marks the field invalid and points it at the error list. Typed maps keep their key and value editor, and read-only and immutable fields stay protected. Fixes #4676. ### Validation - All 463 console tests in 63 files pass, and so does the TypeScript check. - Tests cover typing into the editor, nested NATS objects next to the typed users editor, input that is not a JSON object, schema errors on a valid object, existing values, immutable fields and free-form objects inside arrays. On the order page they cover a create after a form and YAML round trip, saving an edited object, and blocking input that is not JSON in create and edit mode. - The two schema-error tests fail on the component without the change. ### Screenshots   ### Downstream repositories This change preserves the public resource schema and client contract. The file-level trigger map was reviewed; no companion repository update is required. - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note fix(dashboard): allow editing free-form objects in application forms ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a JSON editor for configuration fields that accept objects with arbitrary properties. Edit nested values directly, with changes retained when switching between form and YAML views. * **Bug Fixes** * Invalid JSON is flagged and prevents create or update submissions until corrected. The editor supports empty objects, read-only fields, and objects nested in arrays, and makes validation errors accessible. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
6f49e5f427 |
feat(openbao): optional static-key auto-unseal and apiserver egress label (#4766)
## What this PR does This continues #4168 by @txmazing, which has been idle since 2026-09-10. The first commit is the work from #4168 squashed into one, with @txmazing as author. The other two commits constrain the new values and complete the documentation. Five changes to the managed OpenBAO app (`packages/apps/openbao`). 1. **Optional static-key auto-unseal** (#2787, #2483). `seal.type` is `shamir`, the unchanged default, or `static`. With `static` the chart mounts the Secret named in `seal.secretName` through the upstream chart's `server.extraVolumes` and adds OpenBAO's `seal "static"` stanza to the standalone and the Raft config, so the pods unseal themselves after a restart. `seal.previousSecretName` and `seal.previousKeyId` carry the n-1 key during a rotation. The chart never generates the key. A cluster administrator creates the Secret in the tenant namespace, because the `cozy:tenant:*` roles grant nothing on Secrets. A way for tenants to supply secrets by reference is proposed separately in cozystack/community#82. 2. **No silent seal change.** The template reads the seal in use from the `<release>-config` ConfigMap and refuses a different `seal.type` unless `seal.allowMigration: true` acknowledges a migration. Going from `static` back to `shamir` is refused, because the chart cannot render the disabled stanza that direction needs. 3. **Apiserver egress label** (#2793). The server pods carry `policy.cozystack.io/allow-to-apiserver: "true"`, so `service_registration "kubernetes"` reaches the API server and HA pods no longer hang at start. 4. **Constrained values.** The upstream chart passes the server config through `tpl`, and its start script replaces upper case placeholders such as `HOSTNAME` in it. A key identifier with template delimiters would run as a template inside helm-controller, which runs as cluster-admin, so `seal.keyId` and `seal.previousKeyId` take lowercase alphanumerics, hyphens, dots and underscores. The Secret names become pod volume names `userconfig-<name>`, so they take DNS labels of at most 52 characters. A previous Secret or key identifier equal to the current one fails at render. The apps API only defaults against the schema, and Helm enforces these patterns at install and upgrade. 5. **README.** The trade-off of `static`, the key Secret, the rotation with the pod replacement that the `OnDelete` strategy requires, the migration from Shamir step by step after the OpenBAO guide, and the one-time pod replacement after an upgrade so that existing pods get the label. ### Validation - `helm unittest .` in `packages/apps/openbao` passes 28 of 28 with helm-unittest 1.1.2, the version CI pins, and with 1.2.1. - Dropping the key identifier patterns, moving the Secret name limit to 51 or 53, or removing either equality guard turns the suite red each time. - Rendering this chart and then the vendored `openbao` chart with a template in `seal.keyId` now stops at the schema. Without the pattern the same two-stage render executed it, `lookup` included. - With default values, standalone and with `replicas: 3`, `helm template` renders the same as `main` apart from the six-line `extraLabels` block. - `make generate` in the package with cozyvalues-gen v1.7.0 and at the repository root with Go 1.27.1 leaves the tree unchanged. `make unit-tests` passes apart from seven BATS tests that fail the same way on a clean `main` under macOS, most of them because macOS ships no `timeout`. In `make test-controllers` only `internal/backupcontroller` fails, because its tests do not build on current `main` either, which #4768 fixes. `hack/check-commit-trailers.sh` passes and `cmd/api-gate` reports no sizeable API change. - Nothing here was run on a cluster. #4168 reports a Cozystack v1.6.3 cluster where a `replicas: 1` instance with `seal.type: static` came back `Sealed false` after `kubectl delete pod`. TLS between pods and an init or bootstrap job are not covered. Both are on the #2787 list and independent of this change. ### Screenshots No dashboard code change. The application form gains the `seal` group from the regenerated `openAPISchema` and `keysOrder`. ### Downstream repositories Walked the trigger map against the diff. The new `seal` field in `packages/apps/openbao/values.schema.json` reaches the hand-written `cozystack_openbao` resource of the Terraform provider. That is tracked in cozystack/terraform-provider-cozystack#44, which also needs `allowMigration` and the value constraints. The website reference page is generated from this `README.md` for the apps listed in its `Makefile`, and `openbao` is in `APPS`, so the page follows the next stable tag without a follow-up. The website pages that mention the apiserver label describe it in general terms and carry no OpenBAO workaround. There is no `hack/` change, no platform values change, no variant and no change to ApplicationDefinition semantics. - [ ] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [x] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: https://github.com/cozystack/terraform-provider-cozystack/issues/44 - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note feat(openbao): the OpenBAO app can auto-unseal with OpenBAO's static-key seal (`seal.type: static`) from a Secret that a cluster administrator creates in the tenant namespace, with n-1 rotation through `seal.previousSecretName` and `seal.previousKeyId`. Shamir stays the default, and changing the seal of an existing instance needs `seal.allowMigration`. Server pods now carry `policy.cozystack.io/allow-to-apiserver: "true"`, so HA instances no longer hang at start behind the apiserver egress policy. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * OpenBAO supports static sealing with keys stored in an existing Secret; Shamir sealing remains the default. * Configure current and previous keys to support key rotation in standalone and high-availability deployments. Keep the previous key until stored keys have been re-wrapped. * Seal-type changes are validated. Shamir-to-static migration requires explicit acknowledgement; static-to-Shamir migration is not supported. * Static-seal settings validate required key details and Secret names. Server pods receive a label needed by the configured API-server egress policy. * **Documentation** * Added guidance for configuring static sealing, managing Secrets, rotating keys, and migrating seal types. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
8c8f2522ee |
fix(cilium): keep the host mark on host traffic to a local pod
Since v1.20.0 the bpf_host SNAT conflict check fires for any packet carrying the host mark on every device bpf_host runs on, and the SNAT path replaces that mark with SNAT_DONE. With kube-ovn chaining a host connection to a pod on the same node leaves through ovn0, so the pod's to-container program sees SNAT_DONE and classifies the source as world instead of host. The implicit localhost allow then stops matching: kubelet probes fail under any default-deny ingress policy that does not admit world, and a world deny drops the API server calling a webhook on its own node. Carry a verbatim backport of cilium/cilium#49232, which skips the conflict check when the destination is a local endpoint: such traffic never leaves the node and cannot collide with pod egress SNAT. Keeping the hunks identical to upstream lets the patch be dropped as soon as a shipped cilium release contains the fix. Without chaining, host traffic to a local pod does not pass to-netdev and nothing changes. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <f@lex.la> |
||
|
|
b64e12b0cf |
docs(cilium): re-anchor comments the v1.20.2 bump made stale
The admission-webhook deny policies in ingress-nginx and kubeovn-webhook cite Cilium source and the vendored values by line number. The bump moved endpointLockdownOnMapOverflow and the policy-map ordering block in pkg/endpoint/bpf.go, so the cited lines pointed elsewhere. Name the key and the function instead, which survive the next bump, and move the getEndpointSelector citation to v1.20.2, where the cited lines are unchanged. The kubeProxyReplacement pin explained the service translation in terms of v1.19.5. With Gateway API on, v1.20.2 keeps socket LB in the host namespace, so pod-namespace connections are translated per packet in bpf_lxc before egress policy runs, which is what the pin relies on. The same holds for the e2e image mirror, whose egress-policy comment in hack/e2e-talos-image-cache.yaml described socket LB. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <f@lex.la> |