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