Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .dmtlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,69 @@ linters-settings:
- kind: Deployment
name: dvcr
container: dvcr-garbage-collection
templates:
exclude-rules:
# These mount-points.yaml directories pre-create mount points for containerd strict mode.
# They are consumed by pods that are NOT rendered from this module's Helm templates:
# virt-launcher (created per-VM by KubeVirt at runtime), CDI importer/cloner/uploadserver and
# dvcr importer/uploader (created on demand by the controllers), and the virt-*/cdi-* components
# deployed by virt-operator/cdi-operator. The mount-points linter only inspects Helm pod
# controllers, so it cannot see these mountPaths and reports false positives.
mount-points:
- /auth
- /certs
- /data
- /dev/bus/usb
- /dvcr-auth
- /dvcr-src-auth
- /etc/docker/registry
- /etc/libvirt
- /etc/podinfo
- /etc/ssl/docker
- /etc/virt-api/certificates
- /etc/virt-controller/certificates
- /etc/virt-controller/exportca
- /etc/virt-handler/clientcertificates
- /etc/virt-handler/servercertificates
- /etc/virt-operator/certificates
- /etc/virtualization-api-proxy/certificates
- /etc/virtualization-api/certificates
- /etc/virtualization-audit/certificates
- /init/usr/bin
- /kubeconfig.local
- /opt
- /path
- /pods
- /profile-data
- /proxycerts
- /run/ca-bundle/cdi-uploadserver-client-signer-bundle
- /run/ca-bundle/cdi-uploadserver-signer-bundle
- /run/cdi/clone/source
- /run/cdi/token/keys
- /run/certs/cdi-apiserver-server-cert
- /run/certs/cdi-apiserver-signer-bundle
- /run/certs/cdi-uploadserver-client-signer
- /run/certs/cdi-uploadserver-signer
- /run/cilium
- /run/kubevirt
- /run/kubevirt-libvirt-runtimes
- /run/kubevirt-private
- /scratch
- /shared
- /tmp/k8s-webhook-server/serving-certs
- /usr/lib/modules
- /var/cache/libvirt
- /var/lib/kubelet/device-plugins
- /var/lib/kubelet/plugins
- /var/lib/kubelet/plugins_registry
- /var/lib/kubelet/pods
- /var/lib/kubevirt
- /var/lib/kubevirt-node-labeller
- /var/lib/libvirt
- /var/lib/libvirt/qemu
- /var/lib/libvirt/qemu/nvram
- /var/lib/libvirt/swtpm
- /var/lib/registry
- /var/lib/swtpm-localca
- /var/log/libvirt
- /var/run/cdi
1 change: 1 addition & 0 deletions .github/actions/milestone-changelog/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ runs:
vdsnapshot
vmsnapshot
vmrestore
vmpool
disks
vd
images
Expand Down
18 changes: 15 additions & 3 deletions .github/scripts/bash/e2e/cleanup-nightly-resources.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ source "${SCRIPT_DIR}/common.sh"
LABEL_SELECTOR="${LABEL_SELECTOR:-test=nightly-e2e}"
KEEP_HOURS="${KEEP_HOURS:-47}"
FRIDAY_KEEP_HOURS="${FRIDAY_KEEP_HOURS:-71}"
# sds-elastic (Ceph) nested clusters are heavy, so they are torn down sooner (~1 day)
# and are not granted the Friday extension. Matched by storage type in the resource name.
ELASTIC_KEEP_HOURS="${ELASTIC_KEEP_HOURS:-23}"
ELASTIC_NAME_PATTERN="${ELASTIC_NAME_PATTERN:-sds-elastic}"

current_date_seconds="$(date -u +%s)"

Expand All @@ -35,20 +39,28 @@ collect_items_json() {

should_keep() {
local created_at="$1"
local name="$2"
local resource_created_at_seconds
local age_seconds
local weekday_of_day
local keep_hours="${KEEP_HOURS}"
local friday_keep_hours="${FRIDAY_KEEP_HOURS}"

if [[ "${name}" == *"${ELASTIC_NAME_PATTERN}"* ]]; then
keep_hours="${ELASTIC_KEEP_HOURS}"
friday_keep_hours="${ELASTIC_KEEP_HOURS}"
fi

resource_created_at_seconds="$(date -d "${created_at}" -u +%s)"
age_seconds="$(( current_date_seconds - resource_created_at_seconds ))"
weekday_of_day="$(date -d "${created_at}" -u +%u)"

if [ "${age_seconds}" -lt "$(( KEEP_HOURS * 3600 ))" ]; then
if [ "${age_seconds}" -lt "$(( keep_hours * 3600 ))" ]; then
echo "keep"
return 0
fi

if [ "${weekday_of_day}" -eq 5 ] && [ "${age_seconds}" -lt "$(( FRIDAY_KEEP_HOURS * 3600 ))" ]; then
if [ "${weekday_of_day}" -eq 5 ] && [ "${age_seconds}" -lt "$(( friday_keep_hours * 3600 ))" ]; then
echo "keep"
return 0
fi
Expand All @@ -69,7 +81,7 @@ cleanup_kind() {
created_at="$(echo "${item}" | jq -r '.created_at')"
[ -z "${name}" ] && continue

decision="$(should_keep "${created_at}")"
decision="$(should_keep "${created_at}" "${name}")"
if [ "${decision}" = "keep" ]; then
printf "%-63s %22s\n" "[INFO] Keep ${kind}/${name}:" "created_at ${created_at}"
continue
Expand Down
134 changes: 134 additions & 0 deletions .github/scripts/bash/e2e/configure-sds-elastic.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#!/usr/bin/env bash

# Copyright 2026 Flant JSC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -Eeuo pipefail

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=.github/scripts/bash/e2e/wait-sds-elastic.sh
source "${SCRIPT_DIR}/wait-sds-elastic.sh"

ELASTIC_CLUSTER_NAME=elastic
ELASTIC_STORAGE_CLASS=nested-ceph-rbd
# StorageClassMigration needs a second RBD storage class as a migration target.
ELASTIC_STORAGE_CLASSES=(nested-ceph-rbd nested-ceph-rbd-r3)

# sds-elastic (Ceph via Rook) is Experimental, so enable it and its dependencies
# (sds-node-configurator, csi-ceph). On the stage profile the modules are absent in
# the stage registry, so pull them from the deckhouse-prod ModuleSource created by
# enable-sdn.sh; otherwise use the default deckhouse source.
apply_module_configs() {
local source_field=" source: deckhouse"

if [ -n "${MODULE_SOURCE_REGISTRY_CFG:-}" ]; then
source_field=" source: deckhouse-prod"
fi

kubectl apply -f - <<EOF
---
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: sds-node-configurator
spec:
enabled: true
version: 1
${source_field}
---
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: csi-ceph
spec:
enabled: true
version: 1
${source_field}
settings:
cephfsEnabled: false
---
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: sds-elastic
spec:
enabled: true
version: 1
${source_field}
settings:
dataNodes:
nodeSelector:
node-role.deckhouse.io/worker: ""
EOF
}

echo "[INFO] Allow experimental modules (sds-elastic is Experimental)"
kubectl patch mc deckhouse --type=merge \
-p '{"spec":{"settings":{"allowExperimentalModules":true}}}'

d8_queue

if [ -n "${MODULE_SOURCE_REGISTRY_CFG:-}" ]; then
echo "[INFO] Apply sds-elastic ModuleConfigs with deckhouse-prod source (stage profile)"
else
echo "[INFO] Apply sds-elastic ModuleConfigs with deckhouse source"
fi
apply_module_configs

echo "[INFO] Wait for sds-node-configurator to be ready"
kubectl wait --for=jsonpath='{.status.phase}'=Ready modules sds-node-configurator --timeout=300s

echo "[INFO] Wait for csi-ceph to be ready"
kubectl wait --for=jsonpath='{.status.phase}'=Ready modules csi-ceph --timeout=600s

echo "[INFO] Wait for sds-elastic to be ready"
kubectl wait --for=jsonpath='{.status.phase}'=Ready modules sds-elastic --timeout=600s

echo "[INFO] Wait for raw block devices to be discovered"
elastic_blockdevices_ready

echo "[INFO] Label consumable block devices as OSDs (app=elastic-osd)"
for bd in $(kubectl get blockdevices.storage.deckhouse.io -o json | jq -r '.items[] | select(.status.consumable == true) | .metadata.name'); do
echo "[INFO] Label blockdevice ${bd} app=elastic-osd"
kubectl label blockdevice "${bd}" app=elastic-osd --overwrite
done

echo "[INFO] Create ElasticCluster (host networking)"
kubectl apply -f ./elastic-cluster.yaml

echo "[INFO] Wait for ElasticCluster to be ready"
elastic_cluster_ready "${ELASTIC_CLUSTER_NAME}"

echo "[INFO] Create ElasticStorageClasses (RBD: replica-2 default + replica-3 migration target)"
kubectl apply -f ./elastic-storage-class.yaml

for sc in "${ELASTIC_STORAGE_CLASSES[@]}"; do
echo "[INFO] Wait for StorageClass ${sc} to appear"
for i in $(seq 1 30); do
if kubectl get storageclass "${sc}" >/dev/null 2>&1; then
echo "[SUCCESS] StorageClass ${sc} is present"
break
fi
echo "[INFO] Wait 10s for StorageClass ${sc} (attempt ${i}/30)"
sleep 10
done
done

echo "[INFO] Set default cluster storage class to ${ELASTIC_STORAGE_CLASS}"
kubectl patch mc global --type='json' \
-p='[{"op": "replace", "path": "/spec/settings/defaultClusterStorageClass", "value": "'"${ELASTIC_STORAGE_CLASS}"'"}]'

echo "[INFO] Show existing storageclasses and volumesnapshotclasses"
kubectl get storageclass
kubectl get volumesnapshotclass || echo "[WARNING] No volumesnapshotclasses found"
6 changes: 3 additions & 3 deletions .github/scripts/bash/e2e/power-off-nested-vms.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=.github/scripts/bash/e2e/common.sh
source "${SCRIPT_DIR}/common.sh"

# Constants (nested cluster: 1 master + 3 workers x2)
REQUIRED_MEM_GI=86
REQUIRED_CPU=26
# Constants ((nested cluster: 1 master + 3 workers) x3: replicated + nfs + sds-elastic)
REQUIRED_MEM_GI=129
REQUIRED_CPU=39
MIN_MEM_GI_PER_NODE=12
MIN_CPU_PER_NODE=4
MIN_NODES_FOR_PLACEMENT=3
Expand Down
13 changes: 13 additions & 0 deletions .github/scripts/bash/e2e/render-dvp-static-values.sh
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,19 @@ envsubst_variables="$(grep -oE '\$\{[A-Z0-9_]+\}' values.yaml.tmpl | sort -u | t
envsubst "${envsubst_variables}" \
< values.yaml.tmpl > values.yaml

# The template defines one additional worker disk. When ADDITIONAL_DISK_COUNT > 1
# (e.g. sds-elastic runs several Ceph OSDs per node), append the extra disks, each
# of ADDITIONAL_DISK_SIZE, to every worker node group.
additional_disk_count="${ADDITIONAL_DISK_COUNT:-1}"
if (( additional_disk_count > 1 )); then
for (( d = 2; d <= additional_disk_count; d++ )); do
# ADDITIONAL_DISK_SIZE is exported by the workflow step env and read by yq's env().
yq eval --inplace \
'(.instances.additionalNodes[] | select(.name == "worker") | .cfg.additionalDisks) += [{"size": env(ADDITIONAL_DISK_SIZE)}]' \
values.yaml
done
fi

mkdir -p tmp
touch tmp/discovered-values.yaml

Expand Down
Loading
Loading