Commit Graph
5128 Commits
Author SHA1 Message Date
Arsolitt 0fb0de7062 feat(kubernetes): add migration guard for ephemeralStorage field rename
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 19:12:44 +03:00
Arsolitt c2eb6c0b3d docs(kubernetes): fix storageClass default value in README parameter table
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 19:12:44 +03:00
Arsolitt 70dbb12450 fix(kubernetes): add kubebuilder default annotation to StorageClass field
The NodeGroup.StorageClass field lacked a +kubebuilder:default annotation,
causing a semantic inconsistency: the map-level default in ConfigSpec
included "storageClass": "" but CRD defaulting would not inject it at the
leaf level when a user specified a nodeGroup without storageClass.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 19:12:44 +03:00
Arsolitt a0b18b37c5 test(kubernetes): document test schema deviation from production defaults
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:04 +03:00
Arsolitt a451a898d6 docs(kubernetes): document ephemeralStorage to diskSize breaking change
Add a Breaking Changes section noting that ephemeralStorage has been
renamed to diskSize with no backward-compatibility fallback.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:04 +03:00
Arsolitt fccea96730 fix(kubernetes): remove empty default from storageClass in schema
Drop the explicit `"default": ""` from storageClass so the field is
simply absent when not set, matching how other optional string fields
behave in the schema.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:04 +03:00
Arsolitt 7a215ea809 test(kubernetes): add storageClass to defaulting test schema
Include storageClass field in the test schema and default values so
the defaulting test covers the new per-nodeGroup storageClass property.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:04 +03:00
Arsolitt 5560162934 test(kubernetes): add KubeadmConfigTemplate persistent storage tests
Verify that the KubeadmConfigTemplate correctly configures XFS
filesystem, disk partitioning, mount points, bind-mounts for kubelet
and containerd, and preKubeadmCommands guards.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:04 +03:00
Arsolitt ca12f28734 test(kubernetes): add multi-nodegroup dataVolumeTemplate test
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:04 +03:00
Arsolitt a336f1812c fix(kubernetes): add default value for storageClass in schema
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:03 +03:00
Arsolitt d1dfb75581 fix(kubernetes): add explicit overwrite false to disk_setup for persistent storage safety
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:03 +03:00
Arsolitt 6403982039 test(kubernetes): add helm test for diskSize default fallback
Verify that KubevirtMachineTemplate renders 20Gi storage when diskSize
is not explicitly set, ensuring the default value propagates correctly.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:03 +03:00
Arsolitt ad2705b81f fix(kubernetes): rename ephemeralStorage to diskSize in defaulting tests
Align test schema and assertions with the field rename from
ephemeralStorage to diskSize introduced in the production code.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:03 +03:00
Arsolitt c434fbb1a7 fix(kubernetes): include per-nodeGroup storageClass in values default
Add storageClass: "" to nodeGroups.md0 in values.yaml so that the
code generator picks it up and places it into keysOrder for the
dashboard field ordering.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:03 +03:00
Arsolitt 2de4a81623 refactor(kubernetes): deduplicate test fixtures in cluster_test.yaml
Extract repeated values (_cluster, _namespace, version, controlPlane,
nodeGroups base config) into a shared values/common.yaml fixture loaded
at suite level, so each test case only overrides the fields it varies.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:03 +03:00
Arsolitt d0c13a4638 fix(kubernetes): regenerate CRD and schema files
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:02 +03:00
Arsolitt f708953270 fix(kubernetes): restore storageClass in keysOrder for nodeGroups
Add the storageClass key back into the keysOrder array for
nodeGroups so the dashboard renders the field in the correct
position alongside diskSize and other per-group settings.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:02 +03:00
Arsolitt ad3fbc1e55 fix(kubernetes): quote storage values and guard bind-mount commands
Quote diskSize and storageClassName Helm template outputs to prevent
bare numeric or special-char values from causing YAML parse errors.

Also ensure mount-point directories exist before bind-mounting and skip
the mount when the target is already a mountpoint, avoiding failures
on node reboot or re-provisioning.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:02 +03:00
Arsolitt cf98381d48 docs(kubernetes): document automatic block size matching for worker node disks
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:02 +03:00
Arsolitt b5e89c56e2 fix(kubernetes): set matchVolume blockSize on disk-kubelet for DRBD 4Kn compatibility
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:02 +03:00
Arsolitt baad81333b fix(kubernetes): regenerate deepcopy for DiskSize field rename
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:02 +03:00
Arsolitt 68e9529b72 fix(kubernetes): remove storageClass from keysOrder to match generator output
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:02 +03:00
Arsolitt 92b6409c5a fix(kubernetes): add test target to Makefile for CI
The helm unit tests in tests/cluster_test.yaml were silently skipped by CI
because the Makefile had no test target. CI runs hack/helm-unit-tests.sh
which only invokes make test when the target exists.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:01 +03:00
Arsolitt 1e455a1d34 test(kubernetes): add helm unit tests for cluster template
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:01 +03:00
Arsolitt fe6ef58b0a fix(kubernetes): add explanatory comments for non-obvious template values
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:01 +03:00
Arsolitt e1ab6f6274 fix(kubernetes): add storageClass to keysOrder for nodeGroups
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:01 +03:00
Arsolitt 97a2585cf9 feat(kubernetes): add per-nodeGroup storageClass for worker node disks
Allow each node group to specify its own storageClass for persistent
worker node disks. When empty, the cluster default StorageClass is used.
This enables using local storage for worker disks while keeping
replicated storage for tenant workloads.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:01 +03:00
Arsolitt 7b7686096e fix(kubernetes): disable CDI populator for blank DataVolumes
Add cdi.kubevirt.io/storage.usePopulator: "false" annotation to
the dataVolumeTemplate to prevent CDI volume population flow.

The populator mechanism creates an intermediate "prime" PVC and
rebinds the PV, which causes ClaimMisbound errors with LINSTOR CSI.
The legacy import path writes directly to the target PVC.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:01 +03:00
Arsolitt 90e4aba4ef fix(kubernetes): set fixed 2Gi ephemeral-storage for virt-launcher pod
With PVC-backed persistent disks, the virt-launcher pod no longer needs
ephemeral-storage sized to the full disk. Set a fixed 2Gi allocation
for QEMU runtime needs and proper scheduler behavior.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:00 +03:00
Arsolitt 0ac228036a feat(kubernetes)!: replace emptyDisk with persistent dataVolumeTemplates for worker nodes
Replace the ephemeral emptyDisk volume with a CDI dataVolumeTemplate
backed by the tenant's storageClass. This ensures kubelet certificates,
kubeconfig, and containerd state survive VM reboots, preventing worker
nodes from falling out of the cluster.

Changes in the KubevirtMachineTemplate:
- Add dataVolumeTemplates with a blank source disk sized by diskSize
- Switch the volume reference from emptyDisk to dataVolume
- Rename disk and volume from "ephemeral" to "disk-kubelet"

Changes in the KubeadmConfigTemplate:
- Rename filesystem label from "ephemeral" to "persistent"
- Update all mount paths from /ephemeral to /persistent

BREAKING CHANGE: Worker node VMs now use persistent PVC-backed disks
instead of ephemeral emptyDisk volumes. Existing clusters will trigger
a rolling replacement of worker nodes on upgrade.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:00 +03:00
Arsolitt dfa6fd9911 feat(kubernetes)!: rename ephemeralStorage to diskSize in node group config
Rename the ephemeralStorage field to diskSize in the NodeGroup typedef
and default values to reflect the upcoming switch from ephemeral
emptyDisk volumes to persistent dataVolumeTemplates for worker nodes.

BREAKING CHANGE: The nodeGroups.*.ephemeralStorage field has been renamed
to nodeGroups.*.diskSize. Users must update their values overrides.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 18:40:00 +03:00
IvanHunters 5b2501db91 test(api): add security tests for TenantNamespace IDOR fix
Added comprehensive unit tests for authorization logic:

- hasAccessToNamespace() tests:
  - User subject access (positive and negative cases)
  - Group subject access
  - ServiceAccount subject access
  - ServiceAccount with empty namespace (defaults to RoleBinding ns)
  - Privileged groups (system:masters, cozystack-cluster-admin)

- Get() handler tests:
  - Returns namespace when user has access
  - Returns NotFound when user lacks access (not Forbidden)
  - Returns NotFound for non-tenant namespaces

All tests verify that authorization correctly enforces RoleBinding-based
access control and prevents IDOR vulnerabilities.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-04-23 18:17:47 +03:00
IvanHunters 64a3edff01 fix(api): prevent IDOR in TenantNamespace Get and Watch handlers
Fixed two IDOR vulnerabilities allowing authenticated users to access
metadata of any tenant namespace without proper authorization.

Changes:
- Added hasAccessToNamespace() for efficient single-namespace access checks
- Get() now verifies access before returning namespace metadata
- Watch() filters events per-namespace with proper authorization
- Returns NotFound (not Forbidden) to prevent tenant enumeration

Performance optimization:
- hasAccessToNamespace() lists RoleBindings only in target namespace
  instead of listing all cluster RoleBindings (order of magnitude faster)
- Watch handler logs authorization errors for security audit

Additional fixes:
- Handle ServiceAccount subjects with empty namespace correctly
- Add klog error logging for failed authorization checks

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
2026-04-23 18:13:10 +03:00
Aleksei Sviridkin 7e887ed723 docs(agents): document make generate requirement before committing (#2469)
## What this PR does

Adds explicit guidance to `docs/agents/contributing.md` about running
`make generate` in any touched package before committing. Pre-commit CI
runs `make generate` in every package and fails with exit code 123 on
any uncommitted generator output (regenerated `README.md`, reordered
`values.schema.json`, refreshed
`packages/system/<name>-rd/cozyrds/<name>.yaml`).

Recent PRs have tripped on this during review cycles. Documenting it in
the contributing checklist saves a round-trip.

### Release note

```release-note
NONE
```


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

* **Documentation**
* Require regenerating and committing generated artifacts when
designated source files are edited.
* Added a section listing generated artifacts per package and concrete
regeneration/staging steps.
* Documented CI enforcement that detects unstaged generator output and
blocks PRs.
* Added guidance for rerunning generation after amended commits, plus
updated commit-scope guidance (now “not exhaustive”) and included
“agents” in allowed scopes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-23 18:08:26 +03:00
Aleksei Sviridkin 4813566a30 docs(agents): mark scopes list as illustrative examples
Address review feedback from gemini-code-assist on docs/agents/contributing.md:11:
Scope linters kept flagging valid scopes like 'agents' as unknown because
the list read as exhaustive. Annotate it as examples (not exhaustive) and
add 'agents' to the Other group so both humans and review bots stop
tripping on scopes that are already in regular use across the repo
history.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
2026-04-23 18:02:04 +03:00
Aleksei Sviridkin 41fd80711b docs(agents): fix grammar in regen discovery hint
Address review feedback from gemini-code-assist on docs/agents/contributing.md:30:
Reword "likely to need regenerated" (regional construction) to
"likely needs to be regenerated" for standard technical prose.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
2026-04-23 18:00:07 +03:00
Aleksei Sviridkin c34a9db6bd docs(agents): broaden make generate example to apps packages
Address review feedback from coderabbitai on docs/agents/contributing.md:26:
Replace the hard-coded packages/extra/<name> path in the example with
packages/<apps-or-extra>/<name> so the example matches the preceding
text that describes both apps and extra packages.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
2026-04-23 17:59:49 +03:00
Arsolitt 8aedc35b7d docs(kubernetes): note autoscaler visibility gap for eviction percentages without effective memory
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:58:29 +03:00
Arsolitt 103570e4c0 fix(kubernetes): remove unused variable and generalize memory guard error message
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:51:37 +03:00
Arsolitt 32d652b00d fix(kubernetes): use cpuToMillicores for CPU parsing and clarify eviction error messages
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:43:49 +03:00
Aleksei Sviridkin adc7abe5c1 feat(ingress): add loadBalancer exposure mode via CiliumLoadBalancerIPPool
Service.spec.externalIPs is deprecated upstream in Kubernetes v1.36
(KEP-5707, kubernetes#137293). The AllowServiceExternalIPs feature gate
is expected to default to off around v1.40 and the implementation to
be removed around v1.43. For bare-metal installs that rely on
externalIPs today, cozystack needs a migration path.

This change adds an opt-in 'loadBalancer' exposure mode for the
ingress-nginx Service:

- New platform value 'publishing.exposure' (enum: externalIPs |
  loadBalancer, default externalIPs). Plumbed through cozystack-values
  into each tenant's ingress HelmRelease via the new 'expose-mode' key.
- Unknown values and loadBalancer with an empty externalIPs list fail
  the chart render with explicit error messages, rather than silently
  producing a broken Service.
- When exposure=loadBalancer and the current namespace matches
  publishing.ingressName, the Service becomes type: LoadBalancer with
  externalTrafficPolicy: Local.
- A new template renders a CiliumLoadBalancerIPPool whose blocks come
  from publishing.externalIPs (IPv4 addresses get /32, IPv6 addresses
  get /128) and whose serviceSelector uses Cilium's synthetic
  io.kubernetes.service.namespace key combined with the standard
  app.kubernetes.io/name: ingress-nginx label. No custom label is
  written to the Service itself, avoiding cross-tenant collisions from
  user-defined labels.

Default behaviour is unchanged: without opting in, the Service is
still ClusterIP + spec.externalIPs as today.

Scope: only ingress-nginx is migrated by this setting. Other cozystack
components that still write Service.spec.externalIPs directly (notably
the vpn app) must be migrated separately before the v1.40 feature gate
flip.

Tests: packages/extra/ingress/tests/exposure_test.yaml adds 13
helm-unittest cases covering both modes, IPv4/IPv6, empty-token
filtering, unknown-mode rejection, and the non-matching-namespace
fallback.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
2026-04-23 17:35:36 +03:00
Aleksei Sviridkin 3f36a1b45b fix(cilium): rebuild image multi-arch and pin tag to 1.19.3
The previous image digest in values.yaml pointed at a single-arch
linux/arm64 manifest because 'make image' was run from an arm64 host
with the default buildx platform. Cozystack targets amd64 (Talos build
output, E2E runners, most real-world clusters) and also arm64 for
hybrid fleets, so Helm install would fail on amd64 nodes with 'no
matching manifest for linux/amd64 in the manifest list entries'
whenever somebody installed directly from this commit between merge
and the next release-tag CI rebuild.

Fix: rebuilt the image locally with
PLATFORM='linux/amd64,linux/arm64' make image from a buildx
docker-container driver, pushed the multi-arch manifest, and
refreshed values.yaml with:

- digest of the new multi-arch manifest list (verified via
  'docker manifest inspect': amd64 sha256:e1977323..., arm64
  sha256:8f5ab529...).
- tag bumped from 'latest' (emitted by the common-envs.mk settag
  macro on a non-tagged checkout) to '1.19.3', matching the
  established convention in every other packages/system/*/values.yaml
  so reviewers and incident response have a human-readable version
  anchor independent of digest chasing.

The Makefile is left untouched so the CI builder (which only uses the
default docker driver) keeps building single-arch for whatever
architecture it runs on; multi-arch is a responsibility of the
release-tag pipeline or an explicit local rebuild.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
2026-04-23 17:33:19 +03:00
Arsolitt 390bdc4936 fix(kubernetes): remove deprecated kubelet CLI flags
Remove cgroups-per-qos, cgroup-driver, and kernel-memcg-notification from
kubeletExtraArgs. These flags are deprecated or already removed from kubelet CLI,
and their functionality is either the default behavior or handled via
KubeletConfiguration.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:57 +03:00
Arsolitt a3b35c676b chore(kubernetes): add .PHONY declarations to Makefile
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:57 +03:00
Arsolitt 7deeaa691f docs(kubernetes): use 'supported' instead of 'latest' for patch version wording
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:57 +03:00
Arsolitt 0a350fc196 fix(kubernetes): produce clean integer output from cpuToMillicores and add CPU annotation tests
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:57 +03:00
Arsolitt 34c5868c59 fix(kubernetes): add grace periods for all soft eviction signals
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:57 +03:00
Arsolitt 6f748d0e96 fix(kubernetes): improve mixed eviction type error message with override guidance
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:56 +03:00
Arsolitt 545f35638a fix(kubernetes): preserve disk eviction thresholds alongside memory in kubeletExtraArgs
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:56 +03:00
Arsolitt af5a27afef docs(kubernetes): fix annotation target in kubelet reservation docs
Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-04-23 17:02:56 +03:00