mirror of
https://github.com/lingble/talos.git
synced 2025-11-02 13:38:12 +00:00
chore: move bash tests to integration
move extensions and secureboot tests to integration. Makes it easier to test. Signed-off-by: Noel Georgi <git@frezbo.dev>
This commit is contained in:
@@ -443,7 +443,7 @@ local integration_qemu_trusted_boot = Step('e2e-qemu-trusted-boot', target='e2e-
|
|||||||
IMAGE_REGISTRY: local_registry,
|
IMAGE_REGISTRY: local_registry,
|
||||||
VIA_MAINTENANCE_MODE: 'true',
|
VIA_MAINTENANCE_MODE: 'true',
|
||||||
WITH_TRUSTED_BOOT_ISO: 'true',
|
WITH_TRUSTED_BOOT_ISO: 'true',
|
||||||
WITH_TEST: 'validate_booted_secureboot',
|
EXTRA_TEST_ARGS: '-talos.trustedboot',
|
||||||
});
|
});
|
||||||
|
|
||||||
local build_race = Step('build-race', target='initramfs installer', depends_on=[load_artifacts], environment={ IMAGE_REGISTRY: local_registry, PUSH: true, TAG_SUFFIX: '-race', WITH_RACE: '1', PLATFORM: 'linux/amd64' });
|
local build_race = Step('build-race', target='initramfs installer', depends_on=[load_artifacts], environment={ IMAGE_REGISTRY: local_registry, PUSH: true, TAG_SUFFIX: '-race', WITH_RACE: '1', PLATFORM: 'linux/amd64' });
|
||||||
@@ -455,11 +455,10 @@ local integration_provision_tests_track_1 = Step('provision-tests-track-1', priv
|
|||||||
local integration_provision_tests_track_2 = Step('provision-tests-track-2', privileged=true, depends_on=[integration_provision_tests_prepare], environment={ IMAGE_REGISTRY: local_registry });
|
local integration_provision_tests_track_2 = Step('provision-tests-track-2', privileged=true, depends_on=[integration_provision_tests_prepare], environment={ IMAGE_REGISTRY: local_registry });
|
||||||
|
|
||||||
local integration_extensions = Step('e2e-extensions', target='e2e-qemu', privileged=true, depends_on=[extensions_patch_manifest], environment={
|
local integration_extensions = Step('e2e-extensions', target='e2e-qemu', privileged=true, depends_on=[extensions_patch_manifest], environment={
|
||||||
SHORT_INTEGRATION_TEST: 'yes',
|
QEMU_MEMORY_WORKERS: '4096',
|
||||||
QEMU_MEMORY_WORKERS: '3072',
|
|
||||||
WITH_CONFIG_PATCH_WORKER: '@_out/extensions-patch.json',
|
WITH_CONFIG_PATCH_WORKER: '@_out/extensions-patch.json',
|
||||||
WITH_TEST: 'run_extensions_test',
|
|
||||||
IMAGE_REGISTRY: local_registry,
|
IMAGE_REGISTRY: local_registry,
|
||||||
|
EXTRA_TEST_ARGS: '-talos.extensions.testtype=qemu',
|
||||||
});
|
});
|
||||||
local integration_cilium = Step('e2e-cilium', target='e2e-qemu', privileged=true, depends_on=[load_artifacts], environment={
|
local integration_cilium = Step('e2e-cilium', target='e2e-qemu', privileged=true, depends_on=[load_artifacts], environment={
|
||||||
SHORT_INTEGRATION_TEST: 'yes',
|
SHORT_INTEGRATION_TEST: 'yes',
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -16,7 +16,7 @@ CLOUD_IMAGES_EXTRA_ARGS ?= ""
|
|||||||
|
|
||||||
ARTIFACTS := _out
|
ARTIFACTS := _out
|
||||||
TOOLS ?= ghcr.io/siderolabs/tools:v1.5.0
|
TOOLS ?= ghcr.io/siderolabs/tools:v1.5.0
|
||||||
PKGS ?= v1.5.0
|
PKGS ?= v1.6.0-alpha.0-5-g7717b7e
|
||||||
EXTRAS ?= v1.5.0
|
EXTRAS ?= v1.5.0
|
||||||
# renovate: datasource=github-tags depName=golang/go
|
# renovate: datasource=github-tags depName=golang/go
|
||||||
GO_VERSION ?= 1.20
|
GO_VERSION ?= 1.20
|
||||||
|
|||||||
@@ -195,8 +195,6 @@ case "${TEST_MODE:-default}" in
|
|||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
get_kubeconfig
|
get_kubeconfig
|
||||||
validate_virtio_modules
|
|
||||||
validate_rlimit_nofile
|
|
||||||
run_talos_integration_test
|
run_talos_integration_test
|
||||||
run_kubernetes_integration_test
|
run_kubernetes_integration_test
|
||||||
|
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ function run_talos_integration_test {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
"${INTEGRATION_TEST}" -test.v -talos.failfast -talos.talosctlpath "${TALOSCTL}" -talos.kubectlpath "${KUBECTL}" -talos.provisioner "${PROVISIONER}" -talos.name "${CLUSTER_NAME}" "${TEST_RUN[@]}" "${TEST_SHORT[@]}"
|
"${INTEGRATION_TEST}" -test.v -talos.failfast -talos.talosctlpath "${TALOSCTL}" -talos.kubectlpath "${KUBECTL}" -talos.provisioner "${PROVISIONER}" -talos.name "${CLUSTER_NAME}" "${EXTRA_TEST_ARGS[@]}" "${TEST_RUN[@]}" "${TEST_SHORT[@]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
function run_talos_integration_test_docker {
|
function run_talos_integration_test_docker {
|
||||||
@@ -170,7 +170,7 @@ function run_talos_integration_test_docker {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
"${INTEGRATION_TEST}" -test.v -talos.talosctlpath "${TALOSCTL}" -talos.kubectlpath "${KUBECTL}" -talos.k8sendpoint 127.0.0.1:6443 -talos.provisioner "${PROVISIONER}" -talos.name "${CLUSTER_NAME}" "${TEST_RUN[@]}" "${TEST_SHORT[@]}"
|
"${INTEGRATION_TEST}" -test.v -talos.talosctlpath "${TALOSCTL}" -talos.kubectlpath "${KUBECTL}" -talos.k8sendpoint 127.0.0.1:6443 -talos.provisioner "${PROVISIONER}" -talos.name "${CLUSTER_NAME}" "${EXTRA_TEST_ARGS[@]}" "${TEST_RUN[@]}" "${TEST_SHORT[@]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
function run_kubernetes_conformance_test {
|
function run_kubernetes_conformance_test {
|
||||||
@@ -221,81 +221,6 @@ function build_registry_mirrors {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function run_extensions_test {
|
|
||||||
# e2e-qemu creates 3 controlplanes
|
|
||||||
# use a worker node to test extensions
|
|
||||||
"${TALOSCTL}" config node 172.20.1.5
|
|
||||||
|
|
||||||
echo "Testing firmware extensions..."
|
|
||||||
${TALOSCTL} ls /lib/firmware | grep amd-ucode
|
|
||||||
${TALOSCTL} ls /lib/firmware | grep bnx2x
|
|
||||||
${TALOSCTL} ls /lib/firmware | grep i915
|
|
||||||
${TALOSCTL} ls /lib/firmware | grep intel-ucode
|
|
||||||
|
|
||||||
echo "Testing kernel modules tree extension..."
|
|
||||||
${TALOSCTL} get extensions modules.dep
|
|
||||||
KERNEL_VERSION=$(${TALOSCTL} get extensions modules.dep -o json | jq -r '.spec.metadata.version')
|
|
||||||
${TALOSCTL} ls "/lib/modules/${KERNEL_VERSION}/extras/" | grep gasket
|
|
||||||
${TALOSCTL} read "/lib/modules/${KERNEL_VERSION}/modules.dep" | grep -E gasket
|
|
||||||
${TALOSCTL} ls "/lib/modules/${KERNEL_VERSION}/extras/" | grep drbd
|
|
||||||
${TALOSCTL} read "/lib/modules/${KERNEL_VERSION}/modules.dep" | grep -E drbd
|
|
||||||
${TALOSCTL} ls "/lib/modules/${KERNEL_VERSION}/kernel/drivers/video/" | grep nvidia
|
|
||||||
${TALOSCTL} read "/lib/modules/${KERNEL_VERSION}/modules.dep" | grep -E nvidia
|
|
||||||
|
|
||||||
echo "Testing drbd and gasket modules are loaded..."
|
|
||||||
${TALOSCTL} read /proc/modules | grep -E drbd
|
|
||||||
${TALOSCTL} read /proc/modules | grep -E gasket
|
|
||||||
|
|
||||||
echo "Testing kernel modules signature..."
|
|
||||||
${TALOSCTL} read "/lib/modules/${KERNEL_VERSION}/extras/drbd.ko" | ${MODULE_SIG_VERIFY} -cert "${KERNEL_MODULE_SIGNING_PUBLIC_KEY}" -module -
|
|
||||||
${TALOSCTL} read "/lib/modules/${KERNEL_VERSION}/extras/gasket.ko" | ${MODULE_SIG_VERIFY} -cert "${KERNEL_MODULE_SIGNING_PUBLIC_KEY}" -module -
|
|
||||||
${TALOSCTL} read "/lib/modules/${KERNEL_VERSION}/kernel/drivers/video/nvidia.ko" | ${MODULE_SIG_VERIFY} -cert "${KERNEL_MODULE_SIGNING_PUBLIC_KEY}" -module -
|
|
||||||
|
|
||||||
echo "Testing iscsi-tools extensions service..."
|
|
||||||
${TALOSCTL} services ext-iscsid | grep -E "STATE\s+Running"
|
|
||||||
${TALOSCTL} services ext-tgtd | grep -E "STATE\s+Running"
|
|
||||||
|
|
||||||
echo "Testing nut-client extensions service..."
|
|
||||||
${TALOSCTL} services ext-nut-client | grep -E "STATE\s+Running"
|
|
||||||
|
|
||||||
echo "Testing gVsisor..."
|
|
||||||
${KUBECTL} apply -f "${PWD}/hack/test/gvisor/manifest.yaml"
|
|
||||||
sleep 10
|
|
||||||
${KUBECTL} wait --for=condition=ready pod nginx-gvisor --timeout=2m
|
|
||||||
|
|
||||||
echo "Testing hello-world extension service..."
|
|
||||||
${TALOSCTL} services ext-hello-world | grep -E "STATE\s+Running"
|
|
||||||
curl http://172.20.1.5/ | grep Hello
|
|
||||||
|
|
||||||
echo "Testing tailscale extension service..."
|
|
||||||
${TALOSCTL} services ext-tailscale | grep -E "STATE\s+Running"
|
|
||||||
${TALOSCTL} get links tailscale0
|
|
||||||
|
|
||||||
echo "Testing qemu-guest-agent extension service..."
|
|
||||||
${TALOSCTL} services ext-qemu-guest-agent | grep -E "STATE\s+Running"
|
|
||||||
# get exisitng boot id
|
|
||||||
BOOT_ID=$(get_boot_id)
|
|
||||||
NODE_HOSTNAME=$(${TALOSCTL} get hostname -o json | jq -r '.spec.hostname')
|
|
||||||
CLUSTERNAME=$(cut -d '-' -f 1-2 <<< "${NODE_HOSTNAME}")
|
|
||||||
# issue a reboot via qemu-guest-agent
|
|
||||||
echo '{"execute":"guest-shutdown", "arguments": {"mode": "reboot"}}' | socat - unix-connect:"${HOME}/.talos/clusters/${CLUSTERNAME}/${NODE_HOSTNAME}.sock"
|
|
||||||
# wait for the node to reboot
|
|
||||||
${TALOSCTL} -n 172.20.1.2 health
|
|
||||||
NEW_BOOT_ID=$(get_boot_id)
|
|
||||||
# verify that the boot id has changed
|
|
||||||
if [ "${BOOT_ID}" == "${NEW_BOOT_ID}" ]; then
|
|
||||||
echo "ERROR: boot id has not changed, reboot failed"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# set talosctl config back to the first controlplane
|
|
||||||
"${TALOSCTL}" config node 172.20.1.2
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_boot_id() {
|
|
||||||
${TALOSCTL} read /proc/sys/kernel/random/boot_id
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_csi_tests {
|
function run_csi_tests {
|
||||||
${HELM} repo add rook-release https://charts.rook.io/release
|
${HELM} repo add rook-release https://charts.rook.io/release
|
||||||
${HELM} repo update
|
${HELM} repo update
|
||||||
@@ -314,21 +239,6 @@ function run_csi_tests {
|
|||||||
KUBERNETES_SERVICE_HOST="" KUBECONFIG="${TMP}/kubeconfig" "${KUBESTR}" fio --storageclass ceph-block --size 10G
|
KUBERNETES_SERVICE_HOST="" KUBECONFIG="${TMP}/kubeconfig" "${KUBESTR}" fio --storageclass ceph-block --size 10G
|
||||||
}
|
}
|
||||||
|
|
||||||
function validate_virtio_modules {
|
|
||||||
${TALOSCTL} read /proc/modules | grep -q virtio
|
|
||||||
}
|
|
||||||
|
|
||||||
function validate_rlimit_nofile {
|
|
||||||
# verify that RLIMIT_NOFILE is set to 1048576
|
|
||||||
${KUBECTL} run --rm --restart=Never -it rlimit-test --image=alpine -- /bin/sh -c "ulimit -n" | grep 1048576
|
|
||||||
}
|
|
||||||
|
|
||||||
function validate_booted_secureboot {
|
|
||||||
${TALOSCTL} dmesg | grep "Secure boot enabled"
|
|
||||||
${TALOSCTL} get securitystate -o json
|
|
||||||
${TALOSCTL} get securitystate -o json | jq -e '.spec.secureBoot == true'
|
|
||||||
}
|
|
||||||
|
|
||||||
function install_and_run_cilium_cni_tests {
|
function install_and_run_cilium_cni_tests {
|
||||||
get_kubeconfig
|
get_kubeconfig
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"path": "/machine/install/extensions",
|
"path": "/machine/install/extensions",
|
||||||
"value": [
|
"value": [
|
||||||
{
|
{
|
||||||
"image": map(select(. | contains("nvidia-container-toolkit") or contains("nvidia-fabricmanager") | not)) | .[]
|
"image": map(select(. | contains("nvidia") or contains("tailscale") | not)) | .[]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -20,11 +20,68 @@
|
|||||||
"path": "/machine/kernel",
|
"path": "/machine/kernel",
|
||||||
"value": {
|
"value": {
|
||||||
"modules": [
|
"modules": [
|
||||||
|
{
|
||||||
|
"name": "asix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ax88179_178a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ax88796b"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cdc_ether"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cdc_mbim"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cdc_ncm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cdc_subset"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cdc_wdm"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "drbd"
|
"name": "drbd"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "gasket"
|
"name": "gasket"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "net1080"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "option"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "qmi_wwan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "r8153_ecm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "thunderbolt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "thunderbolt_net"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "usb_wwan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "usbnet"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "usbserial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "zaurus"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "zfs"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ import "github.com/stretchr/testify/suite"
|
|||||||
|
|
||||||
var allSuites []suite.TestingSuite
|
var allSuites []suite.TestingSuite
|
||||||
|
|
||||||
|
const (
|
||||||
|
provisionerDocker = "docker"
|
||||||
|
provisionerQEMU = "qemu"
|
||||||
|
)
|
||||||
|
|
||||||
// GetAllSuites returns all the suites for API test.
|
// GetAllSuites returns all the suites for API test.
|
||||||
//
|
//
|
||||||
// Depending on build tags, this might return different lists.
|
// Depending on build tags, this might return different lists.
|
||||||
|
|||||||
198
internal/integration/api/common.go
Normal file
198
internal/integration/api/common.go
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
//go:build integration_api
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/siderolabs/go-retry/retry"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/client-go/tools/remotecommand"
|
||||||
|
"k8s.io/kubectl/pkg/scheme"
|
||||||
|
|
||||||
|
"github.com/siderolabs/talos/internal/integration/base"
|
||||||
|
"github.com/siderolabs/talos/pkg/machinery/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CommonSuite verifies some default settings such as ulimits.
|
||||||
|
type CommonSuite struct {
|
||||||
|
base.K8sSuite
|
||||||
|
|
||||||
|
ctx context.Context //nolint:containedctx
|
||||||
|
ctxCancel context.CancelFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// SuiteName ...
|
||||||
|
func (suite *CommonSuite) SuiteName() string {
|
||||||
|
return "api.CommonSuite"
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupTest ...
|
||||||
|
func (suite *CommonSuite) SetupTest() {
|
||||||
|
if suite.Cluster.Provisioner() == provisionerDocker {
|
||||||
|
suite.T().Skip("skipping default values tests in docker")
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure API calls have timeout
|
||||||
|
suite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 10*time.Minute)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TearDownTest ...
|
||||||
|
func (suite *CommonSuite) TearDownTest() {
|
||||||
|
if suite.ctxCancel != nil {
|
||||||
|
suite.ctxCancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestVirtioModulesLoaded verifies that the virtio modules are loaded.
|
||||||
|
func (suite *CommonSuite) TestVirtioModulesLoaded() {
|
||||||
|
if suite.Cluster.Provisioner() == provisionerQEMU {
|
||||||
|
suite.T().Skip("skipping virtio modules tests in qemu")
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedVirtIOModules := []string{
|
||||||
|
"virtio_balloon",
|
||||||
|
"virtio_pci",
|
||||||
|
"virtio_pci_legacy_dev",
|
||||||
|
"virtio_pci_modern_dev",
|
||||||
|
}
|
||||||
|
|
||||||
|
node := suite.RandomDiscoveredNodeInternalIP()
|
||||||
|
|
||||||
|
ctx := client.WithNode(suite.ctx, node)
|
||||||
|
|
||||||
|
fileReader, err := suite.Client.Read(ctx, "/proc/modules")
|
||||||
|
defer func() {
|
||||||
|
err = fileReader.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(fileReader)
|
||||||
|
|
||||||
|
var loadedModules []string
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
loadedModules = append(loadedModules, strings.Split(scanner.Text(), " ")[0])
|
||||||
|
}
|
||||||
|
suite.Require().NoError(scanner.Err())
|
||||||
|
|
||||||
|
for _, expectedModule := range expectedVirtIOModules {
|
||||||
|
suite.Require().Contains(loadedModules, expectedModule, "expected module %s to be loaded", expectedModule)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestCommonDefaults verifies that the default ulimits are set.
|
||||||
|
func (suite *CommonSuite) TestCommonDefaults() {
|
||||||
|
expectedUlimit := `
|
||||||
|
core file size (blocks) (-c) 0
|
||||||
|
data seg size (kb) (-d) unlimited
|
||||||
|
scheduling priority (-e) 0
|
||||||
|
file size (blocks) (-f) unlimited
|
||||||
|
max locked memory (kb) (-l) 8192
|
||||||
|
max memory size (kb) (-m) unlimited
|
||||||
|
open files (-n) 1048576
|
||||||
|
POSIX message queues (bytes) (-q) 819200
|
||||||
|
real-time priority (-r) 0
|
||||||
|
stack size (kb) (-s) 8192
|
||||||
|
cpu time (seconds) (-t) unlimited
|
||||||
|
virtual memory (kb) (-v) unlimited
|
||||||
|
file locks (-x) unlimited
|
||||||
|
`
|
||||||
|
|
||||||
|
_, err := suite.Clientset.CoreV1().Pods("default").Create(suite.ctx, &corev1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "defaults-test",
|
||||||
|
},
|
||||||
|
Spec: corev1.PodSpec{
|
||||||
|
Containers: []corev1.Container{
|
||||||
|
{
|
||||||
|
Name: "defaults-test",
|
||||||
|
Image: "alpine",
|
||||||
|
Command: []string{
|
||||||
|
"tail",
|
||||||
|
"-f",
|
||||||
|
"/dev/null",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, metav1.CreateOptions{})
|
||||||
|
defer suite.Clientset.CoreV1().Pods("default").Delete(suite.ctx, "defaults-test", metav1.DeleteOptions{}) //nolint:errcheck
|
||||||
|
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// wait for the pod to be ready
|
||||||
|
suite.Require().NoError(retry.Constant(8*time.Minute, retry.WithUnits(time.Second*10)).Retry(
|
||||||
|
func() error {
|
||||||
|
pod, podErr := suite.Clientset.CoreV1().Pods("default").Get(suite.ctx, "defaults-test", metav1.GetOptions{})
|
||||||
|
if podErr != nil {
|
||||||
|
return retry.ExpectedErrorf("error getting pod: %s", podErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pod.Status.Phase != corev1.PodRunning {
|
||||||
|
return retry.ExpectedErrorf("pod is not running yet: %s", pod.Status.Phase)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
stdout, stderr, err := suite.executeRemoteCommand("default", "defaults-test", "ulimit -c -d -e -f -l -m -n -q -r -s -t -v -x")
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
suite.Require().Equal("", stderr)
|
||||||
|
suite.Require().Equal(strings.TrimPrefix(expectedUlimit, "\n"), stdout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *CommonSuite) executeRemoteCommand(namespace, podName, command string) (string, string, error) {
|
||||||
|
cmd := []string{
|
||||||
|
"/bin/sh",
|
||||||
|
"-c",
|
||||||
|
command,
|
||||||
|
}
|
||||||
|
req := suite.Clientset.CoreV1().RESTClient().Post().Resource("pods").Name(podName).
|
||||||
|
Namespace(namespace).SubResource("exec")
|
||||||
|
option := &corev1.PodExecOptions{
|
||||||
|
Command: cmd,
|
||||||
|
Stdin: false,
|
||||||
|
Stdout: true,
|
||||||
|
Stderr: true,
|
||||||
|
TTY: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
req.VersionedParams(
|
||||||
|
option,
|
||||||
|
scheme.ParameterCodec,
|
||||||
|
)
|
||||||
|
|
||||||
|
exec, err := remotecommand.NewSPDYExecutor(suite.RestConfig, "POST", req.URL())
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
|
||||||
|
err = exec.StreamWithContext(suite.ctx, remotecommand.StreamOptions{
|
||||||
|
Stdout: &stdout,
|
||||||
|
Stderr: &stderr,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return stdout.String(), stderr.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
allSuites = append(allSuites, &CommonSuite{})
|
||||||
|
}
|
||||||
382
internal/integration/api/extensions.go
Normal file
382
internal/integration/api/extensions.go
Normal file
@@ -0,0 +1,382 @@
|
|||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
//go:build integration_api
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cosi-project/runtime/pkg/resource"
|
||||||
|
"github.com/cosi-project/runtime/pkg/safe"
|
||||||
|
"github.com/cosi-project/runtime/pkg/state"
|
||||||
|
"github.com/siderolabs/go-retry/retry"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
nodev1 "k8s.io/api/node/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
|
"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers"
|
||||||
|
"github.com/siderolabs/talos/internal/integration/base"
|
||||||
|
machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine"
|
||||||
|
"github.com/siderolabs/talos/pkg/machinery/client"
|
||||||
|
"github.com/siderolabs/talos/pkg/machinery/config/machine"
|
||||||
|
"github.com/siderolabs/talos/pkg/machinery/constants"
|
||||||
|
"github.com/siderolabs/talos/pkg/machinery/resources/network"
|
||||||
|
"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExtensionsSuite verifies Talos is securebooted.
|
||||||
|
type ExtensionsSuite struct {
|
||||||
|
base.K8sSuite
|
||||||
|
|
||||||
|
ctx context.Context //nolint:containedctx
|
||||||
|
ctxCancel context.CancelFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtensionsTestType specifies the type of extensions test to run.
|
||||||
|
type ExtensionsTestType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ExtensionsTestTypeNone disables extensions tests.
|
||||||
|
ExtensionsTestTypeNone ExtensionsTestType = "none"
|
||||||
|
// ExtensionsTestTypeQEMU enables qemu extensions tests.
|
||||||
|
ExtensionsTestTypeQEMU ExtensionsTestType = "qemu"
|
||||||
|
// ExtensionsTestTypeNvidia enables nvidia extensions tests.
|
||||||
|
ExtensionsTestTypeNvidia ExtensionsTestType = "nvidia"
|
||||||
|
// ExtensionsTestTypeNvidiaFabricManager enables nvidia fabric manager extensions tests.
|
||||||
|
ExtensionsTestTypeNvidiaFabricManager ExtensionsTestType = "nvidia-fabricmanager"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SuiteName ...
|
||||||
|
func (suite *ExtensionsSuite) SuiteName() string {
|
||||||
|
return "api.ExtensionsSuite"
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupTest ...
|
||||||
|
func (suite *ExtensionsSuite) SetupTest() {
|
||||||
|
if testing.Short() {
|
||||||
|
suite.T().Skip("skipping in short mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
if suite.Cluster.Provisioner() == provisionerDocker {
|
||||||
|
suite.T().Skip("skipping extensions tests in docker")
|
||||||
|
}
|
||||||
|
|
||||||
|
if suite.ExtensionsTestType == string(ExtensionsTestTypeNone) {
|
||||||
|
suite.T().Skip("skipping as extensions test are not enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure API calls have timeout
|
||||||
|
suite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TearDownTest ...
|
||||||
|
func (suite *ExtensionsSuite) TearDownTest() {
|
||||||
|
if suite.ctxCancel != nil {
|
||||||
|
suite.ctxCancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestExtensionsExpectedPaths verifies expected paths are present.
|
||||||
|
func (suite *ExtensionsSuite) TestExtensionsExpectedPaths() {
|
||||||
|
if suite.ExtensionsTestType != string(ExtensionsTestTypeQEMU) {
|
||||||
|
suite.T().Skip("skipping as qemu extensions test are not enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedPaths := []string{
|
||||||
|
"/lib/firmware/amd-ucode",
|
||||||
|
"/lib/firmware/bnx2x",
|
||||||
|
"/lib/firmware/i915",
|
||||||
|
"/lib/firmware/intel-ucode",
|
||||||
|
}
|
||||||
|
|
||||||
|
node := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)
|
||||||
|
ctx := client.WithNode(suite.ctx, node)
|
||||||
|
|
||||||
|
for _, path := range expectedPaths {
|
||||||
|
stream, err := suite.Client.LS(ctx, &machineapi.ListRequest{
|
||||||
|
Root: path,
|
||||||
|
Types: []machineapi.ListRequest_Type{machineapi.ListRequest_DIRECTORY},
|
||||||
|
})
|
||||||
|
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
suite.Require().NoError(helpers.ReadGRPCStream(stream, func(info *machineapi.FileInfo, node string, multipleNodes bool) error {
|
||||||
|
suite.Require().Equal(path, info.Name, "expected %s to exist", path)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestExtensionsExpectedModules verifies expected modules are loaded and in modules.dep.
|
||||||
|
func (suite *ExtensionsSuite) TestExtensionsExpectedModules() {
|
||||||
|
// expectedModulesModDep is a map of module name to module.dep name
|
||||||
|
expectedModulesModDep := map[string]string{
|
||||||
|
"asix": "asix.ko",
|
||||||
|
"ax88179_178a": "ax88179_178a.ko",
|
||||||
|
"ax88796b": "ax88796b.ko",
|
||||||
|
"cdc_ether": "cdc_ether.ko",
|
||||||
|
"cdc_mbim": "cdc_mbim.ko",
|
||||||
|
"cdc_ncm": "cdc_ncm.ko",
|
||||||
|
"cdc_subset": "cdc_subset.ko",
|
||||||
|
"cdc_wdm": "cdc-wdm.ko",
|
||||||
|
"drbd": "drbd.ko",
|
||||||
|
"gasket": "gasket.ko",
|
||||||
|
"net1080": "net1080.ko",
|
||||||
|
"option": "option.ko",
|
||||||
|
"qmi_wwan": "qmi_wwan.ko",
|
||||||
|
"r8153_ecm": "r8153_ecm.ko",
|
||||||
|
"thunderbolt": "thunderbolt.ko",
|
||||||
|
"thunderbolt_net": "thunderbolt-net.ko",
|
||||||
|
"usb_wwan": "usb_wwan.ko",
|
||||||
|
"usbnet": "usbnet.ko",
|
||||||
|
"zaurus": "zaurus.ko",
|
||||||
|
"zfs": "zfs.ko",
|
||||||
|
}
|
||||||
|
|
||||||
|
if suite.ExtensionsTestType == string(ExtensionsTestTypeNvidia) || suite.ExtensionsTestType == string(ExtensionsTestTypeNvidiaFabricManager) {
|
||||||
|
expectedModulesModDep = map[string]string{
|
||||||
|
"nvidia": "nvidia.ko",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)
|
||||||
|
ctx := client.WithNode(suite.ctx, node)
|
||||||
|
|
||||||
|
fileReader, err := suite.Client.Read(ctx, "/proc/modules")
|
||||||
|
defer func() {
|
||||||
|
err = fileReader.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(fileReader)
|
||||||
|
|
||||||
|
var loadedModules []string
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
loadedModules = append(loadedModules, strings.Split(scanner.Text(), " ")[0])
|
||||||
|
}
|
||||||
|
suite.Require().NoError(scanner.Err())
|
||||||
|
|
||||||
|
fileReader, err = suite.Client.Read(ctx, fmt.Sprintf("/lib/modules/%s/modules.dep", constants.DefaultKernelVersion))
|
||||||
|
defer func() {
|
||||||
|
err = fileReader.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
scanner = bufio.NewScanner(fileReader)
|
||||||
|
|
||||||
|
var modulesDep []string
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
modulesDep = append(modulesDep, filepath.Base(strings.Split(scanner.Text(), ":")[0]))
|
||||||
|
}
|
||||||
|
suite.Require().NoError(scanner.Err())
|
||||||
|
|
||||||
|
for module, moduleDep := range expectedModulesModDep {
|
||||||
|
suite.Require().Contains(loadedModules, module, "expected %s to be loaded", module)
|
||||||
|
suite.Require().Contains(modulesDep, moduleDep, "expected %s to be in modules.dep", moduleDep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestExtensionsExpectedServices verifies expected services are running.
|
||||||
|
func (suite *ExtensionsSuite) TestExtensionsExpectedServices() {
|
||||||
|
expectedServices := []string{
|
||||||
|
"ext-hello-world",
|
||||||
|
"ext-iscsid",
|
||||||
|
"ext-nut-client",
|
||||||
|
"ext-qemu-guest-agent",
|
||||||
|
"ext-tgtd",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tailscale service keeps on restarting unless authed, so this test is disabled for now.
|
||||||
|
if ok := os.Getenv("TALOS_INTEGRATION_RUN_TAILSCALE"); ok != "" {
|
||||||
|
expectedServices = append(expectedServices, "ext-tailscale")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ExtensionsTestType(suite.ExtensionsTestType) {
|
||||||
|
case ExtensionsTestTypeNone:
|
||||||
|
case ExtensionsTestTypeQEMU:
|
||||||
|
case ExtensionsTestTypeNvidia:
|
||||||
|
expectedServices = []string{"ext-nvidia-persistenced"}
|
||||||
|
case ExtensionsTestTypeNvidiaFabricManager:
|
||||||
|
expectedServices = []string{
|
||||||
|
"ext-nvidia-persistenced",
|
||||||
|
"ext-nvidia-fabricmanager",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suite.testServicesRunning(expectedServices)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestExtensionsQEMUGuestAgent verifies qemu guest agent is working.
|
||||||
|
func (suite *ExtensionsSuite) TestExtensionsQEMUGuestAgent() {
|
||||||
|
if suite.ExtensionsTestType != string(ExtensionsTestTypeQEMU) || suite.Cluster.Provisioner() != "qemu" {
|
||||||
|
suite.T().Skip("skipping as qemu extensions test are not enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
node := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)
|
||||||
|
ctx := client.WithNode(suite.ctx, node)
|
||||||
|
|
||||||
|
hostnameSpec, err := safe.StateWatchFor[*network.HostnameStatus](
|
||||||
|
ctx,
|
||||||
|
suite.Client.COSI,
|
||||||
|
network.NewHostnameStatus(network.NamespaceName, resource.ID("hostname")).Metadata(),
|
||||||
|
state.WithEventTypes(state.Created, state.Updated),
|
||||||
|
)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
bootID, err := suite.ReadBootID(ctx)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
clusterStatePath, err := suite.Cluster.StatePath()
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
conn, err := net.Dial("unix", filepath.Join(clusterStatePath, hostnameSpec.TypedSpec().Hostname+".sock"))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
defer conn.Close() //nolint:errcheck
|
||||||
|
|
||||||
|
_, err = conn.Write([]byte(`{"execute":"guest-shutdown", "arguments": {"mode": "reboot"}}`))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
suite.AssertBootIDChanged(ctx, bootID, node, time.Minute*5)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestExtensionsTailscale verifies tailscale is working.
|
||||||
|
func (suite *ExtensionsSuite) TestExtensionsTailscale() {
|
||||||
|
if suite.ExtensionsTestType != string(ExtensionsTestTypeQEMU) {
|
||||||
|
suite.T().Skip("skipping as qemu extensions test are not enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tailscale service keeps on restarting unless authed, so this test is disabled for now.
|
||||||
|
if ok := os.Getenv("TALOS_INTEGRATION_RUN_TAILSCALE"); ok == "" {
|
||||||
|
suite.T().Skip("skipping as tailscale integration tests are not enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
node := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)
|
||||||
|
ctx := client.WithNode(suite.ctx, node)
|
||||||
|
|
||||||
|
linkSpec, err := safe.StateWatchFor[*network.LinkStatus](
|
||||||
|
ctx,
|
||||||
|
suite.Client.COSI,
|
||||||
|
network.NewHostnameStatus(network.NamespaceName, resource.ID("tailscale0")).Metadata(),
|
||||||
|
state.WithEventTypes(state.Created, state.Updated),
|
||||||
|
)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
suite.Require().Equal("tun", linkSpec.TypedSpec().Kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestExtensionsHelloWorldService verifies hello world service is working.
|
||||||
|
func (suite *ExtensionsSuite) TestExtensionsHelloWorldService() {
|
||||||
|
if suite.ExtensionsTestType != string(ExtensionsTestTypeQEMU) {
|
||||||
|
suite.T().Skip("skipping as qemu extensions test are not enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
node := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)
|
||||||
|
|
||||||
|
url := url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: node,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.Get(url.String()) //nolint:noctx
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
defer resp.Body.Close() //nolint:errcheck
|
||||||
|
|
||||||
|
respBody, err := io.ReadAll(resp.Body)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
suite.Require().Equal("Hello from Talos Linux Extension Service!", string(respBody))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestExtensionsGvisor verifies gvisor runtime class is working.
|
||||||
|
func (suite *ExtensionsSuite) TestExtensionsGvisor() {
|
||||||
|
if suite.ExtensionsTestType != string(ExtensionsTestTypeQEMU) {
|
||||||
|
suite.T().Skip("skipping as qemu extensions test are not enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := suite.Clientset.NodeV1().RuntimeClasses().Create(suite.ctx, &nodev1.RuntimeClass{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "gvisor",
|
||||||
|
},
|
||||||
|
Handler: "runsc",
|
||||||
|
}, metav1.CreateOptions{})
|
||||||
|
defer suite.Clientset.NodeV1().RuntimeClasses().Delete(suite.ctx, "gvisor", metav1.DeleteOptions{}) //nolint:errcheck
|
||||||
|
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
_, err = suite.Clientset.CoreV1().Pods("default").Create(suite.ctx, &corev1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "nginx-gvisor",
|
||||||
|
},
|
||||||
|
Spec: corev1.PodSpec{
|
||||||
|
Containers: []corev1.Container{
|
||||||
|
{
|
||||||
|
Name: "nginx-gvisor",
|
||||||
|
Image: "nginx",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, metav1.CreateOptions{})
|
||||||
|
defer suite.Clientset.CoreV1().Pods("default").Delete(suite.ctx, "nginx-gvisor", metav1.DeleteOptions{}) //nolint:errcheck
|
||||||
|
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// wait for the pod to be ready
|
||||||
|
suite.Require().NoError(retry.Constant(4*time.Minute, retry.WithUnits(time.Second*10)).Retry(
|
||||||
|
func() error {
|
||||||
|
pod, err := suite.Clientset.CoreV1().Pods("default").Get(suite.ctx, "nginx-gvisor", metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return retry.ExpectedErrorf("error getting pod: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pod.Status.Phase != corev1.PodRunning {
|
||||||
|
return retry.ExpectedErrorf("pod is not running yet: %s", pod.Status.Phase)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ExtensionsSuite) testServicesRunning(services []string) {
|
||||||
|
node := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)
|
||||||
|
ctx := client.WithNode(suite.ctx, node)
|
||||||
|
|
||||||
|
items, err := safe.StateListAll[*v1alpha1.Service](ctx, suite.Client.COSI)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
for _, expected := range services {
|
||||||
|
svc, found := items.Find(func(s *v1alpha1.Service) bool {
|
||||||
|
return s.Metadata().ID() == expected
|
||||||
|
})
|
||||||
|
if !found {
|
||||||
|
suite.T().Fatalf("expected %s to be registered", expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
suite.Require().True(svc.TypedSpec().Running, "expected %s to be running", expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
allSuites = append(allSuites, &ExtensionsSuite{})
|
||||||
|
}
|
||||||
@@ -42,6 +42,14 @@ func (suite *ResetSuite) SetupTest() {
|
|||||||
suite.T().Skip("skipping in short mode")
|
suite.T().Skip("skipping in short mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !suite.Capabilities().SupportsReboot {
|
||||||
|
suite.T().Skip("cluster doesn't support reboot (and reset)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if suite.Cluster == nil {
|
||||||
|
suite.T().Skip("without full cluster state reset test is not reliable (can't wait for cluster readiness in between resets)")
|
||||||
|
}
|
||||||
|
|
||||||
// make sure we abort at some point in time, but give enough room for Resets
|
// make sure we abort at some point in time, but give enough room for Resets
|
||||||
suite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 30*time.Minute)
|
suite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 30*time.Minute)
|
||||||
}
|
}
|
||||||
@@ -55,17 +63,9 @@ func (suite *ResetSuite) TearDownTest() {
|
|||||||
|
|
||||||
// TestResetNodeByNode Resets cluster node by node, waiting for health between Resets.
|
// TestResetNodeByNode Resets cluster node by node, waiting for health between Resets.
|
||||||
func (suite *ResetSuite) TestResetNodeByNode() {
|
func (suite *ResetSuite) TestResetNodeByNode() {
|
||||||
if !suite.Capabilities().SupportsReboot {
|
if suite.Capabilities().SecureBooted {
|
||||||
suite.T().Skip("cluster doesn't support reboot (and reset)")
|
// this is because in secure boot mode, the machine config is only applied and cannot be passed as kernel args
|
||||||
}
|
suite.T().Skip("skipping as talos is explicitly trusted booted")
|
||||||
|
|
||||||
if suite.Capabilities().TrustedBoot {
|
|
||||||
// this is because with trusted boot the talos.config is only applied and cannot be passed as kernel args
|
|
||||||
suite.T().Skip("cluster has trusted boot enabled, doesn't support reset")
|
|
||||||
}
|
|
||||||
|
|
||||||
if suite.Cluster == nil {
|
|
||||||
suite.T().Skip("without full cluster state reset test is not reliable (can't wait for cluster readiness in between resets)")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initNodeAddress := ""
|
initNodeAddress := ""
|
||||||
@@ -114,17 +114,9 @@ func (suite *ResetSuite) TestResetNodeByNode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *ResetSuite) testResetNoGraceful(nodeType machine.Type) {
|
func (suite *ResetSuite) testResetNoGraceful(nodeType machine.Type) {
|
||||||
if !suite.Capabilities().SupportsReboot {
|
if suite.Capabilities().SecureBooted {
|
||||||
suite.T().Skip("cluster doesn't support reboot (and reset)")
|
// this is because in secure boot mode, the machine config is only applied and cannot be passed as kernel args
|
||||||
}
|
suite.T().Skip("skipping as talos is explicitly trusted booted")
|
||||||
|
|
||||||
if suite.Capabilities().TrustedBoot {
|
|
||||||
// this is because with trusted boot the talos.config is only applied and cannot be passed as kernel args
|
|
||||||
suite.T().Skip("cluster has trusted boot enabled, doesn't support reset")
|
|
||||||
}
|
|
||||||
|
|
||||||
if suite.Cluster == nil {
|
|
||||||
suite.T().Skip("without full cluster state reset test is not reliable (can't wait for cluster readiness in between resets)")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
node := suite.RandomDiscoveredNodeInternalIP(nodeType)
|
node := suite.RandomDiscoveredNodeInternalIP(nodeType)
|
||||||
@@ -165,14 +157,6 @@ func (suite *ResetSuite) TestResetNoGracefulControlplane() {
|
|||||||
//
|
//
|
||||||
//nolint:dupl
|
//nolint:dupl
|
||||||
func (suite *ResetSuite) TestResetWithSpecEphemeral() {
|
func (suite *ResetSuite) TestResetWithSpecEphemeral() {
|
||||||
if !suite.Capabilities().SupportsReboot {
|
|
||||||
suite.T().Skip("cluster doesn't support reboot (and reset)")
|
|
||||||
}
|
|
||||||
|
|
||||||
if suite.Cluster == nil {
|
|
||||||
suite.T().Skip("without full cluster state reset test is not reliable (can't wait for cluster readiness in between resets)")
|
|
||||||
}
|
|
||||||
|
|
||||||
node := suite.RandomDiscoveredNodeInternalIP()
|
node := suite.RandomDiscoveredNodeInternalIP()
|
||||||
|
|
||||||
suite.T().Log("Resetting node with spec=[EPHEMERAL]", node)
|
suite.T().Log("Resetting node with spec=[EPHEMERAL]", node)
|
||||||
@@ -214,17 +198,9 @@ func (suite *ResetSuite) TestResetWithSpecEphemeral() {
|
|||||||
//
|
//
|
||||||
//nolint:dupl
|
//nolint:dupl
|
||||||
func (suite *ResetSuite) TestResetWithSpecState() {
|
func (suite *ResetSuite) TestResetWithSpecState() {
|
||||||
if !suite.Capabilities().SupportsReboot {
|
if suite.Capabilities().SecureBooted {
|
||||||
suite.T().Skip("cluster doesn't support reboot (and reset)")
|
// this is because in secure boot mode, the machine config is only applied and cannot be passed as kernel args
|
||||||
}
|
suite.T().Skip("skipping as talos is explicitly trusted booted")
|
||||||
|
|
||||||
if suite.Capabilities().TrustedBoot {
|
|
||||||
// this is because with trusted boot the talos.config is only applied and cannot be passed as kernel args
|
|
||||||
suite.T().Skip("cluster has trusted boot enabled, doesn't support reset")
|
|
||||||
}
|
|
||||||
|
|
||||||
if suite.Cluster == nil {
|
|
||||||
suite.T().Skip("without full cluster state reset test is not reliable (can't wait for cluster readiness in between resets)")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
node := suite.RandomDiscoveredNodeInternalIP()
|
node := suite.RandomDiscoveredNodeInternalIP()
|
||||||
@@ -281,14 +257,6 @@ func (suite *ResetSuite) TestResetWithSpecState() {
|
|||||||
//
|
//
|
||||||
//nolint:dupl
|
//nolint:dupl
|
||||||
func (suite *ResetSuite) TestResetDuringBoot() {
|
func (suite *ResetSuite) TestResetDuringBoot() {
|
||||||
if !suite.Capabilities().SupportsReboot {
|
|
||||||
suite.T().Skip("cluster doesn't support reboot (and reset)")
|
|
||||||
}
|
|
||||||
|
|
||||||
if suite.Cluster == nil {
|
|
||||||
suite.T().Skip("without full cluster state reset test is not reliable (can't wait for cluster readiness in between resets)")
|
|
||||||
}
|
|
||||||
|
|
||||||
node := suite.RandomDiscoveredNodeInternalIP()
|
node := suite.RandomDiscoveredNodeInternalIP()
|
||||||
nodeCtx := client.WithNodes(suite.ctx, node)
|
nodeCtx := client.WithNodes(suite.ctx, node)
|
||||||
|
|
||||||
|
|||||||
114
internal/integration/api/trustedboot.go
Normal file
114
internal/integration/api/trustedboot.go
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
//go:build integration_api
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cosi-project/runtime/pkg/resource"
|
||||||
|
"github.com/cosi-project/runtime/pkg/safe"
|
||||||
|
"github.com/cosi-project/runtime/pkg/state"
|
||||||
|
|
||||||
|
"github.com/siderolabs/talos/internal/integration/base"
|
||||||
|
"github.com/siderolabs/talos/pkg/machinery/client"
|
||||||
|
runtimeres "github.com/siderolabs/talos/pkg/machinery/resources/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TrustedBootSuite verifies Talos is securebooted.
|
||||||
|
type TrustedBootSuite struct {
|
||||||
|
base.K8sSuite
|
||||||
|
|
||||||
|
ctx context.Context //nolint:containedctx
|
||||||
|
ctxCancel context.CancelFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// SuiteName ...
|
||||||
|
func (suite *TrustedBootSuite) SuiteName() string {
|
||||||
|
return "api.TrustedBootSuite"
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupTest ...
|
||||||
|
func (suite *TrustedBootSuite) SetupTest() {
|
||||||
|
if suite.Cluster.Provisioner() == provisionerDocker {
|
||||||
|
suite.T().Skip("skipping trustedboot tests in docker")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !suite.TrustedBoot {
|
||||||
|
suite.T().Skip("skipping since talos.trustedboot is false")
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure API calls have timeout
|
||||||
|
suite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TearDownTest ...
|
||||||
|
func (suite *TrustedBootSuite) TearDownTest() {
|
||||||
|
if suite.ctxCancel != nil {
|
||||||
|
suite.ctxCancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTrustedBootState verifies that the system is booted in secure boot mode
|
||||||
|
// and that the disks are encrypted.
|
||||||
|
func (suite *TrustedBootSuite) TestTrustedBootState() {
|
||||||
|
node := suite.RandomDiscoveredNodeInternalIP()
|
||||||
|
ctx := client.WithNode(suite.ctx, node)
|
||||||
|
|
||||||
|
securityResource, err := safe.StateWatchFor[*runtimeres.SecurityState](
|
||||||
|
ctx,
|
||||||
|
suite.Client.COSI,
|
||||||
|
runtimeres.NewSecurityStateSpec(runtimeres.NamespaceName).Metadata(),
|
||||||
|
state.WithEventTypes(state.Created, state.Updated),
|
||||||
|
)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
suite.Require().True(securityResource.TypedSpec().SecureBoot)
|
||||||
|
|
||||||
|
stateResource, err := safe.StateWatchFor[*runtimeres.MountStatus](
|
||||||
|
ctx,
|
||||||
|
suite.Client.COSI,
|
||||||
|
runtimeres.NewMountStatus(runtimeres.NamespaceName, resource.ID("STATE")).Metadata(),
|
||||||
|
state.WithEventTypes(state.Created, state.Updated),
|
||||||
|
)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
suite.Require().True(stateResource.TypedSpec().Encrypted)
|
||||||
|
|
||||||
|
ephemeralResource, err := safe.StateWatchFor[*runtimeres.MountStatus](
|
||||||
|
ctx,
|
||||||
|
suite.Client.COSI,
|
||||||
|
runtimeres.NewMountStatus(runtimeres.NamespaceName, resource.ID("EPHEMERAL")).Metadata(),
|
||||||
|
state.WithEventTypes(state.Created, state.Updated),
|
||||||
|
)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
suite.Require().True(ephemeralResource.TypedSpec().Encrypted)
|
||||||
|
|
||||||
|
dmesgStream, err := suite.Client.Dmesg(
|
||||||
|
suite.ctx,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
logReader, err := client.ReadStream(dmesgStream)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
var dmesg bytes.Buffer
|
||||||
|
_, err = io.Copy(bufio.NewWriter(&dmesg), logReader)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
suite.Require().Contains(dmesg.String(), "Secure boot enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
allSuites = append(allSuites, &TrustedBootSuite{})
|
||||||
|
}
|
||||||
@@ -17,12 +17,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/cosi-project/runtime/pkg/safe"
|
||||||
|
"github.com/cosi-project/runtime/pkg/state"
|
||||||
"github.com/siderolabs/go-retry/retry"
|
"github.com/siderolabs/go-retry/retry"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"google.golang.org/grpc/backoff"
|
"google.golang.org/grpc/backoff"
|
||||||
|
|
||||||
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime"
|
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime"
|
||||||
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot"
|
|
||||||
"github.com/siderolabs/talos/pkg/cluster"
|
"github.com/siderolabs/talos/pkg/cluster"
|
||||||
"github.com/siderolabs/talos/pkg/cluster/check"
|
"github.com/siderolabs/talos/pkg/cluster/check"
|
||||||
machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine"
|
machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine"
|
||||||
@@ -32,6 +33,7 @@ import (
|
|||||||
"github.com/siderolabs/talos/pkg/machinery/config/configloader"
|
"github.com/siderolabs/talos/pkg/machinery/config/configloader"
|
||||||
"github.com/siderolabs/talos/pkg/machinery/config/machine"
|
"github.com/siderolabs/talos/pkg/machinery/config/machine"
|
||||||
"github.com/siderolabs/talos/pkg/machinery/constants"
|
"github.com/siderolabs/talos/pkg/machinery/constants"
|
||||||
|
runtimeres "github.com/siderolabs/talos/pkg/machinery/resources/runtime"
|
||||||
"github.com/siderolabs/talos/pkg/provision"
|
"github.com/siderolabs/talos/pkg/provision"
|
||||||
"github.com/siderolabs/talos/pkg/provision/access"
|
"github.com/siderolabs/talos/pkg/provision/access"
|
||||||
)
|
)
|
||||||
@@ -147,7 +149,7 @@ type Capabilities struct {
|
|||||||
RunsTalosKernel bool
|
RunsTalosKernel bool
|
||||||
SupportsReboot bool
|
SupportsReboot bool
|
||||||
SupportsRecover bool
|
SupportsRecover bool
|
||||||
TrustedBoot bool
|
SecureBooted bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capabilities returns a set of capabilities to skip tests for different environments.
|
// Capabilities returns a set of capabilities to skip tests for different environments.
|
||||||
@@ -167,12 +169,20 @@ func (apiSuite *APISuite) Capabilities() Capabilities {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = apiSuite.Client.LS(context.Background(), &machineapi.ListRequest{
|
ctx := context.Background()
|
||||||
Root: sdboot.SystemdBootStubInfoPath,
|
ctx, ctxCancel := context.WithTimeout(ctx, 2*time.Minute)
|
||||||
Types: []machineapi.ListRequest_Type{machineapi.ListRequest_REGULAR},
|
|
||||||
}); err == nil {
|
defer ctxCancel()
|
||||||
caps.TrustedBoot = true
|
|
||||||
}
|
securityResource, err := safe.StateWatchFor[*runtimeres.SecurityState](
|
||||||
|
ctx,
|
||||||
|
apiSuite.Client.COSI,
|
||||||
|
runtimeres.NewSecurityStateSpec(runtimeres.NamespaceName).Metadata(),
|
||||||
|
state.WithEventTypes(state.Created, state.Updated),
|
||||||
|
)
|
||||||
|
apiSuite.Require().NoError(err)
|
||||||
|
|
||||||
|
caps.SecureBooted = securityResource.TypedSpec().SecureBoot
|
||||||
|
|
||||||
return caps
|
return caps
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ type TalosSuite struct {
|
|||||||
TalosctlPath string
|
TalosctlPath string
|
||||||
// KubectlPath is a path to kubectl binary
|
// KubectlPath is a path to kubectl binary
|
||||||
KubectlPath string
|
KubectlPath string
|
||||||
|
// ExtensionsTestType the type of extensions test to run
|
||||||
|
ExtensionsTestType string
|
||||||
|
// TrustedBoot tells if the cluster is secure booted and disks are encrypted
|
||||||
|
TrustedBoot bool
|
||||||
|
|
||||||
discoveredNodes cluster.Info
|
discoveredNodes cluster.Info
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"k8s.io/client-go/discovery"
|
"k8s.io/client-go/discovery"
|
||||||
"k8s.io/client-go/dynamic"
|
"k8s.io/client-go/dynamic"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ type K8sSuite struct {
|
|||||||
Clientset *kubernetes.Clientset
|
Clientset *kubernetes.Clientset
|
||||||
DynamicClient dynamic.Interface
|
DynamicClient dynamic.Interface
|
||||||
DiscoveryClient *discovery.DiscoveryClient
|
DiscoveryClient *discovery.DiscoveryClient
|
||||||
|
RestConfig *rest.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetupSuite initializes Kubernetes client.
|
// SetupSuite initializes Kubernetes client.
|
||||||
@@ -54,6 +56,7 @@ func (k8sSuite *K8sSuite) SetupSuite() {
|
|||||||
config.Host = k8sSuite.K8sEndpoint
|
config.Host = k8sSuite.K8sEndpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
k8sSuite.RestConfig = config
|
||||||
k8sSuite.Clientset, err = kubernetes.NewForConfig(config)
|
k8sSuite.Clientset, err = kubernetes.NewForConfig(config)
|
||||||
k8sSuite.Require().NoError(err)
|
k8sSuite.Require().NoError(err)
|
||||||
|
|
||||||
|
|||||||
@@ -34,18 +34,20 @@ var allSuites []suite.TestingSuite
|
|||||||
|
|
||||||
// Flag values.
|
// Flag values.
|
||||||
var (
|
var (
|
||||||
failFast bool
|
failFast bool
|
||||||
crashdumpEnabled bool
|
crashdumpEnabled bool
|
||||||
talosConfig string
|
trustedBoot bool
|
||||||
endpoint string
|
talosConfig string
|
||||||
k8sEndpoint string
|
endpoint string
|
||||||
expectedVersion string
|
k8sEndpoint string
|
||||||
expectedGoVersion string
|
expectedVersion string
|
||||||
talosctlPath string
|
expectedGoVersion string
|
||||||
kubectlPath string
|
talosctlPath string
|
||||||
provisionerName string
|
kubectlPath string
|
||||||
clusterName string
|
extensionsTestType string
|
||||||
stateDir string
|
provisionerName string
|
||||||
|
clusterName string
|
||||||
|
stateDir string
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestIntegration ...
|
// TestIntegration ...
|
||||||
@@ -85,14 +87,16 @@ func TestIntegration(t *testing.T) {
|
|||||||
for _, s := range allSuites {
|
for _, s := range allSuites {
|
||||||
if configuredSuite, ok := s.(base.ConfiguredSuite); ok {
|
if configuredSuite, ok := s.(base.ConfiguredSuite); ok {
|
||||||
configuredSuite.SetConfig(base.TalosSuite{
|
configuredSuite.SetConfig(base.TalosSuite{
|
||||||
Endpoint: endpoint,
|
Endpoint: endpoint,
|
||||||
K8sEndpoint: k8sEndpoint,
|
K8sEndpoint: k8sEndpoint,
|
||||||
Cluster: cluster,
|
Cluster: cluster,
|
||||||
TalosConfig: talosConfig,
|
TalosConfig: talosConfig,
|
||||||
Version: expectedVersion,
|
Version: expectedVersion,
|
||||||
GoVersion: expectedGoVersion,
|
GoVersion: expectedGoVersion,
|
||||||
TalosctlPath: talosctlPath,
|
TalosctlPath: talosctlPath,
|
||||||
KubectlPath: kubectlPath,
|
KubectlPath: kubectlPath,
|
||||||
|
ExtensionsTestType: extensionsTestType,
|
||||||
|
TrustedBoot: trustedBoot,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,6 +133,7 @@ func init() {
|
|||||||
|
|
||||||
flag.BoolVar(&failFast, "talos.failfast", false, "fail the test run on the first failed test")
|
flag.BoolVar(&failFast, "talos.failfast", false, "fail the test run on the first failed test")
|
||||||
flag.BoolVar(&crashdumpEnabled, "talos.crashdump", true, "print crashdump on test failure (only if provisioner is enabled)")
|
flag.BoolVar(&crashdumpEnabled, "talos.crashdump", true, "print crashdump on test failure (only if provisioner is enabled)")
|
||||||
|
flag.BoolVar(&trustedBoot, "talos.trustedboot", false, "enable tests for trusted boot mode")
|
||||||
|
|
||||||
flag.StringVar(
|
flag.StringVar(
|
||||||
&talosConfig,
|
&talosConfig,
|
||||||
@@ -149,6 +154,7 @@ func init() {
|
|||||||
flag.StringVar(&expectedGoVersion, "talos.go.version", constants.GoVersion, "expected Talos version")
|
flag.StringVar(&expectedGoVersion, "talos.go.version", constants.GoVersion, "expected Talos version")
|
||||||
flag.StringVar(&talosctlPath, "talos.talosctlpath", "talosctl", "The path to 'talosctl' binary")
|
flag.StringVar(&talosctlPath, "talos.talosctlpath", "talosctl", "The path to 'talosctl' binary")
|
||||||
flag.StringVar(&kubectlPath, "talos.kubectlpath", "kubectl", "The path to 'kubectl' binary")
|
flag.StringVar(&kubectlPath, "talos.kubectlpath", "kubectl", "The path to 'kubectl' binary")
|
||||||
|
flag.StringVar(&extensionsTestType, "talos.extensions.testtype", "none", "The type of extensions test to run (none, qemu, nvida, nvidia-fabricmanager)")
|
||||||
|
|
||||||
flag.StringVar(&provision_test.DefaultSettings.CIDR, "talos.provision.cidr", provision_test.DefaultSettings.CIDR, "CIDR to use to provision clusters (provision tests only)")
|
flag.StringVar(&provision_test.DefaultSettings.CIDR, "talos.provision.cidr", provision_test.DefaultSettings.CIDR, "CIDR to use to provision clusters (provision tests only)")
|
||||||
flag.Var(&provision_test.DefaultSettings.RegistryMirrors, "talos.provision.registry-mirror", "registry mirrors to use (provision tests only)")
|
flag.Var(&provision_test.DefaultSettings.RegistryMirrors, "talos.provision.registry-mirror", "registry mirrors to use (provision tests only)")
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// DefaultKernelVersion is the default Linux kernel version.
|
// DefaultKernelVersion is the default Linux kernel version.
|
||||||
DefaultKernelVersion = "6.1.42-talos"
|
DefaultKernelVersion = "6.1.45-talos"
|
||||||
|
|
||||||
// DefaultKernelModulesPath is the default path to the kernel modules.
|
// DefaultKernelModulesPath is the default path to the kernel modules.
|
||||||
DefaultKernelModulesPath = "/lib/modules" + "/" + DefaultKernelVersion
|
DefaultKernelModulesPath = "/lib/modules" + "/" + DefaultKernelVersion
|
||||||
@@ -440,7 +440,7 @@ const (
|
|||||||
TrustdUserID = 51
|
TrustdUserID = 51
|
||||||
|
|
||||||
// DefaultContainerdVersion is the default container runtime version.
|
// DefaultContainerdVersion is the default container runtime version.
|
||||||
DefaultContainerdVersion = "1.6.22"
|
DefaultContainerdVersion = "1.6.23"
|
||||||
|
|
||||||
// SystemContainerdNamespace is the Containerd namespace for Talos services.
|
// SystemContainerdNamespace is the Containerd namespace for Talos services.
|
||||||
SystemContainerdNamespace = "system"
|
SystemContainerdNamespace = "system"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
v1.5.0
|
v1.6.0-alpha.0-5-g7717b7e
|
||||||
Reference in New Issue
Block a user