mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-08 21:14:56 +09:00
cc51e040ae1677c3e643ad06d50bc6c5e5cce1b8
6488
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
cc51e040ae |
fix(mongodb): keep the cleanup escape hatch off legacy operator CRs, and surface a stuck finalizer
The skip-artifact-cleanup annotation reaches releaseMongoDBCleanup before the ownership check, and the operator-CR delete sat outside the finalizer gate, so a legacy backup (no delete-backup finalizer) lost its PerconaServerMongoDBBackup record when a tenant set the annotation to release a stuck Backup or applied it across a namespace during teardown. That record is what a psmdb restore-by-name resolves against, and both the RBAC comment and the docs promise it is never touched. Gate every write in the release on the finalizer being present: an unowned (legacy) CR or one that cannot be read at all is left intact, and the Cozystack Backup still releases. Surface a failed finalizer strip. The release must proceed even against an unreachable CR, but the swallowed patch error left the operator CR holding percona.com/delete-backup — pinning its namespace in Terminating, the outcome the branch exists to prevent — while the Event reported the success case. Emit a FinalizerNotStripped Warning naming the object so an operator can find it. Mark the sibling backup fields (schedule, retentionPolicy, destinationPath, endpointURL, insecureSkipTLSVerify, s3AccessKey, s3SecretKey) as ignored under useSystemBucket, so a tenant editing one instead of the flag itself is not misled by a description that describes only the legacy flow; regenerate the schema, README and mongodb-rd. Pair the insecureSkipTLSVerify rendering assertion with a case that flips the platform knob on, so the two together discriminate the rendered value from a hardcoded default. Assisted-By: LLM Signed-off-by: Andrey Kolkov <androndo@gmail.com> |
||
|
|
d58322e253 |
fix(mongodb): let the system-bucket cleanup escape hatch survive an unreadable operator CR
The two give-up paths sat behind the operator-CR Get, so a Get that hard-fails the way a removed CRD (NoKindMatchError) or a revoked verb (Forbidden) does returned the error and never reached the release — leaving a Backup that keeps its cleanup finalizer and requeues forever, exactly in the situation someone sets the escape-hatch annotation to get out of. Read the skip annotation before any apiserver call (as the Redis cleanup does) so it always releases, and classify NoMatchError alongside NotFound (as the Job/Redis cleanups do) so a missing CRD reads as "gone". releaseMongoDBCleanup now takes the CR name and treats every apiserver step as best-effort, so the release is never blocked by the same unreachable CR. Also correct the docs, which promised an automatic release when "the operator is down": only a terminating namespace or the annotation release. A down operator in a live namespace keeps the Backup in Terminating as a visible signal, which is what the code does. Assisted-By: LLM Signed-off-by: Andrey Kolkov <androndo@gmail.com> |
||
|
|
542f42ef67 |
fix(mongodb): make the system-bucket cleanup teardown-safe and single-source its ownership
Four issues in the system-bucket cleanup path. Teardown wedge. The cleanup requeued forever waiting for the operator to prune, and the escape-hatch annotation released the Cozystack Backup without touching the delete-backup finalizer the driver stamps on the operator CR. So a namespace teardown, where the operator's delete-backup step cannot run (it execs against a pbm agent that is going away), left the operator CR — and the namespace — stuck in Terminating with no way out but hand-patching finalizers. Cleanup now detects a terminating namespace (as Redis/Rabbitmq do) and, on that or the annotation, strips its own finalizer and releases, leaving the object for a bucket lifecycle policy. Needs patch on perconaservermongodbbackups for the finalizer strip. Ownership was read from two places written at different times: the finalizer (stamped when the operator CR is created) and a driverMetadata flag (written when the artifact is created, a later reconcile). If the app's useSystemBucket flag flipped between them they disagreed. Read ownership from the finalizer on the one CR named in driverMetadata (the one the driver minted): resolving it by name, never by scan, keeps the operator's own cron-* task-minted backups (which do carry percona.com/delete-backup at v1.22.0) out of scope, so the finalizer on that named CR is an unambiguous single marker. Drops the driverMetadata flag. Injection error was terminal. A transient server-side apply — an apiserver hiccup, or a conflict while the operator writes the same cluster — failed the BackupJob outright. Requeue with backoff instead, bounded by the existing deadline, matching the cluster/app read errors alongside it. Injection ran before the enabled check, mutating a cluster that can never back up. Gate it on backup.enabled so a disabled cluster is left untouched. Also: reframe the restore S3 backfill as the defensive guard it is (the pinned operator always echoes status.s3, so the live path normally carries coordinates), and correct the psmdbtypes doc that still claimed the driver never patches the operator CRs. Assisted-By: LLM Signed-off-by: Andrey Kolkov <androndo@gmail.com> |
||
|
|
f27a02f1b6 |
docs(mongodb): correct the inlined-storage story and surface the TLS knob
The strategy godoc still said the storage config is NOT inlined and the strategy only names the storage — which controller-gen copies verbatim into the CRD, so kubectl explain served the new s3 field and its own denial from one object. Rewrite it (and the StorageName field doc) to describe both flows, and regenerate the CRD. Render insecureSkipTLSVerify on the default MongoDB strategy: the field is plumbed end to end into the driver-injected storage entry and backed by a platform knob, but the template set only forcePathStyle, pinning it to false so a self-signed external S3 that Redis backups honour would fail MongoDB x509 verification. Pin it in the rendering test alongside the other s3 coordinates. Fix the useSystemBucket field description: angle brackets rendered as empty HTML tags in the README table and the dashboard schema, so wrap the path in backticks (as the postgres field already does) and note that schedule, retentionPolicy and PITR are ignored on this flow. Regenerate the chart schema, README and mongodb-rd. Assisted-By: LLM Signed-off-by: Andrey Kolkov <androndo@gmail.com> |
||
|
|
1d05dafb2e |
fix(mongodb): own and prune the system-bucket archive, and heal the restore read path
Two correctness gaps on the useSystemBucket flow. Retention. Gating spec.backup.tasks out of the chart also dropped the keep that psmdb task retention used, and an on-demand PerconaServerMongoDBBackup is not covered by task retention, so nothing pruned the shared cozy-backups bucket — a retention-swept Plan grew it unboundedly for every tenant at once. Own the archive the way the Redis/Rabbitmq drivers own theirs: stamp the operator's percona.com/delete-backup finalizer onto the backups minted on this flow, and on Cozystack Backup deletion delete that operator CR and wait for the finalizer to free the object before releasing. A legacy backup (tenant's own bucket) keeps the pre-existing hands-off no-op. Adds the delete verb on perconaservermongodbbackups and a skip-artifact-cleanup escape hatch for a wedged operator, matching the sibling drivers. Also drops the unused update verb from the psmdb cluster RBAC (server-side apply is a patch, not an update). Restore. resolveMongoDBBackupSource returned early off the live operator Backup CR whenever it reported a destination, copying status.s3 as-is. On this flow the operator can echo a destination with status.s3 empty (the storage was injected, not declared), and the target has no declared storage to resolve from either, so the restore stranded with no coordinates. Backfill a missing live S3 block from the snapshot the BackupJob recorded. Also correct the precondition godoc: the pbm agents start on spec.backup.enabled alone; the declared storage is required by the backup CR's resolution, not by the agents. Assisted-By: LLM Signed-off-by: Andrey Kolkov <androndo@gmail.com> |
||
|
|
47fe7c9630 |
test(mongodb): pin the restore credential swap and document the opt-out
The restore-time decision to re-point a backup's credentialsSecret at the
target cluster lived inline in reconcileMongoDBRestore with no test, so the
same-bucket guard that keeps a cross-flow restore from authenticating
against the wrong bucket could be dropped unnoticed. Extract it into
mongodbRestoreCredentialsSecret and cover all four
{legacy,system}x{legacy,system} combinations; neutralising the bucket
match now reddens the suite. The projected-secret skip is kept as well: a
target storage sharing the platform bucket but naming a different secret is
better restored with the platform-projected cozy-backups-creds than with
that secret.
Document the reverse toggle: flipping useSystemBucket true->false leaves
the driver-injected s3-storage on the live PerconaServerMongoDB under the
driver's field manager, which the chart does not own and never prunes. It
is inert once backups are disabled; the operator must delete it by hand to
return the release to the legacy flow.
Signed-off-by: Andrey Kolkov <androndo@gmail.com>
Assisted-By: LLM
|
||
|
|
9545bee233 |
fix(mongodb): correct system-bucket prose, pin strategy rendering, make restore credential swap flow-aware
Several comments and the useSystemBucket field description had drifted from
what the code does.
The strategy header still said the $bucketName gate was "not because it
needs the value" and that the sibling strategies needed the bucket name
while this one only asked for ordering, but the strategy now renders
bucket: {{ $bucketName }} for the injected coordinates, so it needs the
value; the precondition comment claimed the s3-storage entry exists on
backup.enabled=true, which is only the legacy flow. The rendering-test
comment carried the same "needs no bucket coordinates" claim. The
useSystemBucket field description said injection happens "at first BackupJob
time" (it now runs on every BackupJob) and that backups scope to
<namespace>/<release> (the prefix templates the application name, not the
release), and it ran ~700 chars of implementation detail into the CRD that
backup-classes.md already carries; trimmed and corrected, then regenerated
schema/README/types/cozyrds. Same <release> slip fixed in the driver
comment and the docs.
Nothing asserted the new strategy rendering. Added the MongoDB row to the
endpoint-form suite (s3.endpointUrl, scheme preserved both ways) and field
assertions to the rendering suite — bucket, endpointUrl, region,
credentialsSecret, forcePathStyle, and prefix, which must reach the CR as a
literal go-template string so the driver can template it per-application;
a stray brace would empty it with every doc-count test still green.
The restore credential swap broke across flows. It replaced the source
credentialsSecret with whatever the target declared, comparing no buckets,
so a system-bucket backup restored into a legacy target kept the platform
bucket against the tenant's own -s3-creds, and a legacy backup restored
into a system-bucket target got cozy-backups-creds against the tenant
bucket - both AccessDenied. Skip the swap when the source already names the
platform-projected cozy-backups-creds (it outlives the source app, nothing
to repair), and only adopt a target credential whose storage is on the
same bucket as the archive. psmdbStorageS3 now reads .s3.bucket alongside
.s3.credentialsSecret; TestPsmdbTargetCredentialsSecret covers the match,
the cross-bucket refusal, and the empty-bucket no-op.
Also drop the post-apply re-Get: the typed SSA Patch decodes the server's
merged object back into the passed struct, so the precondition reads the
injected storage from it instead of a follow-up Get that hit the informer
cache and briefly reported Ready=False on the happy path.
Signed-off-by: Andrey Kolkov <androndo@gmail.com>
Assisted-By: LLM
|
||
|
|
4ea4888685 |
fix(mongodb): key system-bucket injection off the app flag, not live storage
The MongoDB backup driver decided what to inject and what to record from the live cluster's storage set rather than from the app's opt-in flag. That had three consequences. The snapshot fallback fired for legacy apps too. Its gate was `snap.S3 == nil && rendered.S3 != nil`, but the coordinates moved onto the shared cozy-default strategy, so rendered.S3 is now non-nil for every MongoDB app. A legacy backup written to the tenant's own bucket got its snapshot rewritten to the platform bucket, sending restore to the wrong place. Gate the fallback on the app's backup.useSystemBucket flag instead, threaded through createMongoDBBackupArtifact, and pin the legacy case. The injected storage never caught up with the strategy. Injection was gated on the named storage being absent, so it ran once per cluster and froze the coordinates at the first backup; a later endpoint/region change or bucket re-provision was a silent no-op, and Helm could not repair it because the useSystemBucket chart renders no storages. Key injection off the app flag and re-apply on every BackupJob (the prefix is deterministic, so this never splits the archive the way CNPG's serverName would). Add UseSystemBucket to mongodbapp.MongoDBSpec so a legacy app is protected by the flag, not by whatever happens to be on the cluster. The docs said the opposite of what the driver does. backup-classes.md claimed "the MongoDB driver cannot inject its S3 target per-backup"; correct it and add an opt-in-to-the-system-bucket section that names which values stop being read and that scheduled backups + PITR must move to a Plan. Fix the endpoint table row, the tuning reference, the RBAC comment that said the driver never patches, the strategy header/inline comments, and the example comment. Also assert notExists on spec.backup.pitr in the helm test, and lift the duplicated cozy-backups-creds default into a const. Signed-off-by: Andrey Kolkov <androndo@gmail.com> Assisted-By: LLM |
||
|
|
c036efaa5a |
test(mongodb): cover system-bucket storage injection gate and builder
Extract the two untested contracts from applyMongoDBSystemStorage into
pure functions and unit-test both, mirroring the CNPG driver's
buildBarmanObjectStore split:
- shouldInjectMongoDBSystemStorage decides whether the driver injects the
system-bucket storage; the tests pin both branches, including the one
that leaves a legacy app's manual bucket untouched.
- buildMongoDBSystemStorageEntry builds the {type:s3,s3:{...}} entry,
defaulting credentialsSecret and omitting forcePathStyle when nil.
Also add a helm-unittest for the restore.yaml guard rejecting
bootstrap.enabled together with backup.useSystemBucket.
Signed-off-by: Andrey Kolkov <androndo@gmail.com>
Assisted-By: LLM
|
||
|
|
730592f323 |
feat(mongodb): support the system-bucket backup flow (useSystemBucket)
MongoDB was the only cozy-default app with no useSystemBucket flow: its backup storage was always static on the app CR (bucket/endpoint/creds from backup.* values + a chart-emitted <release>-s3-creds Secret), so a tenant could not back up to the platform system bucket out of the box the way postgres/clickhouse/etc. do. PBM takes bucket/endpointUrl/region/prefix as static CR fields (not secret refs) and the platform bucket name/endpoint are only known at BackupJob time, so - unlike ClickHouse's runtime env secretKeyRef - the chart cannot render them. The fix mirrors the CNPG driver: the chart adds a useSystemBucket flag that keeps spec.backup.enabled (so the pbm agents run) but omits the static storages/tasks/pitr and the creds Secret; the cozy-default MongoDB strategy carries the coordinates (endpointUrl already scheme'd by the endpoint helper, credentialsSecret cozy-backups-creds); and the psmdb driver SSA-injects spec.backup.storages[s3-storage] onto the live PerconaServerMongoDB at BackupJob time under its own field manager with ForceOwnership, so a Flux re-render never reverts it. Injection is gated on the storage being absent, so a legacy app that ships its own static storage is left untouched. The backup snapshot falls back to the strategy coordinates when the operator status echo is empty, so the restore path rebuilds backupSource (credentialsSecret cozy-backups-creds is projected into the restore namespace before dispatch). RBAC grows patch/update on perconaservermongodbs for the injection. A bootstrap.enabled + useSystemBucket render guard mirrors postgres. Signed-off-by: Andrey Kolkov <androndo@gmail.com> Assisted-By: LLM |
||
|
|
cd91627c78 |
feat(marketplace): register a tapped repository's apps on connect (#4308)
## Problem Connecting a marketplace repository materialized its `PackageSource` but created no `Package`, so its `ApplicationDefinition`s never rendered and its apps never appeared in the dashboard catalog until a manual `cozypkg add`. The dashboard cannot drive that step: the package list it shows is computed from the `ApplicationDefinition`s, which do not exist yet, a chicken-and-egg that leaves a connected repository unbrowsable. ## Fix The tap materializer creates a tap-managed registration `Package` for each materialized `PackageSource` that has a `default` variant, the same way the platform ships a `Package` per built-in app. Its install-marked components (the `ApplicationDefinition` registrations) deploy on connect, so the apps become browsable; the app components carry no `install` block and are still instantiated per user resource, so registration deploys no user workload. Privileged install components are not installed without confirmation. The check is at the install site: the Package reconciler skips a privileged install component of a Package that still carries the marketplace-tap label (a tap auto-registration the operator has not confirmed) and reports `Ready=False PrivilegedNotConfirmed`, and `resolvePrivilegedNamespaces` gates the PodSecurity label on the same predicate. `cozypkg add --allow-privileged` sheds the label (an explicit ownership handover), which is the confirmation; a platform Package never carries the label. Putting the check where the install happens closes the window a materializer-side guard would race, so the earlier install-safety de-register machinery is removed. Two further best-effort layers close the paths a lingering artifact or release could take when a source revision flips a previously benign component to privileged: `cleanupOrphanedHelmReleases` treats an unconfirmed privileged component as not-desired and removes a HelmRelease left from an earlier benign revision, and the PackageSource reconciler withholds a privileged component's `ExternalArtifact` until confirmed (re-running on confirmation through a Package watch), so the helm-controller has no privileged content to upgrade to. A component flipped to privileged in a new revision can still be materialized by source-watcher before any reconciler observes the flip; closing that race fully requires decoupling the catalog registration from install, tracked in #4359. `cozypkg untap` and the dashboard disconnect remove the registration `Package` too, so the apps de-register (its registration HelmReleases and their `ApplicationDefinition`s are garbage-collected); running instances are left in place but unmanaged until re-tapped, the same outcome as `cozypkg del`. Teardown deletes the Package under a UID + ResourceVersion precondition with a re-classify-on-conflict retry, so it never clobbers a Package a concurrent `cozypkg add` handover has just confirmed. `cozypkg add` re-opens a tap auto-registration for variant selection and hands it over to the user. ## Verification - The install-site privileged gate is covered by a Package-reconciler test (a managed registration with a privileged default variant creates no privileged HelmRelease and does not raise the namespace; a confirmed Package installs) and is mutation-verified. - The two best-effort layers each have a mutation-verified test: cleanup of a HelmRelease left when a benign component flips to privileged, and withholding of a privileged component's `ExternalArtifact` while the registration is unconfirmed (a non-tap platform source is never gated). - The `cozypkg add` handover is covered by a test asserting the tap label, the source annotation and the PackageSource ownerRef are shed and the variant pinned. - The teardown delete precondition is covered by a test in which a handover lands between the read and the delete; the precondition makes the delete conflict and the retry re-classifies and spares the user's Package. Earlier end-to-end on a dev cluster (predates the install-site refactor and the layers above) with a real public demo repository `oci://docker.io/999669/cozy-gitea:v1.0.0` confirmed the connect→auto-register→instance→disconnect flow: `cozypkg tap` alone registered the app within ~10s; a `Gitea` instance reached Ready and served `/api/healthz`; `cozypkg untap` de-registered it and left the running instance. etcd healthy, `cozystack-platform` untouched. ```release-note Tapping a marketplace repository now registers its applications in the catalog on connect, without a manual `cozypkg add`. ``` |
||
|
|
aa20495df3 |
feat(marketplace): register a tapped repository's apps on connect
Connecting a marketplace repository materialized its PackageSource but created no Package, so its ApplicationDefinitions never rendered and its apps never appeared in the dashboard catalog until a manual `cozypkg add` the dashboard cannot drive (the package list is computed from the ApplicationDefinitions, which do not exist yet). The tap materializer now creates a tap-managed registration Package for each materialized PackageSource, the way the platform ships a Package per built-in app, so the ApplicationDefinition registrations deploy on connect and the apps become browsable; the app components carry no install block and are still instantiated per user resource. Privileged install components of an unconfirmed tap auto-registration (a Package that still carries the marketplace-tap label) are refused on several best-effort layers: the Package reconciler skips their HelmRelease and prunes a lingering one at the install site, and the PackageSource reconciler withholds their ExternalArtifact so the helm-controller has no privileged content to deploy, re-running on confirmation via a Package watch. `cozypkg add --allow-privileged` sheds the label as an explicit ownership handover, which is the confirmation; a platform Package never carries the label. A benign component flipped to privileged in a new revision can still be materialized by source-watcher before these layers observe the flip; closing that race fully requires decoupling the catalog registration from install and is tracked in issue #4359. `cozypkg untap` and the dashboard disconnect remove the registration Package (de-registering the apps) under a UID + ResourceVersion precondition, so a concurrent `cozypkg add` handover is never clobbered; running instances are left but unmanaged. `cozypkg add` re-opens a tap auto-registration for variant selection and hands it over. The cozystack-api ClusterRole gains delete on packages for the disconnect path. Assisted-by: LLM Signed-off-by: IvanHunters <xorokhotnikov@gmail.com> |
||
|
|
92d2eede52 |
test(opensearch): separate the mount-plan rewrite from the roll onto it (#4279)
## What this is
`Refs #4259`. A diagnosis of the opensearch suite timeout plus the one
in-repo change it warrants: making the failing step say which of its two
candidates actually happened. It does **not** claim to fix the root
cause — see "What this does not do".
## What the run actually showed
The `verify-statefulset-rolled-onto-the-new-mount-plan` assert erred
with exactly two field failures, both under `status`: `(currentRevision
== updateRevision): false` and `updatedReplicas: field not found`. No
volume field appears in the error list, and `readyReplicas: 1` shows as
an unchanged line, so the pod was Ready at the deadline and nothing had
replaced it. Per e2e-testing.md ("Reading a failure diff: the actual
side is a projection"), the real cause is the error line, not the diff —
and a Chainsaw diff projects the live object onto the expected fields,
so the three `http-ca` / `http-cert` / `http-key` lines showing in the
diff are the expected tree, not proof the volumes are absent. Read that
way, the volume assertions matched: the three volumes were present on
the live template. The "volumes missing" reading is the projection trap
the doc warns against.
## Which candidate
Candidate (b): the template was rewritten onto the subPath mount plan,
and the operator has not restarted the pod onto it. This is consistent
with the source, traced against opensearch-k8s-operator v2.8.0 as
vendored:
- The chart renders the CR correctly — `generate` dropped, `secret` and
`caSecret` named — proven by
`packages/apps/opensearch/tests/tls_upgrade_test.yaml`.
- Given that CR, `pkg/reconcilers/tls.go` `handleHttp` appends exactly
the three volumes the step asserts (`http-ca` from
`opensearch-test.http-ca`, `http-key` and `http-cert` from
`opensearch-test-http-server`), and `pkg/reconcilers/cluster.go`
`reconcileNodeStatefulSet` writes that template onto the StatefulSet.
Three branches return ahead of that write — no node-pool config hash,
the `opensearch.role` recreate, and parallel recovery — but the
parallel-recovery gate is `ReadyReplicas < replicas-1`, unreachable at
one replica, so the write happens. The reconcilers that run ahead of the
cluster reconciler do not stop it either: the TLS reconciler runs first
and returns the admin-certificate path's result, empty in the ordinary
case, and `securityconfig.Reconcile` short-circuits to nil when the
security-config checksum is unchanged, which the move does not change.
So the operator does write the volumes.
- The nodePool StatefulSet is `OnDelete` (`pkg/builders/cluster.go` sets
`UpdateStrategy.Type: OnDelete` alongside `PodManagementPolicy:
OrderedReady`), so the StatefulSet controller never deletes the pod to
apply a template change: `podManagementPolicy` orders creation and
deletion during scaling, `updateStrategy` decides the update. The roll
is the operator's rolling-restart reconciler's to drive
(`pkg/reconcilers/rollingRestart.go`) — it deletes the pod itself. It
needs `status.Initialized`, it needs `ReadyReplicas == replicas` (a
Ready pod is a precondition, not the blocker), then it opens a client to
the OpenSearch API and calls `CheckClusterStatusForRestart`, which holds
the restart while the cluster is red; on yellow the gate now enables
shard allocation, waits for every data node to join, waits for shard
activity to settle, then proceeds (#4317 deleted the old
`.opensearch-observability` carve-out, and this suite builds the
operator with that patch). Any of those gates can sit indefinitely.
`status.currentRevision` never advances by itself under `OnDelete`; the
operator patches it once `updatedReplicas == replicas`, so the second
assert's own condition cannot go true unless that reconciler ran to the
end.
- The pod's startup probe is a TCP check on 9200
(`builders/cluster.go`), so "connection refused" is OpenSearch not
listening, not a probe-scheme mismatch. The plaintext `GET / HTTP/1.1`
from `curl/8.5.0` on the TLS listener is neither the startup/liveness
probe (TCP) nor the readiness probe (`curl -k https://localhost:9200`,
localhost, HTTPS) — it is external traffic to the LoadBalancer address,
a red herring for the stall.
## What this changes
The step now runs two asserts instead of one. The first waits for the
operator to rewrite the template onto the three volumes, on a
reconcile-scale budget (6m) — a failure here is the operator not writing
them (candidate a). The second waits for the roll to complete onto that
template, on the pod-lifetime budget (12m) — a failure here with the
first green is the roll not completing (candidate b): the operator never
restarting the pod, which the rolling-restart reconciler holds while
`CheckClusterStatusForRestart` reports the cluster red — on yellow the
gate enables shard allocation, waits for every data node to join, waits
for shard activity to settle, then proceeds — or a replacement that was
deleted but never came Ready. The second assert carries the three volume
projections and `observedGeneration == metadata.generation` as well, so
the roll is pinned to the template the first assert checked rather than
to whatever revision is current when the status converges. The suite
`catch` also captures the StatefulSet as YAML and as a describe, and the
operator's own log, because `updateRevision`, `currentRevision`,
`generation` and `updatedReplicas` are what separate the two halves —
describe alone omits them — and the restart decision is logged in the
operator, not in the cluster pods. The reconciler logs `Starting rolling
restart of the StatefulSet` (`rollingRestart.go:155`) once its early
gates (`Initialized`, ready-replica, update-pending) pass; it builds its
OpenSearch client just before, at `:138`, and that client pings the
cluster — so a run whose log lacks `Starting rolling restart` either had
an earlier gate hold it silently or had the client ping fail loudly, not
only the former, while that line present followed by a `Couldn't proceed
with rolling restart ... because <reason>` line names a health-stage
hold (the health gate is `CheckClusterStatusForRestart`, and it is not
the last: `PreparePodForDelete` follows it). The operator-log `tail` was
raised so it spans the whole assert window rather than a third of it.
## What this does not do
It does not fix the stall; #4317 does, and is already merged. The run
that captured this (`Run E2E tests`, job 104576486900) shows the
rolling-restart reconciler holding on health: the manager logged
`Starting rolling restart of the StatefulSet opensearch-test-nodes`
(`rollingRestart.go:155`, printed only after the `Initialized` and
ready-replica gates passed) and then, every ten seconds to the deadline,
`Couldn't proceed with rolling restart ... waiting for health to be
green` (`os_data_service.go:180`), which is reached only after
`GetFlatClusterSettings` returned 2xx (`os_client.go:224` makes anything
else an error). So the operator reached the cluster and the cluster
answered; health held the restart. #4259 established why, and the CA
move plays no part: on a single data node the bootstrap node leaving is
audited into a fresh `security-auditlog-*` index with one replica, that
replica has nowhere to go, the cluster stays yellow for good, and the
v2.8.0 restart gate opens only on green (or on a yellow
`.opensearch-observability`) so it never opens. #4317 backports
opensearch-project/opensearch-k8s-operator#1569 to fix that gate; this
PR is only the diagnostic split that names which half of the roll a
failure is. The split content itself is not the failure: on `49f3f059f`
both asserts passed, the second after 1m47s, and this change touches
only the step's comments and the operator-log tail, not the assertions.
With this change in place, a future occurrence names the half, and the
catch carries the roll's own fields and the operator log, so the
crust-gather can be read against a specific claim rather than an
ambiguous one.
### Release note
```release-note
NONE
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Tests**
* Improved OpenSearch StatefulSet failure diagnostics by capturing YAML,
detailed resource descriptions, and the latest operator pod logs.
* Expanded rolling-restart verification to check volume projections,
template updates, rollout readiness, observed and metadata generations,
and revision consistency.
* Separated template validation from rollout completion checks with
dedicated six- and twelve-minute time limits.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
||
|
|
e32353e839 |
docs(agents): correct the labeler's trigger list (#4090)
## What this PR does The PR Title Auto-Labeling section still lists `edited` among the events `.github/workflows/pr-labeler.yaml` runs on. That trigger was dropped in #3211 — the workflow carries the note at the top of its `on:` block, and the v1.6.0 changelog records the change — so the document and the workflow have disagreed since. I hit it the way the document's intended reader would. Three PRs opened with GitHub's branch-derived titles, corrected afterwards to Conventional Commits, and the labels did not follow: `area/uncategorized` on all three and no `kind/feature`, because nothing re-ran. The second paragraph this PR adds is that consequence, which is the part a contributor actually needs: a corrected title does not re-label until the next push or a reopen, and since the labeler only ever adds, the `area/uncategorized` left by the first title stays until a human removes it. ### Screenshots Not applicable — no UI change. ### Downstream repositories I walked the trigger map in `docs/agents/contributing.md` against this diff. The only file it touches is that document, and the two triggers pointing at it are narrower than this change: `cozystack/community` restates the **commit convention** from it (types, scopes, sign-off, the `Assisted-by: LLM` trailer) and the **PR template and downstream checklist**, and `cozystack/ccp` gates its `package-bump` skill on the same commit convention. Neither restates the labeler's event list, which is what changes here. Nothing else in the map reaches a docs-only change. - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note NONE ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Documentation** - Clarified when pull request title auto-labeling runs. - Documented that title edits do not trigger relabeling. - Explained that existing labels remain until a push or reopen, while additional uncategorized labels require manual removal. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
6cd78b0e30 |
feat(platform): make the Keycloak realm name configurable (#4237)
## What this PR does Fixes #4216. The Keycloak realm name `cozy` was hardcoded across every SSO component, so operators could not rename the realm without patching vendored templates that `make update` reverts. The kube-apiserver OIDC issuer is already configurable out-of-band via talm `oidcIssuerUrl`, which made the mismatch worse: pointing the apiserver at a custom realm left the dashboard, linstor-gui and the generated kubeconfig on `cozy`, so SSO broke with an issuer mismatch. This adds a single `authentication.oidc.realmName` (default `cozy`) to the platform Package values and threads it through the `_cluster` channel so every consumer resolves the same realm: keycloak-configure (realm, clients and `cozystack-cluster-admin` roles), the dashboard and linstor-gui gatekeepers (issuer/login/logout URLs), the info kubeconfig, and — beyond the components listed in the issue — the Grafana and managed-Kubernetes apiserver OIDC issuers, which carried the same hardcoded `/realms/cozy` in their `_helpers.tpl` and would otherwise have left SSO half-broken. `keycloakInternalUrl` is now derived from `realmName` when left unset, so the realm is named in one place. Its default changed from the literal in-cluster URL to `null` with a documented tri-state: `null` derives `http://keycloak-http.cozy-keycloak.svc:8080/realms/<realmName>`; `""` keeps the existing escape hatch that restores external OIDC discovery; any explicit value is used verbatim. A stock cluster renders the byte-identical `keycloak-internal-url` it did before, so existing clusters are unaffected on upgrade. The Kubernetes CR object names (`keycloakrealm-cozy`, `keycloak-cozy`) and the `realmRef` that clients point at are internal resource names, not the realm's technical name, and stay fixed — the EDP operator resolves clients into the renamed realm through the unchanged `realmRef`. Covered by helm-unittest across all seven affected packages, written test-first (red → green, mutation-verified): default stays `cozy`, a custom realm reaches every URL, the derived internal URL follows `realmName`, the `""` escape hatch survives a custom realm, and a numeric/reserved realm name stays a string. `packages/extra/info` had no unit-test target, so one was added. ### Downstream repositories `cozystack/website` needs a follow-up: `content/en/docs/next/operations/configuration/platform-package.md` is a hand-written table of the `spec.components.platform.values.*` keys and does not yet list `authentication.oidc.realmName`. Leaving the box unticked for a maintainer to action rather than filing a speculative PR. - [ ] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: document `authentication.oidc.realmName` in `platform-package.md` - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note feat(platform): the Keycloak realm name is now configurable via `authentication.oidc.realmName` (default `cozy`), threaded consistently through the apiserver OIDC issuer, dashboard, linstor-gui, Grafana, the managed-Kubernetes apiserver and the generated kubeconfig. Set it to the same realm as the talm `oidcIssuerUrl`. The `authentication.oidc.keycloakInternalUrl` default changed from the literal in-cluster URL to `null`, which now derives `http://keycloak-http.cozy-keycloak.svc:8080/realms/<realmName>`; clusters that leave it unset render the identical URL as before, and `""` still selects external OIDC discovery. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added configurable Keycloak realm support across OIDC integrations, including Kubernetes, dashboards, monitoring, kubeconfig, and authentication services. * The realm defaults to `cozy` and can be customized through platform authentication settings. * Internal Keycloak URLs are derived from the configured realm when not explicitly provided. * Added realm-name validation and support for explicitly disabling derived internal URLs. * **Documentation** * Updated OIDC guidance to describe configurable realm behavior and defaults. * **Tests** * Added coverage for custom realms, defaults, validation, and generated OIDC URLs. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
6677c24beb |
fix(ci): fail the trailer check on an empty commit range (#4278)
## What `hack/check-commit-trailers.sh` printed `Commit trailers OK: 0 commit(s) checked.` and exited 0 when the range it was given resolved to zero commits, so a run that examined nothing was indistinguishable from a clean run. An empty range now prints a message naming the empty case and exits 1. ## Why The documented pre-push recipe in `docs/agents/contributing.md` is `hack/check-commit-trailers.sh origin/main..HEAD`. The range is resolved in the process working directory, so an agent whose shell sits in a different checkout than the branch resolves it against the wrong `HEAD` and gets nothing — and the old green there was a green nobody could tell from a real one, defeating the check precisely when the checkout is misconfigured. The CI path is unaffected: `.github/workflows/pre-commit.yml` builds the range from a pull request's merge base and head SHA, which GitHub refuses to open with no commits between the two, and which goes empty only once the base has absorbed the head's commits and there is nothing left to merge, where a red trailer check is harmless. ## Test TDD, bats: the previously buggy `accepts an empty range` test is inverted into `fails on an empty range instead of reporting OK`, which asserts a non-zero exit, that the message names the empty case, and that the `Commit trailers OK` line is absent. Mutation-verified — removing the guard turns it RED, restoring it turns it GREEN. Full suite: 28 passing, 0 failing. ## Release note ```release-note Local runs of `hack/check-commit-trailers.sh` now fail on an empty commit range instead of reporting OK, so the documented pre-push check no longer passes silently when it examined nothing. ``` Fixes #4263 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Bug Fixes** - Commit trailer checks now fail when the specified commit range contains no commits. - Empty ranges no longer report a misleading successful validation. - Error output clearly indicates that no commits were checked. - **Tests** - Added coverage confirming empty commit ranges return a failure status and appropriate diagnostic output. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
a1b32f2e5a |
ci(workflows): build Talos only when its sources changed (#4021)
Stacked on #4020, not independently mergeable. Nothing on the same-repo PR path consumes either half of what `build-talos` produces. `image-talos` pushes `${REGISTRY}/talos:pr-N-sha`, which no chart in the tree references and which is not even version-tagged here (`PUBLISH_VERSIONED` and `PUBLISH_FLOATING` are both 0). `image-matchbox` stamps `packages/extra/bootbox/images/matchbox.tag`, and that one line is the whole content of `pr-patch-fragment-talos` - checked against the artifact from a real run - but bootbox is opt-in and the E2E platform Package does not enable it, so no run pulls the image. Unstamped tag leaves installer artifact pointing at released matchbox, which is a valid ref nothing on this path resolves. So the job ran a privileged siderolabs imager build on every PR for two artifacts with no reader. Now it runs when the PR touched `packages/core/talos`, and `finalize` accepts a skipped result as well as a successful one. Without that second half skipping it would block finalize, and therefore e2e, on nearly every PR. Forks keep the unconditional build, and the reason is not about talos. `e2e-fork.yaml` publish job requires at least one OCI archive to exist, an invariant that holds today only because this job always ran, so a fork PR touching nothing under `packages/` would arrive with an empty export and fail a legitimate run. Teaching that guard what `plan` expected to build is work in the fork allowlist path and belongs in its own change. Saving is about 1.5-2 min of critical path. Main point is removing a privileged image build that nobody reads from every pull request. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **CI Improvements** - Pull request validation now runs Talos builds only when relevant changes require them, while retaining full validation for fork-based contributions. - Finalization correctly handles skipped Talos builds and preserves generated boot artifacts when builds succeed. - Changed-file detection now accounts for renames, deletions, and shared build inputs. - **Documentation** - Updated testing and build guidance to reflect the current validation behavior. - **Tests** - Added comprehensive coverage for build classification, workflow outputs, skipped jobs, and artifact handling. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
7fd8376ccb |
fix(ci): fail the trailer check on an empty commit range
The pre-push recipe resolves origin/main..HEAD in the process working directory, so an agent whose shell sits in a checkout at or behind the base resolves it to zero commits and the check printed "Commit trailers OK" with exit 0. A run that examined nothing was indistinguishable from a clean one, defeating the recipe exactly when the checkout is wrong. Treat an empty range as a named failure so the misconfiguration is loud; the CI path is unaffected because it builds the range from a pull request's merge base and head, which is empty only once nothing is left to merge. Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
142a14cb69 |
fix(platform): reject an empty realm name instead of coercing it to cozy
realmName resolved through `| default "cozy"`, which fires on both null and "". Unset (null) legitimately means the default, but an explicit "" is a meaningless value and coercing it hid the mistake. Split the two: null falls back to cozy, an empty string reaches the charset guard and is rejected — the same null-vs-"" distinction keycloakInternalUrl already draws a few lines below. Assisted-by: LLM Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
ff637ed9a2 |
fix(platform): validate the realm-name charset and regenerate kubernetes artifacts
The realm-name guard checked only the type and echoed the parsed value back, so its hint told an operator who wrote `on` to set realmName: "true" — the token YAML had already discarded. Drop the echo and add a slug-charset check: the name is spliced verbatim into URL path segments and a shell token, so a "/" or a space must be rejected at the source rather than split a URL or the hook script downstream. The description edit in the previous commit was hand-applied to the generated kubernetes README and never reached the Go types, leaving pre-commit red; regenerate both with cozyvalues-gen. Finish the oidc-tenant System-mode prose that still read cozy as a fixed name. Assisted-by: LLM Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
949096694b |
fix(platform): reject non-string realm names and shell-quote the hook realm
A realmName that YAML resolves to an int or a bool (a bare 123, or a reserved word like on/off) was coerced with toString, silently renaming the realm to something the operator never typed (on -> "true"). Fail the render with a quoting hint at the source instead of surfacing it later as a broken issuer URL. The update-email hook Job interpolated the realm into its shell script unquoted, so a name carrying a space or a shell metacharacter could break or inject into the script; single-quote it. The Grafana and managed-cluster issuer helpers build the URL with printf %s straight off the channel value, so guard them with toString for the same non-string reason. Name the configured realm in the tenant kube-apiserver oidc.mode description and the Grafana identity-mode comment, which still read cozy as if it were fixed. Assisted-by: LLM Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
a3df02df23 |
fix(kubernetes): name the configured realm in the OIDC denial message
The claimValidationRules message in the System-mode AuthenticationConfiguration hardcoded "in the cozy realm", so on a renamed realm it told a rejected user to look in a realm that no longer exists. Build it from the same realm the issuer uses (toString-guarded, as the derived issuer URL already is). Assisted-by: LLM Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
80d32b3ab7 |
fix(keycloak): complete realm-name coverage and guard non-string names
The enable-update-email hook Job in keycloak-configure still pinned REALM=cozy, so on a custom realmName it waited on a realm the chart never provisions and the cold install timed out — the one seventh consumer left behind, and the only value nobody could set without breaking the install. A bare-integer or YAML-reserved realm name reached the printf %s that builds the derived keycloakInternalUrl as a Go int, rendering a "%!s(...)" format error into the URL; coerce the name to a string once at the source. Document that renaming the realm on a running cluster provisions a fresh empty realm and orphans the accounts in the old one, and note in the OIDC tenant and grafana guides that the realm name is now the configurable default. info/Makefile carried NAME=etcd, so cozyhr drove the wrong release from that package; correct it while touching the file. Assisted-by: LLM Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
44a9a8e735 |
feat(platform): make the Keycloak realm name configurable
The realm name "cozy" was hardcoded in keycloak-configure (which owns the realm, its clients and the cozystack-cluster-admin roles), in the dashboard and linstor-gui gatekeepers, in the info kubeconfig, and in the Grafana and managed-Kubernetes apiserver OIDC issuers. Operators could not rename the realm without patching vendored templates, which `make update` reverts. The apiserver OIDC issuer is already configurable via talm oidcIssuerUrl, so pointing it at a custom realm left every SSO component on "cozy" and broke login with an issuer mismatch. authentication.oidc.realmName (default "cozy") now rides the _cluster channel so every consumer resolves the same realm, and the default keycloakInternalUrl is derived from it so the realm is named in one place. Assisted-by: LLM Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
8799a4e4aa |
fix(cluster-api): backport live migration before host eviction (#4291)
## What this PR does CAPK v0.1.10 handles host eviction by draining and deleting the guest VMI. It also looks up the physical host name in the guest cluster, and a recreated guest can remain cordoned. Backport CAPK #374, #389 and #392 onto the current provider API and runtime, with separate bounded submission, active migration and fallback windows, and ordinary VMIM objects without a priority, a field the pinned `kubevirt.io/api` v1.5.0 does not carry. The submitted VMIM deadline survives reconciliation; expired, invalid or legacy marker values enter the existing fallback path. Add the manager build to the package pipeline, read its digest pin through the provider imageUrl override, and ship VMIM create permission in the compressed provider manifest. Source tests and four packaging checks pass, including failed-build pin preservation and the rendered ConfigMap payload. The regression tests include unprocessed submissions, legacy and invalid deadline values, repeated reconciles, and a fresh active migration window after submission expiry. The updated manager also cross-compiles for linux/amd64 with Go1.26.4. The previous OCI build predates the submission-deadline correction and does not validate an image containing this change. The updated source still needs the maintainer-owned image build described below. The checked-in pin still identifies the original upstream image, so installing this source chart directly does not enable the backport. The regular main and release builds now include this package, stamp the built image digest, and package that exact artifact; the release workflow also commits the generated pin. Pre-merge E2E validation needs a maintainer-owned build because fork publication only allows image repositories already present in the base tree. ### Downstream repositories - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note fix(cluster-api): attempt live migration before drain/delete on External eviction, use the guest node name for fallback drain, and uncordon recreated guests. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added a Cluster API Provider KubeVirt image pinned to version 0.1.10. - Added migration-first workload eviction with fallback draining and node recovery. - Added permission to create virtual machine migration resources. - Included the provider image in builds and deployment templates. - **Bug Fixes** - Preserved migration deadlines across retries and improved recovery after interrupted or completed migrations. - Added a bounded wait for migrations before falling back to draining. - **Documentation** - Documented the provider image version, patches, build process, and release considerations. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
13a2a0fd2e |
fix(registry): preserve write options in aggregated storage (#3937)
## What this PR does Preserves Kubernetes write options when the application, tenant-secret, and security-group APIs delegate create, update, and delete operations to controller-runtime. Passing an API options object only through `client.*Options.Raw` is insufficient because controller-runtime's `As*Options()` methods rebuild `Raw` from the typed fields; dry-run, field manager, field validation, delete propagation, grace periods, and preconditions were silently lost. The new converters populate the typed client options, and all affected application, tenant-secret, and security-group paths use them. The force-create PUT path preserves the caller's options as well. TenantSecret PATCH is served through Get and Update. Backend rejections surfaced by these writes now keep their machine-readable status on the wire: the application storage rebuilds the `StatusError` with context instead of flattening it through `fmt.Errorf`, so a quota or admission rejection answers 403/409 with its reason instead of a generic 500 with none. Tap storage uses a different client and is outside this change. This was reproduced on Cozystack 1.6.1: `kubectl apply --dry-run=server` against an `apps.cozystack.io` resource performed a real write and created the release. Validation: - `go test ./pkg/registry/...`: passed. - `go test -race ./pkg/registry/...`: passed. - `make generate`: no diff. - `make manifests`: no diff. ### Screenshots Not a UI change. ### Downstream repositories Walked the trigger map against the registry implementation and tests. No external schema, CRD, package layout, tooling anchor, or downstream hardcoded contract changes. - [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(registry): preserve dry-run and other Kubernetes write options in application, tenant-secret, and security-group storage operations, and keep backend error statuses on the wire ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Bug Fixes** - REST create, update, and delete operations now preserve request options such as dry-run, field management, validation, deletion propagation, and preconditions. - Force-create and HelmRelease update requests now retain their supplied options. - Dry-run security group deletions now accurately report their prospective completion state without modifying stored data. - Delete and other REST errors now preserve their original status, reason, and HTTP code while adding context. - **Tests** - Added coverage for write-option handling across applications, tenant secrets, security groups, and shared option conversions. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
3219f7ee9a |
fix(backups): give the barman-cloud sidecar its own resources (#4220)
## What this PR does The barman-cloud plugin injects its sidecar with no resource requests or limits. What that means depends on the namespace. A tenant with `resourceQuotas` set ships a `LimitRange` that defaults containers to 128Mi (`packages/apps/tenant/templates/quota.yaml`), so there the sidecar inherits that default and is OOMKilled mid-backup. A namespace without a `LimitRange`, which is `cozy-keycloak` and any tenant that leaves `resourceQuotas` empty, gave the sidecar no requests and no limit at all, so nothing reserved memory for it and nothing bounded it. The failure on the tenant path is quiet from the control plane: the `ObjectStore` stays healthy, the `Cluster` stays `Ready`, and only the backup fails. Observed on a 1.6 cluster while backing up a 38 MB database: `lastState.terminated.reason: OOMKilled`, `exit 137`, four restarts on the sidecar, and a cgroup high-water mark of 254 MiB. `container_memory_working_set_bytes` peaked at only 64 MiB over the same window — it is sampled, and it misses the spike that actually triggers the kill, which is why the working-set number does not explain the failure on its own. Both paths that build an ObjectStore now carry resources: - `cozy-lib.barman.sidecarConfiguration`, used by `packages/apps/postgres` for the backup and recovery ObjectStores and by `packages/system/keycloak`; - `barmanSidecarConfiguration()` in `internal/backupcontroller/cnpgstrategy_controller.go`, which builds the platform's own ObjectStore on the `useSystemBucket=true` path. Requests are 100m/256Mi with a 1Gi memory limit on every caller: 256Mi holds the measured working set and 1Gi is four times the measurement, which is also the ceiling a caller without a LimitRange gets where it had none. No CPU limit is set, following the `entityOperator` precedent in `packages/apps/kafka/templates/kafka.yaml`: a throttled sidecar stalls WAL archiving instead of failing it, which is harder to notice than an outright failure. Measured CPU peak was 50 mCPU. Inside a tenant the limit is charged against the `ResourceQuota` `limits.memory` budget, 1Gi per instance pod; a 4Gi tenant spends a quarter of it per Postgres instance. The helper is renamed from `checksumSidecarConfiguration` to `sidecarConfiguration`, because it no longer carries only the checksum pin and its name and doc comment would otherwise be wrong. Tests cover both paths and both render sites: a new helm suite in `packages/apps/postgres`, extra assertions in the existing keycloak suite, an assertion in the controller test, and a deepcopy test for the new field. Each of them fails against the unfixed sources. One thing this PR deliberately does not do. This is the fifth time the 128Mi tenant default has been worked around per component — kafka and zookeeper presets (#2537), the kafka entity-operator (#2934), the cert-manager cainjector (#3199), and the note carried in the etcd-operator values. Whether the default itself should move looks like your call rather than something to fold into a fix for one sidecar, so it is left alone here. ### Screenshots Not a UI change. ### Downstream repositories Walked the trigger map in `docs/agents/contributing.md` against the diff, entry by entry. The change touches one cozy-lib helper, the two chart templates that include it, one Go function, and tests. It adds, renames or removes no package; changes no `values.yaml`, `values.schema.json`, `Chart.yaml` or `README.md`, so no version enum, default or generated artifact moves; changes no `ApplicationDefinition` semantics, no `release.prefix`, no output Secret or Service name; touches no CRD, no namespace, no `hack/` file, no telemetry metric or label, no `cozy-proxy` annotation, no node or network requirement, and no commit or PR convention. No entry matches. - [x] No downstream repository is affected by this change ### Release note ```release-note fix(backups): give the barman-cloud sidecar its own resources The barman-cloud sidecar was injected without resource requests or limits, so in tenant namespaces it inherited the 128Mi `LimitRange` default and was OOMKilled during backups while the `ObjectStore` and the `Cluster` both stayed healthy. It now requests 100m/256Mi and caps memory at 1Gi on the chart path and on the platform's Go path alike; in namespaces without a LimitRange the sidecar had no limit before and gets the same 1Gi ceiling. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added explicit CPU and memory resource settings for barman-cloud backup and recovery sidecars. - Backup sidecars request 100m CPU and 256Mi memory, with a 1Gi memory limit. - Recovery sidecars receive a 1Gi memory limit. - Preserved the S3 checksum configuration. - **Bug Fixes** - Prevented sidecars from inheriting unsuitable tenant resource limits. - Ensured resource settings are preserved when backup configuration is copied. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
d71e78a74a |
fix(linstor): wait for temporary probe devices (#4100)
## What this PR does Backports [LINBIT/linstor-server#528](https://github.com/LINBIT/linstor-server/pull/528) to the LINSTOR 1.33.3 build used by piraeus-server. A ZFS probe volume can be created before udev publishes its device path, leaving the pool without I/O properties and blocking replica placement on 4K pools. Wait for the probe device before reading its properties, retry up to three times and report failures. Skip null paths in the existing volume list and fall back to a probe when ZFS has no usable path. Serialize probe creation and cleanup, stop after cleanup failures and preserve interrupts. Inactive LVM volumes retain the existing no-probe behavior. Validation: all six patches apply together to v1.33.3. All 1026 tests and `assemble` pass on Linux amd64 with JDK 11, including 17 regression tests; 14 of those fail without this patch. `checkstyleMain` reports the same existing return-inside-for error at `DrbdAdm.java:970` from `retry-secondary-after-mkfs.diff`, reproduced without this patch; no new findings. ### Downstream repositories - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note fix(linstor): wait for ZFS probe devices before reading pool I/O properties to avoid incorrect block sizes and failed replica placement ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Bug Fixes** - Improved storage device probing by waiting for temporary devices to become available and retrying when necessary. - Improved compatibility with ZFS volumes when standard device paths are unavailable. - Prevented unnecessary probing of inactive shared LVM volumes. - Improved handling of interrupted probes and cleanup failures. - **Documentation** - Added documentation describing storage probing behavior and compatibility updates. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
ee09e73343 |
fix(kafka): make topics[].config optional (#3935)
## What this PR does Makes `topics[].config` optional across the Kafka typed API, generated schema, documentation, and chart contract. The KafkaTopic template already omits an empty config, and Strimzi accepts the field as optional; the Cozystack schema was the layer incorrectly rejecting such topics. The Helm test renders a topic without config and asserts `spec.config` is absent. The Chainsaw fixture also omits config and waits for the resulting KafkaTopic to reach Ready. Go API compatibility: `Topic.Config` changes from `runtime.RawExtension` to `*runtime.RawExtension`, so Go callers constructing that field must pass a pointer. The Terraform provider intentionally does not model Kafka topic tuning (`config`), so this does not require a provider follow-up. Validation: - `helm unittest packages/apps/kafka`: 36/36 passed. - `go vet ./kafka` in `api/apps/v1alpha1`: clean; the package has no test files, so this shows it compiles. - root `make generate`, which owns `zz_generated.deepcopy.go`, and `make -C packages/apps/kafka generate`: no diff. ### Screenshots Not a UI change. ### Downstream repositories Walked the trigger map against all nine changed files. The provider's Kafka model deliberately excludes `topics[].config`; no downstream repository mirrors this nested field or its requiredness. - [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(kafka): allow topics to omit the optional Strimzi config map ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Kafka topic configuration is now optional. Topics can be created without explicitly providing configuration settings. - Topic configuration is omitted from serialized resources when not specified. - **Bug Fixes** - Improved handling of topic resources without configuration, including correct readiness validation and rendering. - **Documentation** - Updated Kafka configuration documentation and schemas to reflect that topic configuration is optional. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
8540e746f8 |
fix(seaweedfs): parse naming-audit timestamps portably across GNU and BSD date (#4282)
Fixes #4273 `hack/seaweedfs-naming-audit.sh` read PV and `first_deployed` timestamps with `date -u -d`, a spelling only GNU `date` accepts. On a host with BSD `date` (macOS, or any host without GNU coreutils on `PATH`) the call failed, its stderr was discarded by the `2>/dev/null` on the same line, and `|| return 0` turned that host-tool failure into the audit's "no epoch available" signal. Every tenant then read as MIXED with "direction cannot be established", as though the cluster carried no evidence rather than the host carrying no readable clock — and since the audit gates a destructive runbook step, that indistinguishability is the problem. A new `parse_epoch` helper tries the GNU spelling (`date -d`) and then the BSD one (`date -j -f`), each with its own stderr muted, and uses whichever the host speaks. Both call sites (`first_deployed` and `pv_epoch`) route through it, so the audit now works on GNU and BSD hosts alike with no behaviour change for a valid timestamp on a GNU host. Crucially it keeps the two outcomes the issue asks to be separated distinct. A timestamp that is *present but readable by neither form* is no longer folded into the silent absent-evidence branch: `parse_epoch` fails loudly via `audit_fatal`, names the value, and aborts — the same fail-closed contract the rest of the script already follows. The legitimate absent-evidence cases the comment at the `pv_epoch` block reasons about — an unbound claim, a NotFound PVC/PV — stay on their benign path and still degrade to the conservative "classify by hand" note. ## Tests The suite is bats via `hack/cozytest.sh`. New coverage, each RED before the fix and GREEN after (mutation-verified: reverting the fix turns them RED again): - `parse_epoch` reads an RFC3339 timestamp to the epoch the issue quotes, on GNU or BSD date. The test runs under a deliberately non-UTC `TZ` (`XXX5`), not UTC: both call sites pass `-u`, which makes GNU and BSD alike parse the zoneless 19-char value as UTC, so the absolute epoch is TZ-independent — measured on a BSD host, `1789470000` with `-u` versus `1789488000` without. Dropping `-u` would move the value, so running under a non-UTC `TZ` pins that flag as a regression guard. The classifier's own relative comparison is timezone-immune regardless. - `parse_epoch` fails loudly, on stderr, on a value neither form can read — and writes nothing to stdout. - The MIXED path classifies as OVERLAP under a BSD-only `date`, byte-identical to the golden the GNU path produces, instead of "direction cannot be established". A `date` shim on `PATH` reproduces the bug deterministically on a GNU CI runner, where it is otherwise invisible. - The `first_deployed` call site (the second one the issue names) parses under a BSD-only `date` instead of aborting the whole audit. - A PV whose `creationTimestamp` is present but unparseable is fatal, not the absent-evidence branch — proving the two are not collapsed at the real call site. `dash -n` confirms the script stays POSIX-clean for the CI shell. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Bug Fixes** - Improved timestamp handling across GNU and BSD environments. - Audits now report an explicit failure when a provided deployment or volume timestamp cannot be parsed, instead of treating it as missing evidence. - Preserved the existing behavior for genuinely absent timestamps. - **Tests** - Added coverage for GNU and BSD timestamp parsing, invalid values, deployment timestamps, and invalid volume timestamps. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
939e6a118d |
fix(mongodb): fill the dashboard credentials on a first install (#4014)
## What this PR does The dashboard Secret `<release>-credentials` ships with an empty `password` and an empty `uri`, and keeps them for the whole life of the database. `templates/credentials.yaml` resolved the password with `lookup` from `internal-<release>-users`, which the Percona operator creates only after Helm has already rendered the release. The first-install lookup therefore returns nothing, and no later event re-renders a release whose chart and values are unchanged, so the empty values are never repaired. The chart stated this in a comment and in the README, and two unit tests asserted the empty values as intended behaviour. The chart now owns those credentials. It generates the operator's system-user passwords, writes them to the Secret named by `spec.secrets.users`, and fills the dashboard Secret from the same values in the same pass, so the two cannot disagree. Two properties the implementation keeps: - An upgrade never rotates a live password. Every value is reused from the existing Secret when there is one, and generated only when neither the users Secret nor the operator's internal copy holds it. - A database created before this change keeps the Secret the operator generated for it. Ownership is decided by the `meta.helm.sh/release-name` annotation rather than by the Secret's existence, so the chart neither tries to adopt an object Helm did not apply, nor drops it from the manifest on a later upgrade and deletes it. Such a release gets its `<release>-credentials` filled on its next upgrade, with the password the operator had already assigned. Verified on a running v1.6.1 install with the pre-change chart: re-rendering the release filled `password` and `uri` from the operator's existing Secret, the password was not rotated, the pod was not restarted, and those credentials authenticate as `databaseAdmin`. `helm unittest`: 137 tests, 10 suites, all passing. The suite now mocks `lookup` through `kubernetesProvider` for the three branches a fresh render never reaches: a helm-owned users Secret is reused, a Secret the release does not own stays out of the manifest while its password still reaches `<release>-credentials`, and the operator copy rebuilds a missing users Secret. Forcing generation over a live Secret, dropping the operator-copy fallback, or inverting the ownership test each turns the suite red. On the not-owned path a missing password key now fails the render instead of producing a password the users Secret never receives, and the README upgrade section describes the carry-over rather than a rotation. ### Screenshots Not a UI change in this repository. The dashboard renders the Secret as it finds it; only its contents change. ### Downstream repositories Walked the trigger map in `docs/agents/contributing.md` against the diff. The diff touches three files, all under `packages/apps/mongodb`: one template, its test suite, and the package README. No package is added, renamed or removed; `values.yaml` and `values.schema.json` are untouched, so no field, default or version enum moves; no output Secret or Service is renamed, and `<release>-credentials` keeps its name; nothing under `hack/`, `packages/core`, or the `ApplicationDefinition` CRD is involved. The README edit rides the path that is already automated: `mongodb` is in the `APPS` list of the website `Makefile`, so the reference page is regenerated from it on a stable tag. - [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(mongodb): the dashboard credentials Secret is now filled on a first install, instead of carrying an empty password and uri until someone runs helm upgrade by hand ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * MongoDB installations now provide usable credentials and connection URIs from the first deployment. * System-user passwords are generated automatically and stored securely. * Existing passwords are preserved during upgrades without rotation. * Connection details support both replica-set and sharded MongoDB deployments. * Credentials include all required system users with generated passwords. * Credential values are restored when an existing users secret is unavailable. * **Documentation** * Updated MongoDB credential documentation to describe automatic generation, secure storage, and upgrade behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
324a342e61 |
test(seaweedfs): make the BSD-date shim honor the audit's real format string
The two end-to-end tests that reproduce issue #4273 on a GNU runner drive the audit through _write_fake_date, a `date` shim that rejects the GNU `-d` spelling so the script must take its BSD `date -j -f` branch. But the shim discarded the format argument the script passed and recomputed the epoch with its own hardcoded `%Y-%m-%dT%H:%M:%S`. So the one string those tests exist to protect -- the audit's BSD format spelling, which is the whole of #4273 -- was never actually exercised: a regression in it left the tests green. The only test that hits a real BSD `date -j -f` short- circuits on the GNU branch on the CI runner, so the gap was invisible exactly where the gate runs. The shim now captures both the format and the value and uses the format the audit passed. On a BSD host it honors it through real `-j -f`, so a wrong format fails as production would; on a GNU-only runner, which has no `-j` to enforce a format, it falls back to `-d` only for the exact format the audit is supposed to pass, so a regressed spelling is not silently rescued and the tests turn red on the very runner they guard. Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
6aa4ca954a |
fix(seaweedfs): parse naming-audit timestamps portably across GNU and BSD date
The naming audit read PV and first_deployed timestamps with `date -u -d`, a spelling only GNU date accepts. On a host with BSD date the call failed, its stderr was discarded by the `2>/dev/null` on the same line, and `|| return 0` turned that host-tool failure into the audit's "no epoch" signal -- so every tenant read as MIXED with "direction cannot be established", as if the cluster lacked the evidence rather than the host lacking a readable clock. Since the audit gates a destructive runbook step, that indistinguishability is the defect. parse_epoch now tries the GNU spelling then the BSD one (`date -j -f`) and uses whichever the host speaks, so both call sites work on GNU and BSD hosts alike with no behaviour change for a valid timestamp on GNU. A timestamp that is present but readable by neither form is no longer folded into the absent-evidence branch: it is fatal and names the value, keeping a genuine parse failure loud and distinct from the legitimate "no bound PV age" case (unbound claim, NotFound PVC/PV) the audit conservatively degrades on. Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io> |
||
|
|
1b576bc638 |
fix(registry): drop the backing object's UID from remapped error details
WrapPreservingStatus rewrites Group, Kind and Name of a backend status to the aggregated resource but left Details.UID as the HelmRelease's, so a client that keys on details saw an identity the tenant cannot look up. The UID goes with the rest of the remap, and a test pins it. Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com> Assisted-by: LLM |
||
|
|
29351bd7fa |
fix(registry): report aggregated resource identity in errors
Backing resource names are not part of the aggregated API contract. Clients need the requested resource identity and the original status code and reason to handle rejected writes consistently. Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com> Assisted-by: LLM |
||
|
|
39da2300d2 |
fix(registry): keep backend status codes on aggregated write errors
Aggregated endpoints must retain backend HTTP codes and reasons so clients can distinguish conflicts and admission failures. Dry-run deletion also depends on current finalizers, which a cached read can miss. Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com> Assisted-by: LLM |
||
|
|
a20c706940 |
fix(registry): align dry-run with storage semantics
Dry-run must expose the same deletion state as a real request without persisting it. Shared option objects can hide dropped fields in tests, and an unreachable patch method offers no API coverage. Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com> Assisted-by: LLM |
||
|
|
a9812477e2 |
fix(registry): preserve write options in aggregated storage
Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com> Assisted-by: LLM |
||
|
|
9fac0add84 |
docs(mongodb): describe the upgrade as a carry-over, not a rotation
The upgrade section still promised a password rotation and a regenerated credentials Secret. With the operator-copy fallback the chart reads the current passwords from internal-<release>-users and writes the same values, so nothing rotates and no session breaks. Assisted-by: LLM Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com> |
||
|
|
0e17c6f65e |
test(mongodb): pin the reuse, fallback and ownership branches with lookup fixtures
Every test rendered with an empty lookup, so the branch that keeps a live password could be deleted with the suite green. Three fixtures through kubernetesProvider cover what a fresh render never reaches: a helm-owned users Secret is reused, a Secret the release does not own stays out of the manifest while its password still reaches the credentials, and the operator copy rebuilds a missing users Secret. Values with URI-reserved characters cover the userinfo encoding, and both Secrets are asserted Opaque again. Assisted-by: LLM Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com> |
||
|
|
f0da352b30 |
fix(mongodb): refuse to invent a password for a users Secret the chart does not own
On the not-owned path a missing password key produced a generated password that reached <release>-credentials but never the users Secret the operator reads, so the dashboard advertised a password MongoDB never had. The render now fails and names the Secret and the key. The operator fills every key itself, so only a hand-made partial Secret reaches this branch. Assisted-by: LLM Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com> |
||
|
|
348a65d18b |
docs(mongodb): keep the credentials paragraphs on one line
Two paragraphs under Credentials were hard-wrapped at 80 columns, the one place in this README that was; the rest follows the one-line-per-paragraph rule the repository asks for in markdown. Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com> Assisted-by: LLM |
||
|
|
66a00f552e |
fix(mongodb): url-encode the username in the connection uri
Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com> |
||
|
|
b4be956d7e |
fix(mongodb): fill the dashboard credentials on a first install
Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com> |
||
|
|
4dc6065ec9 |
fix(backups): give the sidecar sizing its reason per caller
The Keycloak comment and the helper doc claimed the tenant LimitRange as the reason for the resources, but cozy-keycloak has no LimitRange and neither does a tenant that leaves resourceQuotas empty: there the sidecar had no requests and no limit at all, and the change gives it a 1Gi ceiling where there was none. The comments and both doc blocks now say what applies to each caller. No rendered object changes. Assisted-by: LLM Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com> |
||
|
|
9214430bd8 |
fix(backups): give the barman-cloud sidecar its own resources
The barman-cloud plugin injects its sidecar without resource requests or limits. Tenant namespaces ship a LimitRange that defaults containers to 128Mi, so the sidecar inherits that default and is OOMKilled mid-backup: the ObjectStore stays healthy, the Cluster stays Ready, and only the backup fails. A cgroup high-water mark of 254 MiB on a 38 MB database shows the default cannot hold it. The shared cozy-lib helper and the Go path that builds the platform's own ObjectStore now request 100m/256Mi and cap memory at 1Gi. No CPU limit is set, matching the entityOperator precedent in the kafka chart: a throttled sidecar stalls WAL archiving instead of failing it. The helper is renamed from checksumSidecarConfiguration to sidecarConfiguration, since it no longer carries only the checksum pin. Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com> |
||
|
|
bc2ba106e1 |
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> |
||
|
|
0e4d6a305c |
test(cluster-api): declare the subshell EXIT traps in the CAPK bats suite
hack/bats-no-exit-trap.bats is an exact ratchet, and the new suite installs three traps inside explicit subshells without declaring them, so make unit-tests fails on the merge commit. The header now declares the count and says why the three are not debt. Assisted-by: LLM Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com> |
||
|
|
c85f35070c |
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> |
||
|
|
bb3a2fa220 |
docs(cluster-api): clarify trusted backport image delivery
Signed-off-by: Yan Bondarenko <202671653+yankawai@users.noreply.github.com> |