Commit Graph
3228 Commits
Author SHA1 Message Date
Arsolitt 7fe749e2bb fix(kubernetes): use cozy-lib helper for CPU millicore parsing in auto-compute
The auto-compute block used raw `float64` cast on `$effectiveCpu`, which
breaks when the value is in millicore notation like "4000m". Use the
`cozy-lib.resources.toFloat` helper that already handles the `m` suffix.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:55 +03:00
Arsolitt 1702c143db feat(kubernetes): auto-compute kubelet CPU reservations from node capacity
Compute $effectiveCpu alongside $effectiveMemory using the same pattern:
5% of node CPU clamped to [50m, 500m], replacing the hardcoded 100m
default. Adds total CPU validation and a guard for CPU overrides
without known node capacity.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:55 +03:00
Arsolitt c968247dd8 fix(kubernetes): harden kubelet reservation validation and add missing tests
Add eviction percentage validation (non-numeric, out-of-range, zero, negative),
guard against overrides without effective memory, use ceil instead of int for
allocatable annotation, remove dead code in capacity annotation branches, fix
README threshold (5.12 GiB -> 5 GiB), and document capacity annotation semantics.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:54 +03:00
Arsolitt 4292401d66 test(kubernetes): update reservation validation tests for expanded regex hints
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:54 +03:00
Arsolitt 937a27b39b fix(kubernetes): include eviction threshold in allocatable memory calculation
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:54 +03:00
Arsolitt 6639e5c316 fix(kubernetes): accept all valid K8s quantity forms in reservation validation
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:54 +03:00
Arsolitt 09517c42ec refactor(kubernetes): collapse reservation validation into range loop
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:54 +03:00
Arsolitt 3f7e3b737c refactor(kubernetes): use sprig min/max for kubelet reservation clamp
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:54 +03:00
Arsolitt df8663cd3c test(kubernetes): update instanceType test to expect validation failure
The test previously verified silent fallback to 256Mi when instanceType
lookup returned nil. Now that the template validates instanceType
existence, the test expects a failedTemplate error instead.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:53 +03:00
Arsolitt c7c7574d7a test(kubernetes): add eviction-reservation interaction tests and document eviction-minimum-reclaim
Add two test cases verifying that the template correctly renders when
eviction thresholds interact with explicit reservations — both an
aggressive absolute eviction on a small node and a typical production
config with reasonable thresholds.

Also add a brief rationale comment for the hardcoded
eviction-minimum-reclaim value in cluster.yaml.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:53 +03:00
Arsolitt a9e224e840 fix(kubernetes): raise kubelet reservation floor clamp from 64Mi to 256Mi
The minimum auto-computed kubelet memory reservation is now 256Mi instead
of 64Mi. This provides a safer default for small nodes where 64Mi is
insufficient for system daemons and kubelet runtime overhead.

The 512Mi node test now expects a validation error since the floor clamp
produces 256Mi+256Mi which equals the node memory. The 4Gi node test
expects 256Mi (clamped from 204Mi) instead of the raw 5% value.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:53 +03:00
Arsolitt c6b7f3d6e7 fix(kubernetes): clean up kubelet reservation template and add instanceType fallback test
Remove no-op mulf-by-1.0 in total reserved memory calculation, expand
memory quantity regex to accept base-10 suffixes (k, M, G, T, P, E) in
addition to binary suffixes, and remove hard fail on nil instanceType
lookup so the 64Mi floor fallback works in helm unittest.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:53 +03:00
Arsolitt 6eb2a7f078 docs(kubernetes): document hardcoded eviction parameters in kubelet defaults table
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:53 +03:00
Arsolitt 1f8ada572c fix(kubernetes): validate absolute eviction format and guard against memory over-reservation
Add regex format validation for absolute eviction threshold values before
they reach toFloat conversion, preventing silent zero returns on invalid
input like "banana". Add a check that systemReservedMemory + kubeReservedMemory
does not exceed effective node memory. Include helm unit tests for both
validations.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:53 +03:00
Arsolitt d21307a18b docs(kubernetes): fix version range and document kubelet auto-computation
Update the supported Kubernetes version range from 1.28-1.33 to
1.30-1.35 to match the actual values.schema.json enum. Add a new
"Kubelet Resource Reservations" section explaining the auto-computation
formula (5% of effective memory, clamped to [64Mi, 1Gi]), default
values for all kubelet parameters, and a configuration example.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:53 +03:00
Arsolitt b21dedad64 fix(kubernetes): validate reservation formats and reject mixed eviction types
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:52 +03:00
Arsolitt fe48c726c8 fix(kubernetes): add absolute eviction threshold validation and remove unrelated changes
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:52 +03:00
Arsolitt c2fb855f0e fix(kubernetes): make kubelet field optional and fix description consistency
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:52 +03:00
Arsolitt 656792033f test(kubernetes): add helm unit tests for kubelet reservation
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:52 +03:00
Arsolitt 546c167041 fix(kubernetes): fix kubelet reservation bugs and add eviction validation
Fix empty instanceType dict truthiness check to prevent nil pointer errors
when instanceType is not set. Add validation that evictionHardMemory is
strictly less than evictionSoftMemory. Fix evictionHardMemory default
from 10% to 7% and add missing evictionSoftMemory field. Remove kubelet
from required array in schema for backwards compatibility.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:52 +03:00
Arsolitt a2ba939d49 fix(kubernetes): use pods-only enforce-node-allocatable
Enforcing system-reserved and kube-reserved cgroups requires
pre-created cgroup slices that may not exist in the VM image,
causing kubelet to fail on startup.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:52 +03:00
Arsolitt 63633987e3 feat(kubernetes): make eviction-soft threshold configurable
Add evictionSoftMemory field to kubelet configuration with default 10%.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:51 +03:00
IvanHunters 079ec7c1f5 fix(kubernetes): add kubelet reserved resources and cgroup enforcement
Configure kubelet with proper resource reservations and cgroup enforcement
to prevent OOM kills when memory pressure occurs.

Configuration:
- systemReserved: 100m CPU, 512Mi memory (OS daemons)
- kubeReserved: 100m CPU, 512Mi memory (kubelet, containerd)
- evictionHard: 512Mi threshold (immediate eviction)
- evictionSoft: 1Gi threshold with 90s grace period
- evictionMinimumReclaim: 256Mi (guaranteed reclaim after eviction)
- enforce-node-allocatable: creates hard cgroup limits for reservations
- cgroups-per-qos: enables QoS-based resource isolation
- cgroup-driver: systemd (matches containerd configuration)
- kernel-memcg-notification: faster memory pressure detection

Allocatable calculation for 16Gi VM:
  VM capacity:           16.00 Gi
  - systemReserved:      -0.50 Gi (enforced via cgroup)
  - kubeReserved:        -0.50 Gi (enforced via cgroup)
  - evictionHard buffer: -0.50 Gi
  - kernel/page cache:   -0.25 Gi (implicit)
  ----------------------------------------
  Allocatable (safe):    14.25 Gi

Key improvement: enforce-node-allocatable creates hard cgroup limits,
preventing system/kubelet processes from exceeding reservations and
killing kubelet via OOM.

Related issue: tenant VMs experiencing kubelet crashes after 15-30min
due to insufficient reserved memory (100Mi vs required 1.75Gi total)
and lack of cgroup enforcement.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-04-23 17:02:51 +03:00
Arsolitt c39249233c fix(kubernetes): adjust kubelet reservation defaults
Lower minimum memory reservation clamp from 256Mi to 64Mi to support
smaller instance types. Reduce eviction threshold from 10% to 7%.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:51 +03:00
Arsolitt cbc23a3f3b fix(kubernetes): make kubelet reservation fields optional
Mark all Kubelet struct fields optional in values.yaml so existing
Kubernetes CRs without a kubelet block still pass schema validation
while defaults are injected via the template.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:51 +03:00
Arsolitt 6c11ecd51a feat(kubernetes): add dynamic kubelet memory reservations for worker nodes
Kubelet on worker VMs used to join with empty kubeletExtraArgs, so
allocatable memory equaled guest memory and the OS plus kubelet had
no reservation. Under pressure, Linux OOM killer could terminate
kubelet, taking the node NotReady before graceful pod eviction.

Introduce per-group kubelet reservations with sane defaults:
- system-reserved and kube-reserved memory auto-computed as 5% of
  effective guest memory, clamped to [256Mi, 1Gi]
- CPU reserved 100m for each
- eviction-hard memory.available<10% (scales with VM size)

Effective memory is taken from group.resources.memory when set,
otherwise resolved from instanceType via the existing Helm lookup
already used for capacity annotations. Users can override any field
per node group via nodeGroups[*].kubelet.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:51 +03:00
myasnikovdaniil 24d48bd075 fix(ci): harden changelog generation in tags.yaml (v1.3.0 regression) (#2460)
## What this PR does

Fixes the failures that blocked the v1.3.0 release pipeline (workflow
run [24765377017]) and closes the gap in `docs/agents/changelog.md` that
made them possible.

### Bug 1 — pathspec error in `Create changelog branch and commit`

After the Copilot step, the workflow runs `git checkout -b
"$CHANGELOG_BRANCH" origin/main`. Copilot CLI was invoked with
`--allow-all-tools` and had committed the generated changelog onto HEAD
of `main`, so the reset to `origin/main` deleted the tracked file, and
`git add "$CHANGELOG_FILE"` then failed with `fatal: pathspec ... did
not match any files`.

Fix (commit 2):

- Snapshot the file across the branch switch so the checkout cannot drop
it.
- `set -euo pipefail` so any failure surfaces loudly.
- Drop the dead "no changes to commit" soft-branch — the earlier
`check_changelog` step gates this step on the file being absent from
`origin/main`, so `git commit` must produce a diff; if it doesn't (e.g.
empty file), fail loud instead of pushing an empty branch.
- Fail-early file-existence check with `::error::` annotation, and
`VERSION` moved to step `env:`.

### Bug 2 — no timeout on `Generate changelog using AI`

The re-run hung in Copilot for 10+ minutes with zero log output. With no
`timeout-minutes`, a hung Copilot would hold a self-hosted runner for 6
hours (job default).

Fix (commit 2): `timeout-minutes: 30` (the prior successful run took ~26
minutes).

### Root-cause fix — scope the agent prompt

`docs/agents/changelog.md` is the actual prompt driving Copilot. It
ended with "Save the changelog" and gave no boundary, so an agent with
`--allow-all-tools` could reasonably interpret "done" as "commit, push,
open a PR".

Fix (commit 1):

- Add a "Scope and boundaries" section at the top stating the single
deliverable is `docs/changelogs/v<version>.md` and enumerating forbidden
operations (git commit / push / branch / tag / reset / merge / rebase,
PR creation, GitHub API writes, modifying any file other than the
changelog).
- Add an explicit "then exit" at the end of Step 9 with a back-reference
to the scope section.
- Scoped "unless the caller explicitly instructs otherwise" so
interactive IDE use stays flexible.

With the rules in the doc, CI and interactive callers share the same
boundary, and the workflow prompt becomes a one-line invocation
(`--prompt "Generate the release changelog for tag v${VERSION}. Follow
the instructions in @docs/agents/changelog.md exactly, including the
'Scope and boundaries' section at the top. ..."`).

### Files touched

- `docs/agents/changelog.md` — +16 / -0 (scope section + exit rule)
- `.github/workflows/tags.yaml` — +36 / -31 (timeout + rewritten commit
step + simplified prompt)

Other jobs in the workflow (`prepare-release`, `update-website-docs`)
are untouched.

### Release note

```release-note
NONE
```

[24765377017]:
https://github.com/cozystack/cozystack/actions/runs/24765377017

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Improved release automation reliability with stricter verification,
enforced error handling, and a timeout for changelog generation
* Ensured automated commits/pushes occur only after successful output
validation to prevent accidental repository mutations

* **Documentation**
* Clarified agent instructions to produce a single changelog file and
terminate, and to restrict the agent to read-only inspection during
generation
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-23 16:45:16 +05:00
myasnikovdaniil a92dc769a1 docs(changelog): correct v1.3.0 postgres and linstor-gui entries (#2458)
## What this PR does

Post-release cleanup of `docs/changelogs/v1.3.0.md` so the notes match
what users actually experience in v1.3.0. No code changes.

- **Rewrite the postgres major-features entry** so author
(`@myasnikovdaniil`), PR (`#2369`), and description all line up with the
`17.7-standard-trixie` pin + migration-37 `imageName` rewrite that
actually shipped. The previous entry credited `#2304` with a description
matching a superseded `spec.version=v17` backfill approach.
- **Remove the duplicate `#2364` postgres bug-fix entry** — the same
work is now folded into the single major-features entry above, with
backport references to `#2309` (v1.2.1) and `#2364` (v1.2.2).
- **Remove the `[linstor-gui] Restrict to cozystack-cluster-admin group`
security entry.** The vulnerable state never shipped in a tagged
release, so there is nothing user-facing to announce. The
`cozystack-cluster-admin`-group restriction is already described in the
linstor-gui Feature Highlights section as part of the feature's day-one
shipping behavior.

### Release note

```release-note
[]
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Updated v1.3.0 changelog with clarified PostgreSQL system version
pinning details and removed redundant entries for improved documentation
clarity.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-23 14:09:36 +05:00
Myasnikov Daniil 76c4eabdff fix(ci): use a read-only app token for the Copilot step
Review feedback on PR #2460: the Generate changelog using AI step ran
Copilot with --allow-all-tools and GH_TOKEN set to the write-capable
installation token issued to the job (contents: write,
pull-requests: write on all cozystack/* repos). The scope rules in
docs/agents/changelog.md and the step prompt tell the agent not to
use those permissions, but nothing at the token layer prevented it.

Mint a second, read-only installation token from the same app
(same COZYSTACK_CI_APP_ID / COZYSTACK_CI_PRIVATE_KEY, scoped to
contents/pull-requests/metadata read) and pass that one to the AI
step instead. The write-capable token is still used by the checkout,
commit/push, and PR-creation steps that actually need it.

This is defense in depth: even if a future prompt change or agent
misbehavior ignored the scope rules, the token itself has no write
capability on any repository in the cozystack org. No new secret,
no new GitHub App install, no admin-side change — the RO token is
minted in the same workflow from the same app credentials.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-04-23 12:26:14 +05:00
Myasnikov Daniil e7e83b0d0b fix(ci): reject empty changelog file before commit
Review feedback on PR #2460: the existing `[ -f ]` check catches
missing files but a zero-byte `docs/changelogs/v${VERSION}.md` would
still be staged and committed — `git add` + `git commit -s` on a new
empty file succeeds and produces a real commit, leaving the
downstream PR with no actual changelog content.

Add a `[ -s ]` guard after the existence check: if the Generate
changelog using AI step produces an empty file, emit a matching
`::error::` annotation and exit 1 before snapshotting.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-04-23 12:25:30 +05:00
Myasnikov Daniil 3c95f30521 docs(agents): scope git-write ban to cozystack working tree
Review feedback on PR #2460: the previous "do not write to refs, HEAD,
or remotes" wording contradicted the explicit allowance of `git fetch`
(which updates remote-tracking refs) and the mandatory cross-repo
checks in Step 6, which `cd` into `_repos/<repo>` and run
`git checkout`, `git pull`, etc.

Sharpen the scope paragraph:

- The git-write ban is now explicitly scoped to the cozystack working
  tree — it bans writing to local branches, tags, or HEAD in that
  repo, not "refs/HEAD/remotes" globally.
- `git fetch` is called out as expected.
- Local git operations inside disposable `_repos/` clones
  (`git checkout`, `git pull`, etc.) are explicitly allowed, with
  the remaining rules (no push, no PR creation, no API writes)
  applying to any repository.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-04-23 12:25:19 +05:00
myasnikovdaniil f505c4da75 fix(backups): move velero-configmap Role to velero chart (#2459)
## What this PR does

The `backupstrategy-controller` chart declared a `Role` and
`RoleBinding` scoped to the `cozy-velero` namespace (for managing
`ResourceModifier` ConfigMaps consumed by Velero Restore). Because
`cozystack.velero` is an optional package, that namespace does not exist
in bundles that do not enable velero — and `backupstrategy-controller`
is a **default** package. Helm install aborted with:

```
namespaces "cozy-velero" not found
```

which blocked the entire
`cozy-backup-controller/backupstrategy-controller` HelmRelease on any
cluster where velero was not explicitly enabled (including the E2E
environment).

This PR moves that Role/RoleBinding into the velero chart
(`packages/system/velero/templates/backupstrategy-controller-rbac.yaml`),
so the permission grant only exists when velero is actually installed —
where it is useful. The RoleBinding subject points to the stable
`backupstrategy-controller` ServiceAccount in `cozy-backup-controller`.

### Release note

```release-note
fix(backups): moved the velero-namespaced ResourceModifier ConfigMap Role and RoleBinding from the backupstrategy-controller chart into the velero chart. This unblocks installs of backupstrategy-controller on bundles that do not enable velero (previously the HelmRelease failed with `namespaces "cozy-velero" not found`).
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Reorganized RBAC configuration for the backup strategy controller by
consolidating namespace-scoped role definitions in the Velero chart
template
* Updated role bindings and permissions structure across system packages

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-23 11:57:54 +05:00
Myasnikov Daniil c4477259c7 fix(backups): move velero-configmap Role to velero chart
The backupstrategy-controller chart declared a Role/RoleBinding in the
cozy-velero namespace for ResourceModifier ConfigMap management. Because
velero is an optional package, that namespace does not exist in bundles
without velero, so Helm install aborted with "namespaces \"cozy-velero\"
not found" and blocked the default install of backupstrategy-controller.

Move the Role and RoleBinding into the velero chart so they are created
only when velero is actually installed. The RoleBinding subject points
to the backupstrategy-controller ServiceAccount in its fixed namespace
(cozy-backup-controller).

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-04-23 10:41:41 +05:00
Myasnikov Daniil 3720f0f3f2 fix(ci): harden tags.yaml changelog job against agent misbehavior
Three changes to the generate-changelog job to fix the v1.3.0
release pipeline failure (run 24765377017) and make the job robust
to whatever state the Copilot step leaves behind.

1. Add `timeout-minutes: 30` to the Generate changelog using AI
   step. On the v1.3.0 re-run the step hung silently for 10+
   minutes; with no timeout a hung Copilot would hold a self-hosted
   runner for up to 6 hours (job default). The previous successful
   run took ~26 minutes, so 30 is a reasonable ceiling.

2. Replace the terse, ambiguous Copilot prompt with a one-liner
   that invokes docs/agents/changelog.md directly. The "Scope and
   boundaries" section added to that doc in the previous commit is
   now the single source of truth for what the agent may and may
   not do, so the workflow only needs to pass the version and
   point at the relevant doc. VERSION is moved to step env: to
   match GitHub's workflow-injection hardening guidance.

3. Rewrite the Create changelog branch and commit step:
   - add `set -euo pipefail` so any failure is visible
   - validate the file exists up front and fail loud with
     `::error::` if not
   - copy the file to a tempfile BEFORE `git checkout -b`, so the
     checkout to `origin/main` cannot remove it (this is the fix
     for the original pathspec error the v1.3.0 run hit)
   - use `trap` to clean up the tempfile on any exit path
   - move VERSION to env
   - drop the dead "no changes to commit" branch: the check_changelog
     step earlier in the job gates this step on the file being
     absent from origin/main, so `git add` + `git commit` must
     produce a diff. If they don't (e.g. Copilot emitted an empty
     file), fail loud instead of pushing an empty branch.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-04-23 10:33:12 +05:00
Myasnikov Daniil e1c6f9c029 docs(agents): scope changelog.md to a file-only deliverable
The v1.3.0 release pipeline broke because Copilot, invoked by
.github/workflows/tags.yaml with --allow-all-tools, committed the
generated changelog onto HEAD of main on its own. The workflow's
next step — `git checkout -b ... origin/main` — then wiped the file,
and `git add` failed with a pathspec error.

The root cause is in this document. The checklist ends with "Save
the changelog", which an agent with broad tool access can reasonably
interpret as "also commit it, push it, and open a PR". There was no
explicit boundary.

Add a "Scope and boundaries" section at the top and an explicit
"then exit" at the end of Step 9:

- The single deliverable is docs/changelogs/v<version>.md.
- Forbidden by default: git commit / push / checkout (to switch
  branches) / branch / tag / reset / merge / rebase; PR creation;
  GitHub API writes (POST/PATCH/DELETE); modifying any file other
  than the changelog.
- Read-only analysis (git log/show/fetch/diff, gh pr view, gh api
  GET) remains expected.
- Auxiliary repo clones under _repos/ remain allowed for cross-repo
  analysis per Step 6.
- Scoped "unless the caller explicitly instructs otherwise" so
  interactive use with an IDE remains flexible.

With the rules in the doc, CI and interactive callers share the
same boundary; the workflow can invoke the doc with a one-line
prompt instead of re-stating the constraints every time.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-04-23 10:22:09 +05:00
Myasnikov Daniil 44bc79cef1 docs(changelog): correct v1.3.0 postgres and linstor-gui entries
Post-release cleanup of docs/changelogs/v1.3.0.md so the notes match
what users actually experience in the released v1.3.0:

- Rewrite the postgres major-features entry so author (myasnikovdaniil),
  PR (#2369), and description all match the 17.7-standard-trixie pin +
  migration-37 imageName rewrite that actually shipped. The previous
  entry credited #2304 (superseded spec.version=v17 backfill approach).
- Remove the duplicate #2364 postgres bug-fix entry; the same work is
  now folded into the single major-features entry above, with backport
  references to #2309 (v1.2.1) and #2364 (v1.2.2).
- Remove the [linstor-gui] Restrict to cozystack-cluster-admin group
  security entry. The vulnerable state never shipped in a tagged
  release, so there is nothing user-facing to announce; the restriction
  is already described in the linstor-gui Feature Highlights section
  as part of the feature's day-one behavior.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-04-23 10:17:30 +05:00
IvanHunters 5c89a2cf83 Release v1.3.0 (#2452)
This PR prepares the release `v1.3.0`.
v1.3.0
2026-04-22 16:16:29 +03:00
myasnikovdaniil 7fff77f82f docs: add changelog for v1.3.0 (#2453)
This PR adds the changelog for release `v1.3.0`.

✅ Changelog has been automatically generated in
`docs/changelogs/v1.3.0.md`.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Published Cozystack v1.3.0 release notes featuring LINSTOR scheduler
extender for storage-aware pod placement, managed LINSTOR GUI web
console, VM Default Images catalog, expanded observability with Events
dashboard and S3 metering, cross-namespace VMInstance backup/restore,
and various platform enhancements and bug fixes.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-22 15:56:19 +05:00
Myasnikov DaniilandClaude Opus 4.7 1eeeb2652a docs: add changelog for v1.3.0
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-04-22 15:51:08 +05:00
cozystack-ci[bot] b52e2801b4 Prepare release v1.3.0
Signed-off-by: cozystack-ci[bot] <274107086+cozystack-ci[bot]@users.noreply.github.com>
2026-04-22 07:28:09 +00:00
IvanHunters 907bdba397 fix(harbor): remove incorrect tenant module flags (#2444)
## What this PR does

Harbor is a PaaS service (`category: PaaS`), not a tenant module. It is
not deployed automatically into tenant namespaces — there is no
corresponding manifest in `packages/apps/tenant/templates/`, unlike
actual tenant modules (monitoring, ingress, etcd, info, seaweedfs).

Two flags were incorrectly set on its `ApplicationDefinition`:

- `spec.dashboard.module: true` — caused Harbor to appear in the sidebar
"Modules" section and be excluded from its proper PaaS category.
- `spec.release.labels."internal.cozystack.io/tenantmodule": "true"` —
caused controllers (`pkg/registry/core/tenantmodule`, dashboard) to
treat the Harbor HelmRelease as a tenant module.

Both flags are removed so Harbor is listed correctly under PaaS and
handled as an ordinary managed application.

### Release note

```release-note
fix(harbor): remove incorrect tenant module flags from Harbor ApplicationDefinition so it appears under the PaaS category in the dashboard and is no longer treated as a tenant module
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
  * Simplified internal application configuration settings.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
api/apps/v1alpha1/v1.3.0
2026-04-22 10:09:05 +03:00
IvanHunters 8a5fea5bab fix(kube-ovn): bump kube-ovn to v1.15.10 with port-group regression fix (#2443)
## What this PR does

Bumps `packages/system/kubeovn` to `cozystack/kubeovn-chart` tag
`v1.15.10-cozy.1`, which:

1. Updates upstream kube-ovn from v1.15.3 to v1.15.10 (latest patch in
the v1.15 series).
2. Carries a patch over `pkg/controller/pod.go` that preserves a VM
LSP's port-group memberships when kubernetes GCs a completed
virt-launcher pod while another virt-launcher pod of the same VM is
still running.

Without the patch, the destination pod of a successful live migration
loses its security groups, network policies and node-scoped routing
after kubernetes cleans up the source pod, and only recovers after a
`kube-ovn-controller` restart. The buggy code path is identical between
v1.15.3, v1.15.10, release-1.15 HEAD and master HEAD — confirmed by diff
and by reproduction on a cozystack cluster.

- Upstream issue: kubeovn/kube-ovn#6665
- Upstream fix PR: kubeovn/kube-ovn#6666
- Chart carry: cozystack/kubeovn-chart#4

### Release note

```release-note
fix(kube-ovn): bump kube-ovn to v1.15.10 and carry upstream fix that keeps VM LSP port-group memberships when kubernetes GCs a completed virt-launcher pod (post-migration regression)
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* VpcEgressGateway CRD extended with optional resources
(claims/limits/requests) and bandwidth (ingress/egress) fields.
  * Added a pre-upgrade hook to run compatibility steps before upgrades.
  * CNI DaemonSet now optionally respects MTU when configured.

* **Bug Fixes**
* Updated Kube-OVN and NAT gateway container images to the latest
maintenance release.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-22 10:08:45 +03:00
IvanHunters 48a1723c9f fix(kube-ovn): resolve kubeovn-plunger RBAC forbidden on deployments (#2441)
## What this PR does

Fixes an RBAC failure in `kube-ovn-plunger` that prevented it from
reconciling the `ovn-central` Deployment:

```
deployments.apps is forbidden: User "system:serviceaccount:cozy-kubeovn:kube-ovn-plunger"
cannot list resource "deployments" in API group "apps" at the cluster scope
```

Two causes addressed:

- The controller-runtime cache issued cluster-wide list/watch for
Deployments and Pods by default. The manager cache is now scoped to the
kube-ovn namespace, so requests go to the namespaced endpoints covered
by the Role.
- The Role's deployments rule used `resourceNames`, which does not apply
to list/watch in Kubernetes RBAC. The restriction is removed; the Role
is still namespace-scoped via RoleBinding to the `cozy-kubeovn`
namespace.

`--kube-ovn-namespace` and `--ovn-central-name` are now passed to the
binary from chart values so the previously unused value is wired up.

### Release note

```release-note
fix(kube-ovn): fix kubeovn-plunger RBAC forbidden error on ovn-central Deployment reconcile
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added configurable parameters for KubeOVN namespace and OVN central
name in deployment configuration.

* **Improvements**
* Enhanced cache configuration with namespace-scoped resource management
capabilities.
* Updated RBAC permissions to remove resource-specific constraints,
enabling broader deployment access.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-22 10:08:18 +03:00
Andrei KvapilandClaude 68a624dccb fix(harbor): remove incorrect tenant module flags
Harbor is a PaaS service, not a tenant module. It is not deployed
automatically into tenant namespaces (no manifest in
packages/apps/tenant/templates/). Remove the misplaced
`dashboard.module: true` flag and
`internal.cozystack.io/tenantmodule: "true"` release label so Harbor
appears under the PaaS category in the dashboard and is not treated as
a tenant module by the controllers.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2026-04-21 20:26:13 +02:00
Andrei KvapilandClaude bb4be57774 fix(kube-ovn): bump kube-ovn to v1.15.10 with port-group regression fix
Pulls cozystack/kubeovn-chart v1.15.10-cozy.1, which bumps upstream
kube-ovn from v1.15.3 to v1.15.10 and carries a patch over
pkg/controller/pod.go that preserves a VM LSP's port-group memberships
when kubernetes GCs a completed virt-launcher pod while another
virt-launcher pod of the same VM is still running.

Without the patch, the destination pod of a successful live migration
loses its security groups, network policies and node-scoped routing
after kubernetes cleans up the migration source pod, and only recovers
after a kube-ovn-controller restart.

Upstream issue: kubeovn/kube-ovn#6665
Upstream fix PR: kubeovn/kube-ovn#6666
Chart carry: cozystack/kubeovn-chart#4

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2026-04-21 20:09:19 +02:00
myasnikovdaniil 358ac66a2a feat(dashboard): add RestoreJob list, add page, and sidebar link (#2437)
## What this PR does

- Introduce list, details, create, and sidebar views for `RestoreJob` in
the dashboard controller.
- Auto-generate stable component IDs for sidebar entries and detail
sub-blocks so upserts remain consistent across reconciles.
- Render a single "Same as backup" fallback for an omitted
`spec.targetApplicationRef` on the details view instead of concatenating
three missing-path fallbacks.
- Mark non-CRD-backed `stock-project-factory-*-details` sidebars
(`kube-*`, `plan`, `backupjob`, `backup`, `restorejob`) as static so
they pick up consistent managed-by labels.

### Release note

```release-note
[dashboard] Add RestoreJob views (list, details, create, sidebar link) to the dashboard controller.
```

## Test plan

- [x] Deploy controller to dev stand and open the restore pages in the
dashboard
- [x] Create a RestoreJob through the UI against an existing Backup;
reconcile succeeds and the details view renders
- [ ] CI green

## Previous PR
https://github.com/cozystack/cozystack/pull/2387


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Introduced comprehensive RestoreJobs dashboard interface enabling
users to view and manage backup restoration operations.
* New RestoreJobs section added to the Backups menu with dedicated
details page and navigation.
* Dashboard displays restore job status, phase, backup references,
target applications, and operation timestamps for easy monitoring.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-21 20:28:38 +05:00
Andrei KvapilandClaude 04cc1633be fix(kube-ovn): scope kubeovn-plunger cache and RBAC to its namespace
The kubeovn-plunger controller-runtime cache attempted cluster-wide
list/watch on Deployments and Pods, which the namespace-scoped Role
cannot satisfy. Additionally, the deployments rule relied on
resourceNames, which does not restrict list/watch verbs and left the
permission effectively unusable.

Scope the manager cache to the kube-ovn namespace so list/watch hit
the namespaced API, and drop resourceNames from the deployments rule.
Wire --kube-ovn-namespace and --ovn-central-name through the
Deployment so values are actually consumed.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2026-04-21 17:13:27 +02:00
myasnikovdaniil aa8ea10392 fix(platform): migrate ACME HTTP-01 to ingressClassName API (#2436)
## What this PR does

HTTP-01 ACME issuance in Cozystack has been relying on deprecated
cert-manager fields that happen to still work, but point at a
non-existent ingress class on default installs.

**The bug:**
- `ClusterIssuer`s (`letsencrypt-prod`, `letsencrypt-stage`) hardcode
`http01.ingress.class: nginx`, but Cozystack's nginx ingress classes are
named after tenants (`tenant-root`, `tenant-*`) — there is no class
called `nginx`.
- Every ingress that needs a cert overrides this with the deprecated
annotation `acme.cert-manager.io/http01-ingress-class: <class>`.
cert-manager still honors it, which is why issuance works at all.
- Mixing the modern `ingressClassName` field with the legacy
`http01-ingress-class` annotation produces `fields ingressClassName and
class cannot be set at the same time` (cert-manager#6651), so the
migration has to be atomic.

**The fix:**
- Parameterize the `ClusterIssuer` HTTP-01 solver from
`_cluster.expose-ingress` (default `tenant-root`) using the modern
`ingressClassName` field.
- Rename the override annotation on all ingresses to the modern
`acme.cert-manager.io/http01-ingress-ingressclassname`.
- No new features, no behavior change for operators who already set
`_cluster.expose-ingress` correctly — just removes the dependency on the
deprecated API and stops pointing at a phantom class.

Touched ingresses (9 templates): keycloak, dashboard, linstor-gui,
bucket, grafana, alerta, bootbox/matchbox, seaweedfs, harbor. Plus
`seaweedfs` values.yaml default annotation and the
`cert-manager-issuers` ClusterIssuer template.

Verified renders for `http01` + `tenant-root`, `http01` + custom class,
and `dns01` (correctly omits the http01 branch).

### Release note

```release-note
fix(platform): ACME HTTP-01 challenges now use the modern `ingressClassName` API and target the tenant ingress class from `_cluster.expose-ingress` (default `tenant-root`) instead of a hardcoded `nginx` class that did not exist on most installs. Ingress templates switched from the deprecated `acme.cert-manager.io/http01-ingress-class` annotation to `acme.cert-manager.io/http01-ingress-ingressclassname`.
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **Chores**
* Updated cert-manager ACME HTTP-01 solver annotations across ingress
configurations to use the newer `ingressclassname` format for improved
compatibility with current cert-manager versions.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-21 18:39:28 +05:00
myasnikovdaniil 6f85f378ff ci(docs): promote next/ trunk on new minor/major releases (#2433)
## What this PR does

Updates the `update-website-docs` job in `.github/workflows/tags.yaml`
to match the new docs-versioning contract introduced in
cozystack/website#495.

The website repo replaces the old "pre-create `vX.Y/` draft directory"
scheme with a permanent `content/en/docs/next/` trunk. Released version
directories are no longer implicitly pre-created — the upstream release
workflow owns the explicit decision of when to promote `next/` →
`vX.Y/`.

### Changes

- **New step `Determine if this release promotes next/`** — parses the
tag and only sets `promote=true` for final `vX.Y.Z` tags where
`content/en/docs/vX.Y/` does not already exist. Prereleases
(`vX.Y.Z-rc.N`, etc.) and patch releases skip promotion.
- **New step `Promote next/ to released version`** — gated on
`promote=true`; runs `make release-next RELEASE_TAG=<tag>`.
- **Step order**: `release-next` runs **before** `update-all`. This way
`update-all` routes into the freshly-created `vX.Y/` directory (per the
website Makefile's routing logic), and `next/` stays untouched as the
trunk for the following release.
- **`git add content hugo.yaml`** — `release-next` registers the new
version in `hugo.yaml` via `register_version.sh`, so the commit step
must stage it.
- Converted the existing `update-all` step to use `env:` vars for
consistency with the new step and workflow-injection hardening.

### Behaviour by tag

| Tag | `release-next`? | `update-all` targets |
|-----|-----------------|----------------------|
| `v1.3.0` (v1.3 does not exist) | yes — promotes next/ → v1.3/ | v1.3/
|
| `v1.3.1` (v1.3 exists) | no — skipped | v1.3/ |
| `v1.3.0-rc.1` | no — skipped (prerelease) | next/ |
| `v2.0.0` (v2.0 does not exist) | yes — promotes next/ → v2.0/ | v2.0/
|

### Release note

```release-note
Release tagging now promotes the website's `next/` docs trunk to `vX.Y/` when cutting a new minor or major release (requires cozystack/website#495 to be merged first).
```

### Dependency

Must not merge until cozystack/website#495 is merged on `main` of the
website repo, otherwise `make release-next` won't exist there and
new-minor release tags will fail.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated release automation to apply conditional logic for version
promotion based on tag patterns and documentation availability. Modified
documentation staging behavior in release workflows.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-21 18:17:01 +05:00
Myasnikov Daniil 6105882856 fix(dashboard): address review feedback on RestoreJob views
- Replace rename-only wording on spec.targetApplicationRef form labels so
  users discover that the field also supports restoring into a different
  application, not just renaming.
- Drop VMInstance-specific keys from the spec.options form label; the
  restore options are driver-specific, so hardcoding one driver's keys is
  misleading once other drivers land.
- Render a single "Same as backup" fallback for an omitted
  spec.targetApplicationRef on the details page instead of the noisy
  "-.-/-" produced by concatenating three missing path fallbacks.
- De-duplicate the time-block / time-icon / time-value component IDs
  within the restorejob-details factory by prefixing them with
  created-, started-at-, and completed-at-.
- Mark non-CRD-backed stock-project-factory-*-details sidebars (kube-*,
  plan, backupjob, backup, restorejob) as static in
  upsertMultipleSidebars so they pick up consistent managed-by labels
  instead of being left unmanaged.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-04-21 17:27:30 +05:00