Commit Graph
5471 Commits
Author SHA1 Message Date
myasnikovdaniil 9ad9ac0eef [Backport release-1.6] fix(backups): refuse a foreign -orig PVC and record the kept disk's reclaim policy (#5079)
## What this PR does

Backport of #4671 and #4672 to release-1.6.

- #4672 builds on #4671, so both go in one PR, picked in order.
- The test file needs the `errors` and `strings` imports on release-1.6,
one conflicting test hunk in #4672 is resolved to the original's side.

### Screenshots

Not a UI change.

### Downstream repositories

The website v1.6 backup-and-recovery page tells users to delete
`*-orig-*` PVCs to free storage, which a Retain PV does not do, and does
not mention the new reclaim-policy annotation, I will open a website
issue for it.

- [ ] 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(backups): an in-place VM restore with keepOriginalPVC now fails, before the VM is halted, when the <disk>-orig-<hash> PVC it would keep the disk under already exists and was not created by this RestoreJob (for instance one left by a deleted RestoreJob of the same name), instead of skipping the rename and restoring without keeping the current disk. Any other failure to keep a disk, including a race in which the rename read its just-created -orig PVC back through the cache and failed, now holds the restore back and retries it before its DataVolume is deleted. Previously such a restore reported success without restoring the disk. The PV's reclaim policy before the switch to Retain is recorded in the backups.cozystack.io/original-reclaim-policy annotation on the PV and the -orig PVC; set it back on the PV before deleting the -orig PVC, or its volume is not reclaimed.

fix(backups): an in-place VMInstance RestoreJob with keepOriginalPVC=false now deletes each original disk PVC, and waits for it to be gone, before Velero restores it. Previously the PVC was left in place, Velero skipped restoring its data, the RestoreJob still reported Succeeded, and the disk's HelmRelease could never recreate its DataVolume ("Destination PVC already exists"). A Velero RestoreJob now also fails before touching the application when its Velero Backup is gone or not Completed, for example after the Backup expired at its TTL.
```
2026-10-23 22:40:12 +05:00
myasnikovdaniil 92dc76dfe7 [Backport release-1.6] fix(platform): stop treating a failed ConfigMap read as a fresh cluster (#5078)
## What this PR does

Backport of #4792 to release-1.6.

- Context-only conflict in `run-migrations.sh`, the bats test and
testdata are dropped because the runner harness is not on release-1.6.
`targetVersion` is untouched.

### 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:

### 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.
```
2026-10-23 22:40:04 +05:00
myasnikovdaniil b8e8265e04 [Backport release-1.6] fix(operator): rebuild each changed ArtifactGenerator generation once (#5076)
## What this PR does

Backport of #4594 to release-1.6.

- Only the test file conflicted, an unrelated main-only test in the same
hunk is left out.

### 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:

### Release note

```release-note
fix(operator): rebuild an ArtifactGenerator once after each spec change, so an upgrade no longer leaves a component on artifacts built from the previous spec (for example a chart missing a library it now needs).
```
2026-10-23 22:39:56 +05:00
myasnikovdaniil d217770275 [Backport release-1.6] fix(api): pass the stored object to UpdatedObject in tenantsecret Update (#5075)
## What this PR does

Backport of #4603 to release-1.6.

- The original's test file does not exist on release-1.6, an equivalent
regression test is added to `rest_write_options_test.go`, where the
Update tests live on this line.

### 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:

### Release note

```release-note
fix(api): PATCH, `kubectl label` and `kubectl edit` on an existing TenantSecret no longer fail with 404 NotFound.
```
2026-10-23 22:39:49 +05:00
myasnikovdaniil ad8c630a1b [Backport release-1.6] fix(clickhouse, workloadmonitor): add the cluster domain to keeper hosts and stop a PVC nil dereference (#5065)
# Description
Backport of #4608 to `release-1.6`.
2026-10-23 22:39:42 +05:00
myasnikovdaniil d4b4216e58 [Backport release-1.6] fix(cluster-api): resync capi-operator every minute (#5081)
## What this PR does

Backport of #4939 to release-1.6.

- Clean pick, the bats test is adapted to the release-1.6 runner (no
`test_helper`). Opened by hand because labelling the original again
would re-run its release-1.7 backport.

### 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:

### Release note

```release-note
fix(cluster-api): resync capi-operator every minute so a provider left not ready across an operator restart recovers in about two minutes instead of about twenty
```
2026-10-23 20:00:59 +05:00
myasnikovdaniil 2f820f7e6a [Backport release-1.6] fix(tenant): skip Cilium policies on isp-hosted without Cilium (#5080)
## What this PR does

Backport of #4710 to release-1.6.

- The traces-central templates do not exist on release-1.6, so their
hunks and the matching unit-test assertions are dropped, a test case
that relied on a main-only cozy-lib change uses `_cluster: {}` instead.

### 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:

### Release note

```release-note
fix(tenant): the tenant chart no longer fails to install on the isp-hosted variants when the host has no Cilium. There, the Cilium network policies are created only if the host serves the Cilium policy API; otherwise tenants get no network isolation from Cozystack. Other variants are unchanged.
```
2026-10-23 20:00:52 +05:00
myasnikovdaniil 86c6c4f4a1 [Backport release-1.6] fix(linstor): mark volumes restored from a snapshot DRBD-initialized (#5077)
## What this PR does

Backport of #4866 to release-1.6.

- Only the patches README conflicted (an entry for a patch that does not
exist on release-1.6), the new LINSTOR patch is byte-identical to
main's.

### 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:

### Release note

```release-note
fix(linstor): a PVC restored from a VolumeSnapshot no longer gets a replica with an empty volume marked UpToDate. Volumes restored before this release may still have such a replica; https://github.com/cozystack/cozystack/issues/4862#issuecomment-6106661441 explains how to check and repair them.
```
2026-10-23 20:00:46 +05:00
myasnikovdaniil c10c1c87d5 [Backport release-1.6] fix(opensearch-operator): let a permanently yellow cluster restart (#5074)
## What this PR does

Backport of #4317, #4323 and #4341 to release-1.6.

- Ordered series, picked in merge order, the chainsaw e2e test commit is
dropped because release-1.6 has no OpenSearch e2e.
- Conflicts only in the Dockerfile header comments, the image directory
ends up byte-identical to main.
- On release-1.6 the opensearch chart still turns `drainDataNodes` on
for every release (main limits it to clusters with more than two data
nodes, a change that came with #2682 and is not on this line), so a
single-node cluster still cannot finish a rolling restart here. The
release note below is adjusted for that.

### 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:

### Release note

```release-note
fix(opensearch-operator): a multi-node cluster that stays yellow because of an auto-created index no longer blocks its rolling restart, the operator stops excluding a node whose drain cannot finish, and every call to the cluster's HTTP API now has a timeout. On release-1.6 a single-node cluster still cannot finish a rolling restart, that part needs a chart change that ships with the next minor.
```
2026-10-23 20:00:41 +05:00
myasnikovdaniil e218261556 [Backport release-1.6] fix(platform): accept the container gpu-operator variant in iaas (#5073)
## What this PR does

Backport of #4101 to release-1.6.

- Conflict only in comments of `packages/core/platform/values.yaml`,
release-1.6's KubeVirt settings are kept as they are.

### Screenshots

Not a UI change.

### Downstream repositories

The website v1.6 page `operations/gpu-container-workloads.md` says the
iaas bundle accepts only `default` or `vgpu`, it needs an update once
this ships, I will open a website issue for it.

- [ ] 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(platform): accept `container` as a value for `bundles.iaas.gpuOperatorVariant`, so the gpu-operator variant the platform already ships can be selected from platform values instead of a hand-crafted Package CR. The KubeVirt `HostDevices` feature gate and `permittedHostDevices` table are now emitted for the `default` and `vgpu` variants only; `container` serves GPUs to pods and gets neither.
```
2026-10-23 20:00:34 +05:00
myasnikovdaniil 9efccef357 [Backport release-1.6] fix(opensearch-operator): align DNS_BASE with the platform cluster domain (#5072)
## What this PR does

Backport of #4185 to release-1.6.

- Conflict in `packages/core/platform/templates/apps.yaml`: release-1.6
has no keda block, so only the `opensearch-operator.manager.dnsBase`
entry is added.

### 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:

### Release note

```release-note
fix(opensearch-operator): the operator's DNS_BASE now follows the platform cluster domain (`networking.clusterDomain`) instead of the upstream `cluster.local` default, so the securityconfig job and OpenSearch Dashboards reach the cluster on installations that use `cozy.local`. On upgrade, an existing `<release>-securityconfig-update` Job that is already stuck waiting on the old hostname is not recreated by the operator: delete it once by hand and the next reconcile recreates it against the new hostname. Existing certificates keep their SANs and keep working, nothing in-cluster verifies them.
```
2026-10-23 20:00:27 +05:00
myasnikovdaniil 73a5983db3 [Backport release-1.6] fix(kubevirt): route the export proxy to the Service KubeVirt creates (#5068)
# Description
Backport of #4637 to `release-1.6`.
2026-10-23 00:25:34 +05:00
myasnikovdaniil 58e22940c9 [Backport release-1.6] fix(linstor): adopt existing CR on 409 AlreadyExists in k8s backend (#5067)
# Description
Backport of #4532 to `release-1.6`.
2026-10-23 00:25:29 +05:00
myasnikovdaniil c2c9d5ee88 [Backport release-1.6] fix(backups): hold a BackupJob while its application is being restored (#5066)
# Description
Backport of #4544 to `release-1.6`.
2026-10-23 00:25:25 +05:00
myasnikovdaniil a084883200 [Backport release-1.6] fix(backups): fail Velero RestoreJob rename for non-VMInstance kinds (#5064)
# Description
Backport of #4426 to `release-1.6`.
2026-10-23 00:25:20 +05:00
myasnikovdaniil f25dc69c8c [Backport release-1.6] fix(capi): ship the core provider manifests the repository actually holds (#5063)
# Description
Backport of #4483 to `release-1.6`.
2026-10-23 00:25:16 +05:00
myasnikovdaniil ee19e8dbbc [Backport release-1.6] fix(dashboard): raise the console nginx header buffers for large OIDC tokens (#5062)
# Description
Backport of #4376 to `release-1.6`.
2026-10-23 00:25:11 +05:00
myasnikovdaniil a521806f49 [Backport release-1.6] fix(virtual-machine): guard Kube-OVN IP lookup (#5061)
# Description
Backport of #4013 to `release-1.6`.
2026-10-23 00:25:07 +05:00
myasnikovdaniil 24e23cfdaa [Backport release-1.6] fix(kubernetes): bound the remaining pre-delete hook deletions (#5060)
# Description
Backport of #3604 to `release-1.6`.
2026-10-23 00:25:01 +05:00
myasnikovdaniil d8e5b71414 [Backport release-1.6] fix(opensearch): give the securityconfig update job its own resources (#5059)
# Description
Backport of #4228 to `release-1.6`.
2026-10-23 00:24:56 +05:00
myasnikovdaniil 7da3978ead [Backport release-1.6] fix(clickhouse): assign DB_LIST so backup retention cleanup runs (#5058)
# Description
Backport of #3760 to `release-1.6`.
2026-10-23 00:24:52 +05:00
myasnikovdaniil ff40efd206 [Backport release-1.6] fix(dashboard): stop requesting offline_access so logout can revoke sessions (#5057)
# Description
Backport of #3447 to `release-1.6`.
2026-10-23 00:24:47 +05:00
myasnikovdaniil 65d6d03139 [Backport release-1.6] fix(dashboard): re-authenticate on 401 instead of failing silently (#5056)
# Description
Backport of #3115 to `release-1.6`.
2026-10-23 00:24:43 +05:00
myasnikovdaniil 9631162ea7 [Backport release-1.6] fix(kubernetes): raise kubevirt-csi API client rate limits (#5055)
# Description
Backport of #3428 to `release-1.6`.
2026-10-23 00:24:38 +05:00
myasnikovdaniil e11ff3d636 [Backport release-1.6] fix(http-cache,vpa): fix haproxy 3.3 backend name conflict and vpa-for-vpa OOM (#5054)
# Description
Backport of #2654 to `release-1.6`.
2026-10-23 00:24:34 +05:00
myasnikovdaniil 3d17c312bf [Backport release-1.6] fix(kubernetes): reconcile KCCM EndpointSlices when tenant node VMIs change (#5053)
# Description
Backport of #3500 to `release-1.6`.
2026-10-23 00:24:28 +05:00
myasnikovdaniil 75ac7c149b [Backport release-1.6] chore(etcd-operator): bump to v0.5.6 (#5052)
# Description
Backport of #4425 to `release-1.6`.
2026-10-23 00:24:24 +05:00
IvanHunters 44b443fb48 build(opensearch-operator): run the patched tree's tests under -race
The timeout tests drive a listener from one goroutine and inspect what it
accepted from another. The plain run passes an unsynchronised access there, so
nothing in this repository would catch one. The builder image carries cgo and
gcc, and the package images are built natively on x86-64 runners, so the
detector is supported where this runs.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit 48058dcc74)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:42:48 +00:00
IvanHunters 7ff67bfb9a fix(opensearch-operator): bound every call to a cluster's HTTP API
Upstream gives the operator's calls to a cluster no deadline of any kind. The
transport it builds carries no dial, handshake or response-header timeout, no
http.Client is configured, the calls the client makes on its own behalf pass
context.Background(), and the ones that take a context from the caller are
handed one with no deadline on it. A cluster that accepts a connection and then
says nothing holds such a call for as long as the process lives, and with one
worker per controller that single call stops every OpenSearchCluster from being
reconciled. The deletion that then waits out its whole termination timeout is
the visible end of it.

The bound goes on the RoundTripper, the one level every request passes through,
the ones opensearch-go builds for itself included: before a client's first
request the library runs a product check that carries a context.Background() of
its own and decodes the body of the answer, and a client is built per reconcile,
so that check runs on every one. The deadline cannot be released when RoundTrip
returns, because the body goes back to the caller still open; it rides on the
body and is released by Close, the way http.Client applies its own Timeout.

That bounds one attempt. opensearch-go retries a request up to three more times
on 502, 503 and 504 and the transport's deadline starts over on each, so the
calls carry a deadline a second time for the series: through requestContext
where the call decodes the answer before it returns, and through performRequest
where the still-open body goes back to the caller. The dial and the TLS
handshake keep a shorter bound of their own, so an unreachable node fails in a
third of the budget with an error that names what went wrong.

Each of those bounds has a test that fails when it is removed.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit 1a2c87635a)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:42:48 +00:00
IvanHunters a2805e3547 build(opensearch-operator): run the patched tree's tests in the image build
The patches under images/opensearch-operator/patches carry their own tests and
nothing runs them. The build compiles main.go, and go-unit-tests in the root
Makefile covers this repository's own Go tree, so a test file that had stopped
compiling still produced an image:

    printf 'func Broken() { this is not go }' >> restart_gate_test.go
    go build -a -o manager main.go   # exit 0

Run go test over the two package trees the patches touch before building the
binary. Both run without a cluster, and the stage takes about eight minutes on
an arm64 builder, most of it the module download the build needs anyway.

Assisted-by: LLM
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit 000e2e3121)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:42:47 +00:00
IvanHunters ce29a18dd4 fix(opensearch-operator): stop excluding a node whose drain cannot finish
The yellow restart gate carried in the previous patch lets a permanently
yellow cluster through, and with three or more nodes packages/apps/opensearch
turns drainDataNodes on. The restart then reaches PreparePodForDelete, which
excludes the candidate from allocation before it can know whether the drain
will finish. On the cluster that made the gate wait it never finishes: a shard
on that node has nowhere else to go, which is the same condition holding the
cluster yellow. The exclusion is withdrawn only after a pod is really deleted,
so a data node stays out of allocation for as long as the restart is stuck,
shedding its shards onto the rest of the cluster and buying nothing.

Ask the allocator before excluding anything, and only while nothing is moving,
so a drain that is making progress costs nothing. A started shard answering
can_move_to_other_node: no means the drain cannot finish, and then no exclusion
is written and one left by an earlier pass is withdrawn. The two-data-node path
keeps its behaviour, because it never waits for a full drain.

Checking after the fact instead would flap: the next reconcile, ten seconds
later, would exclude the node again.

Upstream as opensearch-project/opensearch-k8s-operator#1585, fixed there by
#1586; the patch goes away with the first release carrying it.

Backport: the Dockerfile header keeps release-1.6's trace paragraph,
placed between the new ones as on main.

Assisted-by: LLM
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
(cherry picked from commit 28195d3ef8)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:42:41 +00:00
Aleksei Sviridkin 4f8c0a6fda fix(tenant): skip Cilium policies on isp-hosted without Cilium
The isp-hosted variants install no CNI of their own, so on a host
without Cilium the cilium.io/v2 kinds do not exist and the tenant
install fails, taking the root tenant and everything that depends on
cozystack-basics down with it.

The policies now render on isp-hosted only when the host serves both
Cilium policy kinds. On every other variant Cozystack installs Cilium
itself, so they keep rendering unconditionally: a CRD that is missing
at render time there fails the install loudly instead of leaving the
tenant without network isolation, because helm-controller does not
re-render a release when only API discovery changes.

On isp-hosted without Cilium the tenant gets no network isolation from
Cozystack; isolating tenants is then up to the host's CNI.

release-1.6 has no shared-central tracing templates, so their hunks,
the tenant.tracingCentralEgress helper beside the new one and the
tracing cases of the test suite are left out. cozy-lib on this branch
fails on an absent _cluster, as the rest of the chart already does,
so the no-_cluster case runs with an empty _cluster instead.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
(cherry picked from commit 3b5af9dc55)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:38:43 +00:00
Mattia Eleuteri 8fcf66892b fix(backups): delete a restored disk's PVC only once the restore can run
Deleting the original PVC of a keepOriginalPVC=false restore is only
safe when Velero can put the disk back. The Backup artifact outlives
the Velero Backup it points to, which Velero garbage-collects at TTL,
and nothing checked it before prepareForRestore halted the VM and
deleted the disks: a restore of an expired backup lost the volume where
it used to fail with the disk intact. The Velero Backup must now exist
and be Completed before any preparation starts.

A DataVolume that survives its deletion makes CDI recreate the claim
under the original name, which Velero then skips as an existing PVC,
so the restore would end Succeeded on a freshly imported disk. A failed
DataVolume deletion now fails the restore, and the PVCs are deleted
only once every DataVolume is gone. Reading the DataVolume back needs
get on datavolumes, which the ClusterRole did not grant.

Assisted-by: LLM
Signed-off-by: Mattia Eleuteri <mattia@hidora.io>
(cherry picked from commit 6d064a8602)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:37:52 +00:00
Mattia Eleuteri 2844cc7595 fix(backups): delete the original PVC of an in-place VM restore without keepOriginalPVC
With keepOriginalPVC=false the restore deleted each DataVolume with
Orphan propagation and left its PVC in place for Velero to overwrite.
Velero never overwrites a PVC: its CSI restore action skips the data
mover for a claim that already exists, and existingResourcePolicy=update
fails to patch the immutable spec of a bound claim, so it only stamps
its labels on it. The RestoreJob then reports Succeeded with the disk
still holding its pre-restore data.

The claim left behind also breaks the disk for good. It has lost its
owner reference to the orphaned DataVolume, and it lacks the
cdi.kubevirt.io/storage.populatedFor annotation that the backed-up copy
carries, so the CDI webhook refuses the DataVolume the resumed
HelmRelease creates ("Destination PVC already exists"), on every
reconcile.

Delete the PVC once its DataVolume is gone, and hold the Velero Restore
until the claim has actually disappeared: one still mounted stays
Terminating behind pvc-protection, and Velero would take it for an
existing claim again.

The test file conflicted on release-1.6 only in the line the new helper
replaces, which this branch spells boolPtr(false) where main spells
new(false); the helper and both tests are taken as they are on main.

Assisted-by: LLM
Signed-off-by: Mattia Eleuteri <mattia@hidora.io>
(cherry picked from commit 6ea713d09b)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:37:47 +00:00
Aleksei Sviridkin a08713ef7e fix(platform): accept the container gpu-operator variant in iaas
The cozystack.gpu-operator PackageSource ships three variants: default,
vgpu and container. The iaas bundle's variant guard accepted only the
first two, so selecting container failed the render on a value the
package ships, values-container.yaml configures deliberately, and the
variant bats suite already covers.

The exclusion was coherent when it was written and stopped being so
immediately. The container variant and the guard landed within minutes
of each other from parallel branches, neither an ancestor of the other,
variant first. Until the guard, the bundle hardcoded the default variant
and container was selected by hand-crafting a Package CR, so leaving it
out of a bundle-side list cost nothing. The guard then made the bundle
the variant owner and closed that route without noticing it was one; its
comment describes itself as typo protection and names passthrough as the
example typo.

The KubeVirt side is not a bare allowlist edit. The container variant
serves GPUs to pods through the device plugin and runs no VM-facing
GPU stack: sandboxWorkloads and vfioManager are both off and the host
driver stays bound. Both KubeVirt-side pieces the bundle wires are
VM-facing — the HostDevices feature gate advertises a capability such
a node cannot serve, and permittedHostDevices lists resources no
sandbox device plugin registers there. Both are now emitted only for
default and vgpu, and container yields the gpu-operator Package with
the kubevirt component untouched.

Comments and docs that described the KubeVirt mirroring as
unconditional on variant, or the container variant as unmerged and
unavailable, are corrected to match.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
(cherry picked from commit 6e8566a94c)

Adapted for release-1.6: the conflict in packages/core/platform/values.yaml
sat in the kubevirt block, where main also carries a disabledFeatureGates
key that this branch does not have. The branch's kubevirt.migrations
setting is kept as it was and only the reworded gpu block comment is
taken from the original.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:36:29 +00:00
Mattia Eleuteri c66417b403 fix(backups): read the keepOriginalPVC rename back past the cache
renamePVC created the -orig PVC, then read it back through the cached
client to learn its UID. The informer had often not seen the PVC yet, so
the read failed with NotFound. On a two-disk VM restore one disk was
kept and the other was not; with that error turned into an event, its
DataVolume was deleted, the original PVC stayed in place and Velero
skipped it, and the restore reported success without restoring the
disk. The -orig PVC was left Pending on the same PV, by then Retain.

Create already returns the UID, so the read-back goes. The other reads
the rename decides on, the -orig and original PVCs and the PV, go
through the manager's uncached reader, and the PV rebind retries on
conflict, since the PV controller writes the PV once the original PVC
is deleted.

A rename that fails for any reason other than an -orig name taken by
another PVC now requeues the restore instead of failing it. The
DataVolume is still there, and the retry finds its own -orig PVC by the
RestoreJob UID and resumes where it stopped.

Assisted-by: LLM
Signed-off-by: Mattia Eleuteri <mattia@hidora.io>
(cherry picked from commit cc7f98142a)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:36:01 +00:00
Aleksei Sviridkin 19a81c399d fix(linstor): mark volumes restored from a snapshot DRBD-initialized
linstor-csi restores a snapshot on one node and autoplaces the other
replicas. In LINSTOR v1.33.3 the restored volume definition has no
DRBD_INITIALIZED flag, so the initial UpToDate race is still open, and
Linstor/Drbd/InitialUptoDateOn, copied from the source volume through
the snapshot, names the node that won it for the source. When a
replica is autoplaced on that node, the empty new volume wins the
race: it gets a random current UUID and a fresh filesystem, and goes
StandAlone against the restored replica. A pod attached there sees an
empty volume.

Backport the upstream fix, released in LINSTOR v1.34.0, which sets the
flag on a restore unless the resource definition asks for new metadata
through ForceInitialSyncPermanent, as a backup does. Nothing wins the
race any more, and an autoplaced replica resyncs from the restored one
like any replica added to an existing volume.

The patches README conflicted, because main also lists
native-protoc.diff there and this branch has no such patch. Only the
new entry is taken.

Link: https://github.com/LINBIT/linstor-server/commit/9d8cdf5118338fc72a34bb99799e452e031ea8f6
Closes: #4862

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
(cherry picked from commit e5689e2a63)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:35:54 +00:00
Mattia Eleuteri 3c67cb5a77 fix(backups): refuse a foreign -orig PVC and record the kept disk's reclaim policy
renamePVC returned early whenever a PVC named <dv>-orig-<hash> already
existed, without checking it came from this rename. The hash covers
only the RestoreJob name, so a RestoreJob created under the name of a
deleted one finds the -orig PVC its predecessor left behind. The rename
was skipped, the DataVolume deleted anyway, and the restore ran as if
keepOriginalPVC were false while reporting success: the live disk was
not kept, and the -orig name held an older one. Any other rename
failure ended the same way, since its error only became an event.

A -orig PVC now records the UID of the RestoreJob that created it. A
name held by any other PVC fails the restore before the VM is halted,
an interrupted rename of our own resumes instead of stopping halfway,
and a rename failure fails the restore before the DataVolume goes.

The PV is switched to Retain so it outlives the original PVC, and the
policy it had was discarded. Nothing in the controller deletes the
-orig PVC or restores that policy, so a PV that was Delete stayed
Retain and its volume leaked once an operator removed the claim. The
policy is now recorded on the PV and on the -orig PVC, and the restore
scenario documents how to set it back.

On release-1.6 the test file also imports strings and the apimachinery
errors package, which main's copy had already gained from earlier
commits that are not on this branch.

Assisted-by: LLM
Signed-off-by: Mattia Eleuteri <mattia@hidora.io>
(cherry picked from commit d8d9608e22)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:35:46 +00:00
Aleksei Sviridkin 8dac5a4e37 fix(platform): stop treating a failed ConfigMap read as a fresh cluster
run-migrations.sh decided whether cozystack-version exists by the exit
status of a silenced kubectl get, so a timeout or a dropped connection
counted as "no ConfigMap": the runner stamped the target version and
exited 0, and every pending migration was skipped for good. The hook Job
only renders when the ConfigMap already exists, so in practice an error
was the only way to reach that branch.

--ignore-not-found suppresses NotFound alone; any other error keeps its
non-zero status and now fails the pod, so the Job retries the read.

Backport adaptation: hack/run-migrations.bats and its fake kubectl do
not exist on release-1.6, so the test changes are dropped; the script
conflict was context only and the "Starting migrations" banner stays
above the check. targetVersion is unchanged.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
(cherry picked from commit cbbb69afc3)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:35:44 +00:00
Myasnikov Daniil da52bc0c0d fix(cluster-api): resync capi-operator every minute
A restarted capi-operator v0.19.0 drops the create events for the
provider Deployments it finds already running
(kubernetes-sigs/cluster-api-operator#1031). A provider whose Ready
condition went False while the operator was down therefore keeps it
until that Deployment changes or the informer resyncs, and the first
resync after a restart lands two periods later because the handler
registers after the informer has listed. With the 10m default that is
about 20 minutes, during which capi-providers-core times out on the
CoreProvider and everything depending on it waits; every further
operator restart starts the clock again.

With a one-minute period the same repro recovered 2m02s after the
operator took its lease, against no recovery within 4m26s with the
default on the same cluster. A resync replays the cache and, with
providers in sync, ends in "No changes detected" and an unchanged
condition, so it writes nothing to the API server; the operator logged
about 15 lines a minute and used 2m CPU and 26Mi of memory.

The upstream chart has no value for the flag, so a package patch that
make update reapplies adds one, and a bats test holds the rendered
argument.

The test is adapted for the release-1.6 runner: hack/test_helper.bash
does not exist here, so the `load test_helper` line is dropped, and the
scratch file falls back to the cozytest.sh workspace. The assertion is
unchanged.

Assisted-by: LLM
(cherry picked from commit c2dab12a2e)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:35:36 +00:00
Pujitha Paladugu 5397e0e120 fix(api): pass the stored object to UpdatedObject in tenantsecret Update
Motivation: a PATCH (kubectl patch, label, edit) against an existing
TenantSecret answered 404 NotFound while GET on the same name succeeded.
REST.Update called objInfo.UpdatedObject(ctx, nil). The apiserver patch
handler builds the patched object from that old object alone, so with nil it
takes its create-new-object branch and returns NotFound from inside the
handler. The same nil also made the patch reach admission as CREATE rather
than UPDATE.

Approach: hand UpdatedObject the stored Secret converted with
secretToTenant when it exists, and nil only when it does not (the
forceCreate path, unchanged), matching what the generic store and the
sibling application and securitygroup registries do.

Validation: added TestUpdate_PassesStoredObjectToUpdatedObjectInfo, which
drives Update with a patch-style UpdatedObjectInfo that fails on a nil old
object. It fails before the change ("UpdatedObject received a nil old
object") and passes after. Ran `go test ./pkg/registry/...` and
`go build ./pkg/... ./cmd/...`, all passing. Not run: a live cluster
kubectl patch, or the real apiserver patch handler.

Known limitation, unchanged by this fix: tenantToSecret prefers Data over
StringData when Data is non-empty, so a patch that only sets stringData on a
secret that already has data is a no-op, exactly as a GET-then-PUT edit of
stringData already is. Patching data or metadata works. That precedence is a
separate design question and is left alone here.

Report: https://github.com/cozystack/cozystack/issues/3601

Backport note: rest_write_test.go does not exist on release-1.6, so its
hunk is dropped and the regression test is added to
rest_write_options_test.go, the file that carries the Update tests on
this branch. The test body is the original's, with the fake client read
back directly because the backingSecret and testCtx helpers are absent.

Assisted-by: LLM
Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com>
(cherry picked from commit e11e239044)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:35:32 +00:00
Aleksei Sviridkin c6e6dd519d fix(operator): rebuild each changed ArtifactGenerator generation once
source-watcher builds an ArtifactGenerator from the spec it read when
its reconcile started, but its final status patch re-reads the live
object and marks Ready with the live generation. If the spec changes
during a build, which an upgrade does as it rolls out a new packages
source and new copy rules within seconds of each other, the generator
reports the new generation as built while its artifacts come from the
old one, and source-watcher never rebuilds them. A chart can then ship
without a library its templates now require.

The generator status cannot tell a stale build from a good one, so the
operator forces one rebuild of every changed generation once it
reports Ready, through the existing force-drift path. An unchanged spec
rebuilds to the same digest, so nothing downstream moves. The recovery
messages no longer name one upstream race, since they now serve two.

Upstream: fluxcd/source-watcher#384.

The conflict was in the test file only: main appends the new tests
right after TestReconcileArtifactGeneratorsLayersValuesFiles, which
this branch does not have and this change does not touch, so the
hunk is resolved to the new tests alone and that test is left out.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
(cherry picked from commit adc2dcb5ca)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:35:25 +00:00
Aleksei Sviridkin f78d3a4e1c fix(opensearch-operator): let a permanently yellow cluster restart
The operator restarts a node only when its health gate opens, and the
gate wanted green, or yellow caused by the observability index alone. A
cluster whose replicas can never be assigned reaches neither: on a single
data node any index with a replica is yellow for good, and the operator
itself turns on the audit log that creates one on the first audited
event. From then on nothing that needs a restart was ever rolled out, a
version upgrade and the move of the HTTP listener onto the cert-manager
chain included.

Upstream rewrote the gate to let a yellow cluster through once allocation
is enabled, every data node has joined and no shard is moving, and to
refuse instead to restart a node that holds the only active copy of a
shard meant to have others. No released operator carries that change, so
it is carried here as a patch against the pinned version, together with
the upstream tests for it.

Backport: the Dockerfile header keeps release-1.6's trace paragraph,
placed after the new one as on main.

Signed-off-by: Aleksei Sviridkin <f@lex.la>
Assisted-by: LLM
(cherry picked from commit d9fbeab33c)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:35:21 +00:00
Aleksei Sviridkin d39934e6e1 test(platform): pin the opensearch-operator DNS base wiring
Two ends of the same path. The platform suite pins that the shared
values Secret carries networking.clusterDomain to the operator under
the subchart key, and the package suite pins that a domain set on that
key reaches the manager container as DNS_BASE, with the upstream
cluster.local default intact when nothing sets it.

Every pattern in the platform suite anchors dnsBase to its
opensearch-operator and manager parents rather than matching the key
anywhere in the payload. An unanchored pattern is satisfied by any
sibling block that happens to carry the same domain, which leaves the
assertion green after the block it is meant to pin has been deleted.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
(cherry picked from commit b083d8e9e6)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:34:24 +00:00
Aleksei Sviridkin a285ce82af fix(opensearch-operator): resolve in-cluster names on the platform domain
The operator reads DNS_BASE and builds every in-cluster name it needs
from it: the securityconfig job target, its own OpenSearch API client
URL, the Dashboards host, and the SANs it writes into node
certificates. The vendored chart defaults that to cluster.local, so on
a cluster whose domain is cozy.local the securityconfig job never
resolves its target, the .opendistro_security index is never created,
and the OpenSearch nodes never go Ready.

The domain the platform already holds could not reach the operator
before: _cluster stops at each package's own templates and never
reaches a vendored subchart, and the wrapper's values.yaml is not
templated. Carry it in the shared values Secret under the subchart key
instead, the same way the KEDA cluster domain travels, so the vendored
chart picks it up with no patch and a package rendered without the
Secret keeps the upstream cluster.local fallback.

A global key would have worked for the operator but reaches every
release on the cluster, and the vendored smee chart in bootbox cannot
render once global is non-empty. Scoping the value to the subchart
that consumes it avoids putting every other package on that path.

The diagnosis and the first working fix came from fuad00 in an earlier
pull request.

Adapted for release-1.6: the conflict in
packages/core/platform/templates/apps.yaml is resolved by keeping only
the opensearch-operator block. The keda block it was added next to on
main does not exist on this branch and is not brought in.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
(cherry picked from commit 857ad4a128)
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-10-22 10:34:21 +00:00
Aleksei Sviridkin 8a07d509b2 fix(tenant): allow tenant egress to the KubeVirt export proxy
The vm-exportproxy Ingress is served by the ingress controller in
tenant-root, and tenant egress is default-deny. Nothing allowed traffic
to virt-exportproxy in cozy-kubevirt, so the Ingress stayed unreachable
even with the right backend Service. The new policy renders wherever
allow-to-cdi-upload-proxy does, but narrows the destination to the
export proxy pods and their container port.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
(cherry picked from commit a1416655f4)
2026-10-22 10:31:10 +00:00
Aleksei Sviridkin 1f284944e4 fix(kubevirt): route the export proxy to the Service KubeVirt creates
virt-operator names the export proxy Service virt-exportproxy. The
Ingress and the TLSRoute publishing vm-exportproxy.<host> named a
vm-exportproxy Service instead, which nothing creates, so both routes
had no backend. The public hostname stays vm-exportproxy.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
(cherry picked from commit 1e81164d0e)
2026-10-22 10:31:10 +00:00
Aleksei Sviridkin 0fd0ef0824 fix(linstor): adopt existing CR on 409 AlreadyExists in k8s backend
The fabric8 client retries a POST after a 5xx or a dropped
connection, so a create that the apiserver already persisted can come
back as 409 AlreadyExists. A single-object transaction has no
rollback entry, so the controller drops the key from memory while the
CR stays in the apiserver, and the caching client never re-reads it:
every later write of that key fails the same way until the controller
restarts.

This left a CDI scratch PV stuck in Released, because linstor-csi
starts every volume delete by setting BalanceResourcesEnabled on the
resource definition and that write never succeeded.

Treat 409 on create as success when the object exists: take its
resourceVersion and replace it with the intended content.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
(cherry picked from commit 11ba78a2b9)
2026-10-22 10:31:07 +00:00
Mattia Eleuteri 1ac8f0e61d fix(backups): match a Velero restore in its Backup's API group
The Velero driver resolves a restore's target from the Backup's
applicationRef, overriding only the kind and name, and restores the
Backup's resources. A targetApplicationRef.apiGroup never reaches it.
The restore gate honoured that group all the same, so a Velero
RestoreJob naming another group let a BackupJob of the application
actually being restored start against it, and held one of an
application the restore never touches.

Assisted-by: LLM
Signed-off-by: Mattia Eleuteri <mattia@hidora.io>
(cherry picked from commit 28e42fbe4d)
2026-10-22 10:31:05 +00:00
Mattia Eleuteri 2b22401df2 fix(backups): hold a BackupJob while its application is being restored
Nothing on the backup path looks at restores. A Plan creates its
BackupJobs on schedule, and the BackupJob reconciler dispatches them to
their driver whatever else is happening to the application. For CNPG that
is not merely a backup of a half-restored state: every BackupJob reconcile
re-applies the Cluster's barman plugin, and on a cluster under an in-place
restore it can land after the chart has re-rendered the Cluster with its
new serverName and put it back on the source's. The restored cluster then
archives onto the source's WAL prefix and its recovery fails with "WAL
archive check failed ... Expected empty archive". This was reproduced
with a backup triggered a few seconds after an in-place restore, and an
hourly plan overlaps a restore of up to thirty minutes about half the
time.

A BackupJob that has not started yet now waits while a non-terminal
RestoreJob in its namespace writes into the same application, resolved
as the drivers resolve it: the Backup's applicationRef, with the target's
kind and name when a targetApplicationRef is set, and the target's API
group only when it names one. A RestoreJob whose Backup is gone holds
nothing, since the restore controller fails it on its next pass.
options.targetNamespace is honoured only for a Backup taken by the Velero
strategy, the one driver that reads it; the CNPG and Job-based drivers
ignore the option and restore in place, so their restores hold whatever
it says.

The held job stays Pending with a Ready=False RestoreInProgress condition
naming the restore and is requeued, rather than failed, so a scheduled run
still happens once the restore ends. A failed write of that status is
returned, so the manager retries it. When the restore ends the condition is
removed before the job starts, since it would otherwise read "waiting"
until the driver next writes Ready, which for a healthy run is when the
backup completes. A run that has already started is left alone: its driver
owns state the gate would strand.

Assisted-by: LLM
Signed-off-by: Mattia Eleuteri <mattia@hidora.io>
(cherry picked from commit af8cf743cd)
2026-10-22 10:31:04 +00:00