diff --git a/api/resource/definitions/cri/cri.proto b/api/resource/definitions/cri/cri.proto index 3c4f4b3cc4..841a22481f 100755 --- a/api/resource/definitions/cri/cri.proto +++ b/api/resource/definitions/cri/cri.proto @@ -6,6 +6,13 @@ option go_package = "github.com/siderolabs/talos/pkg/machinery/api/resource/defi option java_package = "dev.talos.api.resource.definitions.cri"; import "google/protobuf/struct.proto"; +import "resource/definitions/enums/enums.proto"; + +// ImageCacheConfigSpec represents the ImageCacheConfig. +message ImageCacheConfigSpec { + talos.resource.definitions.enums.CriImageCacheStatus status = 1; + repeated string roots = 2; +} // SeccompProfileSpec represents the SeccompProfile. message SeccompProfileSpec { diff --git a/api/resource/definitions/enums/enums.proto b/api/resource/definitions/enums/enums.proto index 40779750dd..d169afec9a 100755 --- a/api/resource/definitions/enums/enums.proto +++ b/api/resource/definitions/enums/enums.proto @@ -396,6 +396,14 @@ enum BlockVolumeType { VOLUME_TYPE_TMPFS = 2; } +// CriImageCacheStatus describes image cache status type. +enum CriImageCacheStatus { + IMAGE_CACHE_STATUS_UNKNOWN = 0; + IMAGE_CACHE_STATUS_DISABLED = 1; + IMAGE_CACHE_STATUS_PREPARING = 2; + IMAGE_CACHE_STATUS_READY = 3; +} + // KubespanPeerState is KubeSpan peer current state. enum KubespanPeerState { PEER_STATE_UNKNOWN = 0; diff --git a/go.mod b/go.mod index 202cef0296..c5c693eb29 100644 --- a/go.mod +++ b/go.mod @@ -88,6 +88,7 @@ require ( github.com/godbus/dbus/v5 v5.1.0 github.com/golang/mock v1.6.0 github.com/google/cadvisor v0.51.0 + github.com/google/cel-go v0.22.0 github.com/google/go-containerregistry v0.20.2 github.com/google/go-tpm v0.9.1 github.com/google/nftables v0.2.0 @@ -140,7 +141,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.5 + github.com/siderolabs/go-blockdevice/v2 v2.0.6 github.com/siderolabs/go-circular v0.2.1 github.com/siderolabs/go-cmd v0.1.3 github.com/siderolabs/go-copy v0.1.0 @@ -160,7 +161,6 @@ require ( github.com/siderolabs/kms-client v0.1.0 github.com/siderolabs/net v0.4.0 github.com/siderolabs/proto-codec v0.1.1 - github.com/siderolabs/protoenc v0.2.1 // indirect github.com/siderolabs/siderolink v0.3.11 github.com/siderolabs/talos/pkg/machinery v1.9.0-alpha.2 github.com/spf13/cobra v1.8.1 @@ -177,7 +177,6 @@ require ( go.etcd.io/etcd/etcdutl/v3 v3.5.17 go.uber.org/zap v1.27.0 go4.org/netipx v0.0.0-20231129151722-fdeea329fbba - golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/net v0.31.0 golang.org/x/oauth2 v0.24.0 golang.org/x/sync v0.9.0 @@ -267,7 +266,6 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/cel-go v0.22.0 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect @@ -328,6 +326,7 @@ require ( github.com/prometheus/common v0.55.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/siderolabs/protoenc v0.2.1 // indirect github.com/siderolabs/tcpproxy v0.1.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/afero v1.10.0 // indirect @@ -353,6 +352,7 @@ require ( go.opentelemetry.io/otel/trace v1.31.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.29.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/mod v0.21.0 // indirect golang.org/x/tools v0.26.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect diff --git a/go.sum b/go.sum index d7f69f8a4b..477c688c43 100644 --- a/go.sum +++ b/go.sum @@ -648,8 +648,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.5 h1:VLmIdDB/1P30Inrpe94FQAz4WUpByGwun5ZeTekxIQc= -github.com/siderolabs/go-blockdevice/v2 v2.0.5/go.mod h1:74htzCV913UzaLZ4H+NBXkwWlYnBJIq5m/379ZEcu8w= +github.com/siderolabs/go-blockdevice/v2 v2.0.6 h1:/NAy3MbNZhjLWo28asZyS/hmf86PEPDMc9i6wIcgbwI= +github.com/siderolabs/go-blockdevice/v2 v2.0.6/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/internal/app/machined/pkg/controllers/block/internal/volumes/format.go b/internal/app/machined/pkg/controllers/block/internal/volumes/format.go index ebe4ba9c22..59f98d9dbd 100644 --- a/internal/app/machined/pkg/controllers/block/internal/volumes/format.go +++ b/internal/app/machined/pkg/controllers/block/internal/volumes/format.go @@ -22,7 +22,7 @@ import ( // Format establishes a filesystem on a block device. // -//nolint:gocyclo +//nolint:gocyclo,cyclop func Format(ctx context.Context, logger *zap.Logger, volumeContext ManagerContext) error { // lock either the parent device or the device itself devPath := volumeContext.Status.ParentLocation @@ -111,6 +111,16 @@ func Format(ctx context.Context, logger *zap.Logger, volumeContext ManagerContex if err = makefs.XFS(volumeContext.Status.MountLocation, makefsOptions...); err != nil { return fmt.Errorf("error formatting XFS: %w", err) } + case block.FilesystemTypeEXT4: + var makefsOptions []makefs.Option + + if volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Label != "" { + makefsOptions = append(makefsOptions, makefs.WithLabel(volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Label)) + } + + if err = makefs.Ext4(volumeContext.Status.MountLocation, makefsOptions...); err != nil { + return fmt.Errorf("error formatting ext4: %w", err) + } default: return fmt.Errorf("unsupported filesystem type: %s", volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type) } @@ -148,6 +158,14 @@ func GrowFilesystem(logger *zap.Logger, volumeContext ManagerContext) error { return fmt.Errorf("error growing XFS: %w", err) } + return nil + case block.FilesystemTypeEXT4: + logger.Info("growing ext4 filesystem", zap.String("device", volumeContext.Status.MountLocation)) + + if err := makefs.Ext4Resize(volumeContext.Status.MountLocation); err != nil { + return fmt.Errorf("error growing ext4: %w", err) + } + return nil default: return fmt.Errorf("unsupported filesystem type to grow: %s", volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type) diff --git a/internal/app/machined/pkg/controllers/block/volume_config.go b/internal/app/machined/pkg/controllers/block/volume_config.go index 46709ede5f..c12fa0fd01 100644 --- a/internal/app/machined/pkg/controllers/block/volume_config.go +++ b/internal/app/machined/pkg/controllers/block/volume_config.go @@ -209,7 +209,7 @@ func (ctrl *VolumeConfigController) Run(ctx context.Context, r controller.Runtim func (ctrl *VolumeConfigController) manageEphemeral(config cfg.Config) func(vc *block.VolumeConfig) error { return func(vc *block.VolumeConfig) error { - extraVolumeConfig := config.Volumes().ByName(constants.EphemeralPartitionLabel) + extraVolumeConfig, _ := config.Volumes().ByName(constants.EphemeralPartitionLabel) vc.TypedSpec().Type = block.VolumeTypePartition diff --git a/internal/app/machined/pkg/controllers/cri/cri.go b/internal/app/machined/pkg/controllers/cri/cri.go index 6efca64a90..1eddf04f33 100644 --- a/internal/app/machined/pkg/controllers/cri/cri.go +++ b/internal/app/machined/pkg/controllers/cri/cri.go @@ -2,4 +2,5 @@ // 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/. +// Package cri provides CRI related controllers. package cri diff --git a/internal/app/machined/pkg/controllers/cri/image_cache_config.go b/internal/app/machined/pkg/controllers/cri/image_cache_config.go new file mode 100644 index 0000000000..370109c658 --- /dev/null +++ b/internal/app/machined/pkg/controllers/cri/image_cache_config.go @@ -0,0 +1,328 @@ +// 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/. + +package cri + +import ( + "context" + "fmt" + "path/filepath" + + "github.com/cosi-project/runtime/pkg/controller" + "github.com/cosi-project/runtime/pkg/safe" + "github.com/cosi-project/runtime/pkg/state" + "github.com/google/cel-go/common/operators" + "github.com/google/cel-go/common/types" + "github.com/siderolabs/gen/optional" + "go.uber.org/zap" + + "github.com/siderolabs/talos/internal/app/machined/pkg/system" + "github.com/siderolabs/talos/internal/app/machined/pkg/system/services" + mountv2 "github.com/siderolabs/talos/internal/pkg/mount/v2" + "github.com/siderolabs/talos/internal/pkg/partition" + "github.com/siderolabs/talos/pkg/machinery/cel" + "github.com/siderolabs/talos/pkg/machinery/cel/celenv" + cfg "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/constants" + "github.com/siderolabs/talos/pkg/machinery/resources/block" + "github.com/siderolabs/talos/pkg/machinery/resources/config" + "github.com/siderolabs/talos/pkg/machinery/resources/cri" + "github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1" +) + +// ServiceManager is the interface to the v1alpha1 services subsystems. +type ServiceManager interface { + IsRunning(id string) (system.Service, bool, error) + Load(services ...system.Service) []string + Start(serviceIDs ...string) error +} + +// ImageCacheConfigController manages configures Image Cache. +type ImageCacheConfigController struct { + V1Alpha1ServiceManager ServiceManager + VolumeMounter func(label string, opts ...mountv2.NewPointOption) error +} + +// Name implements controller.StatsController interface. +func (ctrl *ImageCacheConfigController) Name() string { + return "cri.ImageCacheConfigController" +} + +// Inputs implements controller.StatsController interface. +func (ctrl *ImageCacheConfigController) Inputs() []controller.Input { + return []controller.Input{ + { + Namespace: config.NamespaceName, + Type: config.MachineConfigType, + ID: optional.Some(config.V1Alpha1ID), + Kind: controller.InputWeak, + }, + { + Namespace: block.NamespaceName, + Type: block.VolumeStatusType, + Kind: controller.InputWeak, + }, + { + Namespace: v1alpha1.NamespaceName, + Type: v1alpha1.ServiceType, + ID: optional.Some(RegistrydServiceID), + Kind: controller.InputWeak, + }, + } +} + +// Outputs implements controller.StatsController interface. +func (ctrl *ImageCacheConfigController) Outputs() []controller.Output { + return []controller.Output{ + { + Type: cri.ImageCacheConfigType, + Kind: controller.OutputExclusive, + }, + { + Type: block.VolumeConfigType, + Kind: controller.OutputShared, + }, + } +} + +// Volume configuration constants. +const ( + VolumeImageCacheISO = "IMAGECACHE-ISO" + VolumeImageCacheDISK = constants.ImageCachePartitionLabel + + MinImageCacheSize = 500 * 1024 * 1024 // 500MB + MaxImageCacheSize = 1 * 1024 * 1024 * 1024 // 1GB + + RegistrydServiceID = services.RegistryID +) + +// Run implements controller.StatsController interface. +// +//nolint:gocyclo,cyclop +func (ctrl *ImageCacheConfigController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error { + for { + select { + case <-ctx.Done(): + return nil + case <-r.EventCh(): + } + + cfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID) + if err != nil && !state.IsNotFoundError(err) { + return fmt.Errorf("error getting config: %w", err) + } + + registryDService, err := safe.ReaderGetByID[*v1alpha1.Service](ctx, r, RegistrydServiceID) + if err != nil && !state.IsNotFoundError(err) { + return fmt.Errorf("error getting service: %w", err) + } + + // image cache is disabled + imageCacheDisabled := cfg == nil || cfg.Config().Machine() == nil || !cfg.Config().Machine().Features().ImageCacheEnabled() + + var ( + status cri.ImageCacheStatus + roots []string + ) + + if imageCacheDisabled { + status = cri.ImageCacheStatusDisabled + } else { + status = cri.ImageCacheStatusPreparing + + // image cache is enabled, so create the volume config resources to find the image cache roots + if err = ctrl.createVolumeConfigISO(ctx, r); err != nil { + return fmt.Errorf("error creating volume config: %w", err) + } + + if err = ctrl.createVolumeConfigDisk(ctx, r, cfg.Config()); err != nil { + return fmt.Errorf("error creating volume config: %w", err) + } + + allReady := false + + // analyze volume statuses, and build the roots + for _, volumeID := range []string{VolumeImageCacheISO, VolumeImageCacheDISK} { + root, ready, err := ctrl.getImageCacheRoot(ctx, r, volumeID) + if err != nil { + return fmt.Errorf("error getting image cache root: %w", err) + } + + allReady = allReady && ready + + if rootPath, ok := root.Get(); ok { + roots = append(roots, rootPath) + } + } + + if allReady && len(roots) == 0 { + // all volumes identified, but no roots found + status = cri.ImageCacheStatusDisabled + } + } + + if status == cri.ImageCacheStatusPreparing && len(roots) > 0 { + _, running, err := ctrl.V1Alpha1ServiceManager.IsRunning(RegistrydServiceID) + if err != nil { + ctrl.V1Alpha1ServiceManager.Load(services.NewRegistryD()) + } + + if !running { + if err = ctrl.V1Alpha1ServiceManager.Start(RegistrydServiceID); err != nil { + return fmt.Errorf("error starting service: %w", err) + } + } + + if registryDService != nil && registryDService.TypedSpec().Running && registryDService.TypedSpec().Healthy { + status = cri.ImageCacheStatusReady + } + } + + if err = safe.WriterModify(ctx, r, cri.NewImageCacheConfig(), func(cfg *cri.ImageCacheConfig) error { + cfg.TypedSpec().Status = status + cfg.TypedSpec().Roots = roots + + return nil + }); err != nil { + return fmt.Errorf("error writing ImageCacheConfig: %w", err) + } + } +} + +func (ctrl *ImageCacheConfigController) createVolumeConfigISO(ctx context.Context, r controller.ReaderWriter) error { + builder := cel.NewBuilder(celenv.VolumeLocator()) + + // volume.name == "iso9660" && volume.label.startsWith("TALOS_") + expr := builder.NewCall( + builder.NextID(), + operators.LogicalAnd, + builder.NewCall( + builder.NextID(), + operators.Equals, + builder.NewSelect( + builder.NextID(), + builder.NewIdent(builder.NextID(), "volume"), + "name", + ), + builder.NewLiteral(builder.NextID(), types.String("iso9660")), + ), + builder.NewMemberCall( + builder.NextID(), + "startsWith", + builder.NewSelect( + builder.NextID(), + builder.NewIdent(builder.NextID(), "volume"), + "label", + ), + builder.NewLiteral(builder.NextID(), types.String("TALOS_")), + ), + ) + + boolExpr, err := builder.ToBooleanExpression(expr) + if err != nil { + return fmt.Errorf("error creating boolean expression: %w", err) + } + + return safe.WriterModify(ctx, r, block.NewVolumeConfig(block.NamespaceName, VolumeImageCacheISO), func(volumeCfg *block.VolumeConfig) error { + volumeCfg.TypedSpec().Type = block.VolumeTypeDisk + volumeCfg.TypedSpec().Locator = block.LocatorSpec{ + Match: *boolExpr, + } + volumeCfg.TypedSpec().Mount.TargetPath = constants.ImageCacheISOMountPoint + + return nil + }) +} + +func (ctrl *ImageCacheConfigController) createVolumeConfigDisk(ctx context.Context, r controller.ReaderWriter, cfg cfg.Config) error { + builder := cel.NewBuilder(celenv.VolumeLocator()) + + // volume.partition_label == "IMAGECACHE" + expr := builder.NewCall( + builder.NextID(), + operators.Equals, + builder.NewSelect( + builder.NextID(), + builder.NewIdent(builder.NextID(), "volume"), + "partition_label", + ), + builder.NewLiteral(builder.NextID(), types.String(constants.ImageCachePartitionLabel)), + ) + + locatorExpr, err := builder.ToBooleanExpression(expr) + if err != nil { + return fmt.Errorf("error creating boolean expression: %w", err) + } + + // system_disk + builder = cel.NewBuilder(celenv.DiskLocator()) + + expr = builder.NewIdent(builder.NextID(), "system_disk") + + diskExpr, err := builder.ToBooleanExpression(expr) + if err != nil { + return fmt.Errorf("error creating boolean expression: %w", err) + } + + return safe.WriterModify(ctx, r, block.NewVolumeConfig(block.NamespaceName, VolumeImageCacheDISK), func(volumeCfg *block.VolumeConfig) error { + volumeCfg.TypedSpec().Type = block.VolumeTypePartition + volumeCfg.TypedSpec().Locator = block.LocatorSpec{ + Match: *locatorExpr, + } + + if extraCfg, ok := cfg.Volumes().ByName(constants.ImageCachePartitionLabel); ok { + volumeCfg.TypedSpec().Provisioning.DiskSelector.Match = extraCfg.Provisioning().DiskSelector().ValueOr(*diskExpr) + volumeCfg.TypedSpec().Provisioning.PartitionSpec.Grow = extraCfg.Provisioning().Grow().ValueOr(false) + volumeCfg.TypedSpec().Provisioning.PartitionSpec.MinSize = extraCfg.Provisioning().MinSize().ValueOr(MinImageCacheSize) + volumeCfg.TypedSpec().Provisioning.PartitionSpec.MaxSize = extraCfg.Provisioning().MaxSize().ValueOr(MaxImageCacheSize) + volumeCfg.TypedSpec().Provisioning.PartitionSpec.Label = constants.ImageCachePartitionLabel + volumeCfg.TypedSpec().Provisioning.PartitionSpec.TypeUUID = partition.LinuxFilesystemData + volumeCfg.TypedSpec().Provisioning.FilesystemSpec.Type = block.FilesystemTypeEXT4 + } + + volumeCfg.TypedSpec().Mount.TargetPath = constants.ImageCacheDiskMountPoint + + return nil + }) +} + +func (ctrl *ImageCacheConfigController) getImageCacheRoot(ctx context.Context, r controller.Reader, volumeID string) (optional.Optional[string], bool, error) { + volumeStatus, err := safe.ReaderGetByID[*block.VolumeStatus](ctx, r, volumeID) + if err != nil { + if state.IsNotFoundError(err) { + return optional.None[string](), false, nil + } + + return optional.None[string](), false, fmt.Errorf("error getting volume status: %w", err) + } + + switch volumeStatus.TypedSpec().Phase { //nolint:exhaustive + case block.VolumePhaseMissing: + // image cache is missing + return optional.None[string](), true, nil + case block.VolumePhaseReady: + // fall through to below + default: + // undetermined status + return optional.None[string](), false, nil + } + + volumeConfig, err := safe.ReaderGetByID[*block.VolumeConfig](ctx, r, volumeID) + if err != nil { + return optional.None[string](), false, fmt.Errorf("error getting volume config: %w", err) + } + + if err = ctrl.VolumeMounter(volumeID, mountv2.WithReadonly()); err != nil { + return optional.None[string](), false, fmt.Errorf("error mounting volume: %w", err) + } + + targetPath := volumeConfig.TypedSpec().Mount.TargetPath + + if volumeID == VolumeImageCacheISO { + // the ISO volume has a subdirectory with the actual image cache + targetPath = filepath.Join(targetPath, "imagecache") + } + + return optional.Some(targetPath), true, nil +} diff --git a/internal/app/machined/pkg/controllers/cri/image_cache_config_test.go b/internal/app/machined/pkg/controllers/cri/image_cache_config_test.go new file mode 100644 index 0000000000..131c6992c9 --- /dev/null +++ b/internal/app/machined/pkg/controllers/cri/image_cache_config_test.go @@ -0,0 +1,230 @@ +// 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/. + +package cri_test + +import ( + "path/filepath" + "slices" + "sync" + "testing" + "time" + + "github.com/siderolabs/go-pointer" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + + crictrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cri" + "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" + "github.com/siderolabs/talos/internal/app/machined/pkg/system" + mountv2 "github.com/siderolabs/talos/internal/pkg/mount/v2" + "github.com/siderolabs/talos/pkg/machinery/config/container" + blockcfg "github.com/siderolabs/talos/pkg/machinery/config/types/block" + "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" + "github.com/siderolabs/talos/pkg/machinery/constants" + "github.com/siderolabs/talos/pkg/machinery/resources/block" + "github.com/siderolabs/talos/pkg/machinery/resources/config" + "github.com/siderolabs/talos/pkg/machinery/resources/cri" + v1alpha1res "github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1" +) + +func (suite *ImageCacheConfigSuite) TestReconcileNoConfig() { + ctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) { + asrt.Equal(cri.ImageCacheStatusDisabled, r.TypedSpec().Status) + }) +} + +func (suite *ImageCacheConfigSuite) TestReconcileFeatureNotEnabled() { + cfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{ + MachineConfig: &v1alpha1.MachineConfig{}, + })) + + suite.Require().NoError(suite.State().Create(suite.Ctx(), cfg)) + + ctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) { + asrt.Equal(cri.ImageCacheStatusDisabled, r.TypedSpec().Status) + }) +} + +func (suite *ImageCacheConfigSuite) TestReconcileFeatureEnabled() { + cfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{ + MachineConfig: &v1alpha1.MachineConfig{ + MachineFeatures: &v1alpha1.FeaturesConfig{ + ImageCache: pointer.To(true), + }, + }, + })) + + suite.Require().NoError(suite.State().Create(suite.Ctx(), cfg)) + + ctest.AssertResource(suite, crictrl.VolumeImageCacheISO, func(r *block.VolumeConfig, asrt *assert.Assertions) { + asrt.Equal(`volume.name == "iso9660" && volume.label.startsWith("TALOS_")`, r.TypedSpec().Locator.Match.String()) + }) + ctest.AssertResource(suite, crictrl.VolumeImageCacheDISK, func(r *block.VolumeConfig, asrt *assert.Assertions) { + asrt.Equal(`volume.partition_label == "IMAGECACHE"`, r.TypedSpec().Locator.Match.String()) + }) + + ctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) { + asrt.Equal(cri.ImageCacheStatusPreparing, r.TypedSpec().Status) + }) + + suite.Assert().Empty(suite.getMountedVolumes()) + + // create volume statuses to simulate the volume being ready + vs1 := block.NewVolumeStatus(block.NamespaceName, crictrl.VolumeImageCacheISO) + vs1.TypedSpec().Phase = block.VolumePhaseReady + suite.Require().NoError(suite.State().Create(suite.Ctx(), vs1)) + + vs2 := block.NewVolumeStatus(block.NamespaceName, crictrl.VolumeImageCacheDISK) + vs2.TypedSpec().Phase = block.VolumePhaseWaiting + suite.Require().NoError(suite.State().Create(suite.Ctx(), vs2)) + + // one volume is ready, but second one is not (yet) + ctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) { + asrt.Equal(cri.ImageCacheStatusPreparing, r.TypedSpec().Status) + asrt.Equal([]string{filepath.Join(constants.ImageCacheISOMountPoint, "imagecache")}, r.TypedSpec().Roots) + }) + + suite.Assert().Equal([]string{crictrl.VolumeImageCacheISO}, suite.getMountedVolumes()) + + // mark second as ready + vs2.TypedSpec().Phase = block.VolumePhaseReady + suite.Require().NoError(suite.State().Update(suite.Ctx(), vs2)) + + // now both volumes are ready, but service hasn't started yet + ctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) { + asrt.Equal(cri.ImageCacheStatusPreparing, r.TypedSpec().Status) + asrt.Equal([]string{filepath.Join(constants.ImageCacheISOMountPoint, "imagecache"), constants.ImageCacheDiskMountPoint}, r.TypedSpec().Roots) + }) + + suite.Assert().Equal([]string{crictrl.VolumeImageCacheISO, crictrl.VolumeImageCacheDISK}, suite.getMountedVolumes()) + + // simulate registryd being ready + service := v1alpha1res.NewService(crictrl.RegistrydServiceID) + service.TypedSpec().Healthy = true + service.TypedSpec().Running = true + suite.Require().NoError(suite.State().Create(suite.Ctx(), service)) + + // now both volumes are ready, and service is ready, should be ready + ctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) { + asrt.Equal(cri.ImageCacheStatusReady, r.TypedSpec().Status) + asrt.Equal([]string{filepath.Join(constants.ImageCacheISOMountPoint, "imagecache"), constants.ImageCacheDiskMountPoint}, r.TypedSpec().Roots) + }) +} + +func (suite *ImageCacheConfigSuite) TestReconcileWithImageCacheVolume() { + v1alpha1Cfg := &v1alpha1.Config{ + MachineConfig: &v1alpha1.MachineConfig{ + MachineFeatures: &v1alpha1.FeaturesConfig{ + ImageCache: pointer.To(true), + }, + }, + } + + volumeConfig := blockcfg.NewVolumeConfigV1Alpha1() + volumeConfig.MetaName = constants.ImageCachePartitionLabel + volumeConfig.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustByteSize("10GiB") + + container, err := container.New(v1alpha1Cfg, volumeConfig) + suite.Require().NoError(err) + + cfg := config.NewMachineConfig(container) + + suite.Require().NoError(suite.State().Create(suite.Ctx(), cfg)) + + ctest.AssertResource(suite, crictrl.VolumeImageCacheDISK, func(r *block.VolumeConfig, asrt *assert.Assertions) { + asrt.Equal(`volume.partition_label == "IMAGECACHE"`, r.TypedSpec().Locator.Match.String()) + asrt.Equal(`system_disk`, r.TypedSpec().Provisioning.DiskSelector.Match.String()) + asrt.False(r.TypedSpec().Provisioning.PartitionSpec.Grow) + asrt.EqualValues(crictrl.MinImageCacheSize, r.TypedSpec().Provisioning.PartitionSpec.MinSize) + asrt.EqualValues(10*1024*1024*1024, r.TypedSpec().Provisioning.PartitionSpec.MaxSize) + }) + + ctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) { + asrt.Equal(cri.ImageCacheStatusPreparing, r.TypedSpec().Status) + }) + + // create volume statuses to simulate the volume being ready & missing + vs1 := block.NewVolumeStatus(block.NamespaceName, crictrl.VolumeImageCacheISO) + vs1.TypedSpec().Phase = block.VolumePhaseMissing + suite.Require().NoError(suite.State().Create(suite.Ctx(), vs1)) + + vs2 := block.NewVolumeStatus(block.NamespaceName, crictrl.VolumeImageCacheDISK) + vs2.TypedSpec().Phase = block.VolumePhaseReady + suite.Require().NoError(suite.State().Create(suite.Ctx(), vs2)) + + // simulate registryd being ready + service := v1alpha1res.NewService(crictrl.RegistrydServiceID) + service.TypedSpec().Healthy = true + service.TypedSpec().Running = true + suite.Require().NoError(suite.State().Create(suite.Ctx(), service)) + + // now both volumes are ready, and service is ready, should be ready + ctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) { + asrt.Equal(cri.ImageCacheStatusReady, r.TypedSpec().Status) + asrt.Equal([]string{constants.ImageCacheDiskMountPoint}, r.TypedSpec().Roots) + }) +} + +func (suite *ImageCacheConfigSuite) SetupTest() { + suite.mountedVolumes = nil + + suite.DefaultSuite.SetupTest() +} + +func (suite *ImageCacheConfigSuite) getMountedVolumes() []string { + suite.mountedVolumesMutex.Lock() + defer suite.mountedVolumesMutex.Unlock() + + return suite.mountedVolumes +} + +func TestImageCacheConfigSuite(t *testing.T) { + s := &ImageCacheConfigSuite{ + DefaultSuite: ctest.DefaultSuite{ + Timeout: 5 * time.Second, + }, + } + + s.AfterSetup = func(suite *ctest.DefaultSuite) { + suite.Require().NoError(suite.Runtime().RegisterController(&crictrl.ImageCacheConfigController{ + VolumeMounter: func(label string, opts ...mountv2.NewPointOption) error { + s.mountedVolumesMutex.Lock() + defer s.mountedVolumesMutex.Unlock() + + if slices.Index(s.mountedVolumes, label) >= 0 { + return nil + } + + s.mountedVolumes = append(s.mountedVolumes, label) + + return nil + }, + V1Alpha1ServiceManager: &mockServiceRunner{}, + })) + } + + suite.Run(t, s) +} + +type ImageCacheConfigSuite struct { + ctest.DefaultSuite + + mountedVolumesMutex sync.Mutex + mountedVolumes []string +} + +type mockServiceRunner struct{} + +func (mock *mockServiceRunner) IsRunning(id string) (system.Service, bool, error) { + return nil, true, nil +} + +func (mock *mockServiceRunner) Load(services ...system.Service) []string { + return nil +} + +func (mock *mockServiceRunner) Start(serviceIDs ...string) error { + return nil +} diff --git a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go index 3f86d8971f..ffb19dfcf0 100644 --- a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go +++ b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go @@ -40,6 +40,7 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" runtimelogging "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/logging" "github.com/siderolabs/talos/internal/app/machined/pkg/system" + "github.com/siderolabs/talos/internal/pkg/mount" "github.com/siderolabs/talos/pkg/logging" talosconfig "github.com/siderolabs/talos/pkg/machinery/config/config" "github.com/siderolabs/talos/pkg/machinery/constants" @@ -130,6 +131,10 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error ResourceState: ctrl.v1alpha1Runtime.State().V1Alpha2().Resources(), }, &config.MachineTypeController{}, + &cri.ImageCacheConfigController{ + V1Alpha1ServiceManager: system.Services(ctrl.v1alpha1Runtime), + VolumeMounter: mount.IdempotentSystemPartitionMounter(ctrl.v1alpha1Runtime), + }, &cri.SeccompProfileController{}, &cri.SeccompProfileFileController{ V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(), diff --git a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go index 287f2efef7..7842e57e9e 100644 --- a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go +++ b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go @@ -112,6 +112,7 @@ func NewState() (*State, error) { &cluster.Member{}, &config.MachineConfig{}, &config.MachineType{}, + &cri.ImageCacheConfig{}, &cri.SeccompProfile{}, &etcd.Config{}, &etcd.PKIStatus{}, diff --git a/internal/app/machined/pkg/system/services/registry/registry.go b/internal/app/machined/pkg/system/services/registry/registry.go index 635129cf96..b275cf3274 100644 --- a/internal/app/machined/pkg/system/services/registry/registry.go +++ b/internal/app/machined/pkg/system/services/registry/registry.go @@ -28,6 +28,8 @@ import ( ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/siderolabs/gen/xerrors" "go.uber.org/zap" + + "github.com/siderolabs/talos/pkg/machinery/constants" ) // NewService creates a new instance of the registry service. @@ -53,7 +55,7 @@ func (svc *Service) Run(ctx context.Context) error { mux.HandleFunc("GET /"+p+"/{$}", giveOk) } - server := http.Server{Addr: "127.0.0.1:3172", Handler: mux} + server := http.Server{Addr: constants.RegistrydListenAddress, Handler: mux} errCh := make(chan error, 1) ctx, cancel := context.WithCancel(ctx) diff --git a/internal/app/machined/pkg/system/services/registryd.go b/internal/app/machined/pkg/system/services/registryd.go index ca1e0ca43a..b0c0338881 100644 --- a/internal/app/machined/pkg/system/services/registryd.go +++ b/internal/app/machined/pkg/system/services/registryd.go @@ -10,6 +10,7 @@ import ( "io/fs" "os" + "github.com/cosi-project/runtime/pkg/safe" "go.uber.org/zap/zapcore" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" @@ -21,13 +22,18 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/system/services/registry" "github.com/siderolabs/talos/pkg/conditions" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/constants" + "github.com/siderolabs/talos/pkg/machinery/resources/cri" ) type registryD struct{} +// RegistryID is the ID of the registry service. +const RegistryID = "registryd" + // NewRegistryD returns a new docker mirror registry service. func NewRegistryD() system.Service { return ®istryD{} } -func (r *registryD) ID(runtime.Runtime) string { return "registryd" } +func (r *registryD) ID(runtime.Runtime) string { return RegistryID } func (r *registryD) HealthSettings(runtime.Runtime) *health.Settings { return &health.DefaultSettings } func (r *registryD) PreFunc(context.Context, runtime.Runtime) error { return nil } func (r *registryD) PostFunc(runtime.Runtime, events.ServiceState) error { return nil } @@ -35,13 +41,20 @@ func (r *registryD) Condition(runtime.Runtime) conditions.Condition { retur func (r *registryD) DependsOn(runtime.Runtime) []string { return nil } func (r *registryD) HealthFunc(runtime.Runtime) health.Check { - return func(ctx context.Context) error { return simpleHealthCheck(ctx, "http://127.0.0.1:3172/healthz") } + return func(ctx context.Context) error { + return simpleHealthCheck(ctx, "http://"+constants.RegistrydListenAddress+"/healthz") + } } func (r *registryD) Runner(rt runtime.Runtime) (runner.Runner, error) { it := func(yield func(fs.StatFS) bool) { - // TODO: Replace the code below with reads from `runtime.Runtime`. - for _, root := range []string{"/imagecache", "/var/lib/registry-cache"} { + imageCacheConfig, err := safe.StateGetByID[*cri.ImageCacheConfig](context.Background(), rt.State().V1Alpha2().Resources(), cri.ImageCacheConfigID) + if err != nil { + // we can't handle it here + return + } + + for _, root := range imageCacheConfig.TypedSpec().Roots { if !yield(os.DirFS(root).(fs.StatFS)) { return } diff --git a/internal/pkg/mount/system.go b/internal/pkg/mount/system.go index f0cc88604b..dd1eb7890e 100644 --- a/internal/pkg/mount/system.go +++ b/internal/pkg/mount/system.go @@ -26,6 +26,27 @@ var ( mountpointsMutex sync.RWMutex ) +// IdempotentSystemPartitionMounter is a temporary workaround for not having proper volume mount controller. +func IdempotentSystemPartitionMounter(r runtime.Runtime) func(label string, opts ...mountv2.NewPointOption) error { + return func(label string, opts ...mountv2.NewPointOption) error { + if IsSystemPartitionMounted(label) { + return nil + } + + return SystemPartitionMount(context.Background(), r, log.Default(), label, opts...) + } +} + +// IsSystemPartitionMounted checks if a system partition is mounted by the label. +func IsSystemPartitionMounted(label string) bool { + mountpointsMutex.RLock() + defer mountpointsMutex.RUnlock() + + _, ok := unmounters[label] + + return ok +} + // SystemPartitionMount mounts a system partition by the label. func SystemPartitionMount(ctx context.Context, r runtime.Runtime, logger *log.Logger, label string, opts ...mountv2.NewPointOption) (err error) { volumeStatus, err := safe.StateGetByID[*block.VolumeStatus](ctx, r.State().V1Alpha2().Resources(), label) diff --git a/pkg/machinery/api/resource/definitions/cri/cri.pb.go b/pkg/machinery/api/resource/definitions/cri/cri.pb.go index 8036cc8fad..7920c9c8bb 100644 --- a/pkg/machinery/api/resource/definitions/cri/cri.pb.go +++ b/pkg/machinery/api/resource/definitions/cri/cri.pb.go @@ -13,6 +13,8 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" structpb "google.golang.org/protobuf/types/known/structpb" + + enums "github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums" ) const ( @@ -22,6 +24,60 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// ImageCacheConfigSpec represents the ImageCacheConfig. +type ImageCacheConfigSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Status enums.CriImageCacheStatus `protobuf:"varint,1,opt,name=status,proto3,enum=talos.resource.definitions.enums.CriImageCacheStatus" json:"status,omitempty"` + Roots []string `protobuf:"bytes,2,rep,name=roots,proto3" json:"roots,omitempty"` +} + +func (x *ImageCacheConfigSpec) Reset() { + *x = ImageCacheConfigSpec{} + mi := &file_resource_definitions_cri_cri_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ImageCacheConfigSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ImageCacheConfigSpec) ProtoMessage() {} + +func (x *ImageCacheConfigSpec) ProtoReflect() protoreflect.Message { + mi := &file_resource_definitions_cri_cri_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ImageCacheConfigSpec.ProtoReflect.Descriptor instead. +func (*ImageCacheConfigSpec) Descriptor() ([]byte, []int) { + return file_resource_definitions_cri_cri_proto_rawDescGZIP(), []int{0} +} + +func (x *ImageCacheConfigSpec) GetStatus() enums.CriImageCacheStatus { + if x != nil { + return x.Status + } + return enums.CriImageCacheStatus(0) +} + +func (x *ImageCacheConfigSpec) GetRoots() []string { + if x != nil { + return x.Roots + } + return nil +} + // SeccompProfileSpec represents the SeccompProfile. type SeccompProfileSpec struct { state protoimpl.MessageState @@ -34,7 +90,7 @@ type SeccompProfileSpec struct { func (x *SeccompProfileSpec) Reset() { *x = SeccompProfileSpec{} - mi := &file_resource_definitions_cri_cri_proto_msgTypes[0] + mi := &file_resource_definitions_cri_cri_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -46,7 +102,7 @@ func (x *SeccompProfileSpec) String() string { func (*SeccompProfileSpec) ProtoMessage() {} func (x *SeccompProfileSpec) ProtoReflect() protoreflect.Message { - mi := &file_resource_definitions_cri_cri_proto_msgTypes[0] + mi := &file_resource_definitions_cri_cri_proto_msgTypes[1] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -59,7 +115,7 @@ func (x *SeccompProfileSpec) ProtoReflect() protoreflect.Message { // Deprecated: Use SeccompProfileSpec.ProtoReflect.Descriptor instead. func (*SeccompProfileSpec) Descriptor() ([]byte, []int) { - return file_resource_definitions_cri_cri_proto_rawDescGZIP(), []int{0} + return file_resource_definitions_cri_cri_proto_rawDescGZIP(), []int{1} } func (x *SeccompProfileSpec) GetName() string { @@ -85,20 +141,30 @@ var file_resource_definitions_cri_cri_proto_rawDesc = []byte{ 0x75, 0x72, 0x63, 0x65, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x63, 0x72, 0x69, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0x57, 0x0a, 0x12, 0x53, 0x65, 0x63, 0x63, 0x6f, 0x6d, 0x70, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, - 0x72, 0x75, 0x63, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x70, 0x0a, 0x26, 0x64, - 0x65, 0x76, 0x2e, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x2e, 0x63, 0x72, 0x69, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x74, 0x61, 0x6c, - 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x64, 0x65, - 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x63, 0x72, 0x69, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x6f, 0x1a, 0x26, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x64, 0x65, 0x66, + 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x2f, 0x65, + 0x6e, 0x75, 0x6d, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x7b, 0x0a, 0x14, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, + 0x65, 0x63, 0x12, 0x4d, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x35, 0x2e, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x2e, 0x43, 0x72, 0x69, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x43, 0x61, + 0x63, 0x68, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x05, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x22, 0x57, 0x0a, 0x12, 0x53, 0x65, 0x63, 0x63, 0x6f, + 0x6d, 0x70, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x42, 0x70, 0x0a, 0x26, 0x64, 0x65, 0x76, 0x2e, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x63, 0x72, 0x69, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, 0x6c, 0x61, 0x62, + 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, + 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x63, + 0x72, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -113,18 +179,21 @@ func file_resource_definitions_cri_cri_proto_rawDescGZIP() []byte { return file_resource_definitions_cri_cri_proto_rawDescData } -var file_resource_definitions_cri_cri_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_resource_definitions_cri_cri_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_resource_definitions_cri_cri_proto_goTypes = []any{ - (*SeccompProfileSpec)(nil), // 0: talos.resource.definitions.cri.SeccompProfileSpec - (*structpb.Struct)(nil), // 1: google.protobuf.Struct + (*ImageCacheConfigSpec)(nil), // 0: talos.resource.definitions.cri.ImageCacheConfigSpec + (*SeccompProfileSpec)(nil), // 1: talos.resource.definitions.cri.SeccompProfileSpec + (enums.CriImageCacheStatus)(0), // 2: talos.resource.definitions.enums.CriImageCacheStatus + (*structpb.Struct)(nil), // 3: google.protobuf.Struct } var file_resource_definitions_cri_cri_proto_depIdxs = []int32{ - 1, // 0: talos.resource.definitions.cri.SeccompProfileSpec.value:type_name -> google.protobuf.Struct - 1, // [1:1] is the sub-list for method output_type - 1, // [1:1] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 2, // 0: talos.resource.definitions.cri.ImageCacheConfigSpec.status:type_name -> talos.resource.definitions.enums.CriImageCacheStatus + 3, // 1: talos.resource.definitions.cri.SeccompProfileSpec.value:type_name -> google.protobuf.Struct + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name } func init() { file_resource_definitions_cri_cri_proto_init() } @@ -138,7 +207,7 @@ func file_resource_definitions_cri_cri_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_resource_definitions_cri_cri_proto_rawDesc, NumEnums: 0, - NumMessages: 1, + NumMessages: 2, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/machinery/api/resource/definitions/cri/cri_vtproto.pb.go b/pkg/machinery/api/resource/definitions/cri/cri_vtproto.pb.go index 3829319349..1cbcc2cbf0 100644 --- a/pkg/machinery/api/resource/definitions/cri/cri_vtproto.pb.go +++ b/pkg/machinery/api/resource/definitions/cri/cri_vtproto.pb.go @@ -12,6 +12,8 @@ import ( structpb "github.com/planetscale/vtprotobuf/types/known/structpb" protoimpl "google.golang.org/protobuf/runtime/protoimpl" structpb1 "google.golang.org/protobuf/types/known/structpb" + + enums "github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums" ) const ( @@ -21,6 +23,53 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +func (m *ImageCacheConfigSpec) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ImageCacheConfigSpec) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ImageCacheConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Roots) > 0 { + for iNdEx := len(m.Roots) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Roots[iNdEx]) + copy(dAtA[i:], m.Roots[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Roots[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if m.Status != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *SeccompProfileSpec) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil @@ -71,6 +120,25 @@ func (m *SeccompProfileSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ImageCacheConfigSpec) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Status != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Status)) + } + if len(m.Roots) > 0 { + for _, s := range m.Roots { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + func (m *SeccompProfileSpec) SizeVT() (n int) { if m == nil { return 0 @@ -89,6 +157,108 @@ func (m *SeccompProfileSpec) SizeVT() (n int) { return n } +func (m *ImageCacheConfigSpec) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ImageCacheConfigSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ImageCacheConfigSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + m.Status = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Status |= enums.CriImageCacheStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Roots", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Roots = append(m.Roots, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *SeccompProfileSpec) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/pkg/machinery/api/resource/definitions/enums/enums.pb.go b/pkg/machinery/api/resource/definitions/enums/enums.pb.go index 362532463f..7b4372c4dd 100644 --- a/pkg/machinery/api/resource/definitions/enums/enums.pb.go +++ b/pkg/machinery/api/resource/definitions/enums/enums.pb.go @@ -2102,6 +2102,59 @@ func (BlockVolumeType) EnumDescriptor() ([]byte, []int) { return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{31} } +// CriImageCacheStatus describes image cache status type. +type CriImageCacheStatus int32 + +const ( + CriImageCacheStatus_IMAGE_CACHE_STATUS_UNKNOWN CriImageCacheStatus = 0 + CriImageCacheStatus_IMAGE_CACHE_STATUS_DISABLED CriImageCacheStatus = 1 + CriImageCacheStatus_IMAGE_CACHE_STATUS_PREPARING CriImageCacheStatus = 2 + CriImageCacheStatus_IMAGE_CACHE_STATUS_READY CriImageCacheStatus = 3 +) + +// Enum value maps for CriImageCacheStatus. +var ( + CriImageCacheStatus_name = map[int32]string{ + 0: "IMAGE_CACHE_STATUS_UNKNOWN", + 1: "IMAGE_CACHE_STATUS_DISABLED", + 2: "IMAGE_CACHE_STATUS_PREPARING", + 3: "IMAGE_CACHE_STATUS_READY", + } + CriImageCacheStatus_value = map[string]int32{ + "IMAGE_CACHE_STATUS_UNKNOWN": 0, + "IMAGE_CACHE_STATUS_DISABLED": 1, + "IMAGE_CACHE_STATUS_PREPARING": 2, + "IMAGE_CACHE_STATUS_READY": 3, + } +) + +func (x CriImageCacheStatus) Enum() *CriImageCacheStatus { + p := new(CriImageCacheStatus) + *p = x + return p +} + +func (x CriImageCacheStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CriImageCacheStatus) Descriptor() protoreflect.EnumDescriptor { + return file_resource_definitions_enums_enums_proto_enumTypes[32].Descriptor() +} + +func (CriImageCacheStatus) Type() protoreflect.EnumType { + return &file_resource_definitions_enums_enums_proto_enumTypes[32] +} + +func (x CriImageCacheStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CriImageCacheStatus.Descriptor instead. +func (CriImageCacheStatus) EnumDescriptor() ([]byte, []int) { + return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{32} +} + // KubespanPeerState is KubeSpan peer current state. type KubespanPeerState int32 @@ -2136,11 +2189,11 @@ func (x KubespanPeerState) String() string { } func (KubespanPeerState) Descriptor() protoreflect.EnumDescriptor { - return file_resource_definitions_enums_enums_proto_enumTypes[32].Descriptor() + return file_resource_definitions_enums_enums_proto_enumTypes[33].Descriptor() } func (KubespanPeerState) Type() protoreflect.EnumType { - return &file_resource_definitions_enums_enums_proto_enumTypes[32] + return &file_resource_definitions_enums_enums_proto_enumTypes[33] } func (x KubespanPeerState) Number() protoreflect.EnumNumber { @@ -2149,7 +2202,7 @@ func (x KubespanPeerState) Number() protoreflect.EnumNumber { // Deprecated: Use KubespanPeerState.Descriptor instead. func (KubespanPeerState) EnumDescriptor() ([]byte, []int) { - return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{32} + return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{33} } // NetworkConfigLayer describes network configuration layers, with lowest priority first. @@ -2192,11 +2245,11 @@ func (x NetworkConfigLayer) String() string { } func (NetworkConfigLayer) Descriptor() protoreflect.EnumDescriptor { - return file_resource_definitions_enums_enums_proto_enumTypes[33].Descriptor() + return file_resource_definitions_enums_enums_proto_enumTypes[34].Descriptor() } func (NetworkConfigLayer) Type() protoreflect.EnumType { - return &file_resource_definitions_enums_enums_proto_enumTypes[33] + return &file_resource_definitions_enums_enums_proto_enumTypes[34] } func (x NetworkConfigLayer) Number() protoreflect.EnumNumber { @@ -2205,7 +2258,7 @@ func (x NetworkConfigLayer) Number() protoreflect.EnumNumber { // Deprecated: Use NetworkConfigLayer.Descriptor instead. func (NetworkConfigLayer) EnumDescriptor() ([]byte, []int) { - return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{33} + return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{34} } // NetworkOperator enumerates Talos network operators. @@ -2242,11 +2295,11 @@ func (x NetworkOperator) String() string { } func (NetworkOperator) Descriptor() protoreflect.EnumDescriptor { - return file_resource_definitions_enums_enums_proto_enumTypes[34].Descriptor() + return file_resource_definitions_enums_enums_proto_enumTypes[35].Descriptor() } func (NetworkOperator) Type() protoreflect.EnumType { - return &file_resource_definitions_enums_enums_proto_enumTypes[34] + return &file_resource_definitions_enums_enums_proto_enumTypes[35] } func (x NetworkOperator) Number() protoreflect.EnumNumber { @@ -2255,7 +2308,7 @@ func (x NetworkOperator) Number() protoreflect.EnumNumber { // Deprecated: Use NetworkOperator.Descriptor instead. func (NetworkOperator) EnumDescriptor() ([]byte, []int) { - return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{34} + return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{35} } // RuntimeMachineStage describes the stage of the machine boot/run process. @@ -2310,11 +2363,11 @@ func (x RuntimeMachineStage) String() string { } func (RuntimeMachineStage) Descriptor() protoreflect.EnumDescriptor { - return file_resource_definitions_enums_enums_proto_enumTypes[35].Descriptor() + return file_resource_definitions_enums_enums_proto_enumTypes[36].Descriptor() } func (RuntimeMachineStage) Type() protoreflect.EnumType { - return &file_resource_definitions_enums_enums_proto_enumTypes[35] + return &file_resource_definitions_enums_enums_proto_enumTypes[36] } func (x RuntimeMachineStage) Number() protoreflect.EnumNumber { @@ -2323,7 +2376,7 @@ func (x RuntimeMachineStage) Number() protoreflect.EnumNumber { // Deprecated: Use RuntimeMachineStage.Descriptor instead. func (RuntimeMachineStage) EnumDescriptor() ([]byte, []int) { - return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{35} + return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{36} } var File_resource_definitions_enums_enums_proto protoreflect.FileDescriptor @@ -2734,51 +2787,61 @@ var file_resource_definitions_enums_enums_proto_rawDesc = []byte{ 0x52, 0x54, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x49, 0x53, 0x4b, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, - 0x4d, 0x50, 0x46, 0x53, 0x10, 0x02, 0x2a, 0x53, 0x0a, 0x11, 0x4b, 0x75, 0x62, 0x65, 0x73, 0x70, - 0x61, 0x6e, 0x50, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x50, - 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, - 0x4e, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, - 0x45, 0x5f, 0x55, 0x50, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, - 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x02, 0x2a, 0x88, 0x01, 0x0a, 0x12, - 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4c, 0x61, 0x79, - 0x65, 0x72, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x44, 0x45, 0x46, - 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, - 0x5f, 0x43, 0x4d, 0x44, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4f, - 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, 0x10, 0x02, 0x12, - 0x13, 0x0a, 0x0f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, - 0x4f, 0x52, 0x10, 0x03, 0x12, 0x20, 0x0a, 0x1c, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x4d, - 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x55, 0x52, 0x41, - 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x2a, 0x4b, 0x0a, 0x0f, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x0e, 0x4f, 0x50, 0x45, - 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x44, 0x48, 0x43, 0x50, 0x34, 0x10, 0x00, 0x12, 0x12, 0x0a, - 0x0e, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x44, 0x48, 0x43, 0x50, 0x36, 0x10, - 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x56, 0x49, - 0x50, 0x10, 0x02, 0x2a, 0x9b, 0x02, 0x0a, 0x13, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x4d, - 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x4d, - 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x55, 0x4e, 0x4b, - 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, - 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x42, 0x4f, 0x4f, 0x54, 0x49, 0x4e, 0x47, 0x10, - 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, - 0x47, 0x45, 0x5f, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, - 0x1d, 0x0a, 0x19, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, - 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x54, 0x45, 0x4e, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x03, 0x12, 0x19, - 0x0a, 0x15, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, - 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x41, 0x43, - 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x52, 0x45, 0x42, 0x4f, 0x4f, - 0x54, 0x49, 0x4e, 0x47, 0x10, 0x05, 0x12, 0x1f, 0x0a, 0x1b, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, - 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x53, 0x48, 0x55, 0x54, 0x54, 0x49, 0x4e, 0x47, - 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x06, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x41, 0x43, 0x48, 0x49, - 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x52, 0x45, 0x53, 0x45, 0x54, 0x54, 0x49, - 0x4e, 0x47, 0x10, 0x07, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, - 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x55, 0x50, 0x47, 0x52, 0x41, 0x44, 0x49, 0x4e, 0x47, 0x10, - 0x08, 0x42, 0x74, 0x0a, 0x28, 0x64, 0x65, 0x76, 0x2e, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x64, 0x65, 0x66, 0x69, - 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x5a, 0x48, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, - 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, - 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x2f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x4d, 0x50, 0x46, 0x53, 0x10, 0x02, 0x2a, 0x96, 0x01, 0x0a, 0x13, 0x43, 0x72, 0x69, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, + 0x0a, 0x1a, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x43, 0x41, 0x43, 0x48, 0x45, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1f, + 0x0a, 0x1b, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x43, 0x41, 0x43, 0x48, 0x45, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x55, 0x53, 0x5f, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, + 0x20, 0x0a, 0x1c, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x43, 0x41, 0x43, 0x48, 0x45, 0x5f, 0x53, + 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x52, 0x45, 0x50, 0x41, 0x52, 0x49, 0x4e, 0x47, 0x10, + 0x02, 0x12, 0x1c, 0x0a, 0x18, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x43, 0x41, 0x43, 0x48, 0x45, + 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x59, 0x10, 0x03, 0x2a, + 0x53, 0x0a, 0x11, 0x4b, 0x75, 0x62, 0x65, 0x73, 0x70, 0x61, 0x6e, 0x50, 0x65, 0x65, 0x72, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, + 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, + 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x50, 0x10, 0x01, 0x12, + 0x13, 0x0a, 0x0f, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x4f, + 0x57, 0x4e, 0x10, 0x02, 0x2a, 0x88, 0x01, 0x0a, 0x12, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x0e, 0x43, + 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, + 0x12, 0x0a, 0x0e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x43, 0x4d, 0x44, 0x4c, 0x49, 0x4e, + 0x45, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x50, 0x4c, + 0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4f, 0x4e, 0x46, + 0x49, 0x47, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x20, 0x0a, + 0x1c, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, + 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x2a, + 0x4b, 0x0a, 0x0f, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x0e, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x44, + 0x48, 0x43, 0x50, 0x34, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, + 0x4f, 0x52, 0x5f, 0x44, 0x48, 0x43, 0x50, 0x36, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4f, 0x50, + 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x56, 0x49, 0x50, 0x10, 0x02, 0x2a, 0x9b, 0x02, 0x0a, + 0x13, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x53, + 0x74, 0x61, 0x67, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, + 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, + 0x19, 0x0a, 0x15, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, + 0x5f, 0x42, 0x4f, 0x4f, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x4d, 0x41, + 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x49, 0x4e, 0x53, 0x54, + 0x41, 0x4c, 0x4c, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x41, 0x43, 0x48, + 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x54, 0x45, + 0x4e, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x4d, 0x41, 0x43, 0x48, 0x49, + 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, + 0x10, 0x04, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, + 0x41, 0x47, 0x45, 0x5f, 0x52, 0x45, 0x42, 0x4f, 0x4f, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x05, 0x12, + 0x1f, 0x0a, 0x1b, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, + 0x5f, 0x53, 0x48, 0x55, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x06, + 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, + 0x45, 0x5f, 0x52, 0x45, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x07, 0x12, 0x1b, 0x0a, + 0x17, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x55, + 0x50, 0x47, 0x52, 0x41, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x08, 0x42, 0x74, 0x0a, 0x28, 0x64, 0x65, + 0x76, 0x2e, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x5a, 0x48, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x74, 0x61, + 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, + 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x64, + 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x65, 0x6e, 0x75, 0x6d, 0x73, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2793,7 +2856,7 @@ func file_resource_definitions_enums_enums_proto_rawDescGZIP() []byte { return file_resource_definitions_enums_enums_proto_rawDescData } -var file_resource_definitions_enums_enums_proto_enumTypes = make([]protoimpl.EnumInfo, 36) +var file_resource_definitions_enums_enums_proto_enumTypes = make([]protoimpl.EnumInfo, 37) var file_resource_definitions_enums_enums_proto_goTypes = []any{ (MachineType)(0), // 0: talos.resource.definitions.enums.MachineType (NethelpersAddressFlag)(0), // 1: talos.resource.definitions.enums.NethelpersAddressFlag @@ -2827,10 +2890,11 @@ var file_resource_definitions_enums_enums_proto_goTypes = []any{ (BlockFilesystemType)(0), // 29: talos.resource.definitions.enums.BlockFilesystemType (BlockVolumePhase)(0), // 30: talos.resource.definitions.enums.BlockVolumePhase (BlockVolumeType)(0), // 31: talos.resource.definitions.enums.BlockVolumeType - (KubespanPeerState)(0), // 32: talos.resource.definitions.enums.KubespanPeerState - (NetworkConfigLayer)(0), // 33: talos.resource.definitions.enums.NetworkConfigLayer - (NetworkOperator)(0), // 34: talos.resource.definitions.enums.NetworkOperator - (RuntimeMachineStage)(0), // 35: talos.resource.definitions.enums.RuntimeMachineStage + (CriImageCacheStatus)(0), // 32: talos.resource.definitions.enums.CriImageCacheStatus + (KubespanPeerState)(0), // 33: talos.resource.definitions.enums.KubespanPeerState + (NetworkConfigLayer)(0), // 34: talos.resource.definitions.enums.NetworkConfigLayer + (NetworkOperator)(0), // 35: talos.resource.definitions.enums.NetworkOperator + (RuntimeMachineStage)(0), // 36: talos.resource.definitions.enums.RuntimeMachineStage } var file_resource_definitions_enums_enums_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type @@ -2850,7 +2914,7 @@ func file_resource_definitions_enums_enums_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_resource_definitions_enums_enums_proto_rawDesc, - NumEnums: 36, + NumEnums: 37, NumMessages: 0, NumExtensions: 0, NumServices: 0, diff --git a/pkg/machinery/config/config/machine.go b/pkg/machinery/config/config/machine.go index 7fdcb51415..e1f449ea35 100644 --- a/pkg/machinery/config/config/machine.go +++ b/pkg/machinery/config/config/machine.go @@ -448,6 +448,7 @@ type Features interface { DiskQuotaSupportEnabled() bool HostDNS() HostDNS KubePrism() KubePrism + ImageCacheEnabled() bool } // KubernetesTalosAPIAccess describes the Kubernetes Talos API access features. diff --git a/pkg/machinery/config/config/volume.go b/pkg/machinery/config/config/volume.go index 60393f103e..4d34b95fe1 100644 --- a/pkg/machinery/config/config/volume.go +++ b/pkg/machinery/config/config/volume.go @@ -15,7 +15,7 @@ type VolumesConfig interface { // ByName returns a volume config configuration by name. // // If the configuration is missing, the method a stub which returns implements 'nothing is set' stub. - ByName(name string) VolumeConfig + ByName(name string) (VolumeConfig, bool) } // VolumeConfig defines the interface to access volume configuration. @@ -39,14 +39,14 @@ func WrapVolumesConfigList(configs ...VolumeConfig) VolumesConfig { type volumesConfigWrapper []VolumeConfig -func (w volumesConfigWrapper) ByName(name string) VolumeConfig { +func (w volumesConfigWrapper) ByName(name string) (VolumeConfig, bool) { for _, doc := range w { if doc.Name() == name { - return doc + return doc, true } } - return emptyVolumeConfig{} + return emptyVolumeConfig{}, false } type emptyVolumeConfig struct{} diff --git a/pkg/machinery/config/schemas/config.schema.json b/pkg/machinery/config/schemas/config.schema.json index 181f6e251a..3b502d8787 100644 --- a/pkg/machinery/config/schemas/config.schema.json +++ b/pkg/machinery/config/schemas/config.schema.json @@ -2070,6 +2070,13 @@ "description": "Configures host DNS caching resolver.\n", "markdownDescription": "Configures host DNS caching resolver.", "x-intellij-html-description": "\u003cp\u003eConfigures host DNS caching resolver.\u003c/p\u003e\n" + }, + "imageCache": { + "type": "boolean", + "title": "imageCache", + "description": "Enable Image Cache feature.\n", + "markdownDescription": "Enable Image Cache feature.", + "x-intellij-html-description": "\u003cp\u003eEnable Image Cache feature.\u003c/p\u003e\n" } }, "additionalProperties": false, diff --git a/pkg/machinery/config/types/block/volume_config.go b/pkg/machinery/config/types/block/volume_config.go index d31c6f524a..0e1741beec 100644 --- a/pkg/machinery/config/types/block/volume_config.go +++ b/pkg/machinery/config/types/block/volume_config.go @@ -9,6 +9,7 @@ package block import ( "errors" "fmt" + "slices" "github.com/siderolabs/gen/optional" @@ -151,8 +152,10 @@ func (s *VolumeConfigV1Alpha1) Clone() config.Document { // Validate implements config.Validator interface. func (s *VolumeConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) { - if s.MetaName != constants.EphemeralPartitionLabel { - return nil, errors.New("only EPHEMERAL volumes are supported") + allowedVolumes := []string{constants.EphemeralPartitionLabel, constants.ImageCachePartitionLabel} + + if slices.Index(allowedVolumes, s.MetaName) == -1 { + return nil, fmt.Errorf("only %q volumes are supported", allowedVolumes) } var validationErrors error diff --git a/pkg/machinery/config/types/block/volume_config_test.go b/pkg/machinery/config/types/block/volume_config_test.go index 6c0bc88b2d..230696c479 100644 --- a/pkg/machinery/config/types/block/volume_config_test.go +++ b/pkg/machinery/config/types/block/volume_config_test.go @@ -110,7 +110,7 @@ func TestVolumeConfigValidate(t *testing.T) { return c }, - expectedErrors: "only EPHEMERAL volumes are supported", + expectedErrors: "only [\"EPHEMERAL\" \"IMAGECACHE\"] volumes are supported", }, { name: "invalid disk selector", diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_features.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_features.go index 6b41bcd4ed..de60ab836e 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_features.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_features.go @@ -57,6 +57,11 @@ func (f *FeaturesConfig) KubePrism() config.KubePrism { return f.KubePrismSupport } +// ImageCacheEnabled implements config.Features interface. +func (f *FeaturesConfig) ImageCacheEnabled() bool { + return pointer.SafeDeref(f.ImageCache) +} + const defaultKubePrismPort = 7445 // Enabled implements [config.KubePrism]. diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go index 50dedc7b55..d97b9cc780 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go @@ -2167,6 +2167,9 @@ type FeaturesConfig struct { // description: | // Configures host DNS caching resolver. HostDNSSupport *HostDNSConfig `yaml:"hostDNS,omitempty"` + // description: | + // Enable Image Cache feature. + ImageCache *bool `yaml:"imageCache,omitempty"` } // KubePrism describes the configuration for the KubePrism load balancer. diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go index 6d16aa69ec..c4d2a1b41d 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go @@ -3465,6 +3465,13 @@ func (FeaturesConfig) Doc() *encoder.Doc { Description: "Configures host DNS caching resolver.", Comments: [3]string{"" /* encoder.HeadComment */, "Configures host DNS caching resolver." /* encoder.LineComment */, "" /* encoder.FootComment */}, }, + { + Name: "imageCache", + Type: "bool", + Note: "", + Description: "Enable Image Cache feature.", + Comments: [3]string{"" /* encoder.HeadComment */, "Enable Image Cache feature." /* encoder.LineComment */, "" /* encoder.FootComment */}, + }, }, } diff --git a/pkg/machinery/constants/constants.go b/pkg/machinery/constants/constants.go index d678e5ff95..52913712c3 100644 --- a/pkg/machinery/constants/constants.go +++ b/pkg/machinery/constants/constants.go @@ -1214,6 +1214,18 @@ const ( // MetalAgentModeFlagPath is the path to the file indicating if the node is running in Metal Agent mode. MetalAgentModeFlagPath = "/usr/local/etc/is-metal-agent" + + // ImageCachePartitionLabel is the label for the image cache partition. + ImageCachePartitionLabel = "IMAGECACHE" + + // ImageCacheISOMountPoint is the mount point for the image cache ISO. + ImageCacheISOMountPoint = "/system/imagecache/iso" + + // ImageCacheDiskMountPoint is the mount point for the image cache partition. + ImageCacheDiskMountPoint = "/system/imagecache/disk" + + // RegistrydListenAddress is the address to listen on for the registryd service. + RegistrydListenAddress = "127.0.0.1:3172" ) // See https://linux.die.net/man/3/klogctl diff --git a/pkg/machinery/go.mod b/pkg/machinery/go.mod index 376c3c8ec8..8d9eca4f1d 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.5 + github.com/siderolabs/go-blockdevice/v2 v2.0.6 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 48c2b684c9..47379ea08d 100644 --- a/pkg/machinery/go.sum +++ b/pkg/machinery/go.sum @@ -113,8 +113,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.5 h1:VLmIdDB/1P30Inrpe94FQAz4WUpByGwun5ZeTekxIQc= -github.com/siderolabs/go-blockdevice/v2 v2.0.5/go.mod h1:74htzCV913UzaLZ4H+NBXkwWlYnBJIq5m/379ZEcu8w= +github.com/siderolabs/go-blockdevice/v2 v2.0.6 h1:/NAy3MbNZhjLWo28asZyS/hmf86PEPDMc9i6wIcgbwI= +github.com/siderolabs/go-blockdevice/v2 v2.0.6/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/resources/cri/cri.go b/pkg/machinery/resources/cri/cri.go index 29d1361db9..9f15aedfa7 100644 --- a/pkg/machinery/resources/cri/cri.go +++ b/pkg/machinery/resources/cri/cri.go @@ -2,9 +2,14 @@ // 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/. +// Package cri contains resources related to the Container Runtime Interface (CRI). package cri import "github.com/cosi-project/runtime/pkg/resource" +//go:generate deep-copy -type ImageCacheConfigSpec -type SeccompProfileSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go . + +//go:generate enumer -type=ImageCacheStatus -linecomment -text + // NamespaceName contains resources related to stats. const NamespaceName resource.Namespace = "cri" diff --git a/pkg/machinery/resources/cri/cri_test.go b/pkg/machinery/resources/cri/cri_test.go index 91905bf173..61d5399e82 100644 --- a/pkg/machinery/resources/cri/cri_test.go +++ b/pkg/machinery/resources/cri/cri_test.go @@ -25,6 +25,7 @@ func TestRegisterResource(t *testing.T) { resourceRegistry := registry.NewResourceRegistry(resources) for _, resource := range []meta.ResourceWithRD{ + &cri.ImageCacheConfig{}, &cri.SeccompProfile{}, } { assert.NoError(t, resourceRegistry.Register(ctx, resource)) diff --git a/pkg/machinery/resources/cri/deep_copy.generated.go b/pkg/machinery/resources/cri/deep_copy.generated.go index c0a2d5e0dd..e131a52ad6 100644 --- a/pkg/machinery/resources/cri/deep_copy.generated.go +++ b/pkg/machinery/resources/cri/deep_copy.generated.go @@ -2,10 +2,20 @@ // 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/. -// Code generated by "deep-copy -type SeccompProfileSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT. +// Code generated by "deep-copy -type ImageCacheConfigSpec -type SeccompProfileSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT. package cri +// DeepCopy generates a deep copy of ImageCacheConfigSpec. +func (o ImageCacheConfigSpec) DeepCopy() ImageCacheConfigSpec { + var cp ImageCacheConfigSpec = o + if o.Roots != nil { + cp.Roots = make([]string, len(o.Roots)) + copy(cp.Roots, o.Roots) + } + return cp +} + // DeepCopy generates a deep copy of SeccompProfileSpec. func (o SeccompProfileSpec) DeepCopy() SeccompProfileSpec { var cp SeccompProfileSpec = o diff --git a/pkg/machinery/resources/cri/image_cache_config.go b/pkg/machinery/resources/cri/image_cache_config.go new file mode 100644 index 0000000000..46913e8fd3 --- /dev/null +++ b/pkg/machinery/resources/cri/image_cache_config.go @@ -0,0 +1,70 @@ +// 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/. + +package cri + +import ( + "github.com/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/resource/meta" + "github.com/cosi-project/runtime/pkg/resource/protobuf" + "github.com/cosi-project/runtime/pkg/resource/typed" + + "github.com/siderolabs/talos/pkg/machinery/proto" +) + +// ImageCacheConfigType is type of ImageCacheConfig resource. +const ImageCacheConfigType = resource.Type("ImageCacheConfigs.cri.talos.dev") + +// ImageCacheConfig represents ImageCacheConfig typed resource. +type ImageCacheConfig = typed.Resource[ImageCacheConfigSpec, ImageCacheConfigExtension] + +// ImageCacheConfigID is the ID of the ImageCacheConfig resource. +const ImageCacheConfigID = "image-cache" + +// ImageCacheConfigSpec represents the ImageCacheConfig. +// +//gotagsrewrite:gen +type ImageCacheConfigSpec struct { + Status ImageCacheStatus `yaml:"status" protobuf:"1"` + Roots []string `yaml:"roots" protobuf:"2"` +} + +// NewImageCacheConfig creates new ImageCacheConfig object. +func NewImageCacheConfig() *ImageCacheConfig { + return typed.NewResource[ImageCacheConfigSpec, ImageCacheConfigExtension]( + resource.NewMetadata(NamespaceName, ImageCacheConfigType, ImageCacheConfigID, resource.VersionUndefined), + ImageCacheConfigSpec{}, + ) +} + +// ImageCacheConfigExtension is an auxiliary type for ImageCacheConfig resource. +type ImageCacheConfigExtension struct{} + +// ResourceDefinition implements meta.ResourceDefinitionProvider interface. +func (ImageCacheConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec { + return meta.ResourceDefinitionSpec{ + Type: ImageCacheConfigType, + Aliases: []resource.Type{}, + DefaultNamespace: NamespaceName, + PrintColumns: []meta.PrintColumn{ + { + Name: "Status", + JSONPath: "{.status}", + }, + { + Name: "Roots", + JSONPath: "{.roots}", + }, + }, + } +} + +func init() { + proto.RegisterDefaultTypes() + + err := protobuf.RegisterDynamic[ImageCacheConfigSpec](ImageCacheConfigType, &ImageCacheConfig{}) + if err != nil { + panic(err) + } +} diff --git a/pkg/machinery/resources/cri/imagecachestatus.go b/pkg/machinery/resources/cri/imagecachestatus.go new file mode 100644 index 0000000000..28dd32987a --- /dev/null +++ b/pkg/machinery/resources/cri/imagecachestatus.go @@ -0,0 +1,18 @@ +// 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/. + +package cri + +// ImageCacheStatus describes image cache status type. +type ImageCacheStatus int + +// ImageCacheStatus values. +// +//structprotogen:gen_enum +const ( + ImageCacheStatusUnknown ImageCacheStatus = iota // unknown + ImageCacheStatusDisabled // disabled + ImageCacheStatusPreparing // preparing + ImageCacheStatusReady // ready +) diff --git a/pkg/machinery/resources/cri/imagecachestatus_enumer.go b/pkg/machinery/resources/cri/imagecachestatus_enumer.go new file mode 100644 index 0000000000..81fa88cf1b --- /dev/null +++ b/pkg/machinery/resources/cri/imagecachestatus_enumer.go @@ -0,0 +1,98 @@ +// Code generated by "enumer -type=ImageCacheStatus -linecomment -text"; DO NOT EDIT. + +package cri + +import ( + "fmt" + "strings" +) + +const _ImageCacheStatusName = "unknowndisabledpreparingready" + +var _ImageCacheStatusIndex = [...]uint8{0, 7, 15, 24, 29} + +const _ImageCacheStatusLowerName = "unknowndisabledpreparingready" + +func (i ImageCacheStatus) String() string { + if i < 0 || i >= ImageCacheStatus(len(_ImageCacheStatusIndex)-1) { + return fmt.Sprintf("ImageCacheStatus(%d)", i) + } + return _ImageCacheStatusName[_ImageCacheStatusIndex[i]:_ImageCacheStatusIndex[i+1]] +} + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the stringer command to generate them again. +func _ImageCacheStatusNoOp() { + var x [1]struct{} + _ = x[ImageCacheStatusUnknown-(0)] + _ = x[ImageCacheStatusDisabled-(1)] + _ = x[ImageCacheStatusPreparing-(2)] + _ = x[ImageCacheStatusReady-(3)] +} + +var _ImageCacheStatusValues = []ImageCacheStatus{ImageCacheStatusUnknown, ImageCacheStatusDisabled, ImageCacheStatusPreparing, ImageCacheStatusReady} + +var _ImageCacheStatusNameToValueMap = map[string]ImageCacheStatus{ + _ImageCacheStatusName[0:7]: ImageCacheStatusUnknown, + _ImageCacheStatusLowerName[0:7]: ImageCacheStatusUnknown, + _ImageCacheStatusName[7:15]: ImageCacheStatusDisabled, + _ImageCacheStatusLowerName[7:15]: ImageCacheStatusDisabled, + _ImageCacheStatusName[15:24]: ImageCacheStatusPreparing, + _ImageCacheStatusLowerName[15:24]: ImageCacheStatusPreparing, + _ImageCacheStatusName[24:29]: ImageCacheStatusReady, + _ImageCacheStatusLowerName[24:29]: ImageCacheStatusReady, +} + +var _ImageCacheStatusNames = []string{ + _ImageCacheStatusName[0:7], + _ImageCacheStatusName[7:15], + _ImageCacheStatusName[15:24], + _ImageCacheStatusName[24:29], +} + +// ImageCacheStatusString retrieves an enum value from the enum constants string name. +// Throws an error if the param is not part of the enum. +func ImageCacheStatusString(s string) (ImageCacheStatus, error) { + if val, ok := _ImageCacheStatusNameToValueMap[s]; ok { + return val, nil + } + + if val, ok := _ImageCacheStatusNameToValueMap[strings.ToLower(s)]; ok { + return val, nil + } + return 0, fmt.Errorf("%s does not belong to ImageCacheStatus values", s) +} + +// ImageCacheStatusValues returns all values of the enum +func ImageCacheStatusValues() []ImageCacheStatus { + return _ImageCacheStatusValues +} + +// ImageCacheStatusStrings returns a slice of all String values of the enum +func ImageCacheStatusStrings() []string { + strs := make([]string, len(_ImageCacheStatusNames)) + copy(strs, _ImageCacheStatusNames) + return strs +} + +// IsAImageCacheStatus returns "true" if the value is listed in the enum definition. "false" otherwise +func (i ImageCacheStatus) IsAImageCacheStatus() bool { + for _, v := range _ImageCacheStatusValues { + if i == v { + return true + } + } + return false +} + +// MarshalText implements the encoding.TextMarshaler interface for ImageCacheStatus +func (i ImageCacheStatus) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface for ImageCacheStatus +func (i *ImageCacheStatus) UnmarshalText(text []byte) error { + var err error + *i, err = ImageCacheStatusString(string(text)) + return err +} diff --git a/pkg/machinery/resources/cri/seccomp_profile.go b/pkg/machinery/resources/cri/seccomp_profile.go index 9315b6977e..4fdfc142af 100644 --- a/pkg/machinery/resources/cri/seccomp_profile.go +++ b/pkg/machinery/resources/cri/seccomp_profile.go @@ -13,8 +13,6 @@ import ( "github.com/siderolabs/talos/pkg/machinery/proto" ) -//go:generate deep-copy -type SeccompProfileSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go . - // SeccompProfileType is type of SeccompProfile resource. const SeccompProfileType = resource.Type("SeccompProfiles.cri.talos.dev") diff --git a/website/content/v1.9/reference/api.md b/website/content/v1.9/reference/api.md index 149a0f102a..2676ec226c 100644 --- a/website/content/v1.9/reference/api.md +++ b/website/content/v1.9/reference/api.md @@ -55,6 +55,7 @@ description: Talos gRPC API reference. - [MemberSpec](#talos.resource.definitions.cluster.MemberSpec) - [resource/definitions/cri/cri.proto](#resource/definitions/cri/cri.proto) + - [ImageCacheConfigSpec](#talos.resource.definitions.cri.ImageCacheConfigSpec) - [SeccompProfileSpec](#talos.resource.definitions.cri.SeccompProfileSpec) - [resource/definitions/enums/enums.proto](#resource/definitions/enums/enums.proto) @@ -63,6 +64,7 @@ description: Talos gRPC API reference. - [BlockFilesystemType](#talos.resource.definitions.enums.BlockFilesystemType) - [BlockVolumePhase](#talos.resource.definitions.enums.BlockVolumePhase) - [BlockVolumeType](#talos.resource.definitions.enums.BlockVolumeType) + - [CriImageCacheStatus](#talos.resource.definitions.enums.CriImageCacheStatus) - [KubespanPeerState](#talos.resource.definitions.enums.KubespanPeerState) - [MachineType](#talos.resource.definitions.enums.MachineType) - [NethelpersADSelect](#talos.resource.definitions.enums.NethelpersADSelect) @@ -1288,6 +1290,22 @@ MemberSpec describes Member state. + + +### ImageCacheConfigSpec +ImageCacheConfigSpec represents the ImageCacheConfig. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| status | [talos.resource.definitions.enums.CriImageCacheStatus](#talos.resource.definitions.enums.CriImageCacheStatus) | | | +| roots | [string](#string) | repeated | | + + + + + + ### SeccompProfileSpec @@ -1394,6 +1412,20 @@ BlockVolumeType describes volume type. + + +### CriImageCacheStatus +CriImageCacheStatus describes image cache status type. + +| Name | Number | Description | +| ---- | ------ | ----------- | +| IMAGE_CACHE_STATUS_UNKNOWN | 0 | | +| IMAGE_CACHE_STATUS_DISABLED | 1 | | +| IMAGE_CACHE_STATUS_PREPARING | 2 | | +| IMAGE_CACHE_STATUS_READY | 3 | | + + + ### KubespanPeerState diff --git a/website/content/v1.9/reference/configuration/v1alpha1/config.md b/website/content/v1.9/reference/configuration/v1alpha1/config.md index be297cb91a..237bb6db18 100644 --- a/website/content/v1.9/reference/configuration/v1alpha1/config.md +++ b/website/content/v1.9/reference/configuration/v1alpha1/config.md @@ -2627,6 +2627,7 @@ kubernetesTalosAPIAccess: |`diskQuotaSupport` |bool |
Enable XFS project quota support for EPHEMERAL partition and user disks.Also enables kubelet tracking of ephemeral disk usage in the kubelet via quota.
| | |`kubePrism` |KubePrism |
KubePrism - local proxy/load balancer on defined port that will distributerequests to all API servers in the cluster.
| | |`hostDNS` |HostDNSConfig |Configures host DNS caching resolver. | | +|`imageCache` |bool |Enable Image Cache feature. | | diff --git a/website/content/v1.9/schemas/config.schema.json b/website/content/v1.9/schemas/config.schema.json index 181f6e251a..3b502d8787 100644 --- a/website/content/v1.9/schemas/config.schema.json +++ b/website/content/v1.9/schemas/config.schema.json @@ -2070,6 +2070,13 @@ "description": "Configures host DNS caching resolver.\n", "markdownDescription": "Configures host DNS caching resolver.", "x-intellij-html-description": "\u003cp\u003eConfigures host DNS caching resolver.\u003c/p\u003e\n" + }, + "imageCache": { + "type": "boolean", + "title": "imageCache", + "description": "Enable Image Cache feature.\n", + "markdownDescription": "Enable Image Cache feature.", + "x-intellij-html-description": "\u003cp\u003eEnable Image Cache feature.\u003c/p\u003e\n" } }, "additionalProperties": false,