diff --git a/Makefile b/Makefile index 94e028bca5..d459a1a0a1 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ TOOLS ?= ghcr.io/siderolabs/tools:v1.9.0-1-geaad82f DEBUG_TOOLS_SOURCE := scratch PKGS_PREFIX ?= ghcr.io/siderolabs -PKGS ?= v1.9.0-15-g45c4ba4 +PKGS ?= v1.9.0-21-gc1f06e5 EXTRAS ?= v1.9.0 KRES_IMAGE ?= ghcr.io/siderolabs/kres:latest diff --git a/cmd/talosctl/cmd/mgmt/cluster/create.go b/cmd/talosctl/cmd/mgmt/cluster/create.go index d3c5334d5e..b773094e26 100644 --- a/cmd/talosctl/cmd/mgmt/cluster/create.go +++ b/cmd/talosctl/cmd/mgmt/cluster/create.go @@ -144,6 +144,7 @@ var ( workersMemory int clusterDiskSize int clusterDiskPreallocate bool + diskBlockSize uint clusterDisks []string extraDisks int extraDiskSize int @@ -950,6 +951,7 @@ func create(ctx context.Context) error { Size: uint64(extraDiskSize) * 1024 * 1024, SkipPreallocate: !clusterDiskPreallocate, Driver: driver, + BlockSize: diskBlockSize, }) } @@ -1175,6 +1177,7 @@ func getDisks() ([]*provision.Disk, error) { Size: uint64(clusterDiskSize) * 1024 * 1024, SkipPreallocate: !clusterDiskPreallocate, Driver: "virtio", + BlockSize: diskBlockSize, }, } @@ -1223,6 +1226,7 @@ func getDisks() ([]*provision.Disk, error) { Partitions: diskPartitions, SkipPreallocate: !clusterDiskPreallocate, Driver: "ide", + BlockSize: diskBlockSize, }) } @@ -1274,6 +1278,7 @@ func init() { createCmd.Flags().IntVar(&controlPlaneMemory, "memory", 2048, "the limit on memory usage in MB (each control plane/VM)") createCmd.Flags().IntVar(&workersMemory, "memory-workers", 2048, "the limit on memory usage in MB (each worker/VM)") createCmd.Flags().IntVar(&clusterDiskSize, clusterDiskSizeFlag, 6*1024, "default limit on disk size in MB (each VM)") + createCmd.Flags().UintVar(&diskBlockSize, "disk-block-size", 512, "disk block size (VM only)") createCmd.Flags().BoolVar(&clusterDiskPreallocate, clusterDiskPreallocateFlag, true, "whether disk space should be preallocated") createCmd.Flags().StringSliceVar(&clusterDisks, clusterDisksFlag, []string{}, "list of disks to create for each VM in format: :::") createCmd.Flags().IntVar(&extraDisks, "extra-disks", 0, "number of extra disks to create for each worker VM") diff --git a/go.mod b/go.mod index 4893409588..eb80dcede6 100644 --- a/go.mod +++ b/go.mod @@ -142,7 +142,7 @@ require ( github.com/siderolabs/gen v0.7.0 github.com/siderolabs/go-api-signature v0.3.6 github.com/siderolabs/go-blockdevice v0.4.8 - github.com/siderolabs/go-blockdevice/v2 v2.0.9 + github.com/siderolabs/go-blockdevice/v2 v2.0.11 github.com/siderolabs/go-circular v0.2.1 github.com/siderolabs/go-cmd v0.1.3 github.com/siderolabs/go-copy v0.1.0 diff --git a/go.sum b/go.sum index c66b79c227..fb68687555 100644 --- a/go.sum +++ b/go.sum @@ -645,8 +645,8 @@ github.com/siderolabs/go-api-signature v0.3.6 h1:wDIsXbpl7Oa/FXvxB6uz4VL9INA9fmr github.com/siderolabs/go-api-signature v0.3.6/go.mod h1:hoH13AfunHflxbXfh+NoploqV13ZTDfQ1mQJWNVSW9U= github.com/siderolabs/go-blockdevice v0.4.8 h1:KfdWvIx0Jft5YVuCsFIJFwjWEF1oqtzkgX9PeU9cX4c= github.com/siderolabs/go-blockdevice v0.4.8/go.mod h1:4PeOuk71pReJj1JQEXDE7kIIQJPVe8a+HZQa+qjxSEA= -github.com/siderolabs/go-blockdevice/v2 v2.0.9 h1:OTo+ADN/3LT4XtI8p7Dz3hlh6DJABHwMAnOlK7MOtMk= -github.com/siderolabs/go-blockdevice/v2 v2.0.9/go.mod h1:74htzCV913UzaLZ4H+NBXkwWlYnBJIq5m/379ZEcu8w= +github.com/siderolabs/go-blockdevice/v2 v2.0.11 h1:r7mbbXMn8OZmJA2fJJdomjlZKexRi66ELVZGXJUaNU8= +github.com/siderolabs/go-blockdevice/v2 v2.0.11/go.mod h1:74htzCV913UzaLZ4H+NBXkwWlYnBJIq5m/379ZEcu8w= github.com/siderolabs/go-circular v0.2.1 h1:a++iVCn9jyhICX3POQZZX8n72p2h5JGdGU6w1ulmpcA= github.com/siderolabs/go-circular v0.2.1/go.mod h1:ZDItzVyXK+B/XuqTBV5MtQtSv06VI+oCmWGRnNCATo8= github.com/siderolabs/go-cmd v0.1.3 h1:JrgZwqhJQeoec3QRON0LK+fv+0y7d0DyY7zsfkO6ciw= diff --git a/hack/cri-containerd.toml b/hack/cri-containerd.toml index 11b13933bf..a5c9d2a6bf 100644 --- a/hack/cri-containerd.toml +++ b/hack/cri-containerd.toml @@ -1,7 +1,6 @@ version = 3 disabled_plugins = [ - "io.containerd.nri.v1.nri", "io.containerd.internal.v1.tracing", "io.containerd.snapshotter.v1.blockfile", "io.containerd.tracing.processor.v1.otlp", diff --git a/hack/cri-plugin.part b/hack/cri-plugin.part index bd966e0119..70a2cd369f 100644 --- a/hack/cri-plugin.part +++ b/hack/cri-plugin.part @@ -5,3 +5,6 @@ version = 3 [plugins."io.containerd.cri.v1.runtime".containerd.runtimes.runc] base_runtime_spec = "/etc/cri/conf.d/base-spec.json" + +[plugins."io.containerd.nri.v1.nri"] + disable = true diff --git a/hack/release.toml b/hack/release.toml index 85c81688ab..deb18b851a 100644 --- a/hack/release.toml +++ b/hack/release.toml @@ -7,7 +7,7 @@ match_deps = "^github.com/((talos-systems|siderolabs)/[a-zA-Z0-9-]+)$" ignore_deps = ["github.com/coredns/coredns"] # previous release -previous = "v1.9.0" +previous = "v1.9.1" pre_release = false @@ -18,10 +18,47 @@ preface = """ [notes.updates] title = "Component Updates" description = """\ -* Linux: 6.12.6 -* CNI plugins: 1.6.1 +* Linux: 6.12.9 +* runc: 1.2.4 +* containerd: 2.0.2 Talos is built with Go 1.23.4. +""" + + [notes.kube-apiserver-authorization-config] + title = "kube-apiserver Authorization Config" + description = """\ +When using `.cluster.apiServer.authorizationConfig` the user provided order for the authorizers is honoured and `Node` and `RBAC` authorizers are always added to the end if not explicitly specified. + +Eg: If user provides only `Webhook` authorizer, the final order will be `Webhook`, `Node`, `RBAC`. + +To provide a specific order for `Node` or `RBAC` explicitly, user can provide the authorizer in the order they want. + +Eg: + +```yaml +cluster: + apiServer: + authorizationConfig: + - type: Node + name: Node + - type: Webhook + name: Webhook + webhook: + connectionInfo: + type: InClusterConfig + ... + - type: RBAC + name: rbac +``` + +Usage of `authorization-mode` CLI argument will not support this form of customization. +""" + + [notes.auditd] + title = "auditd" + description = """\ +Kernel parameter `talos.auditd.disabled=1` can be used to disable Talos built-in `auditd` service. """ [make_deps] diff --git a/hack/test/patches/image-cache.yaml b/hack/test/patches/image-cache.yaml index 76b1585856..4d05807a28 100644 --- a/hack/test/patches/image-cache.yaml +++ b/hack/test/patches/image-cache.yaml @@ -23,3 +23,4 @@ name: IMAGECACHE provisioning: diskSelector: match: 'system_disk' + grow: true diff --git a/internal/app/machined/pkg/controllers/k8s/control_plane.go b/internal/app/machined/pkg/controllers/k8s/control_plane.go index 595788ab1e..8d47a78f72 100644 --- a/internal/app/machined/pkg/controllers/k8s/control_plane.go +++ b/internal/app/machined/pkg/controllers/k8s/control_plane.go @@ -131,11 +131,6 @@ func NewControlPlaneAuthorizationController() *ControlPlaneAuthorizationControll var authorizers []k8s.AuthorizationAuthorizersSpec for _, authorizer := range cfgProvider.Cluster().APIServer().AuthorizationConfig() { - // skip Node and RBAC authorizers as we add them by default later on. - if authorizer.Type() == "Node" || authorizer.Type() == "RBAC" { - continue - } - authorizers = slices.Concat(authorizers, []k8s.AuthorizationAuthorizersSpec{ { Type: authorizer.Type(), @@ -145,7 +140,25 @@ func NewControlPlaneAuthorizationController() *ControlPlaneAuthorizationControll }) } - res.TypedSpec().Config = slices.Concat(v1alpha1.APIServerDefaultAuthorizationConfigAuthorizers, authorizers) + if !slices.ContainsFunc(authorizers, func(a k8s.AuthorizationAuthorizersSpec) bool { + return a.Type == "Node" + }) { + authorizers = slices.Insert(authorizers, 0, k8s.AuthorizationAuthorizersSpec{ + Type: "Node", + Name: "node", + }) + } + + if !slices.ContainsFunc(authorizers, func(a k8s.AuthorizationAuthorizersSpec) bool { + return a.Type == "RBAC" + }) { + authorizers = slices.Insert(authorizers, 1, k8s.AuthorizationAuthorizersSpec{ + Type: "RBAC", + Name: "rbac", + }) + } + + res.TypedSpec().Config = authorizers return nil }, diff --git a/internal/app/machined/pkg/controllers/k8s/control_plane_test.go b/internal/app/machined/pkg/controllers/k8s/control_plane_test.go index 0d9a11b232..c870c70c9e 100644 --- a/internal/app/machined/pkg/controllers/k8s/control_plane_test.go +++ b/internal/app/machined/pkg/controllers/k8s/control_plane_test.go @@ -270,10 +270,88 @@ func (suite *K8sControlPlaneSuite) TestReconcileAdditionalAuthorizationConfigAut }, }, }, + { + AuthorizerType: "Node", + AuthorizerName: "bar", + }, + }, + }, + }, + }, + ), + ) + + suite.setupMachine(cfg) + + expectedAuthorizers := []k8s.AuthorizationAuthorizersSpec{ + { + Type: "RBAC", + Name: "foo", + }, + { + Type: "Webhook", + Name: "webhook", + Webhook: map[string]any{ + "timeout": "3s", + "subjectAccessReviewVersion": "v1", + "matchConditionSubjectAccessReviewVersion": "v1", + "failurePolicy": "NoOpinion", + "connectionInfo": map[string]any{ + "type": "InClusterConfig", + }, + }, + }, + { + Type: "Node", + Name: "bar", + }, + } + + rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.AuthorizationConfigID}, + func(authorizationConfig *k8s.AuthorizationConfig, assert *assert.Assertions) { + assert.Equal(expectedAuthorizers, authorizationConfig.TypedSpec().Config) + }, + ) +} + +func (suite *K8sControlPlaneSuite) TestReconcileAdditionalAuthorizationConfigAuthorizersWithOnlyNodeSet() { + u, err := url.Parse("https://foo:6443") + suite.Require().NoError(err) + + cfg := config.NewMachineConfig( + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineType: "controlplane", + }, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, + }, + APIServerConfig: &v1alpha1.APIServerConfig{ + AuthorizationConfigConfig: []*v1alpha1.AuthorizationConfigAuthorizerConfig{ { AuthorizerType: "Node", AuthorizerName: "foo", }, + { + AuthorizerType: "Webhook", + AuthorizerName: "webhook", + AuthorizerWebhook: v1alpha1.Unstructured{ + Object: map[string]any{ + "timeout": "3s", + "subjectAccessReviewVersion": "v1", + "matchConditionSubjectAccessReviewVersion": "v1", + "failurePolicy": "NoOpinion", + "connectionInfo": map[string]any{ + "type": "InClusterConfig", + }, + }, + }, + }, }, }, }, @@ -283,7 +361,15 @@ func (suite *K8sControlPlaneSuite) TestReconcileAdditionalAuthorizationConfigAut suite.setupMachine(cfg) - expectedAuthorizers := slices.Concat(v1alpha1.APIServerDefaultAuthorizationConfigAuthorizers, []k8s.AuthorizationAuthorizersSpec{ + expectedAuthorizers := []k8s.AuthorizationAuthorizersSpec{ + { + Type: "Node", + Name: "foo", + }, + { + Type: "RBAC", + Name: "rbac", + }, { Type: "Webhook", Name: "webhook", @@ -297,7 +383,7 @@ func (suite *K8sControlPlaneSuite) TestReconcileAdditionalAuthorizationConfigAut }, }, }, - }) + } rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.AuthorizationConfigID}, func(authorizationConfig *k8s.AuthorizationConfig, assert *assert.Assertions) { diff --git a/internal/app/machined/pkg/controllers/k8s/endpoint.go b/internal/app/machined/pkg/controllers/k8s/endpoint.go index fbf1450e01..9add5d3f1b 100644 --- a/internal/app/machined/pkg/controllers/k8s/endpoint.go +++ b/internal/app/machined/pkg/controllers/k8s/endpoint.go @@ -269,7 +269,7 @@ func (ctrl *EndpointController) watchKubernetesEndpoint(ctx context.Context, r c func kubernetesEndpointWatcher(ctx context.Context, logger *zap.Logger, client *kubernetes.Client) (chan *corev1.Endpoints, func(), error) { informerFactory := informers.NewSharedInformerFactoryWithOptions( - client.Clientset, 30*time.Second, + client.Clientset, constants.KubernetesInformerDefaultResyncPeriod, informers.WithNamespace(corev1.NamespaceDefault), informers.WithTweakListOptions(func(options *v1.ListOptions) { options.FieldSelector = fields.OneTermEqualSelector("metadata.name", "kubernetes").String() diff --git a/internal/app/machined/pkg/controllers/k8s/internal/nodewatch/nodewatch.go b/internal/app/machined/pkg/controllers/k8s/internal/nodewatch/nodewatch.go index 71672749e2..9c0d042ecf 100644 --- a/internal/app/machined/pkg/controllers/k8s/internal/nodewatch/nodewatch.go +++ b/internal/app/machined/pkg/controllers/k8s/internal/nodewatch/nodewatch.go @@ -9,6 +9,7 @@ import ( "context" "fmt" + "go.uber.org/zap" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" @@ -17,6 +18,7 @@ import ( "k8s.io/client-go/tools/cache" "github.com/siderolabs/talos/pkg/kubernetes" + "github.com/siderolabs/talos/pkg/machinery/constants" ) // NodeWatcher defines a NodeWatcher-based node watcher. @@ -46,10 +48,12 @@ func (r *NodeWatcher) Get() (*corev1.Node, error) { } // Watch starts watching Node state and notifies on updates via notify channel. -func (r *NodeWatcher) Watch(ctx context.Context) (<-chan struct{}, <-chan error, func(), error) { +func (r *NodeWatcher) Watch(ctx context.Context, logger *zap.Logger) (<-chan struct{}, <-chan error, func(), error) { + logger.Debug("starting node watcher", zap.String("nodename", r.nodename)) + informerFactory := informers.NewSharedInformerFactoryWithOptions( r.client.Clientset, - 0, + constants.KubernetesInformerDefaultResyncPeriod, informers.WithTweakListOptions( func(opts *metav1.ListOptions) { opts.FieldSelector = fields.OneTermEqualSelector(metav1.ObjectNameField, r.nodename).String() @@ -88,7 +92,11 @@ func (r *NodeWatcher) Watch(ctx context.Context) (<-chan struct{}, <-chan error, informerFactory.Start(ctx.Done()) + logger.Debug("waiting for node cache sync") + informerFactory.WaitForCacheSync(ctx.Done()) + logger.Debug("node cache sync done") + return notifyCh, watchErrCh, informerFactory.Shutdown, nil } diff --git a/internal/app/machined/pkg/controllers/k8s/node_status.go b/internal/app/machined/pkg/controllers/k8s/node_status.go index 985abbc4db..02bb00817b 100644 --- a/internal/app/machined/pkg/controllers/k8s/node_status.go +++ b/internal/app/machined/pkg/controllers/k8s/node_status.go @@ -158,9 +158,9 @@ func (ctrl *NodeStatusController) Run(ctx context.Context, r controller.Runtime, var watchCtx context.Context watchCtx, watchCtxCancel = context.WithCancel(ctx) //nolint:govet - notifyCh, watchErrCh, notifyCloser, err = nodewatcher.Watch(watchCtx) + notifyCh, watchErrCh, notifyCloser, err = nodewatcher.Watch(watchCtx, logger) if err != nil { - return fmt.Errorf("error setting up registry watcher: %w", err) //nolint:govet + return fmt.Errorf("error setting up node watcher: %w", err) //nolint:govet } } diff --git a/internal/app/machined/pkg/controllers/network/operator/dhcp4.go b/internal/app/machined/pkg/controllers/network/operator/dhcp4.go index ba26fc536b..cfc4e77f5c 100644 --- a/internal/app/machined/pkg/controllers/network/operator/dhcp4.go +++ b/internal/app/machined/pkg/controllers/network/operator/dhcp4.go @@ -111,12 +111,12 @@ func (d *DHCP4) knownHostname(hostname network.HostnameStatusSpec) bool { // be assigned to the associated so that unicast operations can bind successfully. func (d *DHCP4) waitForNetworkReady(ctx context.Context) error { // If an IP address has been registered, wait for the address association to be ready - if len(d.addresses) > 0 { + if addresses := d.AddressSpecs(); len(addresses) > 0 { _, err := d.state.WatchFor(ctx, resource.NewMetadata( network.NamespaceName, network.AddressStatusType, - network.AddressID(d.linkName, d.addresses[0].Address), + network.AddressID(d.linkName, addresses[0].Address), resource.VersionUndefined, ), state.WithPhases(resource.PhaseRunning), @@ -159,7 +159,7 @@ func (d *DHCP4) Run(ctx context.Context, notifyCh chan<- struct{}) { // Perform a lease request or renewal leaseTime, err := d.requestRenew(ctx, hostname) if err != nil && !errors.Is(err, context.Canceled) { - d.logger.Warn("request/renew failed", zap.Error(err), zap.String("link", d.linkName)) + d.logger.Warn("DHCP request/renew failed", zap.Error(err), zap.String("link", d.linkName)) } if err == nil { @@ -235,7 +235,7 @@ func (d *DHCP4) Run(ctx context.Context, notifyCh chan<- struct{}) { d.lease = nil d.logger.Debug("restarting DHCP sequence due to hostname change", - zap.Strings("dhcp_hostname", xslices.Map(d.hostname, func(spec network.HostnameSpecSpec) string { + zap.Strings("dhcp_hostname", xslices.Map(d.HostnameSpecs(), func(spec network.HostnameSpecSpec) string { return spec.Hostname })), ) @@ -532,6 +532,8 @@ func (d *DHCP4) requestRenew(ctx context.Context, hostname network.HostnameStatu //nolint:errcheck defer client.Close() + addresses := d.AddressSpecs() + switch { case d.lease != nil && !d.lease.ACK.ServerIPAddr.IsUnspecified(): d.logger.Debug("DHCP RENEW", zap.String("link", d.linkName)) @@ -539,6 +541,14 @@ func (d *DHCP4) requestRenew(ctx context.Context, hostname network.HostnameStatu case d.lease != nil && d.lease.Offer != nil: d.logger.Debug("DHCP REQUEST FROM OFFER", zap.String("link", d.linkName)) d.lease, err = client.RequestFromOffer(ctx, d.lease.Offer, mods...) + case len(addresses) >= 1: + previousIPAddress := net.IP(addresses[0].Address.Addr().AsSlice()) + + d.logger.Debug("DHCP REQUEST with previous IP", zap.String("link", d.linkName), zap.Stringer("previous_ip", previousIPAddress)) + + d.lease, err = client.Request(ctx, dhcpv4.PrependModifiers(mods, + dhcpv4.WithOption(dhcpv4.OptRequestedIPAddress(previousIPAddress)), + )...) default: d.logger.Debug("DHCP REQUEST", zap.String("link", d.linkName)) d.lease, err = client.Request(ctx, mods...) diff --git a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go index b84cb07325..55d54e7cd4 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go @@ -359,7 +359,18 @@ func StartSyslogd(r runtime.Sequence, _ any) (runtime.TaskExecutionFunc, string) // StartAuditd represents the task to start auditd. func StartAuditd(r runtime.Sequence, _ any) (runtime.TaskExecutionFunc, string) { - return func(_ context.Context, _ *log.Logger, r runtime.Runtime) error { + return func(_ context.Context, logger *log.Logger, r runtime.Runtime) error { + if !r.State().Platform().Mode().InContainer() { + disabledStr := procfs.ProcCmdline().Get(constants.KernelParamAuditdDisabled).First() + disabled, _ := strconv.ParseBool(pointer.SafeDeref(disabledStr)) //nolint:errcheck + + if disabled { + logger.Printf("auditd is disabled by kernel parameter %s", constants.KernelParamAuditdDisabled) + + return nil + } + } + system.Services(r).LoadAndStart(&services.Auditd{}) return nil diff --git a/internal/app/syslogd/internal/parser/parse_test.go b/internal/app/syslogd/internal/parser/parse_test.go index 6ae6ccad83..1aceca1047 100644 --- a/internal/app/syslogd/internal/parser/parse_test.go +++ b/internal/app/syslogd/internal/parser/parse_test.go @@ -6,7 +6,9 @@ package parser_test import ( + "fmt" "testing" + "time" "github.com/stretchr/testify/require" @@ -14,6 +16,8 @@ import ( ) func TestParser(t *testing.T) { + year := time.Now().Year() + for _, tc := range []struct { name string input []byte @@ -22,27 +26,27 @@ func TestParser(t *testing.T) { { name: "RFC3164 without tag and hostname", input: []byte(`<4>Feb 16 17:54:19 time="2024-02-16T17:54:19.857755073Z" level=warning msg="Could not add /dev/mshv to the devices cgroup`), - expected: `{"content":"time=\"2024-02-16T17:54:19.857755073Z\" level=warning msg=\"Could not add /dev/mshv to the devices cgroup","facility":0,"hostname":"localhost","priority":4,"severity":4,"tag":"unknown","timestamp":"2024-02-16T17:54:19Z"}`, //nolint:lll + expected: fmt.Sprintf(`{"content":"time=\"2024-02-16T17:54:19.857755073Z\" level=warning msg=\"Could not add /dev/mshv to the devices cgroup","facility":0,"hostname":"localhost","priority":4,"severity":4,"tag":"unknown","timestamp":"%d-02-16T17:54:19Z"}`, year), //nolint:lll }, { name: "RFC3164 timestamp contains single digit day", input: []byte(`<6>Mar 3 12:55:18 syslogd_test[834097]: Hello, syslogd!`), - expected: `{"content":"Hello, syslogd!","facility":0,"hostname":"localhost","priority":6,"severity":6,"tag":"syslogd_test","timestamp":"2024-03-03T12:55:18Z"}`, + expected: fmt.Sprintf(`{"content":"Hello, syslogd!","facility":0,"hostname":"localhost","priority":6,"severity":6,"tag":"syslogd_test","timestamp":"%d-03-03T12:55:18Z"}`, year), }, { name: "RFC3164 timestamp contains single digit day & without tag and hostname", input: []byte(`<6>Mar 3 12:55:18 Hello, syslogd!`), - expected: `{"content":"Hello, syslogd!","facility":0,"hostname":"localhost","priority":6,"severity":6,"tag":"unknown","timestamp":"2024-03-03T12:55:18Z"}`, + expected: fmt.Sprintf(`{"content":"Hello, syslogd!","facility":0,"hostname":"localhost","priority":6,"severity":6,"tag":"unknown","timestamp":"%d-03-03T12:55:18Z"}`, year), }, { name: "RFC3164 without hostname", input: []byte(`<4>Feb 16 17:54:19 kata[2569]: time="2024-02-16T17:54:19.857755073Z" level=warning msg="Could not add /dev/mshv to the devices cgroup`), - expected: `{"content":"time=\"2024-02-16T17:54:19.857755073Z\" level=warning msg=\"Could not add /dev/mshv to the devices cgroup","facility":0,"hostname":"localhost","priority":4,"severity":4,"tag":"kata","timestamp":"2024-02-16T17:54:19Z"}`, //nolint:lll + expected: fmt.Sprintf(`{"content":"time=\"2024-02-16T17:54:19.857755073Z\" level=warning msg=\"Could not add /dev/mshv to the devices cgroup","facility":0,"hostname":"localhost","priority":4,"severity":4,"tag":"kata","timestamp":"%d-02-16T17:54:19Z"}`, year), //nolint:lll }, { name: "RFC3164 with hostname", input: []byte(`<4>Feb 16 17:54:19 hostname kata[2569]: time="2024-02-16T17:54:19.857755073Z" level=warning msg="Could not add /dev/mshv to the devices cgroup`), - expected: `{"content":"time=\"2024-02-16T17:54:19.857755073Z\" level=warning msg=\"Could not add /dev/mshv to the devices cgroup","facility":0,"hostname":"hostname","priority":4,"severity":4,"tag":"kata","timestamp":"2024-02-16T17:54:19Z"}`, //nolint:lll + expected: fmt.Sprintf(`{"content":"time=\"2024-02-16T17:54:19.857755073Z\" level=warning msg=\"Could not add /dev/mshv to the devices cgroup","facility":0,"hostname":"hostname","priority":4,"severity":4,"tag":"kata","timestamp":"%d-02-16T17:54:19Z"}`, year), //nolint:lll }, { name: "RFC5424", diff --git a/internal/integration/base/k8s.go b/internal/integration/base/k8s.go index a984d86db4..184ef0bcdd 100644 --- a/internal/integration/base/k8s.go +++ b/internal/integration/base/k8s.go @@ -51,6 +51,7 @@ import ( "k8s.io/kubectl/pkg/scheme" taloskubernetes "github.com/siderolabs/talos/pkg/kubernetes" + "github.com/siderolabs/talos/pkg/machinery/constants" ) // K8sSuite is a base suite for K8s tests. @@ -813,9 +814,12 @@ func (k8sSuite *K8sSuite) SetupNodeInformer(ctx context.Context, nodeName string watchCh := make(chan *corev1.Node) - informerFactory := informers.NewSharedInformerFactoryWithOptions(k8sSuite.Clientset, 30*time.Second, informers.WithTweakListOptions(func(options *metav1.ListOptions) { - options.FieldSelector = metadataKeyName + nodeName - })) + informerFactory := informers.NewSharedInformerFactoryWithOptions( + k8sSuite.Clientset, constants.KubernetesInformerDefaultResyncPeriod, + informers.WithTweakListOptions(func(options *metav1.ListOptions) { + options.FieldSelector = metadataKeyName + nodeName + }), + ) nodeInformer := informerFactory.Core().V1().Nodes().Informer() _, err := nodeInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ diff --git a/internal/pkg/dashboard/apidata/node.go b/internal/pkg/dashboard/apidata/node.go index b8da10fd16..940f1e1adf 100644 --- a/internal/pkg/dashboard/apidata/node.go +++ b/internal/pkg/dashboard/apidata/node.go @@ -179,8 +179,8 @@ func (node *Node) UpdateDiff(old *Node) { node.SystemStatDiff = &machine.SystemStat{ // TODO: support other fields CpuTotal: cpuInfoDiff(old.SystemStat.GetCpuTotal(), node.SystemStat.GetCpuTotal()), - ContextSwitches: node.SystemStat.ContextSwitches - old.SystemStat.ContextSwitches, - ProcessCreated: node.SystemStat.ProcessCreated - old.SystemStat.ProcessCreated, + ContextSwitches: node.SystemStat.GetContextSwitches() - old.SystemStat.GetContextSwitches(), + ProcessCreated: node.SystemStat.GetProcessCreated() - old.SystemStat.GetProcessCreated(), } } diff --git a/internal/pkg/discovery/registry/kubernetes.go b/internal/pkg/discovery/registry/kubernetes.go index 13a4ffccfe..ecf1d05910 100644 --- a/internal/pkg/discovery/registry/kubernetes.go +++ b/internal/pkg/discovery/registry/kubernetes.go @@ -12,7 +12,6 @@ import ( "net/netip" "strconv" "strings" - "time" "github.com/siderolabs/gen/value" "github.com/siderolabs/gen/xslices" @@ -265,7 +264,7 @@ func (r *Kubernetes) List(localNodeName string) ([]*cluster.AffiliateSpec, error // Watch starts watching Node state and notifies on updates via notify channel. func (r *Kubernetes) Watch(ctx context.Context, logger *zap.Logger) (<-chan struct{}, func(), error) { - informerFactory := informers.NewSharedInformerFactory(r.client.Clientset, 30*time.Second) + informerFactory := informers.NewSharedInformerFactory(r.client.Clientset, constants.KubernetesInformerDefaultResyncPeriod) notifyCh := make(chan struct{}, 1) diff --git a/internal/pkg/install/install.go b/internal/pkg/install/install.go index 1c262e9b65..d6cac8a51e 100644 --- a/internal/pkg/install/install.go +++ b/internal/pkg/install/install.go @@ -182,6 +182,7 @@ func RunInstallerContainer( constants.KernelParamEventsSink, constants.KernelParamLoggingKernel, constants.KernelParamEquinixMetalEvents, + constants.KernelParamAuditdDisabled, constants.KernelParamDashboardDisabled, constants.KernelParamNetIfnames, constants.KernelParamSELinux, diff --git a/internal/pkg/mount/v2/pseudo.go b/internal/pkg/mount/v2/pseudo.go index ce8bbde2b3..edf4fb36da 100644 --- a/internal/pkg/mount/v2/pseudo.go +++ b/internal/pkg/mount/v2/pseudo.go @@ -9,6 +9,7 @@ import ( "golang.org/x/sys/unix" + "github.com/siderolabs/talos/internal/pkg/selinux" "github.com/siderolabs/talos/pkg/machinery/constants" ) @@ -48,8 +49,8 @@ func PseudoSubMountPoints() Points { ) } - if _, err := os.Stat("/sys/fs/selinux"); err == nil { - // mount selinuxfs if it exists + if selinux.IsEnabled() { + // mount selinuxfs if it is enabled, which implies SELinux is the major LSM points = append(points, NewPoint("selinuxfs", "/sys/fs/selinux", "selinuxfs", WithFlags(unix.MS_NOSUID|unix.MS_NOEXEC|unix.MS_RELATIME)), ) diff --git a/internal/pkg/mount/v2/repair.go b/internal/pkg/mount/v2/repair.go index 06ffacad90..2991063b03 100644 --- a/internal/pkg/mount/v2/repair.go +++ b/internal/pkg/mount/v2/repair.go @@ -12,10 +12,21 @@ import ( // repair a filesystem. func (p *Point) repair(printerOptions PrinterOptions) error { - printerOptions.Printf("filesystem on %s needs cleaning, running repair", p.source) + var repairFunc func(partition string) error - if err := makefs.XFSRepair(p.source, p.fstype); err != nil { - return fmt.Errorf("xfs_repair: %w", err) + switch p.fstype { + case "ext4": + repairFunc = makefs.Ext4Repair + case "xfs": + repairFunc = makefs.XFSRepair + default: + return fmt.Errorf("unsupported filesystem type for repair: %s", p.fstype) + } + + printerOptions.Printf("filesystem (%s) on %s needs cleaning, running repair", p.fstype, p.source) + + if err := repairFunc(p.source); err != nil { + return fmt.Errorf("repair: %w", err) } printerOptions.Printf("filesystem successfully repaired on %s", p.source) diff --git a/pkg/imager/profile/profile.go b/pkg/imager/profile/profile.go index 2cb244ed2d..55499f1455 100644 --- a/pkg/imager/profile/profile.go +++ b/pkg/imager/profile/profile.go @@ -100,6 +100,10 @@ func (p *Profile) Validate() error { // cmdline supports all kinds of customization case OutKindImage: // Image supports all kinds of customization + if p.Output.ImageOptions == nil { + return errors.New("image options are required for image output") + } + if p.Output.ImageOptions.DiskSize == 0 { return errors.New("disk size is required for image output") } diff --git a/pkg/machinery/config/types/block/byte_size.go b/pkg/machinery/config/types/block/byte_size.go index 2e0898743d..fcc5a89056 100644 --- a/pkg/machinery/config/types/block/byte_size.go +++ b/pkg/machinery/config/types/block/byte_size.go @@ -6,6 +6,7 @@ package block import ( "encoding" + "fmt" "slices" "strconv" @@ -80,3 +81,16 @@ func (bs *ByteSize) UnmarshalText(text []byte) error { func (bs ByteSize) IsZero() bool { return bs.value == nil && bs.raw == nil } + +// Merge implements merger interface. +func (bs *ByteSize) Merge(other any) error { + otherBS, ok := other.(ByteSize) + if !ok { + return fmt.Errorf("cannot merge %T with %T", bs, other) + } + + bs.raw = otherBS.raw + bs.value = otherBS.value + + return nil +} diff --git a/pkg/machinery/config/types/block/volume_config_test.go b/pkg/machinery/config/types/block/volume_config_test.go index 230696c479..98c6e2f3ef 100644 --- a/pkg/machinery/config/types/block/volume_config_test.go +++ b/pkg/machinery/config/types/block/volume_config_test.go @@ -184,10 +184,12 @@ func TestVolumeConfigMerge(t *testing.T) { c2.MetaName = constants.EphemeralPartitionLabel require.NoError(t, c2.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 150`))) + require.NoError(t, c2.ProvisioningSpec.ProvisioningMaxSize.UnmarshalText([]byte("2.5TiB"))) require.NoError(t, merge.Merge(c1, c2)) assert.Equal(t, c1.ProvisioningSpec.DiskSelectorSpec.Match, c2.ProvisioningSpec.DiskSelectorSpec.Match) + assert.Equal(t, c1.ProvisioningSpec.ProvisioningMaxSize, c2.ProvisioningSpec.ProvisioningMaxSize) } type validationMode struct{} diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go index 8d14752161..6292c8ddf3 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go @@ -1327,6 +1327,20 @@ func (i *InstallConfig) DiskMatchExpression() (*cel.Expression, error) { exprs = append(exprs, patternMatcherExpr(selector.Modalias, "modalias")) } + // disk.transport != "" (otherwise it might select e.g. DM devices) + exprs = append(exprs, + builder.NewCall( + builder.NextID(), + operators.NotEquals, + builder.NewSelect( + builder.NextID(), + builder.NewIdent(builder.NextID(), "disk"), + "transport", + ), + builder.NewLiteral(builder.NextID(), types.String("")), + ), + ) + if selector.Type != "" { switch selector.Type { case "nvme": // disk.transport == "nvme" @@ -1339,18 +1353,8 @@ func (i *InstallConfig) DiskMatchExpression() (*cel.Expression, error) { builder.NewIdent(builder.NextID(), "disk"), "rotational", )) - case "ssd": // disk.transport != "" && !disk.rotational + case "ssd": // !disk.rotational exprs = append(exprs, - builder.NewCall( - builder.NextID(), - operators.NotEquals, - builder.NewSelect( - builder.NextID(), - builder.NewIdent(builder.NextID(), "disk"), - "transport", - ), - builder.NewLiteral(builder.NextID(), types.String("")), - ), builder.NewCall( builder.NextID(), operators.LogicalNot, @@ -1367,7 +1371,7 @@ func (i *InstallConfig) DiskMatchExpression() (*cel.Expression, error) { } if selector.BusPath != "" { - exprs = append(exprs, patternMatcherExpr(selector.BusPath, "buspath")) + exprs = append(exprs, patternMatcherExpr(selector.BusPath, "bus_path")) } // exclude readonly disks: !disk.readonly diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_provider_test.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_provider_test.go index 7328613c04..fdf2eaaa6a 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_provider_test.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_provider_test.go @@ -35,7 +35,7 @@ func TestInstallDiskSelector(t *testing.T) { }, }, - expected: `disk.size <= 262144u && !disk.readonly && !disk.cdrom`, + expected: `disk.size <= 262144u && disk.transport != "" && !disk.readonly && !disk.cdrom`, }, { name: "size and type", @@ -49,7 +49,8 @@ func TestInstallDiskSelector(t *testing.T) { Type: v1alpha1.InstallDiskType("nvme"), }, - expected: `disk.size == 1048576u && disk.transport == "nvme" && !disk.readonly && !disk.cdrom`, + expected: `disk.size == 1048576u && disk.transport != "" && disk.transport == "nvme" && !disk.readonly && +!disk.cdrom`, }, { name: "size and type and modalias", @@ -64,8 +65,8 @@ func TestInstallDiskSelector(t *testing.T) { Modalias: "pci:1234:5678*", }, - expected: `disk.size == 1048576u && glob("pci:1234:5678*", disk.modalias) && disk.rotational && -!disk.readonly && !disk.cdrom`, + expected: `disk.size == 1048576u && glob("pci:1234:5678*", disk.modalias) && disk.transport != "" && +disk.rotational && !disk.readonly && !disk.cdrom`, }, { name: "ssd", @@ -76,6 +77,16 @@ func TestInstallDiskSelector(t *testing.T) { expected: `disk.transport != "" && !disk.rotational && !disk.readonly && !disk.cdrom`, }, + { + name: "bus path", + + selector: v1alpha1.InstallDiskSelector{ + BusPath: "/pci-0000:00:1f.2/*", + }, + + expected: `disk.transport != "" && glob("/pci-0000:00:1f.2/*", disk.bus_path) && !disk.readonly && +!disk.cdrom`, + }, } { t.Run(test.name, func(t *testing.T) { t.Parallel() diff --git a/pkg/machinery/constants/constants.go b/pkg/machinery/constants/constants.go index a96e9b21f2..3788ae91ef 100644 --- a/pkg/machinery/constants/constants.go +++ b/pkg/machinery/constants/constants.go @@ -14,7 +14,7 @@ import ( const ( // DefaultKernelVersion is the default Linux kernel version. - DefaultKernelVersion = "6.12.6-talos" + DefaultKernelVersion = "6.12.9-talos" // KernelModulesPath is the default path to the kernel modules without the kernel version. KernelModulesPath = "/lib/modules" @@ -80,6 +80,9 @@ const ( // cgroups version to use (default is cgroupsv2, setting this kernel arg to '0' forces cgroupsv1). KernelParamCGroups = "talos.unified_cgroup_hierarchy" + // KernelParamAuditdDisabled is the kernel parameter name for disabling auditd service. + KernelParamAuditdDisabled = "talos.auditd.disabled" + // KernelParamDashboardDisabled is the kernel parameter name for disabling the dashboard. KernelParamDashboardDisabled = "talos.dashboard.disabled" @@ -541,7 +544,7 @@ const ( TrustdUserID = 51 // DefaultContainerdVersion is the default container runtime version. - DefaultContainerdVersion = "2.0.1" + DefaultContainerdVersion = "2.0.2" // SystemContainerdNamespace is the Containerd namespace for Talos services. SystemContainerdNamespace = "system" @@ -1233,6 +1236,9 @@ const ( // RegistrydListenAddress is the address to listen on for the registryd service. RegistrydListenAddress = "127.0.0.1:3172" + + // KubernetesInformerDefaultResyncPeriod is the default resync period for Kubernetes informers. + KubernetesInformerDefaultResyncPeriod = 30 * time.Second ) // See https://linux.die.net/man/3/klogctl diff --git a/pkg/machinery/extensions/extensions_test.go b/pkg/machinery/extensions/extensions_test.go index 91e0842573..e4fe864b72 100644 --- a/pkg/machinery/extensions/extensions_test.go +++ b/pkg/machinery/extensions/extensions_test.go @@ -27,7 +27,7 @@ func TestLoadValidate(t *testing.T) { assert.NoError(t, ext.Validate( extensions.WithValidateConstraints(), extensions.WithValidateContents(), - extensions.WithTalosVersion(version), + extensions.WithTalosVersion(&version), )) } @@ -70,7 +70,7 @@ func TestValidateFailures(t *testing.T) { err = ext.Validate( extensions.WithValidateConstraints(), extensions.WithValidateContents(), - extensions.WithTalosVersion(version), + extensions.WithTalosVersion(&version), ) assert.EqualError(t, err, tt.validateError) diff --git a/pkg/machinery/extensions/validate.go b/pkg/machinery/extensions/validate.go index d295edcc12..83d5b094e5 100644 --- a/pkg/machinery/extensions/validate.go +++ b/pkg/machinery/extensions/validate.go @@ -46,9 +46,9 @@ func WithValidateContents() ValidationOption { } // WithTalosVersion sets the Talos version to validate against. -func WithTalosVersion(version semver.Version) ValidationOption { +func WithTalosVersion(version *semver.Version) ValidationOption { return func(o *ValidationOptions) error { - o.TalosVersion = &version + o.TalosVersion = version return nil } diff --git a/pkg/machinery/gendata/data/pkgs b/pkg/machinery/gendata/data/pkgs index f663bc3926..0cfe110eda 100644 --- a/pkg/machinery/gendata/data/pkgs +++ b/pkg/machinery/gendata/data/pkgs @@ -1 +1 @@ -v1.9.0-15-g45c4ba4 \ No newline at end of file +v1.9.0-21-gc1f06e5 \ No newline at end of file diff --git a/pkg/machinery/go.mod b/pkg/machinery/go.mod index d0036a961f..cd1c251d23 100644 --- a/pkg/machinery/go.mod +++ b/pkg/machinery/go.mod @@ -27,7 +27,7 @@ require ( github.com/siderolabs/crypto v0.5.0 github.com/siderolabs/gen v0.7.0 github.com/siderolabs/go-api-signature v0.3.6 - github.com/siderolabs/go-blockdevice/v2 v2.0.9 + github.com/siderolabs/go-blockdevice/v2 v2.0.11 github.com/siderolabs/go-pointer v1.0.0 github.com/siderolabs/net v0.4.0 github.com/siderolabs/protoenc v0.2.1 diff --git a/pkg/machinery/go.sum b/pkg/machinery/go.sum index 97131a9ce4..9e6dbd96a3 100644 --- a/pkg/machinery/go.sum +++ b/pkg/machinery/go.sum @@ -110,8 +110,8 @@ github.com/siderolabs/gen v0.7.0 h1:uHAt3WD0dof28NHFuguWBbDokaXQraR/HyVxCLw2QCU= github.com/siderolabs/gen v0.7.0/go.mod h1:an3a2Y53O7kUjnnK8Bfu3gewtvnIOu5RTU6HalFtXQQ= github.com/siderolabs/go-api-signature v0.3.6 h1:wDIsXbpl7Oa/FXvxB6uz4VL9INA9fmr3EbmjEZYFJrU= github.com/siderolabs/go-api-signature v0.3.6/go.mod h1:hoH13AfunHflxbXfh+NoploqV13ZTDfQ1mQJWNVSW9U= -github.com/siderolabs/go-blockdevice/v2 v2.0.9 h1:OTo+ADN/3LT4XtI8p7Dz3hlh6DJABHwMAnOlK7MOtMk= -github.com/siderolabs/go-blockdevice/v2 v2.0.9/go.mod h1:74htzCV913UzaLZ4H+NBXkwWlYnBJIq5m/379ZEcu8w= +github.com/siderolabs/go-blockdevice/v2 v2.0.11 h1:r7mbbXMn8OZmJA2fJJdomjlZKexRi66ELVZGXJUaNU8= +github.com/siderolabs/go-blockdevice/v2 v2.0.11/go.mod h1:74htzCV913UzaLZ4H+NBXkwWlYnBJIq5m/379ZEcu8w= github.com/siderolabs/go-pointer v1.0.0 h1:6TshPKep2doDQJAAtHUuHWXbca8ZfyRySjSBT/4GsMU= github.com/siderolabs/go-pointer v1.0.0/go.mod h1:HTRFUNYa3R+k0FFKNv11zgkaCLzEkWVzoYZ433P3kHc= github.com/siderolabs/go-retry v0.3.3 h1:zKV+S1vumtO72E6sYsLlmIdV/G/GcYSBLiEx/c9oCEg= diff --git a/pkg/machinery/imager/quirks/quirks.go b/pkg/machinery/imager/quirks/quirks.go index 6d5b8b11f2..7d133da7b6 100644 --- a/pkg/machinery/imager/quirks/quirks.go +++ b/pkg/machinery/imager/quirks/quirks.go @@ -30,8 +30,8 @@ func New(talosVersion string) Quirks { var minVersionResetOption = semver.MustParse("1.4.0") // Version returns the Talos version. -func (q Quirks) Version() semver.Version { - return *q.v +func (q Quirks) Version() *semver.Version { + return q.v } // SupportsResetGRUBOption returns true if the Talos version supports the reset option in GRUB menu (image and ISO). diff --git a/pkg/makefs/ext4.go b/pkg/makefs/ext4.go index 404a1c3228..0e3be8526b 100644 --- a/pkg/makefs/ext4.go +++ b/pkg/makefs/ext4.go @@ -48,7 +48,25 @@ func Ext4(partname string, setters ...Option) error { // Ext4Resize expands a ext4 filesystem to the maximum possible. func Ext4Resize(partname string) error { + // resizing the filesystem requires a check first + if err := Ext4Repair(partname); err != nil { + return fmt.Errorf("failed to repair before growing ext4 filesystem: %w", err) + } + _, err := cmd.Run("resize2fs", partname) + if err != nil { + return fmt.Errorf("failed to grow ext4 filesystem: %w", err) + } - return err + return nil +} + +// Ext4Repair repairs a ext4 filesystem. +func Ext4Repair(partname string) error { + _, err := cmd.Run("e2fsck", "-f", "-p", partname) + if err != nil { + return fmt.Errorf("failed to repair ext4 filesystem: %w", err) + } + + return nil } diff --git a/pkg/makefs/xfs.go b/pkg/makefs/xfs.go index 8f968e6eb0..c9a9dee39a 100644 --- a/pkg/makefs/xfs.go +++ b/pkg/makefs/xfs.go @@ -20,19 +20,21 @@ const ( // MUST be mounted, or this will fail. func XFSGrow(partname string) error { _, err := cmd.Run("xfs_growfs", "-d", partname) + if err != nil { + return fmt.Errorf("failed to grow XFS filesystem: %w", err) + } return err } // XFSRepair repairs a XFS filesystem on the specified partition. -func XFSRepair(partname, fsType string) error { - if fsType != FilesystemTypeXFS { - return fmt.Errorf("unsupported filesystem type: %s", fsType) - } - +func XFSRepair(partname string) error { _, err := cmd.Run("xfs_repair", partname) + if err != nil { + return fmt.Errorf("error repairing XFS filesystem: %w", err) + } - return err + return nil } // XFS creates a XFS filesystem on the specified partition. diff --git a/pkg/provision/providers/qemu/launch.go b/pkg/provision/providers/qemu/launch.go index 68b76e4d44..a2a463c552 100644 --- a/pkg/provision/providers/qemu/launch.go +++ b/pkg/provision/providers/qemu/launch.go @@ -42,6 +42,7 @@ type LaunchConfig struct { // VM options DiskPaths []string DiskDrivers []string + DiskBlockSizes []uint VCPUCount int64 MemSize int64 KernelImagePath string @@ -339,10 +340,14 @@ func launchVM(config *LaunchConfig) error { for i, disk := range config.DiskPaths { driver := config.DiskDrivers[i] + blockSize := config.DiskBlockSizes[i] switch driver { case "virtio": - args = append(args, "-drive", fmt.Sprintf("format=raw,if=virtio,file=%s,cache=none,", disk)) + args = append(args, + "-drive", fmt.Sprintf("id=virtio%d,format=raw,if=none,file=%s,cache=none", i, disk), + "-device", fmt.Sprintf("virtio-blk-pci,drive=virtio%d,logical_block_size=%d,physical_block_size=%d", i, blockSize, blockSize), + ) case "ide": args = append(args, "-drive", fmt.Sprintf("format=raw,if=ide,file=%s,cache=none,", disk)) case "ahci": @@ -365,7 +370,7 @@ func launchVM(config *LaunchConfig) error { args = append(args, "-drive", fmt.Sprintf("id=scsi%d,format=raw,if=none,file=%s,discard=unmap,aio=native,cache=none", i, disk), - "-device", fmt.Sprintf("scsi-hd,drive=scsi%d,bus=scsi0.0", i), + "-device", fmt.Sprintf("scsi-hd,drive=scsi%d,bus=scsi0.0,logical_block_size=%d,physical_block_size=%d", i, blockSize, blockSize), ) case "nvme": if !nvmeAttached { @@ -378,7 +383,7 @@ func launchVM(config *LaunchConfig) error { args = append(args, "-drive", fmt.Sprintf("id=nvme%d,format=raw,if=none,file=%s,discard=unmap,aio=native,cache=none", i, disk), - "-device", fmt.Sprintf("nvme-ns,drive=nvme%d", i), + "-device", fmt.Sprintf("nvme-ns,drive=nvme%d,logical_block_size=%d,physical_block_size=%d", i, blockSize, blockSize), ) default: return fmt.Errorf("unsupported disk driver %q", driver) diff --git a/pkg/provision/providers/qemu/node.go b/pkg/provision/providers/qemu/node.go index 0c235aee31..c24a0191b3 100644 --- a/pkg/provision/providers/qemu/node.go +++ b/pkg/provision/providers/qemu/node.go @@ -137,8 +137,12 @@ func (p *provisioner) createNode(state *vm.State, clusterReq provision.ClusterRe defaultBootOrder = nodeReq.DefaultBootOrder } - // backwards compatibility, set Driver if not set + // backwards compatibility, set Driver/BlockSize if not set for i := range nodeReq.Disks { + if nodeReq.Disks[i].BlockSize == 0 { + nodeReq.Disks[i].BlockSize = 512 + } + if nodeReq.Disks[i].Driver != "" { continue } @@ -156,6 +160,9 @@ func (p *provisioner) createNode(state *vm.State, clusterReq provision.ClusterRe DiskDrivers: xslices.Map(nodeReq.Disks, func(disk *provision.Disk) string { return disk.Driver }), + DiskBlockSizes: xslices.Map(nodeReq.Disks, func(disk *provision.Disk) uint { + return disk.BlockSize + }), VCPUCount: vcpuCount, MemSize: memSize, KernelArgs: cmdline.String(), diff --git a/pkg/provision/request.go b/pkg/provision/request.go index a682f82a58..bfc39eaa36 100644 --- a/pkg/provision/request.go +++ b/pkg/provision/request.go @@ -164,6 +164,8 @@ type Disk struct { // // Supported types: "virtio", "ide", "ahci", "scsi", "nvme". Driver string + // Block size for the disk, defaults to 512 if not set. + BlockSize uint } // ConfigInjectionMethod describes how to inject configuration into the node. diff --git a/website/content/v1.9/reference/cli.md b/website/content/v1.9/reference/cli.md index 32cb08d23c..fe48468a23 100644 --- a/website/content/v1.9/reference/cli.md +++ b/website/content/v1.9/reference/cli.md @@ -158,6 +158,7 @@ talosctl cluster create [flags] --custom-cni-url string install custom CNI from the URL (Talos cluster) --disable-dhcp-hostname skip announcing hostname via DHCP (QEMU only) --disk int default limit on disk size in MB (each VM) (default 6144) + --disk-block-size uint disk block size (VM only) (default 512) --disk-encryption-key-types stringArray encryption key types to use for disk encryption (uuid, kms) (default [uuid]) --disk-image-path string disk image to use --disk-preallocate whether disk space should be preallocated (default true) diff --git a/website/content/v1.9/talos-guides/configuration/containerd.md b/website/content/v1.9/talos-guides/configuration/containerd.md index f1e89fcc6c..45fc1e3f33 100644 --- a/website/content/v1.9/talos-guides/configuration/containerd.md +++ b/website/content/v1.9/talos-guides/configuration/containerd.md @@ -63,3 +63,21 @@ NODE NAMESPACE ID 172.20.0.5 k8s.io kube-system/kube-proxy-xp7jq registry.k8s.io/pause:3.8 1780 SANDBOX_READY 172.20.0.5 k8s.io └─ kube-system/kube-proxy-xp7jq:kube-proxy:84fc77c59e17 registry.k8s.io/kube-proxy:v1.26.0-alpha.3 1843 CONTAINER_RUNNING ``` + +### Enabling NRI Plugins + +By default, Talos disables [NRI](https://github.com/containerd/containerd/blob/main/docs/NRI.md) plugins in `containerd`, as they might have security implications. +However, if you need to enable them, you can do so by adding the following configuration: + +```yaml +machine: + files: + - content: | + [plugins] + [plugins."io.containerd.nri.v1.nri"] + disable = false + path: /etc/cri/conf.d/20-customization.part + op: create +``` + +After applying the configuration, the NRI plugins can be deployed, for example plugins from [this repository](https://containers.github.io/nri-plugins/stable/docs/index.html).