Commit Graph
3315 Commits
Author SHA1 Message Date
IvanHunters 4874dbe6b2 chore(hetzner-robotlb): update robotlb to 0.1.0
Backport of #4557 to release-1.6. The upstream project moved GitHub organisations from intreecom to treetscom, and no image has been published under the old location since. The chart on this branch still points there, so the component cannot pull at all: the Deployment sits in ImagePullBackOff while the HelmRelease reports healthy, because Helm only waited for the objects to be created.

0.1.0 also carries the fix that makes balancer targeting follow the service's externalTrafficPolicy, which a cluster relying on `Local` needs in order to keep sending traffic only to nodes that run the backing pods.

(cherry picked from commit b314514950)

Assisted-by: LLM
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-10-06 20:35:12 +03:00
Aleksei Sviridkin eeb943144c fix(e2e-sandbox): install mc from its GitHub release
dl.min.io now answers 410 Gone for every community mc build, since
MinIO archived the project, so the sandbox image no longer builds.
The final mc release is still published as a GitHub release asset.
Pin it and verify the per-arch checksum, because the old install
trusted whatever the URL served.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
(cherry picked from commit e66f134564)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-28 14:14:20 +05:00
cozystack-ci[bot] 5a32ce0163 Pin promoted packages artifact for v1.6.4
Signed-off-by: cozystack-ci[bot] <274107086+cozystack-ci[bot]@users.noreply.github.com>
2026-09-28 05:35:29 +00:00
cozystack-ci[bot] cb155b1bf7 Prepare release v1.6.4 (promoted from v1.6.4-rc.1)
Signed-off-by: cozystack-ci[bot] <274107086+cozystack-ci[bot]@users.noreply.github.com>
2026-09-28 05:35:26 +00:00
cozystack-ci[bot] 550a8be0b4 Prepare release v1.6.4-rc.1
Signed-off-by: cozystack-ci[bot] <274107086+cozystack-ci[bot]@users.noreply.github.com>
2026-09-25 12:58:03 +00:00
myasnikovdaniil 6f00d308e4 [Backport release-1.6] feat(kubevirt): expose migration configuration through platform values (#4402)
This reopens a fork backport from a branch in this repository so its CI
can run. The commit is the one from #4339 by @yankawai, unchanged. On
release-1.6 the pull-request CI pushes the images it builds, and a run
from a fork has no registry credentials, so #4339 stopped at the build
jobs and never reached e2e. The description below is the author's.

## What this PR does

Manual backport of #4254 to `release-1.6`.

The automated backport, #4322, stopped with conflict markers in four
files as its only commit, so it is red on DCO and unmergeable as it
stands.

Every conflict has the same cause: the `kubevirt.disabledFeatureGates`
work landed on main after 1.6 was cut, and the cherry-pick carried it
into hunks this line does not have. Four differences follow:

- platform values gains a `kubevirt` block holding `migrations` alone,
and the iaas bundle gains only the migrations hop;
- the wiring test takes the four migrations cases and the case for a
null `kubevirt` block, without the assertions that belong to
disabledFeatureGates cases this line does not have;
- `update_idempotency_test.sh` gains `run_update_logged`, a four-line
helper that arrived on main with that work and the new cases need;
- the kubevirt Makefile header counts six sed patches rather than five.

Verified on this branch: 9 kubevirt chart tests, 31 platform wiring
tests (102 across the platform suite), and `update_idempotency_test`
PASS under GNU make and sed. Removing the new awk guard from the
Makefile turns that test red naming the migrations block, so the ported
guard is doing work. On this line `(.Values.kubevirt).migrations` is the
only reader of `.Values.kubevirt`; rewriting it as
`.Values.kubevirt.migrations` turns the null-block case red with a nil
pointer.

Feature summary, unchanged from #4254: cluster-wide migration settings
could only be applied by patching the KubeVirt CR, because the kubevirt
chart did not render `migrations` and the platform bundle did not
forward it. `kubevirt.migrations` now passes through the generated
Package to `spec.configuration.migrations`. A hand patch of that Package
is undone on the next platform render, so this hop is the only supported
setter.

```yaml
kubevirt:
  migrations:
    bandwidthPerMigration: 625M
    parallelMigrationsPerCluster: 2
    parallelOutboundMigrationsPerNode: 1
```

### Screenshots

Not a UI change.

### Downstream repositories

Walked the trigger map against the diff: platform values, the iaas
bundle and the kubevirt chart. The v1.6 reference page of the platform
values had no `kubevirt` section, so the row goes there as a follow-up
that should land with this backport.

- [ ] No downstream repository is affected by this change
- [x] [cozystack/website](https://github.com/cozystack/website) -
follow-up: cozystack/website#705

### Release note

```release-note
feat(kubevirt): expose `kubevirt.migrations` in the platform values and forward it to `spec.configuration.migrations` on the KubeVirt CR, so live-migration bandwidth and parallelism can be set without patching a Package that the platform re-renders.
```
2026-09-25 14:46:13 +05:00
myasnikovdaniil 0dc238a94a [Backport release-1.6] fix(kubeovn): retry VM migration setup after scheduling (#4328)
# Description
Backport of #4253 to `release-1.6`, together with #3460 which it depends
on. On 1.6 kube-ovn chart and image still come from
cozystack/kubeovn-chart, so draft Dockerfile had nothing to build it and
kubeovn build failed (no `image` target). #3460 moves build in-tree on
same kube-ovn 1.15.10 this branch runs, and brings nightly-mirror fix
for kube-ovn split registry host that becomes needed once kube-ovn is
built by CI. Bot draft also dropped second commit of #4253
(`fix-vmim-target-pod-retry.diff`), it is back now.

I built image locally, all three patches apply to kube-ovn v1.15.10 and
`TestVMIMigrationSchedulingRetry` passes.
2026-09-25 14:46:00 +05:00
myasnikovdaniil 6d25310774 [Backport release-1.6] fix(cluster-api): backport live migration before host eviction (#4474)
# Description
Backport of #4291 to `release-1.6`.
2026-09-25 14:45:54 +05:00
Yan Bondarenko 2744dcf42a docs(cluster-api): explain the omitted migration priority by the pinned API
CAPK v0.1.10 pins kubevirt.io/api v1.5.0, whose
VirtualMachineInstanceMigrationSpec carries only vmiName; upstream #392
sets priority against v1.9.0. The typed migration does not compile against
the pinned API, which is why the patch builds it unstructured.

Assisted-by: LLM
Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com>
(cherry picked from commit bc2ba106e1)
2026-09-25 10:46:45 +05:00
Yan Bondarenko 6360e05c20 fix(cluster-api): bound pending migration submission
A migration that KubeVirt never processes must not block host eviction indefinitely. Keep its submission deadline separate from active migration and fallback drain windows.

Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com>
(cherry picked from commit c85f35070c)
2026-09-25 10:46:45 +05:00
Yan Bondarenko 64b76615ce docs(cluster-api): clarify trusted backport image delivery
Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com>
(cherry picked from commit bb3a2fa220)
2026-09-25 10:46:45 +05:00
Yan Bondarenko a0e1c8a63a fix(cluster-api): backport live migration before host eviction
Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com>
(cherry picked from commit c8f4906e93)
2026-09-25 10:46:44 +05:00
Yan Bondarenko bfb42248db feat(kubevirt): expose migration configuration through platform values
Backport of #4254 to release-1.6.

Cluster-wide migration settings could only be applied by patching the KubeVirt
CR: the kubevirt chart did not render `migrations`, and the platform bundle did
not forward it. The optional `kubevirt.migrations` platform value now passes
through the generated Package to `spec.configuration.migrations`, and a hand
patch of that Package is undone on the next platform render, so this hop is the
only supported setter.

Four differences from main, all from release-1.6 predating the
disabledFeatureGates work:

- platform values gains a `kubevirt` block holding `migrations` alone, and the
  iaas bundle gains only the migrations hop;
- the wiring test takes the four migrations cases and the case for a null
  `kubevirt` block, without the assertions that belong to disabledFeatureGates
  cases absent here;
- update_idempotency_test.sh gains `run_update_logged`, which arrived on main
  alongside that work and the new cases need;
- the kubevirt Makefile header counts six sed patches rather than five.

Verified on this branch: 9 kubevirt chart tests, 31 platform wiring tests (102
across the platform suite), and update_idempotency_test PASS under GNU make and
sed. Removing the new awk guard from the Makefile turns that test red naming the
migrations block, so the ported guard is not decorative. On this line
(.Values.kubevirt).migrations is the only reader of .Values.kubevirt, and
rewriting it as .Values.kubevirt.migrations turns the null-block case red with a
nil pointer.

The automated backport in #4322 stopped with conflict markers in four files as
its only commit, which is why this exists.

Assisted-by: LLM
Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com>
2026-09-25 09:35:57 +05:00
Aleksei Sviridkin d159113a0b fix(linstor): add opt-in graceful satellite shutdown on Talos
Backport of #4292 to release-1.6.

Cozystack's Talos configuration removes the systemd DRBD shutdown guard
without a replacement. talos.gracefulShutdown.enabled, disabled by default,
releases unused Secondary DRBD resources before the satellite stops so their
backing devices, including ZFS zvols, can be released during normal shutdown.
The hook skips Primary resources and open devices, rechecks each candidate,
and stops on ambiguous status, command failure or timeout. It uses no force,
demotion, Kubernetes API calls or extra permissions.

Three differences from main, all from the same cause: release-1.6 has no
drbd.enabled flag, since the DRBD-less-substrate switch landed after 1.6 was
cut. The hook is therefore gated on talos.gracefulShutdown.enabled alone, the
values block adds only that key, and the case asserting the hook is omitted on
a substrate without DRBD is left out along with the flag it sets. The README
line naming both flags names talos.enabled instead. Nothing else differs.

The automated backport in #4320 stopped at the same values.yaml hunk and
pushed the conflict markers as its only commit, which is why this exists.

Verified on this branch: 11 Helm tests and the 20 behavioural Python tests
pass.

Assisted-by: LLM
Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-25 09:35:57 +05:00
Yan Bondarenko e087e38e8a fix(kubeovn): retry migration setup until target pod exists
Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com>
(cherry picked from commit 6e90447091)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-25 09:35:56 +05:00
Yan Bondarenko 0a359e5f4d fix(kubeovn): retry VM migration setup after scheduling
Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com>
(cherry picked from commit 55a2918fcb)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-25 09:35:56 +05:00
Andrei Kvapil 54fac75f80 feat(kubeovn): build the chart and image in-tree
kubeovn was the last package whose chart and image were produced by a
separate repository: packages/system/kubeovn pulled a tarball from the
latest cozystack/kubeovn-chart tag at update time, and that repository
built and pushed the image. The wrapper existed only to cache the
upstream chart; with the current caching that reason is gone, and the
split cost a second repository, a second release step, and a package
whose provenance a reader could not follow without leaving the tree.

Move the wrapper in, shaped like packages/system/cilium: update pulls
the upstream kube-ovn chart directly and applies patches/mtu.diff, and
image builds images/kubeovn and pins the digest into values.yaml. The
MTU patch already carried monorepo-relative paths, so it applies here
unchanged.

Also carries cozystack/kubeovn-chart#5, which never got a tag: pin
OVN_IPSEC_KEY_DIR under /var/lib. The kube-ovn default sits in
/etc/origin, which a Talos node cannot create, so enabling IPsec left
the node without ESP security associations.

Co-authored-by: Timofei Larkin <lllamnyp@gmail.com>
Co-authored-by: Kirill Ilin <stitch14@yandex.ru>
Co-authored-by: Aleksei Sviridkin <f@lex.la>
Assisted-By: Claude
Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io>
(cherry picked from commit 7ebce2e942)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-25 09:35:55 +05:00
myasnikovdaniil e01d3f7891 [Backport release-1.6] fix(opensearch-operator): name the component reconciler a stall sits in (#4377)
# Description
Backport of #4333 to `release-1.6`, together with #4231 which it depends
on. 1.6 has no in-tree opensearch-operator build, so bot draft added
only the Dockerfile and patch from #4333 would never reach an image.
#4231 brings the build (`image` target, values wiring, root `Makefile`
entry) plus its own single-replica fix. In root `Makefile` I kept only
opensearch-operator line, redis-operator is not built in-tree on 1.6.

I built image locally, both patches apply to operator v2.8.0 and stall
watchdog specs from #4333 pass.
2026-09-25 09:34:47 +05:00
IvanHunters 9dabf196c6 docs(kafka): say why the hook's Job and its credentials are reaped differently
The policies are right and nothing here changes them. What is missing is
the reason, and this file has now been changed in both directions inside
a week by people reasoning from the annotations alone, so the reason is
the part worth keeping.

The Job carries no hook-succeeded because the script exits 0 on the
degraded path as well as the clean one, and its log is the only record
that a finalizer outlived the wait; ttlSecondsAfterFinished reaps it on a
timescale a human can act within. The ServiceAccount, Role and
RoleBinding have no such clock, and before-hook-creation fires on a next
activation that after the last uninstall never comes, so without a
terminal policy they sit in the tenant namespace for the life of the
cluster still granting delete over every KafkaTopic in it.

Reaping them cannot strand a running pod, which is the objection the
symmetrical shape was written against: helm applies hook-succeeded only
once the hook is terminal, and activeDeadlineSeconds ends the Job inside
the uninstall hook timeout. hook-failed would decide nothing, because a
failing hook already reaps the earlier successful ones under
hook-succeeded.

Assisted-by: LLM
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit 3a43bcf391)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-24 22:15:47 +05:00
coderabbitai[bot] e96ff897f3 fix(kafka): clean up pre-delete hook ServiceAccount and RBAC on success
(cherry picked from commit a295e29b8a)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-24 22:15:47 +05:00
IvanHunters 8661c6f678 fix(kafka): drop the request timeout that hid the apiserver from the hook
A non-zero --request-timeout makes kubectl skip its in-cluster credentials
altogether. client-go consults them only while the assembled config still
equals the default, and the flag lands in that config, so the branch that
would load the ServiceAccount token never runs. kubectl falls back to its
built-in default cluster, localhost:8080, is refused, and the script reads
the refusal as a failed delete and exits 1. A non-zero pre-delete hook
returns from Uninstall.Run before any resource is removed, so no Kafka
release could finish deleting and helm-controller retried forever.

Measured on the pinned image rather than argued from the docs: with the
token and ca.crt mounted and KUBERNETES_SERVICE_HOST set, the same delete
reaches the cluster without the flag, goes to localhost:8080 with
--request-timeout=20s, goes to localhost:8080 with 1m, and reaches the
cluster again with 0.

The three in-tree hooks that work do not pass it. apps/kubernetes names it
in a comment only, apps/harbor and apps/mariadb never mention it, and
apps/tenant records that its DELETE calls "carry kubectl's default
--request-timeout of 0". The watch stays bounded by --timeout, and the Job
by activeDeadlineSeconds, which is that same shape.

The suite now rejects the flag. It needs the "=" because the explanation
in the script names the flag too, and matching the bare name would fail on
the comment rather than on a use.

Assisted-by: LLM
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit e63b8595d3)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-24 22:15:47 +05:00
IvanHunters 2b1f383ecb fix(kafka): keep the pre-delete hook's credentials as long as its Job
The Job carries no hook-succeeded, so it outlives the hook run and
ttlSecondsAfterFinished reclaims it, which is what leaves a readable
record when the finalizer outlives the wait. Its ServiceAccount, Role and
RoleBinding still carried hook-succeeded and hook-failed, so Helm reaped
them at the end of the run either way and left the Job behind them.

A Job whose ServiceAccount is gone still starts a pod. kubelet mounts the
projected volume without a token, client-go finds no in-cluster config,
kubectl falls back to localhost:8080, and the script takes its catch-all
branch and exits 1. A non-zero pre-delete hook returns from Uninstall.Run
before any resource goes, so the release never finishes deleting and
helm-controller retries it: the e2e run on the merge commit shows six
such pods in five minutes, in two namespaces, every one of them dead the
same way. The hook meant to prevent one stuck Kafka release was instead
stopping all of them.

Give all four objects the same before-hook-creation policy, so the
credentials live exactly as long as the consumer and the next run
replaces them. Both other in-tree hooks that reach the apiserver,
apps/kubernetes and apps/harbor, are symmetric this way already.

The suite now pins the policy on each of the three, because nothing
compared them: the asymmetry rendered cleanly, passed 37 helm-unittest
cases and 5 bats cases, and only a cluster showed it.

Assisted-by: LLM
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit 64d5689434)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-24 22:15:47 +05:00
IvanHunters 36f2963883 test(kafka): anchor the release selector the hook suites assert on
Both suites matched "strimzi.io/cluster=kafka-test" as a bare substring,
and that is a prefix of the sibling release kafka-test2 and of
kafka-test-topics. Rendering the hook with either selector left both
suites green, so neither pinned the scoping they exist to pin. Anchor on
the leading "-l " and on the trailing delimiter; both variants now red in
both suites, and the six earlier hook mutations still red exactly where
they did.

Drop the notMatchRegex on a leading slash. It cannot fail on its own: the
anchored image pattern above rejects a leading slash first, and an empty
_cluster.images-registry renders no slash to begin with. Its rationale
moves into that pattern's comment.

Record why activeDeadlineSeconds and the 180s wait have to move together.
A deadline that fires mid-wait kills the Job, and with backoffLimit: 0 the
hook then returns non-zero, which is the wedged uninstall the deliberate
exit 0 on the timeout branch exists to avoid.

Assisted-by: LLM
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit 637098f222)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-24 22:15:35 +05:00
IvanHunters a1430c9f2d test(kafka): drive the hook suite through the runner CI actually uses
The suite used bats' run helper. make bats-unit-tests does not invoke the bats
binary: it runs hack/cozytest.sh over every hack/*.bats, and that runner
implements @test and little else, so the file died at 'run: command not found'
and took make unit-tests with it. Under bats it was 5/5, which is where the 5/5
in the previous commit came from. Save $? by hand instead, the shape
app-cleanup-hooks_test.bats already uses; verified under both runners.

The fake kubectl no longer defaults DELETE_RC to 0. An unset value made every
failure-path assertion vacuous; now it exits 64 and says so. Cover both
RESTMapper wordings for an absent CRD rather than just the first.

Widen the image pattern to v[0-9]+\.[0-9]+(\.[0-9]+)? like harbor and mariadb:
pinning v1\.32 reintroduced the breakage the digest was made pattern-based to
avoid, one Renovate bump later. Assert the _cluster.images-registry override
and the no-leading-slash default, neither of which was covered: the hook is the
one image in this chart whose pull failure surfaces at uninstall.

Assisted-by: LLM
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit 415aa82409)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-24 22:15:35 +05:00
IvanHunters 30dc75667e test(kafka): run the pre-delete hook against a fake kubectl
The hook's exit code is the whole contract: a non-zero one returns from
Uninstall.Run before any release resource goes, keeping the topic operator
alive; a zero one lets Helm remove it. delete_test.yaml matches manifest text,
so it stayed green when the timeout branch was put back to exit 1, when the
CRD-absent branch was, and when the selector was widened past this release.

Add a bats suite in the shape hack/app-cleanup-hooks_test.bats already uses for
qdrant and harbor: render the script, run it against a fake kubectl, pin the
exit code of each branch. Each of the three mutations above now turns it red.

Drop hook-succeeded from the delete policy and reclaim the Job with
ttlSecondsAfterFinished instead. The script exits 0 on the degraded path too,
where topics still hold the finalizer, so deleting on success removed the only
record of that seconds after it was written. Assert both in delete_test.yaml.

Pin the hook image by shape rather than by literal digest: Renovate rewrites
digests under packages/*/templates/hooks/ and nothing rewrites tests/, so the
literal turns the next bump red for no defect.

Assisted-by: LLM
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit 3326e0fb9e)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-24 22:15:35 +05:00
Yan Bondarenko 985b4c46bf fix(kafka): stop the pre-delete hook from wedging the uninstall
Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com>
(cherry picked from commit 210b7fe30c)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-24 22:15:35 +05:00
Yan Bondarenko 30afb9a26a fix(kafka): delete release topics before the topic operator is removed
Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com>
(cherry picked from commit 44ba13b527)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-24 22:15:34 +05:00
Aleksei Sviridkin aacef01d86 fix(ingress): trust CF-Connecting-IP only from Cloudflare ranges
cloudflareProxy passed the Cloudflare ranges to the controller under
set_real_ip_from, which is an nginx directive and not an ingress-nginx
ConfigMap key, so the controller dropped it without a warning. With
use-forwarded-headers on, the realip module then trusted every source
from the default proxy-real-ip-cidr of 0.0.0.0/0, and any client that
reached the load balancer directly could set CF-Connecting-IP to an
address of its choice. That address is what whitelist-source-range
checks, so the tenant whitelist, and any per-Ingress one, could be
walked past with one header.

proxy-real-ip-cidr is the key the controller reads for the trusted
ranges.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
(cherry picked from commit 3800f63513)
2026-09-24 13:10:31 +00:00
IvanHunters ee8923f351 fix(opensearch-operator): name the component reconciler a stall sits in
The cluster controller runs nine component reconcilers in sequence and none
of them logs unconditionally when it is entered: the TLS one's only line
above its work sits on the no-security early return, which the chart in this
repository never renders, and the rolling restart one opens at V(1), off at
the verbosity the operator ships with. So a call that stops returning leaves
nothing behind at all. The operator log ends on whatever ran before it, the
object is silently no longer reconciled, and from the outside that is
indistinguishable from an operator with nothing to do. Two e2e runs ended
exactly that way, the operator going quiet at the moment the chart rewrote
the CR and never coming back: https://github.com/cozystack/cozystack/issues/4332.

Each component is now wrapped so a call still in flight after a minute
reports its own name and how long it has been running, and keeps reporting on
that interval while it is stuck. A single line dated at the start of a stall
does not answer the question a reader has five minutes in, which is whether
the call is still there. Nothing is written while a component behaves, so a
healthy cluster costs no extra lines.

The finalizer path is left alone: every DeleteResources at this version
returns immediately, so a watchdog there could only spawn goroutines for
calls that cannot block.

A diagnostic rather than a fix: drop it once the stall itself is understood.

Assisted-by: LLM
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit 6a34c9f037)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-24 17:11:35 +05:00
IvanHunters 4ef7efc39d fix(opensearch-operator): keep a single-replica cluster electable after bootstrap
The operator deletes the bootstrap pod as soon as initialization completes and
never looks at the voting configuration first. With one cluster_manager replica
there are exactly two eligible nodes, OpenSearch keeps the configuration at an
odd size of one, and the voter it keeps is the bootstrap node that formed the
cluster. Deleting that pod takes away the only vote there was, and the survivor
can never hold an election again, because changing the configuration itself
needs a quorum. The cluster is unusable about a minute after it installs, and a
node with no cluster-manager still answers the readiness probe, so nothing says
so until something restarts the pod.

Build the operator in-tree, the way kamaji and redis-operator already are, and
carry a patch that excludes the bootstrap node from the voting configuration and
waits for that to commit before deleting the pod. Reaching the cluster is a
precondition rather than a nicety: every failure keeps the pod and requeues,
because a bootstrap pod that outlives its purpose costs a pod, while a cluster
that cannot elect does not recover without a human.

Deleting a pod is a request rather than a wait, so clearing the exclusion
afterwards can find the node still in the cluster and fail. That path requeues
and is retried once the pod is really gone, which keeps a stale entry out of the
capped exclusion list; clearing stays at the API default wait_for_removal=true
so it cannot re-admit a node some other operation is still draining.

Upstream carries the same defect, tracked as
opensearch-project/opensearch-k8s-operator#1448.

Assisted-by: LLM
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit b222cb6580)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-24 17:11:35 +05:00
Myasnikov Daniil 9c6e8301cb docs(e2e): name the container lane's one-per-host limit
SANDBOX_NAME is per-checkout and these are not, which reads like an
oversight until you notice that hack/e2e-compose.yaml's container names
and the data-srvN zpools are global too. Two checkouts on one host
therefore share nodes and pools, and the second one's teardown destroys
the first one's storage.

Recorded rather than fixed. CI cannot reach it -- the lane already asks
for 24 vCPU and 72 GiB against a 32 vCPU / 128 GiB runner, so a second
one does not fit beside it -- and isolating it properly means renaming
the pools, which the LINSTOR storage-pool registration reads.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Assisted-By: LLM
(cherry picked from commit 00c6eb18bf)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-24 14:56:36 +05:00
Myasnikov Daniil f75153ac0a test(e2e): run the merge-gating lanes on Talos containers
The srv1-srv3 nodes of both lanes that gate a merge -- the same-repo one
in pull-requests.yaml and the fork one in e2e-fork.yaml -- run as Talos
containers instead of QEMU guests, so a tenant worker sits at L2 rather
than L3. Measured in CI on commits where both substrates ran the same
tree: whole-job wall clock down 24-49 minutes, essentially all of it in
Chainsaw, while the two tenant-Kubernetes suites go from 1143-2040s to
466-809s and stop depending on the runner's vgif flag.

The node-join soft-red gate goes with the substrate, which is what it
was for. It existed because nested virtualisation on the shared runners
degraded far enough that a worker registering in minutes elsewhere could
miss any deadline this test could afford; #3513 established that the
discriminator was the host's kvm_amd vgif flag, and removing a nesting
level removes what it acted on. So hack/e2e-node-join-soft-red.sh, the
SOFT-RED-node-join.txt marker and the soft_red job outputs are gone from
all four workflows, and a missed deadline is an ordinary red again. The
::warning annotation survives, because the reason a run went red should
be legible without opening the log, and so does the 124-versus-everything
-else test, because "the workers were slow" and "the wait never ran"
send a reader to different places.

Done by swapping the substrate inside the existing e2e jobs rather than
by promoting a separate container job. Those jobs carry more than a
substrate -- the GitHub App token, the report-overrun guard, the images
list, the SSH breakpoint -- and promoting a job that never had them
would have dropped four features without saying so.

Three properties of container mode drive the design, and each fails
quietly rather than loudly. machine.kernel.modules is a silent no-op --
kernel_module_spec.go returns early on ModeContainer with no error and
no event -- so the host loads openvswitch and zfs before the nodes start
and the workflow step asserts both rather than trusting them; a missing
module surfaces an hour later looking like a CNI or a storage
regression. Docker gives a privileged container its own tmpfs /dev
seeded once at creation, so /dev/kvm works but ZFS zvols created later
never appear and linstor-csi fails ControllerPublishVolume; the compose
file binds the host devtmpfs, which is also why talosctl cluster create
docker can never carry LINSTOR. And there is no ARP VIP, so
192.168.123.11 stands in for the QEMU lane's .10.

The QEMU machinery stays in the tree and keeps running: nightly.yaml and
e2e-tag.yaml still call `make prepare-env`, so DRBD, the replicated
StorageClass, its Immediate binding mode, the tenant StorageClass
propagation that only applies to remotely-accessible classes, and the
Cozystack Talos node image with its extensions all keep nightly and
release-candidate coverage. None of them is exercised per pull request
any more. That is the trade.

Nothing on the PR path builds or downloads a nocloud disk now, so
build-talos drops the talos-nocloud step and the talos-image artifact.
build-talos itself stays: finalize consumes its digest fragment.

One property this does not fix, recorded beside the runner class because
it will be read off a red run eventually: a container node reports the
HOST's CPU and memory as capacity, and hack/e2e-container-up.sh counters
that with kubelet systemReserved. That corrects the scheduler and not
what a pod reads from /proc, so a workload sizing itself from
/proc/cpuinfo or /proc/meminfo is configured for the whole runner.

Also carried here because the same files carry them: the ghcr.io
pull-through mirror removal (see #4007 -- whichever lands first makes the
other a no-op), the authoritative HelmRelease readiness gate, the
backup-credential preflight, the prepull guard against an image-less
container fragment, and folding the two standalone OIDC suites into the
latest-version tenant cluster.

Adapted for release-1.6: this branch has no e2e-fork.yaml, no soft-red
gate, no ghcr.io mirror and no backup e2e, so those hunks are dropped
together with the tests for helpers that exist only on main; e2e-tag.yaml
stays on QEMU. The platform Package generator carries the API endpoint
and nothing else, because the linstor drbd.enabled and kubevirt-cdi
importerResources overrides need chart values this branch does not ship;
the container lane gets e2e-side substitutes for them in later commits.
run-kubernetes.sh takes the storage-class helper, the local-lane pool
baseline, the scoped drain and the OIDC fold, while cleanup keeps its
best-effort `|| true`. The OIDC suite references in select-install.sh and
the chainsaw README go with the suites here rather than in a later commit.

(cherry picked from commit 186547d835)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Assisted-by: LLM
2026-09-24 14:56:35 +05:00
Aleksei Sviridkin f80ea540a8 fix(reloader): add startupProbe to survive slow first start under load
Reloader binds its :9090 listener as the last statement of
startReloader, so /live and /metrics answer connection refused until
everything before it has finished. The blocking part of that prologue
is the package-level IsOpenshift = isOpenshift() in pkg/kube, which
issues a GET /apis/project.openshift.io against the API server on a
context carrying no deadline, before main() is even entered. That
latency belongs to the API server, and the container waits it out at a
100m CPU limit.

The chart renders no startupProbe, so the only grace period is the
liveness budget: initialDelaySeconds 10 + periodSeconds 10 *
failureThreshold 5, about 60 seconds. A first start that needs longer
is killed mid-prologue, and the restart does not resume it, it runs it
again from the beginning, so the loop sustains itself. The blast
radius reaches past reloader: the LINSTOR stack lists
cozystack.reloader in dependsOn, which fans out to every component of
that stack, so a reloader stuck in this loop blocks the whole install.

Render a values-driven startupProbe on /live so liveness only begins
evaluating once the listener is up. Budget = periodSeconds 5 times
failureThreshold 45, so about 225 seconds. timeoutSeconds matches the
5s the chart already gives liveness rather than the kubelet default of
1s, which a throttled process can exceed while holding the socket
open.

Both liveness knobs the chart already exposes could buy the same grace
with no patch to carry. Widening failureThreshold buys it permanently,
loosening hang detection for the life of the container.
initialDelaySeconds is start-up-only and would genuinely do, but it is
a fixed blind window on every start, whereas a startup probe returns
liveness to its tight budget the moment the listener binds.

The chart is vendored, so the template change is carried as
patches/deployment-startup-probe.diff and reapplied by `make update`,
which now drives the shared %-update rule with an exact chart version
pin instead of pulling whatever is latest. The patch is applied with
--forward because patch(1) defaults diverge by implementation over a
tree that already carries the change: GNU 2.7.6 refuses and exits 1,
Apple 2.0-12u11 takes its "Assume -R? [y]" default and strips the hunk
back out with exit 0, and GNU under --batch does the same. --forward
refuses in all three.

A helm unittest pins the probe, its budget, the no-op path the
template promises for an unset value, and the liveness numbers the
budget is sized against, so the documented arithmetic cannot drift
away from the chart without a red test. The same target asserts that
the vendored Chart.yaml still records the pinned version, so raising
the pin without re-running `make update` fails instead of leaving the
tree and the pin quietly disagreeing.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
(cherry picked from commit 7f67d02fb7)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-24 12:09:34 +05:00
myasnikovdaniil d3a9a73f1f [Backport release-1.6] fix(apps): let the cleanup hooks watch the objects they delete (#4369)
# Description
Backport of #4135 to `release-1.6`.
2026-09-23 17:58:49 +05:00
myasnikovdaniil 89c44b4d83 [Backport release-1.6] fix(dashboard): let dashboard users read backup CRD schemas (#4307)
# Description
Backport of #4236 to `release-1.6`.
2026-09-23 17:58:42 +05:00
myasnikovdaniil de1f25998f [Backport release-1.6] fix(backups): give the barman-cloud sidecar its own resources (#4336)
# Description
Backport of #4220 to `release-1.6`.
2026-09-23 17:58:38 +05:00
myasnikovdaniil 8697eccd9f [Backport release-1.6] fix(linstor): reconnect only the stalled peer in the satellite plunger (#4319)
# Description
Backport of #4184 to `release-1.6`.
2026-09-23 17:58:34 +05:00
myasnikovdaniil 56bfcbf65a [Backport release-1.6] fix(foundationdb): let tenant roles read the connection ConfigMap (#4315)
# Description
Backport of #4148 to `release-1.6`.
2026-09-23 17:58:31 +05:00
myasnikovdaniil fcc53feeb2 [Backport release-1.6] fix(opensearch): remove the data PVCs when the application is deleted (#4368)
# Description
Backport of #4136 to `release-1.6`.
2026-09-23 17:58:27 +05:00
myasnikovdaniil f6c8f90e78 [Backport release-1.6] fix(nats): merge config.merge.accounts with the generated accounts map (#4321)
# Description
Backport of #4134 to `release-1.6`.
2026-09-23 17:58:23 +05:00
myasnikovdaniil 78e013ee46 [Backport release-1.6] fix(clickhouse): keep the Keeper name inside the StatefulSet volume-name limit (#4314)
# Description
Backport of #4133 to `release-1.6`.
2026-09-23 17:58:20 +05:00
myasnikovdaniil 37ca9b0ac6 [Backport release-1.6] fix(linstor): wait for temporary probe devices (#4335)
# Description
Backport of #4100 to `release-1.6`.
2026-09-23 17:58:15 +05:00
myasnikovdaniil 6672b26836 [Backport release-1.6] fix(mongodb): fill the dashboard credentials on a first install (#4330)
# Description
Backport of #4014 to `release-1.6`.
2026-09-23 17:58:11 +05:00
myasnikovdaniil 4d710fccac [Backport release-1.6] fix(rabbitmq): right-size the default resources preset to s1.nano (#4393)
## What this PR does

Manual backport of #3936 to `release-1.6`.

The automated backport, #4372, pushed conflict markers in
`packages/apps/rabbitmq/README.md` and
`packages/system/rabbitmq-rd/cozyrds/rabbitmq.yaml` as its only commit,
so it would ship them if merged. Both are generated files, and the
conflict is the `tls` block that landed on main after 1.6 was cut.
Everything else applies unchanged, so two differences follow:

- the README parameter table and the cozyrd schema are regenerated from
the 1.6 values with cozyvalues-gen v1.6.0, so they carry the new default
and descriptions without `tls`;
- the 1.6 rabbitmq `Makefile` has no `test` target, so the helm-unittest
sweep would never enter the package and the new preset suite would not
run. The second commit adds the same two lines main already has.

Verified on this branch: the rabbitmq suite passes 4/4, `make -n test`
answers the sweep probe, and a second `make generate` produces no drift.

Change summary, unchanged from #3936: the default `resourcesPreset`
moves from `t1.nano` (128Mi) to `s1.nano` (250m CPU, 512Mi), because a
default-sized RabbitMQ 4.2 broker was OOMKilled on `t1.nano` and never
became Ready. The `resources` and `resourcesPreset` descriptions say the
preset fills every resource `resources` leaves unset.

Close #4372 in favour of this one, or tell me to take a different route
and I will.

### Screenshots

Not a UI change.

### Downstream repositories

Walked the trigger map against the diff: one app chart with a changed
default. The provider follow-up is
cozystack/terraform-provider-cozystack#34, labelled `target/1.7`.

- [ ] 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#34
- [ ]
[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(rabbitmq): raise the default resources preset from t1.nano to s1.nano so a default-sized broker is not OOMKilled. Existing brokers that never set resourcesPreset move to s1.nano on upgrade and roll their pods.
```
2026-09-23 17:58:06 +05:00
myasnikovdaniil 5a5a127fff [Backport release-1.6] fix(kafka): make topics[].config optional (#4334)
# Description
Backport of #3935 to `release-1.6`.
2026-09-23 17:58:02 +05:00
myasnikovdaniil 391425f11b [Backport release-1.6] fix(kubernetes): pin KubeVirt CSI sidecars to SIG Storage releases (#4313)
# Description
Backport of #3934 to `release-1.6`.
2026-09-23 17:57:57 +05:00
Yan Bondarenko 6ec2e052af fix(apps): bound the wait the cleanup hooks now perform
With watch granted, kubectl delete waits for the claims to be gone, and
its default for that wait is a week. A claim held by a pod that will not
stop, or a stuck detach, would hold the post-delete hook until
helm-controller's 300s uninstall budget ran out and leave the
HelmRelease stuck uninstalling.

The PVC deletes in the clickhouse, harbor, mariadb and qdrant hooks now
wait 120s at most and report the claims still terminating by name, and
each Job carries activeDeadlineSeconds 270 with a 10s termination grace
period, the numbers packages/apps/tenant/templates/cleanup-job.yaml
documents against that budget, so a kubectl that never returns cannot
hold the hook either.

The mariadb Role no longer grants watch on the named Secrets: they carry
no finalizer, so the delete never reaches the watch, and a resourceNames
rule does not authorize a collection watch anyway.

Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com>
Assisted-by: LLM
(cherry picked from commit f886f26ad4)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-09-23 13:47:21 +05:00
Yan Bondarenko a8efc0c6bc fix(apps): let the cleanup hooks watch the objects they delete
kubectl delete waits for the object to disappear unless told otherwise,
and that wait is a watch. The post-delete hook Roles of harbor,
clickhouse, mariadb and qdrant granted get, list and delete only, so
every uninstall logged a forbidden watch, the wait was skipped and the
hook reported success before the PVCs were actually gone.

The rules now carry watch for every resource the hooks delete, including
the named Secrets the mariadb hook removes.

Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com>
(cherry picked from commit 711fcc168c)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Assisted-by: LLM
2026-09-23 13:47:21 +05:00
Yan Bondarenko ac1b3c81b8 test(rabbitmq): run the chart suite on the 1.6 line
The 1.6 rabbitmq Makefile has no test target, so the helm-unittest sweep
never enters the package and the preset suite would sit there unrun.
main gained the target earlier; this brings the same two lines.

Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com>
2026-09-23 01:15:39 +03:00
Yan Bondarenko 0cfa93e58b fix(rabbitmq): right-size the default resources preset to s1.nano
A default-sized RabbitMQ 4.2 broker was OOMKilled on t1.nano (128Mi)
and never became Ready; its working set peaked at 125.8Mi. s1.nano keeps
the 250m CPU and gives 512Mi. The resources and resourcesPreset
descriptions now say the preset fills every resource that resources
leaves unset. The parameter table and the cozyrd schema are regenerated
from the 1.6 values, which carry no tls block.

(cherry picked from commit 12e64a99cd)
Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com>
2026-09-23 01:15:39 +03:00