diff --git a/api/resource/definitions/runtime/runtime.proto b/api/resource/definitions/runtime/runtime.proto index 1a546d6c5..8ea61dcb1 100755 --- a/api/resource/definitions/runtime/runtime.proto +++ b/api/resource/definitions/runtime/runtime.proto @@ -53,6 +53,12 @@ message MachineStatusStatus { repeated UnmetCondition unmet_conditions = 2; } +// MaintenanceServiceConfigSpec describes configuration for maintenance service API. +message MaintenanceServiceConfigSpec { + string listen_address = 1; + repeated common.NetIP reachable_addresses = 2; +} + // MetaKeySpec describes status of the defined sysctls. message MetaKeySpec { string value = 1; diff --git a/api/resource/definitions/secrets/secrets.proto b/api/resource/definitions/secrets/secrets.proto index 48e7941db..d04b2dc16 100755 --- a/api/resource/definitions/secrets/secrets.proto +++ b/api/resource/definitions/secrets/secrets.proto @@ -73,6 +73,17 @@ message KubernetesRootSpec { repeated common.NetIP api_server_ips = 14; } +// MaintenanceRootSpec describes maintenance service CA. +message MaintenanceRootSpec { + common.PEMEncodedCertificateAndKey ca = 1; +} + +// MaintenanceServiceCertsSpec describes maintenance service certs secrets. +message MaintenanceServiceCertsSpec { + common.PEMEncodedCertificateAndKey ca = 1; + common.PEMEncodedCertificateAndKey server = 2; +} + // OSRootSpec describes operating system CA. message OSRootSpec { common.PEMEncodedCertificateAndKey ca = 1; diff --git a/internal/app/machined/pkg/controllers/k8s/apiserver_loadbalancer.go b/internal/app/machined/pkg/controllers/k8s/apiserver_loadbalancer.go index abeab3c31..a01449f4d 100644 --- a/internal/app/machined/pkg/controllers/k8s/apiserver_loadbalancer.go +++ b/internal/app/machined/pkg/controllers/k8s/apiserver_loadbalancer.go @@ -188,7 +188,9 @@ func (ctrl *APILoadBalancerController) startLoadBalancer(lbCfg *k8s.LoadBalancer ctrl.balancerHost = spec.Host ctrl.balancerPort = spec.Port - lb, err := controlplane.NewLoadBalancer(ctrl.balancerHost, ctrl.balancerPort, logger) + lb, err := controlplane.NewLoadBalancer(ctrl.balancerHost, ctrl.balancerPort, + logger.WithOptions(zap.IncreaseLevel(zap.ErrorLevel)), // silence the load balancer logs + ) if err != nil { return fmt.Errorf("failed to create load balancer: %w", err) } diff --git a/internal/app/machined/pkg/controllers/runtime/maintenance_config.go b/internal/app/machined/pkg/controllers/runtime/maintenance_config.go new file mode 100644 index 000000000..e24ba40bc --- /dev/null +++ b/internal/app/machined/pkg/controllers/runtime/maintenance_config.go @@ -0,0 +1,129 @@ +// 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 runtime + +import ( + "context" + "fmt" + "net/netip" + + "github.com/cosi-project/runtime/pkg/controller" + "github.com/cosi-project/runtime/pkg/safe" + "github.com/cosi-project/runtime/pkg/state" + "github.com/siderolabs/gen/slices" + "github.com/siderolabs/go-pointer" + "go.uber.org/zap" + + "github.com/siderolabs/talos/pkg/machinery/constants" + "github.com/siderolabs/talos/pkg/machinery/nethelpers" + "github.com/siderolabs/talos/pkg/machinery/resources/config" + "github.com/siderolabs/talos/pkg/machinery/resources/network" + "github.com/siderolabs/talos/pkg/machinery/resources/runtime" + "github.com/siderolabs/talos/pkg/machinery/resources/siderolink" +) + +// MaintenanceConfigController manages Maintenance Service config: which address it should listen on, etc. +type MaintenanceConfigController struct{} + +// Name implements controller.Controller interface. +func (ctrl *MaintenanceConfigController) Name() string { + return "runtime.MaintenanceConfigController" +} + +// Inputs implements controller.Controller interface. +func (ctrl *MaintenanceConfigController) Inputs() []controller.Input { + return []controller.Input{ + { + Namespace: config.NamespaceName, + Type: siderolink.ConfigType, + ID: pointer.To(siderolink.ConfigID), + }, + { + Namespace: network.NamespaceName, + Type: network.NodeAddressType, + ID: pointer.To(network.NodeAddressCurrentID), + }, + } +} + +// Outputs implements controller.Controller interface. +func (ctrl *MaintenanceConfigController) Outputs() []controller.Output { + return []controller.Output{ + { + Type: runtime.MaintenanceServiceConfigType, + Kind: controller.OutputExclusive, + }, + } +} + +// Run implements controller.Controller interface. +// +//nolint:gocyclo +func (ctrl *MaintenanceConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error { + for { + select { + case <-ctx.Done(): + return nil + case <-r.EventCh(): + } + + nodeAddresses, err := safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.NodeAddressCurrentID) + if err != nil && !state.IsNotFoundError(err) { + return fmt.Errorf("error getting node address: %w", err) + } + + var ( + listenAddress string + reachableAddresses []netip.Addr + ) + + if nodeAddresses != nil { + reachableAddresses = nodeAddresses.TypedSpec().IPs() + } + + _, err = safe.ReaderGetByID[*siderolink.Config](ctx, r, siderolink.ConfigID) + + // check if SideroLink config exists: + switch { + // * if it exists, find the SideroLink address and listen only on it + case err == nil: + if nodeAddresses != nil { + sideroLinkAddresses := slices.Filter(nodeAddresses.TypedSpec().IPs(), func(addr netip.Addr) bool { + return network.IsULA(addr, network.ULASideroLink) + }) + + if len(sideroLinkAddresses) > 0 { + listenAddress = nethelpers.JoinHostPort(sideroLinkAddresses[0].String(), constants.ApidPort) + reachableAddresses = sideroLinkAddresses[:1] + } + } + // * if it doesn't exist, listen on '*' + case state.IsNotFoundError(err): + listenAddress = fmt.Sprintf(":%d", constants.ApidPort) + default: + return fmt.Errorf("error getting siderolink config: %w", err) + } + + if listenAddress == "" { + // drop config + if err = r.Destroy(ctx, runtime.NewMaintenanceServiceConfig().Metadata()); err != nil && !state.IsNotFoundError(err) { + return fmt.Errorf("error destroying maintenance config: %w", err) + } + } else { + // create/update config + if err = safe.WriterModify[*runtime.MaintenanceServiceConfig](ctx, r, runtime.NewMaintenanceServiceConfig(), + func(config *runtime.MaintenanceServiceConfig) error { + config.TypedSpec().ListenAddress = listenAddress + config.TypedSpec().ReachableAddresses = reachableAddresses + + return nil + }); err != nil { + return fmt.Errorf("error updating maintenance config: %w", err) + } + } + + r.ResetRestartBackoff() + } +} diff --git a/internal/app/machined/pkg/controllers/runtime/maintenance_config_test.go b/internal/app/machined/pkg/controllers/runtime/maintenance_config_test.go new file mode 100644 index 000000000..e564f5021 --- /dev/null +++ b/internal/app/machined/pkg/controllers/runtime/maintenance_config_test.go @@ -0,0 +1,64 @@ +// 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 runtime_test + +import ( + "net/netip" + "testing" + "time" + + "github.com/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/resource/rtestutils" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + + "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" + runtimectrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime" + "github.com/siderolabs/talos/pkg/machinery/resources/config" + "github.com/siderolabs/talos/pkg/machinery/resources/network" + "github.com/siderolabs/talos/pkg/machinery/resources/runtime" + "github.com/siderolabs/talos/pkg/machinery/resources/siderolink" +) + +func TestMaintenanceConfigSuite(t *testing.T) { + suite.Run(t, &MaintenanceConfigSuite{ + DefaultSuite: ctest.DefaultSuite{ + Timeout: 5 * time.Second, + AfterSetup: func(suite *ctest.DefaultSuite) { + suite.Require().NoError(suite.Runtime().RegisterController(&runtimectrl.MaintenanceConfigController{})) + }, + }, + }) +} + +type MaintenanceConfigSuite struct { + ctest.DefaultSuite +} + +func (suite *MaintenanceConfigSuite) TestReconcile() { + rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{runtime.MaintenanceServiceConfigID}, + func(cfg *runtime.MaintenanceServiceConfig, asrt *assert.Assertions) { + asrt.Equal(":50000", cfg.TypedSpec().ListenAddress) + asrt.Nil(cfg.TypedSpec().ReachableAddresses) + }) + + siderolinkConfig := siderolink.NewConfig(config.NamespaceName, siderolink.ConfigID) + suite.Require().NoError(suite.State().Create(suite.Ctx(), siderolinkConfig)) + + rtestutils.AssertNoResource[*runtime.MaintenanceServiceConfig](suite.Ctx(), suite.T(), suite.State(), runtime.MaintenanceServiceConfigID) + + nodeAddresses := network.NewNodeAddress(network.NamespaceName, network.NodeAddressCurrentID) + nodeAddresses.TypedSpec().Addresses = []netip.Prefix{ + netip.MustParsePrefix("172.16.0.1/24"), + netip.MustParsePrefix("fdae:41e4:649b:9303:2a07:9c7:5b08:aef7/64"), + } + suite.Require().NoError(suite.State().Create(suite.Ctx(), nodeAddresses)) + + rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{runtime.MaintenanceServiceConfigID}, + func(cfg *runtime.MaintenanceServiceConfig, asrt *assert.Assertions) { + asrt.Equal("[fdae:41e4:649b:9303:2a07:9c7:5b08:aef7]:50000", cfg.TypedSpec().ListenAddress) + asrt.Equal([]netip.Addr{netip.MustParseAddr("fdae:41e4:649b:9303:2a07:9c7:5b08:aef7")}, cfg.TypedSpec().ReachableAddresses) + }) +} diff --git a/internal/app/machined/pkg/controllers/runtime/maintenance_service.go b/internal/app/machined/pkg/controllers/runtime/maintenance_service.go new file mode 100644 index 000000000..8f9b76788 --- /dev/null +++ b/internal/app/machined/pkg/controllers/runtime/maintenance_service.go @@ -0,0 +1,283 @@ +// 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 runtime + +import ( + "context" + "fmt" + "net" + "net/netip" + "reflect" + "sync" + "time" + + "github.com/cosi-project/runtime/pkg/controller" + "github.com/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/safe" + "github.com/cosi-project/runtime/pkg/state" + "github.com/siderolabs/crypto/x509" + "github.com/siderolabs/gen/slices" + "github.com/siderolabs/go-pointer" + "go.uber.org/zap" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + + "github.com/siderolabs/talos/internal/app/maintenance" + "github.com/siderolabs/talos/pkg/grpc/factory" + "github.com/siderolabs/talos/pkg/grpc/middleware/authz" + machineryconfig "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/resources/config" + "github.com/siderolabs/talos/pkg/machinery/resources/runtime" + "github.com/siderolabs/talos/pkg/machinery/resources/secrets" +) + +// MaintenanceServiceController runs the maintenance service based on the configuration. +type MaintenanceServiceController struct{} + +// Name implements controller.Controller interface. +func (ctrl *MaintenanceServiceController) Name() string { + return "runtime.MaintenanceServiceController" +} + +// Inputs implements controller.Controller interface. +func (ctrl *MaintenanceServiceController) Inputs() []controller.Input { + return []controller.Input{ + { + Namespace: runtime.NamespaceName, + Type: runtime.MaintenanceServiceRequestType, + ID: pointer.To(runtime.MaintenanceServiceRequestID), + Kind: controller.InputStrong, + }, + { + Namespace: runtime.NamespaceName, + Type: runtime.MaintenanceServiceConfigType, + ID: pointer.To(runtime.MaintenanceServiceConfigID), + Kind: controller.InputWeak, + }, + { + Namespace: secrets.NamespaceName, + Type: secrets.MaintenanceServiceCertsType, + ID: pointer.To(secrets.MaintenanceServiceCertsID), + Kind: controller.InputWeak, + }, + } +} + +// Outputs implements controller.Controller interface. +func (ctrl *MaintenanceServiceController) Outputs() []controller.Output { + return []controller.Output{ + { + Type: config.MachineConfigType, + Kind: controller.OutputShared, + }, + } +} + +// Run implements controller.Controller interface. +// +//nolint:gocyclo,cyclop +func (ctrl *MaintenanceServiceController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error { + var ( + server *grpc.Server + serverWg sync.WaitGroup + listener net.Listener + lastReachableAddresses []string + lastCertificateFingerprint string + usagePrinted bool + ) + + shutdownServer := func(ctx context.Context) { + if server != nil { + shutdownCtx, shutdownCancel := context.WithTimeout(ctx, 5*time.Second) + defer shutdownCancel() + + factory.ServerGracefulStop(server, shutdownCtx) + + serverWg.Wait() + + server = nil + } + + if listener != nil { + listener.Close() //nolint:errcheck + + listener = nil + lastReachableAddresses = nil + } + } + + defer shutdownServer(context.Background()) + + cfgCh := make(chan machineryconfig.Provider) + srv := maintenance.New(cfgCh) + injector := &authz.Injector{ + Mode: authz.ReadOnly, + Logger: logger.Sugar().Debugf, + } + tlsProvider := maintenance.NewTLSProvider() + + for { + select { + case <-ctx.Done(): + return nil + case cfg := <-cfgCh: + configResource := config.NewMachineConfigWithID(cfg, config.MaintenanceID) + + oldConfigResource, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.MaintenanceID) + if err != nil && !state.IsNotFoundError(err) { + return fmt.Errorf("failed to get machine config: %w", err) + } + + if state.IsNotFoundError(err) { + if err = r.Create(ctx, configResource); err != nil { + return fmt.Errorf("failed to create machine config: %w", err) + } + } else { + configResource.Metadata().SetVersion(oldConfigResource.Metadata().Version()) + + if err = configResource.Metadata().SetOwner(oldConfigResource.Metadata().Owner()); err != nil { + return fmt.Errorf("error setting owner: %w", err) + } + + if err = r.Update(ctx, configResource); err != nil { + return fmt.Errorf("failed to update machine config: %w", err) + } + } + + continue + case <-r.EventCh(): + } + + request, err := safe.ReaderGetByID[*runtime.MaintenanceServiceRequest](ctx, r, runtime.MaintenanceServiceRequestID) + if err != nil && !state.IsNotFoundError(err) { + return fmt.Errorf("failed to get maintenance service request: %w", err) + } + + if request == nil { + // no request, nothing to do + shutdownServer(ctx) + + continue + } + + if request.Metadata().Phase() == resource.PhaseTearingDown { + // stop the server & remove the finalizer + shutdownServer(ctx) + + if err = r.RemoveFinalizer(ctx, request.Metadata(), ctrl.Name()); err != nil { + return fmt.Errorf("failed to remove finalizer: %w", err) + } + + continue + } + + cfg, err := safe.ReaderGetByID[*runtime.MaintenanceServiceConfig](ctx, r, runtime.MaintenanceServiceConfigID) + if err != nil && !state.IsNotFoundError(err) { + return fmt.Errorf("failed to get maintenance service config: %w", err) + } + + cert, err := safe.ReaderGetByID[*secrets.MaintenanceServiceCerts](ctx, r, secrets.MaintenanceServiceCertsID) + if err != nil && !state.IsNotFoundError(err) { + return fmt.Errorf("failed to get maintenance service certs: %w", err) + } + + if cert != nil { + if err = tlsProvider.Update(cert); err != nil { + return fmt.Errorf("failed to update tls provider: %w", err) + } + } + + // immediately add a finalizer + if err = r.AddFinalizer(ctx, request.Metadata(), ctrl.Name()); err != nil { + return fmt.Errorf("failed to add finalizer: %w", err) + } + + if cfg == nil { + // no config, nothing to do + shutdownServer(ctx) + + continue + } + + if listener == nil { + listener, err = net.Listen("tcp", cfg.TypedSpec().ListenAddress) + if err != nil { + return fmt.Errorf("failed to listen: %w", err) + } + } + + if server == nil { + tlsConfig, err := tlsProvider.TLSConfig() + if err != nil { + return fmt.Errorf("failed to get tls config: %w", err) + } + + server = factory.NewServer( + srv, + factory.WithDefaultLog(), + factory.ServerOptions( + grpc.Creds( + credentials.NewTLS(tlsConfig), + ), + ), + + factory.WithUnaryInterceptor(injector.UnaryInterceptor()), + factory.WithStreamInterceptor(injector.StreamInterceptor()), + ) + + serverWg.Add(1) + + go func() { + defer serverWg.Done() + + //nolint:errcheck + server.Serve(listener) + }() + } + + // print additional information for the user on important state changes + reachableAddresses := slices.Map(cfg.TypedSpec().ReachableAddresses, netip.Addr.String) + + if !reflect.DeepEqual(lastReachableAddresses, reachableAddresses) { + logger.Info("this machine is reachable at:") + + for _, addr := range reachableAddresses { + logger.Info("\t" + addr) + } + + lastReachableAddresses = reachableAddresses + } + + if cert != nil { + certificateFingerprint, err := x509.SPKIFingerprintFromPEM(cert.TypedSpec().Server.Crt) + if err != nil { + return fmt.Errorf("failed to get certificate fingerprint: %w", err) + } + + fingerprint := certificateFingerprint.String() + + if fingerprint != lastCertificateFingerprint { + logger.Info("server certificate issued", zap.String("fingerprint", fingerprint)) + } + + lastCertificateFingerprint = fingerprint + } + + if !usagePrinted && len(reachableAddresses) > 0 && lastCertificateFingerprint != "" { + firstIP := reachableAddresses[0] + + logger.Sugar().Info("upload configuration using talosctl:") + logger.Sugar().Infof("\ttalosctl apply-config --insecure --nodes %s --file ", firstIP) + logger.Sugar().Info("or apply configuration using talosctl interactive installer:") + logger.Sugar().Infof("\ttalosctl apply-config --insecure --nodes %s --mode=interactive", firstIP) + logger.Sugar().Info("optionally with node fingerprint check:") + logger.Sugar().Infof("\ttalosctl apply-config --insecure --nodes %s --cert-fingerprint '%s' --file ", firstIP, lastCertificateFingerprint) + + usagePrinted = true + } + + r.ResetRestartBackoff() + } +} diff --git a/internal/app/machined/pkg/controllers/runtime/maintenance_service_test.go b/internal/app/machined/pkg/controllers/runtime/maintenance_service_test.go new file mode 100644 index 000000000..b8f975ebc --- /dev/null +++ b/internal/app/machined/pkg/controllers/runtime/maintenance_service_test.go @@ -0,0 +1,223 @@ +// 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 runtime_test + +import ( + "context" + "crypto/tls" + "net" + "net/netip" + "testing" + "time" + + "github.com/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/resource/rtestutils" + "github.com/cosi-project/runtime/pkg/state" + "github.com/cosi-project/runtime/pkg/state/registry" + "github.com/siderolabs/go-retry/retry" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + + "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" + runtimectrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime" + "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets" + talosruntime "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" + "github.com/siderolabs/talos/internal/app/maintenance" + "github.com/siderolabs/talos/pkg/machinery/client" + "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/resources/hardware" + "github.com/siderolabs/talos/pkg/machinery/resources/network" + "github.com/siderolabs/talos/pkg/machinery/resources/runtime" +) + +func TestMaintenanceServiceSuite(t *testing.T) { + suite.Run(t, &MaintenanceServiceSuite{ + DefaultSuite: ctest.DefaultSuite{ + Timeout: 5 * time.Second, + AfterSetup: func(suite *ctest.DefaultSuite) { + maintenance.InjectController(mockController{s: suite.State()}) + + suite.Require().NoError(suite.Runtime().RegisterController(&secrets.MaintenanceRootController{})) + suite.Require().NoError(suite.Runtime().RegisterController(&secrets.MaintenanceCertSANsController{})) + suite.Require().NoError(suite.Runtime().RegisterController(&secrets.MaintenanceController{})) + suite.Require().NoError(suite.Runtime().RegisterController(&runtimectrl.MaintenanceServiceController{})) + }, + }, + }) +} + +type MaintenanceServiceSuite struct { + ctest.DefaultSuite +} + +func (suite *MaintenanceServiceSuite) findListenAddr() string { + l, err := net.Listen("tcp", "127.0.0.1:0") + suite.Require().NoError(err) + + addr := l.Addr().String() + + suite.Require().NoError(l.Close()) + + return addr +} + +func (suite *MaintenanceServiceSuite) TestRunService() { + nodeAddresses := network.NewNodeAddress(network.NamespaceName, network.NodeAddressAccumulativeID) + nodeAddresses.TypedSpec().Addresses = []netip.Prefix{netip.MustParsePrefix("10.0.0.1/24")} + suite.Require().NoError(suite.State().Create(suite.Ctx(), nodeAddresses)) + + maintenanceConfig := runtime.NewMaintenanceServiceConfig() + maintenanceConfig.TypedSpec().ListenAddress = suite.findListenAddr() + maintenanceConfig.TypedSpec().ReachableAddresses = []netip.Addr{netip.MustParseAddr("10.0.0.1")} + suite.Require().NoError(suite.State().Create(suite.Ctx(), maintenanceConfig)) + + maintenanceRequest := runtime.NewMaintenanceServiceRequest() + suite.Require().NoError(suite.State().Create(suite.Ctx(), maintenanceRequest)) + + // wait for the service to be up + suite.AssertWithin(time.Second, 10*time.Millisecond, func() error { + c, err := net.Dial("tcp", maintenanceConfig.TypedSpec().ListenAddress) + + if c != nil { + c.Close() //nolint:errcheck + } + + return retry.ExpectedError(err) + }) + + // test API + mc, err := client.New(suite.Ctx(), + client.WithTLSConfig(&tls.Config{ + InsecureSkipVerify: true, + }), client.WithEndpoints(maintenanceConfig.TypedSpec().ListenAddress), + ) + suite.Require().NoError(err) + + _, err = mc.Version(suite.Ctx()) + suite.Require().ErrorContains(err, "API is not implemented in maintenance mode") + + suite.Require().NoError(mc.Close()) + + // teardown the maintenance service + _, err = suite.State().Teardown(suite.Ctx(), maintenanceRequest.Metadata()) + suite.Require().NoError(err) + + rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{runtime.MaintenanceServiceRequestID}, + func(r *runtime.MaintenanceServiceRequest, asrt *assert.Assertions) { + asrt.Empty(r.Metadata().Finalizers()) + }) + + suite.Require().NoError(suite.State().Destroy(suite.Ctx(), maintenanceRequest.Metadata())) + + _, err = net.Dial("tcp", maintenanceConfig.TypedSpec().ListenAddress) + suite.Require().ErrorContains(err, "connection refused") +} + +type mockController struct { + s state.State +} + +type mockState struct { + s state.State +} + +func (mock mockController) Runtime() talosruntime.Runtime { + return mock +} + +func (mockController) Sequencer() talosruntime.Sequencer { + return nil +} + +func (mockController) Run(context.Context, talosruntime.Sequence, any, ...talosruntime.LockOption) error { + return nil +} + +func (mockController) V1Alpha2() talosruntime.V1Alpha2Controller { + return nil +} + +func (mock mockController) Config() config.Config { + return nil +} + +func (mock mockController) ConfigContainer() config.Container { + return nil +} + +func (mock mockController) LoadAndValidateConfig([]byte) (config.Provider, error) { + return nil, nil +} + +func (mock mockController) RollbackToConfigAfter([]byte, time.Duration) error { + return nil +} + +func (mock mockController) CancelConfigRollbackTimeout() { +} + +func (mock mockController) SetConfig(config.Provider) error { + return nil +} + +func (mock mockController) CanApplyImmediate(config.Provider) error { + return nil +} + +func (mock mockController) GetSystemInformation(context.Context) (*hardware.SystemInformation, error) { + return nil, nil +} + +func (mock mockController) State() talosruntime.State { + return mockState(mock) +} + +func (mock mockController) Events() talosruntime.EventStream { + return nil +} + +func (mock mockController) Logging() talosruntime.LoggingManager { + return nil +} + +func (mock mockController) NodeName() (string, error) { + return "", nil +} + +func (mock mockController) IsBootstrapAllowed() bool { + return false +} + +func (mock mockState) Platform() talosruntime.Platform { + return nil +} + +func (mock mockState) Machine() talosruntime.MachineState { + return nil +} + +func (mock mockState) Cluster() talosruntime.ClusterState { + return nil +} + +func (mock mockState) V1Alpha2() talosruntime.V1Alpha2State { + return mock +} + +func (mock mockState) Resources() state.State { + return mock.s +} + +func (mock mockState) NamespaceRegistry() *registry.NamespaceRegistry { + return nil +} + +func (mock mockState) ResourceRegistry() *registry.ResourceRegistry { + return nil +} + +func (mock mockState) SetConfig(config.Provider) error { + return nil +} diff --git a/internal/app/machined/pkg/controllers/secrets/maintenance.go b/internal/app/machined/pkg/controllers/secrets/maintenance.go new file mode 100644 index 000000000..932ebcb70 --- /dev/null +++ b/internal/app/machined/pkg/controllers/secrets/maintenance.go @@ -0,0 +1,143 @@ +// 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 secrets + +import ( + "context" + stdlibx509 "crypto/x509" + "fmt" + "time" + + "github.com/cosi-project/runtime/pkg/controller" + "github.com/cosi-project/runtime/pkg/safe" + "github.com/cosi-project/runtime/pkg/state" + "github.com/siderolabs/crypto/x509" + "github.com/siderolabs/go-pointer" + "go.uber.org/zap" + + "github.com/siderolabs/talos/pkg/machinery/resources/secrets" + timeresource "github.com/siderolabs/talos/pkg/machinery/resources/time" + "github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1" +) + +// MaintenanceController manages secrets.MaintenanceServiceCerts. +type MaintenanceController struct{} + +// Name implements controller.Controller interface. +func (ctrl *MaintenanceController) Name() string { + return "secrets.MaintenanceController" +} + +// Inputs implements controller.Controller interface. +func (ctrl *MaintenanceController) Inputs() []controller.Input { + return []controller.Input{ + { + Namespace: secrets.NamespaceName, + Type: secrets.MaintenanceRootType, + ID: pointer.To(secrets.MaintenanceRootID), + Kind: controller.InputWeak, + }, + { + Namespace: secrets.NamespaceName, + Type: secrets.CertSANType, + ID: pointer.To(secrets.CertSANMaintenanceID), + Kind: controller.InputWeak, + }, + // time status isn't fetched, but the fact that it is in dependencies means + // that certs will be regenerated on time sync/jump (as reconcile will be triggered) + { + Namespace: v1alpha1.NamespaceName, + Type: timeresource.StatusType, + ID: pointer.To(timeresource.StatusID), + Kind: controller.InputWeak, + }, + } +} + +// Outputs implements controller.Controller interface. +func (ctrl *MaintenanceController) Outputs() []controller.Output { + return []controller.Output{ + { + Type: secrets.MaintenanceServiceCertsType, + Kind: controller.OutputExclusive, + }, + } +} + +// Run implements controller.Controller interface. +// +//nolint:gocyclo +func (ctrl *MaintenanceController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error { + refreshTicker := time.NewTicker(x509.DefaultCertificateValidityDuration / 2) + defer refreshTicker.Stop() + + for { + select { + case <-ctx.Done(): + return nil + case <-r.EventCh(): + case <-refreshTicker.C: + } + + rootSecrets, err := safe.ReaderGetByID[*secrets.MaintenanceRoot](ctx, r, secrets.MaintenanceRootID) + if err != nil { + if state.IsNotFoundError(err) { + continue + } + + return fmt.Errorf("error getting maintenance root secrets: %w", err) + } + + certSANs, err := safe.ReaderGetByID[*secrets.CertSAN](ctx, r, secrets.CertSANMaintenanceID) + if err != nil { + if state.IsNotFoundError(err) { + continue + } + + return fmt.Errorf("error getting certSANs: %w", err) + } + + ca, err := x509.NewCertificateAuthorityFromCertificateAndKey(rootSecrets.TypedSpec().CA) + if err != nil { + return fmt.Errorf("failed to parse CA certificate: %w", err) + } + + serverCert, err := x509.NewKeyPair(ca, + x509.IPAddresses(certSANs.TypedSpec().StdIPs()), + x509.DNSNames(certSANs.TypedSpec().DNSNames), + x509.CommonName(certSANs.TypedSpec().FQDN), + x509.NotAfter(time.Now().Add(x509.DefaultCertificateValidityDuration)), + x509.KeyUsage(stdlibx509.KeyUsageDigitalSignature), + x509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{ + stdlibx509.ExtKeyUsageServerAuth, + }), + ) + if err != nil { + return fmt.Errorf("failed to generate maintenance server cert: %w", err) + } + + if err = safe.WriterModify(ctx, r, secrets.NewMaintenanceServiceCerts(), + func(maintenanceSecrets *secrets.MaintenanceServiceCerts) error { + spec := maintenanceSecrets.TypedSpec() + + spec.CA = &x509.PEMEncodedCertificateAndKey{ + Crt: rootSecrets.TypedSpec().CA.Crt, + } + spec.Server = x509.NewCertificateAndKeyFromKeyPair(serverCert) + + return nil + }); err != nil { + return fmt.Errorf("error modifying resource: %w", err) + } + + serverFingerprint, _ := x509.SPKIFingerprintFromDER(serverCert.Certificate.Certificate[0]) //nolint:errcheck + + logger.Debug("generated new certificates", + zap.Stringer("server", serverFingerprint), + ) + + r.ResetRestartBackoff() + } +} diff --git a/internal/app/machined/pkg/controllers/secrets/maintenance_cert_sans.go b/internal/app/machined/pkg/controllers/secrets/maintenance_cert_sans.go new file mode 100644 index 000000000..c1f67e907 --- /dev/null +++ b/internal/app/machined/pkg/controllers/secrets/maintenance_cert_sans.go @@ -0,0 +1,111 @@ +// 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 secrets + +import ( + "context" + "fmt" + "net/netip" + + "github.com/cosi-project/runtime/pkg/controller" + "github.com/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/safe" + "github.com/cosi-project/runtime/pkg/state" + "github.com/siderolabs/go-pointer" + "go.uber.org/zap" + + "github.com/siderolabs/talos/pkg/machinery/constants" + "github.com/siderolabs/talos/pkg/machinery/resources/network" + "github.com/siderolabs/talos/pkg/machinery/resources/secrets" +) + +// MaintenanceCertSANsController manages secrets.APICertSANs based on configuration. +type MaintenanceCertSANsController struct{} + +// Name implements controller.Controller interface. +func (ctrl *MaintenanceCertSANsController) Name() string { + return "secrets.MaintenanceCertSANsController" +} + +// Inputs implements controller.Controller interface. +// +//nolint:dupl +func (ctrl *MaintenanceCertSANsController) Inputs() []controller.Input { + return []controller.Input{ + { + Namespace: network.NamespaceName, + Type: network.HostnameStatusType, + ID: pointer.To(network.HostnameID), + Kind: controller.InputWeak, + }, + { + Namespace: network.NamespaceName, + Type: network.NodeAddressType, + ID: pointer.To(network.NodeAddressAccumulativeID), + Kind: controller.InputWeak, + }, + } +} + +// Outputs implements controller.Controller interface. +func (ctrl *MaintenanceCertSANsController) Outputs() []controller.Output { + return []controller.Output{ + { + Type: secrets.CertSANType, + Kind: controller.OutputShared, + }, + } +} + +// Run implements controller.Controller interface. +// +//nolint:gocyclo +func (ctrl *MaintenanceCertSANsController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error { + for { + select { + case <-ctx.Done(): + return nil + case <-r.EventCh(): + } + + hostnameStatus, err := safe.ReaderGetByID[*network.HostnameStatus](ctx, r, network.HostnameID) + if err != nil && !state.IsNotFoundError(err) { + return fmt.Errorf("failed to get hostname status: %w", err) + } + + nodeAddresses, err := safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.NodeAddressAccumulativeID) + if err != nil { + if state.IsNotFoundError(err) { + continue + } + + return err + } + + if err = r.Modify(ctx, secrets.NewCertSAN(secrets.NamespaceName, secrets.CertSANMaintenanceID), func(r resource.Resource) error { + spec := r.(*secrets.CertSAN).TypedSpec() + + spec.Reset() + + spec.AppendIPs(nodeAddresses.TypedSpec().IPs()...) + spec.AppendIPs(netip.MustParseAddr("127.0.0.1")) + spec.AppendIPs(netip.MustParseAddr("::1")) + + if hostnameStatus != nil { + spec.AppendDNSNames(hostnameStatus.TypedSpec().DNSNames()...) + } + + spec.FQDN = constants.MaintenanceServiceCommonName + + spec.Sort() + + return nil + }); err != nil { + return err + } + + r.ResetRestartBackoff() + } +} diff --git a/internal/app/machined/pkg/controllers/secrets/maintenance_cert_sans_test.go b/internal/app/machined/pkg/controllers/secrets/maintenance_cert_sans_test.go new file mode 100644 index 000000000..41941ebfd --- /dev/null +++ b/internal/app/machined/pkg/controllers/secrets/maintenance_cert_sans_test.go @@ -0,0 +1,67 @@ +// 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 secrets_test + +import ( + "fmt" + "net/netip" + "testing" + "time" + + "github.com/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/resource/rtestutils" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + + "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" + secretsctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets" + "github.com/siderolabs/talos/pkg/machinery/constants" + "github.com/siderolabs/talos/pkg/machinery/resources/network" + "github.com/siderolabs/talos/pkg/machinery/resources/secrets" +) + +func TestMaintenanceCertSANsSuite(t *testing.T) { + suite.Run(t, &MaintenanceCertSANsSuite{ + DefaultSuite: ctest.DefaultSuite{ + Timeout: 2 * time.Second, + AfterSetup: func(suite *ctest.DefaultSuite) { + suite.Require().NoError(suite.Runtime().RegisterController(&secretsctrl.MaintenanceCertSANsController{})) + }, + }, + }) +} + +type MaintenanceCertSANsSuite struct { + ctest.DefaultSuite +} + +func (suite *MaintenanceCertSANsSuite) TestReconcile() { + nodeAddresses := network.NewNodeAddress( + network.NamespaceName, + network.NodeAddressAccumulativeID, + ) + nodeAddresses.TypedSpec().Addresses = []netip.Prefix{ + netip.MustParsePrefix("10.2.1.3/24"), + netip.MustParsePrefix("172.16.0.1/32"), + } + suite.Require().NoError(suite.State().Create(suite.Ctx(), nodeAddresses)) + + rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{secrets.CertSANMaintenanceID}, + func(certSANs *secrets.CertSAN, asrt *assert.Assertions) { + asrt.Empty(certSANs.TypedSpec().DNSNames) + asrt.Equal("[10.2.1.3 127.0.0.1 172.16.0.1 ::1]", fmt.Sprintf("%v", certSANs.TypedSpec().IPs)) + asrt.Equal(constants.MaintenanceServiceCommonName, certSANs.TypedSpec().FQDN) + }) + + hostnameStatus := network.NewHostnameStatus(network.NamespaceName, network.HostnameID) + hostnameStatus.TypedSpec().Hostname = "bar" + hostnameStatus.TypedSpec().Domainname = "some.org" + suite.Require().NoError(suite.State().Create(suite.Ctx(), hostnameStatus)) + + rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{secrets.CertSANMaintenanceID}, + func(certSANs *secrets.CertSAN, asrt *assert.Assertions) { + asrt.Equal([]string{"bar", "bar.some.org"}, certSANs.TypedSpec().DNSNames) + }) +} diff --git a/internal/app/machined/pkg/controllers/secrets/maintenance_root.go b/internal/app/machined/pkg/controllers/secrets/maintenance_root.go new file mode 100644 index 000000000..407c1e884 --- /dev/null +++ b/internal/app/machined/pkg/controllers/secrets/maintenance_root.go @@ -0,0 +1,61 @@ +// 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 secrets + +import ( + "context" + "fmt" + + "github.com/cosi-project/runtime/pkg/controller" + "github.com/cosi-project/runtime/pkg/safe" + "github.com/siderolabs/crypto/x509" + "go.uber.org/zap" + + "github.com/siderolabs/talos/pkg/machinery/resources/secrets" +) + +// MaintenanceRootController manages secrets.Root based on configuration. +type MaintenanceRootController struct{} + +// Name implements controller.Controller interface. +func (ctrl *MaintenanceRootController) Name() string { + return "secrets.MaintenanceRootController" +} + +// Inputs implements controller.Controller interface. +func (ctrl *MaintenanceRootController) Inputs() []controller.Input { + return nil +} + +// Outputs implements controller.Controller interface. +func (ctrl *MaintenanceRootController) Outputs() []controller.Output { + return []controller.Output{ + { + Type: secrets.MaintenanceRootType, + Kind: controller.OutputExclusive, + }, + } +} + +// Run implements controller.Controller interface. +func (ctrl *MaintenanceRootController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error { + // run this controller only once, as the CA never changes + select { + case <-ctx.Done(): + return nil + case <-r.EventCh(): + } + + return safe.WriterModify(ctx, r, secrets.NewMaintenanceRoot(secrets.MaintenanceRootID), func(root *secrets.MaintenanceRoot) error { + ca, err := x509.NewSelfSignedCertificateAuthority() + if err != nil { + return fmt.Errorf("failed to generate self-signed CA: %w", err) + } + + root.TypedSpec().CA = x509.NewCertificateAndKeyFromCertificateAuthority(ca) + + return nil + }) +} diff --git a/internal/app/machined/pkg/controllers/secrets/maintenance_root_test.go b/internal/app/machined/pkg/controllers/secrets/maintenance_root_test.go new file mode 100644 index 000000000..c8da66fd1 --- /dev/null +++ b/internal/app/machined/pkg/controllers/secrets/maintenance_root_test.go @@ -0,0 +1,39 @@ +// 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 secrets_test + +import ( + "testing" + + "github.com/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/resource/rtestutils" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + + "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" + secretsctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets" + "github.com/siderolabs/talos/pkg/machinery/resources/secrets" +) + +func TestMaintenanceRootSuite(t *testing.T) { + suite.Run(t, &MaintenanceRootSuite{ + DefaultSuite: ctest.DefaultSuite{ + AfterSetup: func(suite *ctest.DefaultSuite) { + suite.Require().NoError(suite.Runtime().RegisterController(&secretsctrl.MaintenanceRootController{})) + }, + }, + }) +} + +type MaintenanceRootSuite struct { + ctest.DefaultSuite +} + +func (suite *MaintenanceRootSuite) TestReconcile() { + rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{secrets.MaintenanceRootID}, + func(root *secrets.MaintenanceRoot, asrt *assert.Assertions) { + asrt.NotEmpty(root.TypedSpec().CA) + }) +} diff --git a/internal/app/machined/pkg/controllers/secrets/maintenance_test.go b/internal/app/machined/pkg/controllers/secrets/maintenance_test.go new file mode 100644 index 000000000..6f8982d23 --- /dev/null +++ b/internal/app/machined/pkg/controllers/secrets/maintenance_test.go @@ -0,0 +1,88 @@ +// 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 secrets_test + +import ( + stdlibx509 "crypto/x509" + "fmt" + "testing" + "time" + + "github.com/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/resource/rtestutils" + "github.com/siderolabs/crypto/x509" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + + "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" + secretsctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets" + "github.com/siderolabs/talos/pkg/machinery/resources/secrets" +) + +func TestMaintenanceSuite(t *testing.T) { + suite.Run(t, &MaintenanceSuite{ + DefaultSuite: ctest.DefaultSuite{ + Timeout: 2 * time.Second, + AfterSetup: func(suite *ctest.DefaultSuite) { + suite.Require().NoError(suite.Runtime().RegisterController(&secretsctrl.MaintenanceController{})) + }, + }, + }) +} + +type MaintenanceSuite struct { + ctest.DefaultSuite +} + +func (suite *MaintenanceSuite) TestReconcile() { + rootSecrets := secrets.NewMaintenanceRoot(secrets.MaintenanceRootID) + + rootCA, err := x509.NewSelfSignedCertificateAuthority( + x509.Organization("talos"), + ) + suite.Require().NoError(err) + + rootSecrets.TypedSpec().CA = &x509.PEMEncodedCertificateAndKey{ + Crt: rootCA.CrtPEM, + Key: rootCA.KeyPEM, + } + suite.Require().NoError(suite.State().Create(suite.Ctx(), rootSecrets)) + + certSANs := secrets.NewCertSAN(secrets.NamespaceName, secrets.CertSANMaintenanceID) + certSANs.TypedSpec().Append( + "example.com", + "foo", + "10.2.1.3", + ) + + certSANs.TypedSpec().FQDN = "maintenance-service" + suite.Require().NoError(suite.State().Create(suite.Ctx(), certSANs)) + + rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{secrets.MaintenanceServiceCertsID}, + func(certs *secrets.MaintenanceServiceCerts, asrt *assert.Assertions) { + spec := certs.TypedSpec() + + asrt.Equal(rootCA.CrtPEM, spec.CA.Crt) + asrt.Nil(spec.CA.Key) + + serverCert, err := spec.Server.GetCert() + asrt.NoError(err) + if err != nil { + return + } + + asrt.Equal([]string{"example.com", "foo"}, serverCert.DNSNames) + asrt.Equal("[10.2.1.3]", fmt.Sprintf("%v", serverCert.IPAddresses)) + + asrt.Equal("maintenance-service", serverCert.Subject.CommonName) + asrt.Empty(serverCert.Subject.Organization) + + asrt.Equal( + stdlibx509.KeyUsageDigitalSignature, + serverCert.KeyUsage, + ) + asrt.Equal([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageServerAuth}, serverCert.ExtKeyUsage) + }) +} 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 86168dcd1..5d26b8c2f 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go @@ -53,7 +53,6 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/system" "github.com/siderolabs/talos/internal/app/machined/pkg/system/events" "github.com/siderolabs/talos/internal/app/machined/pkg/system/services" - "github.com/siderolabs/talos/internal/app/maintenance" "github.com/siderolabs/talos/internal/pkg/console" "github.com/siderolabs/talos/internal/pkg/cri" "github.com/siderolabs/talos/internal/pkg/environment" @@ -76,6 +75,7 @@ import ( "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/kernel" metamachinery "github.com/siderolabs/talos/pkg/machinery/meta" + resourceconfig "github.com/siderolabs/talos/pkg/machinery/resources/config" resourcefiles "github.com/siderolabs/talos/pkg/machinery/resources/files" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" resourceruntime "github.com/siderolabs/talos/pkg/machinery/resources/runtime" @@ -472,7 +472,7 @@ func LoadConfig(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) { }, ) - b, e = receiveConfigViaMaintenanceService(ctx, logger, r) + b, e = receiveConfigViaMaintenanceService(ctx, r) if e != nil { return fmt.Errorf("failed to receive config via maintenance service: %w", e) } @@ -604,7 +604,8 @@ func fetchConfig(ctx context.Context, r runtime.Runtime) (out []byte, err error) return b, nil } -func receiveConfigViaMaintenanceService(ctx context.Context, logger *log.Logger, r runtime.Runtime) ([]byte, error) { +//nolint:gocyclo +func receiveConfigViaMaintenanceService(ctx context.Context, r runtime.Runtime) ([]byte, error) { // add "fake" events to signal when Talos enters and leaves maintenance mode r.Events().Publish(ctx, &machineapi.TaskEvent{ Action: machineapi.TaskEvent_START, @@ -616,28 +617,84 @@ func receiveConfigViaMaintenanceService(ctx context.Context, logger *log.Logger, Task: "runningMaintenance", }) - cfgBytes, err := maintenance.Run(ctx, logger) - if err != nil { - return nil, fmt.Errorf("maintenance service failed: %w", err) + // NOTE: this code is temporary, until the config acquisition is completely rewritten to be controller-based + // so this code looks a bit messy, as it's not conreoller-based + + // start watching for maintenance service generated machine config + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + watchCh := make(chan state.Event) + + if err := r.State().V1Alpha2().Resources().Watch(ctx, resourceconfig.NewMachineConfigWithID(nil, resourceconfig.MaintenanceID).Metadata(), watchCh); err != nil { + return nil, fmt.Errorf("failed to watch for maintenance service generated machine config: %w", err) } - provider, err := configloader.NewFromBytes(cfgBytes) - if err != nil { - return nil, fmt.Errorf("failed to create config provider: %w", err) + // consume the first watch event, it's either Destroyed (if the config is missing), or Created (if the config is there from the previous run) + select { + case ev := <-watchCh: + switch ev.Type { //nolint:exhaustive + case state.Created, state.Destroyed: + // expected + case state.Errored: + return nil, fmt.Errorf("failed to watch for maintenance service generated machine config: %w", ev.Error) + default: + return nil, fmt.Errorf("unexpected event type: %v", ev.Type) + } + case <-ctx.Done(): + return nil, ctx.Err() } - warnings, err := provider.Validate(r.State().Platform().Mode()) - for _, w := range warnings { - logger.Printf("WARNING:\n%s", w) + // create request for maintenance service + req := resourceruntime.NewMaintenanceServiceRequest() + if err := r.State().V1Alpha2().Resources().Create(ctx, req); err != nil { + return nil, fmt.Errorf("failed to create maintenance service request: %w", err) } - if err != nil { - return nil, fmt.Errorf("failed to validate config: %w", err) + // wait for an update from the maintenance service + var processedBytes []byte + +waitForConfig: + for { + select { + case ev := <-watchCh: + switch ev.Type { //nolint:exhaustive + case state.Created, state.Updated: + var err error + + configContainer := ev.Resource.(*resourceconfig.MachineConfig).Container() + + processedBytes, err = configContainer.Bytes() + if err != nil { + return nil, fmt.Errorf("failed to get machine config bytes: %w", err) + } + + // wait for v1alpha1 config to appear + // we should refactor this to do a proper check for "complete" config + if configContainer.RawV1Alpha1() != nil { + break waitForConfig + } + case state.Errored: + return nil, fmt.Errorf("failed to watch for maintenance service generated machine config: %w", ev.Error) + default: + return nil, fmt.Errorf("unexpected event type: %v", ev.Type) + } + case <-ctx.Done(): + return nil, ctx.Err() + } } - processedBytes, err := provider.Bytes() - if err != nil { - return nil, fmt.Errorf("failed to export validated config: %w", err) + // tear down and destroy the maintenance service + if _, err := r.State().V1Alpha2().Resources().Teardown(ctx, req.Metadata()); err != nil { + return nil, fmt.Errorf("failed to teardown maintenance service: %w", err) + } + + if _, err := r.State().V1Alpha2().Resources().WatchFor(ctx, req.Metadata(), state.WithFinalizerEmpty()); err != nil { + return nil, fmt.Errorf("failed to watch for teardown of maintenance service: %w", err) + } + + if err := r.State().V1Alpha2().Resources().Destroy(ctx, req.Metadata()); err != nil { + return nil, fmt.Errorf("failed to destroy maintenance service: %w", err) } return processedBytes, nil diff --git a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go index afd3a278f..414f53095 100644 --- a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go +++ b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go @@ -252,6 +252,8 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error &runtimecontrollers.KmsgLogDeliveryController{ Drainer: drainer, }, + &runtimecontrollers.MaintenanceConfigController{}, + &runtimecontrollers.MaintenanceServiceController{}, &runtimecontrollers.MachineStatusController{ V1Alpha1Events: ctrl.v1alpha1Runtime.Events(), }, @@ -265,6 +267,9 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error &secrets.KubernetesCertSANsController{}, &secrets.KubernetesDynamicCertsController{}, &secrets.KubernetesController{}, + &secrets.MaintenanceController{}, + &secrets.MaintenanceCertSANsController{}, + &secrets.MaintenanceRootController{}, &secrets.RootController{}, &secrets.TrustdController{}, &siderolink.ConfigController{ diff --git a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go index 23b958dd6..c2ef5fbab 100644 --- a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go +++ b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go @@ -177,6 +177,8 @@ func NewState() (*State, error) { &runtime.KernelParamDefaultSpec{}, &runtime.KernelParamStatus{}, &runtime.KmsgLogConfig{}, + &runtime.MaintenanceServiceConfig{}, + &runtime.MaintenanceServiceRequest{}, &runtime.MachineStatus{}, &runtime.MetaKey{}, &runtime.MountStatus{}, @@ -189,6 +191,8 @@ func NewState() (*State, error) { &secrets.Kubernetes{}, &secrets.KubernetesDynamicCerts{}, &secrets.KubernetesRoot{}, + &secrets.MaintenanceServiceCerts{}, + &secrets.MaintenanceRoot{}, &secrets.OSRoot{}, &secrets.Trustd{}, &siderolink.Config{}, diff --git a/internal/app/maintenance/controller.go b/internal/app/maintenance/controller.go new file mode 100644 index 000000000..a147a2d84 --- /dev/null +++ b/internal/app/maintenance/controller.go @@ -0,0 +1,14 @@ +// 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 maintenance + +import "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" + +var runtimeController runtime.Controller + +// InjectController is used to pass the controller into the maintenance service. +func InjectController(c runtime.Controller) { + runtimeController = c +} diff --git a/internal/app/maintenance/main.go b/internal/app/maintenance/main.go deleted file mode 100644 index 5e8bc4240..000000000 --- a/internal/app/maintenance/main.go +++ /dev/null @@ -1,245 +0,0 @@ -// 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 maintenance - -import ( - "context" - "crypto/tls" - "fmt" - "log" - "net" - "net/netip" - "time" - - "github.com/cosi-project/runtime/pkg/resource" - "github.com/cosi-project/runtime/pkg/state" - ttls "github.com/siderolabs/crypto/tls" - "github.com/siderolabs/crypto/x509" - "github.com/siderolabs/gen/slices" - "github.com/siderolabs/gen/value" - "github.com/siderolabs/go-procfs/procfs" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - - "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" - "github.com/siderolabs/talos/internal/app/maintenance/server" - "github.com/siderolabs/talos/pkg/grpc/factory" - "github.com/siderolabs/talos/pkg/grpc/gen" - "github.com/siderolabs/talos/pkg/grpc/middleware/authz" - "github.com/siderolabs/talos/pkg/machinery/constants" - "github.com/siderolabs/talos/pkg/machinery/resources/network" -) - -var ctrl runtime.Controller - -// InjectController is used to pass the controller into the maintenance service. -func InjectController(c runtime.Controller) { - ctrl = c -} - -// Run executes the configuration receiver, returning any configuration it receives. -// -//nolint:gocyclo -func Run(ctx context.Context, logger *log.Logger) ([]byte, error) { - if ctrl == nil { - return nil, fmt.Errorf("controller is not injected") - } - - logger.Println("waiting for network address to be ready") - - if err := network.NewReadyCondition(ctrl.Runtime().State().V1Alpha2().Resources(), network.AddressReady).Wait(ctx); err != nil { - return nil, fmt.Errorf("error waiting for the network to be ready: %w", err) - } - - var sideroLinkAddress netip.Addr - - currentAddresses, err := ctrl.Runtime().State().V1Alpha2().Resources().WatchFor(ctx, - resource.NewMetadata(network.NamespaceName, network.NodeAddressType, network.NodeAddressCurrentID, resource.VersionUndefined), - sideroLinkAddressFinder(&sideroLinkAddress, logger), - ) - if err != nil { - return nil, fmt.Errorf("error getting node addresses: %w", err) - } - - ips := currentAddresses.(*network.NodeAddress).TypedSpec().IPs() - - // hostname might not be available yet, so use it only if it is available - hostnameStatus, err := ctrl.Runtime().State().V1Alpha2().Resources().Get(ctx, resource.NewMetadata(network.NamespaceName, network.HostnameStatusType, network.HostnameID, resource.VersionUndefined)) - if err != nil && !state.IsNotFoundError(err) { - return nil, fmt.Errorf("error getting node hostname: %w", err) - } - - var dnsNames []string - - if hostnameStatus != nil { - dnsNames = hostnameStatus.(*network.HostnameStatus).TypedSpec().DNSNames() - } - - tlsConfig, provider, err := genTLSConfig(ips, dnsNames) - if err != nil { - return nil, err - } - - cert, err := provider.GetCertificate(nil) - if err != nil { - return nil, err - } - - certFingerprint, err := x509.SPKIFingerprintFromDER(cert.Certificate[0]) - if err != nil { - return nil, err - } - - cfgCh := make(chan []byte) - - s := server.New(ctrl, logger, cfgCh) - - injector := &authz.Injector{ - Mode: authz.ReadOnly, - Logger: log.New(logger.Writer(), "machined/authz/injector ", log.Flags()).Printf, - } - - // Start the server. - server := factory.NewServer( - s, - factory.WithDefaultLog(), - factory.ServerOptions( - grpc.Creds( - credentials.NewTLS(tlsConfig), - ), - ), - - factory.WithUnaryInterceptor(injector.UnaryInterceptor()), - factory.WithStreamInterceptor(injector.StreamInterceptor()), - ) - - listener, err := factory.NewListener(factory.Address(formatIP(sideroLinkAddress)), factory.Port(constants.ApidPort)) - if err != nil { - return nil, err - } - - defer func() { - shutdownCtx, shutdownCancel := context.WithTimeout(ctx, 5*time.Second) - defer shutdownCancel() - - factory.ServerGracefulStop(server, shutdownCtx) - }() - - go func() { - //nolint:errcheck - server.Serve(listener) - }() - - if !value.IsZero(sideroLinkAddress) { - ips = []netip.Addr{sideroLinkAddress} - } - - logger.Println("this machine is reachable at:") - - for _, ip := range ips { - logger.Printf("\t%s", ip.String()) - } - - firstIP := "" - - if len(ips) > 0 { - firstIP = ips[0].String() - } - - logger.Println("server certificate fingerprint:") - logger.Printf("\t%s", certFingerprint) - - logger.Println() - logger.Println("upload configuration using talosctl:") - logger.Printf("\ttalosctl apply-config --insecure --nodes %s --file ", firstIP) - logger.Println("or apply configuration using talosctl interactive installer:") - logger.Printf("\ttalosctl apply-config --insecure --nodes %s --mode=interactive", firstIP) - logger.Println("optionally with node fingerprint check:") - logger.Printf("\ttalosctl apply-config --insecure --nodes %s --cert-fingerprint '%s' --file ", firstIP, certFingerprint) - - select { - case cfg := <-cfgCh: - return cfg, nil - case <-ctx.Done(): - return nil, ctx.Err() - } -} - -func formatIP(addr netip.Addr) string { - if value.IsZero(addr) { - return "" - } - - return addr.String() -} - -func genTLSConfig(ips []netip.Addr, dnsNames []string) (tlsConfig *tls.Config, provider ttls.CertificateProvider, err error) { - ca, err := x509.NewSelfSignedCertificateAuthority() - if err != nil { - return nil, nil, fmt.Errorf("failed to generate self-signed CA: %w", err) - } - - ips = append(ips, netip.MustParseAddr("127.0.0.1"), netip.MustParseAddr("::1")) - - netIPs := slices.Map(ips, func(ip netip.Addr) net.IP { return ip.AsSlice() }) - - var generator ttls.Generator - - generator, err = gen.NewLocalGenerator(ca.KeyPEM, ca.CrtPEM) - if err != nil { - return nil, nil, fmt.Errorf("failed to create local generator provider: %w", err) - } - - provider, err = ttls.NewRenewingCertificateProvider(generator, x509.DNSNames(dnsNames), x509.IPAddresses(netIPs)) - if err != nil { - return nil, nil, fmt.Errorf("failed to create local certificate provider: %w", err) - } - - caCertPEM, err := provider.GetCA() - if err != nil { - return nil, nil, fmt.Errorf("failed to get CA: %w", err) - } - - tlsConfig, err = ttls.New( - ttls.WithClientAuthType(ttls.ServerOnly), - ttls.WithCACertPEM(caCertPEM), - ttls.WithServerCertificateProvider(provider), - ) - if err != nil { - return nil, nil, fmt.Errorf("failed to generate tlsconfig: %w", err) - } - - return tlsConfig, provider, nil -} - -func sideroLinkAddressFinder(address *netip.Addr, logger *log.Logger) state.WatchForConditionFunc { - sideroLinkEnabled := false - if procfs.ProcCmdline().Get(constants.KernelParamSideroLink).First() != nil { - sideroLinkEnabled = true - - logger.Println(constants.KernelParamSideroLink + " is enabled, waiting for address") - } - - return state.WithCondition(func(r resource.Resource) (bool, error) { - if resource.IsTombstone(r) { - return false, nil - } - - if !sideroLinkEnabled { - return true, nil - } - - ips := r.(*network.NodeAddress).TypedSpec().IPs() - for _, ip := range ips { - if network.IsULA(ip, network.ULASideroLink) { - *address = ip - - return true, nil - } - } - - return false, nil - }) -} diff --git a/internal/app/maintenance/server/peer.go b/internal/app/maintenance/peer.go similarity index 98% rename from internal/app/maintenance/server/peer.go rename to internal/app/maintenance/peer.go index 7659ec6f3..94a0dc931 100644 --- a/internal/app/maintenance/server/peer.go +++ b/internal/app/maintenance/peer.go @@ -2,7 +2,7 @@ // 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 server +package maintenance import ( "context" diff --git a/internal/app/maintenance/provider.go b/internal/app/maintenance/provider.go new file mode 100644 index 000000000..a4fb2062c --- /dev/null +++ b/internal/app/maintenance/provider.go @@ -0,0 +1,62 @@ +// 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 maintenance + +import ( + stdlibtls "crypto/tls" + "fmt" + "sync/atomic" + + "github.com/siderolabs/crypto/tls" + + "github.com/siderolabs/talos/pkg/machinery/resources/secrets" +) + +// NewTLSProvider creates a new TLS provider for maintenance service. +// +// The provider expects that the certificates are pushed to it. +func NewTLSProvider() *TLSProvider { + return &TLSProvider{} +} + +// TLSProvider provides TLS configuration for maintenance service. +type TLSProvider struct { + serverCert atomic.Pointer[stdlibtls.Certificate] +} + +// TLSConfig generates server-side tls.Config. +func (provider *TLSProvider) TLSConfig() (*stdlibtls.Config, error) { + return tls.New( + tls.WithClientAuthType(tls.ServerOnly), + tls.WithServerCertificateProvider(provider), + ) +} + +// Update the certificate in the provider. +func (provider *TLSProvider) Update(maintenanceCerts *secrets.MaintenanceServiceCerts) error { + serverCert, err := stdlibtls.X509KeyPair(maintenanceCerts.TypedSpec().Server.Crt, maintenanceCerts.TypedSpec().Server.Key) + if err != nil { + return fmt.Errorf("failed to parse server cert and key into a TLS Certificate: %w", err) + } + + provider.serverCert.Store(&serverCert) + + return nil +} + +// GetCA implements tls.CertificateProvider interface. +func (provider *TLSProvider) GetCA() ([]byte, error) { + return nil, nil +} + +// GetCertificate implements tls.CertificateProvider interface. +func (provider *TLSProvider) GetCertificate(h *stdlibtls.ClientHelloInfo) (*stdlibtls.Certificate, error) { + return provider.serverCert.Load(), nil +} + +// GetClientCertificate implements tls.CertificateProvider interface. +func (provider *TLSProvider) GetClientCertificate(*stdlibtls.CertificateRequestInfo) (*stdlibtls.Certificate, error) { + return nil, nil +} diff --git a/internal/app/maintenance/server/server.go b/internal/app/maintenance/server.go similarity index 96% rename from internal/app/maintenance/server/server.go rename to internal/app/maintenance/server.go index ae1d3f9dd..223a5168a 100644 --- a/internal/app/maintenance/server/server.go +++ b/internal/app/maintenance/server.go @@ -2,7 +2,7 @@ // 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 server +package maintenance import ( "context" @@ -27,6 +27,7 @@ import ( "github.com/siderolabs/talos/internal/pkg/configuration" "github.com/siderolabs/talos/pkg/machinery/api/machine" "github.com/siderolabs/talos/pkg/machinery/api/storage" + "github.com/siderolabs/talos/pkg/machinery/config" "github.com/siderolabs/talos/pkg/machinery/config/configloader" v1alpha1machine "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" @@ -38,16 +39,18 @@ type Server struct { machine.UnimplementedMachineServiceServer controller runtime.Controller - logger *log.Logger - cfgCh chan<- []byte + cfgCh chan<- config.Provider server *grpc.Server } // New initializes and returns a `Server`. -func New(c runtime.Controller, logger *log.Logger, cfgCh chan<- []byte) *Server { +func New(cfgCh chan<- config.Provider) *Server { + if runtimeController == nil { + panic("runtime controller is not set") + } + return &Server{ - controller: c, - logger: logger, + controller: runtimeController, cfgCh: cfgCh, } } @@ -104,7 +107,7 @@ Node is running in maintenance mode and does not have a config yet.` return reply, nil } - s.cfgCh <- in.GetData() + s.cfgCh <- cfgProvider return reply, nil } diff --git a/pkg/machinery/api/resource/definitions/runtime/runtime.pb.go b/pkg/machinery/api/resource/definitions/runtime/runtime.pb.go index ec162eca2..c66307b03 100644 --- a/pkg/machinery/api/resource/definitions/runtime/runtime.pb.go +++ b/pkg/machinery/api/resource/definitions/runtime/runtime.pb.go @@ -456,6 +456,62 @@ func (x *MachineStatusStatus) GetUnmetConditions() []*UnmetCondition { return nil } +// MaintenanceServiceConfigSpec describes configuration for maintenance service API. +type MaintenanceServiceConfigSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ListenAddress string `protobuf:"bytes,1,opt,name=listen_address,json=listenAddress,proto3" json:"listen_address,omitempty"` + ReachableAddresses []*common.NetIP `protobuf:"bytes,2,rep,name=reachable_addresses,json=reachableAddresses,proto3" json:"reachable_addresses,omitempty"` +} + +func (x *MaintenanceServiceConfigSpec) Reset() { + *x = MaintenanceServiceConfigSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MaintenanceServiceConfigSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MaintenanceServiceConfigSpec) ProtoMessage() {} + +func (x *MaintenanceServiceConfigSpec) ProtoReflect() protoreflect.Message { + mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MaintenanceServiceConfigSpec.ProtoReflect.Descriptor instead. +func (*MaintenanceServiceConfigSpec) Descriptor() ([]byte, []int) { + return file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{8} +} + +func (x *MaintenanceServiceConfigSpec) GetListenAddress() string { + if x != nil { + return x.ListenAddress + } + return "" +} + +func (x *MaintenanceServiceConfigSpec) GetReachableAddresses() []*common.NetIP { + if x != nil { + return x.ReachableAddresses + } + return nil +} + // MetaKeySpec describes status of the defined sysctls. type MetaKeySpec struct { state protoimpl.MessageState @@ -468,7 +524,7 @@ type MetaKeySpec struct { func (x *MetaKeySpec) Reset() { *x = MetaKeySpec{} if protoimpl.UnsafeEnabled { - mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[8] + mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -481,7 +537,7 @@ func (x *MetaKeySpec) String() string { func (*MetaKeySpec) ProtoMessage() {} func (x *MetaKeySpec) ProtoReflect() protoreflect.Message { - mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[8] + mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -494,7 +550,7 @@ func (x *MetaKeySpec) ProtoReflect() protoreflect.Message { // Deprecated: Use MetaKeySpec.ProtoReflect.Descriptor instead. func (*MetaKeySpec) Descriptor() ([]byte, []int) { - return file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{8} + return file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{9} } func (x *MetaKeySpec) GetValue() string { @@ -520,7 +576,7 @@ type MountStatusSpec struct { func (x *MountStatusSpec) Reset() { *x = MountStatusSpec{} if protoimpl.UnsafeEnabled { - mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[9] + mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -533,7 +589,7 @@ func (x *MountStatusSpec) String() string { func (*MountStatusSpec) ProtoMessage() {} func (x *MountStatusSpec) ProtoReflect() protoreflect.Message { - mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[9] + mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -546,7 +602,7 @@ func (x *MountStatusSpec) ProtoReflect() protoreflect.Message { // Deprecated: Use MountStatusSpec.ProtoReflect.Descriptor instead. func (*MountStatusSpec) Descriptor() ([]byte, []int) { - return file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{9} + return file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{10} } func (x *MountStatusSpec) GetSource() string { @@ -603,7 +659,7 @@ type PlatformMetadataSpec struct { func (x *PlatformMetadataSpec) Reset() { *x = PlatformMetadataSpec{} if protoimpl.UnsafeEnabled { - mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[10] + mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -616,7 +672,7 @@ func (x *PlatformMetadataSpec) String() string { func (*PlatformMetadataSpec) ProtoMessage() {} func (x *PlatformMetadataSpec) ProtoReflect() protoreflect.Message { - mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[10] + mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -629,7 +685,7 @@ func (x *PlatformMetadataSpec) ProtoReflect() protoreflect.Message { // Deprecated: Use PlatformMetadataSpec.ProtoReflect.Descriptor instead. func (*PlatformMetadataSpec) Descriptor() ([]byte, []int) { - return file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{10} + return file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{11} } func (x *PlatformMetadataSpec) GetPlatform() string { @@ -701,7 +757,7 @@ type UnmetCondition struct { func (x *UnmetCondition) Reset() { *x = UnmetCondition{} if protoimpl.UnsafeEnabled { - mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[11] + mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -714,7 +770,7 @@ func (x *UnmetCondition) String() string { func (*UnmetCondition) ProtoMessage() {} func (x *UnmetCondition) ProtoReflect() protoreflect.Message { - mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[11] + mi := &file_resource_definitions_runtime_runtime_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -727,7 +783,7 @@ func (x *UnmetCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use UnmetCondition.ProtoReflect.Descriptor instead. func (*UnmetCondition) Descriptor() ([]byte, []int) { - return file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{11} + return file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{12} } func (x *UnmetCondition) GetName() string { @@ -803,44 +859,52 @@ var file_resource_definitions_runtime_runtime_proto_rawDesc = []byte{ 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x55, 0x6e, 0x6d, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x75, 0x6e, 0x6d, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, - 0x23, 0x0a, 0x0b, 0x4d, 0x65, 0x74, 0x61, 0x4b, 0x65, 0x79, 0x53, 0x70, 0x65, 0x63, 0x12, 0x14, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x22, 0xa2, 0x01, 0x0a, 0x0f, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x53, 0x70, 0x65, 0x63, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x66, 0x69, 0x6c, 0x65, - 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x65, - 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, - 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x22, 0xf5, 0x01, 0x0a, 0x14, 0x50, 0x6c, - 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x53, 0x70, - 0x65, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1a, - 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, - 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, - 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x7a, 0x6f, 0x6e, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, - 0x04, 0x73, 0x70, 0x6f, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x73, 0x70, 0x6f, - 0x74, 0x22, 0x3c, 0x0a, 0x0e, 0x55, 0x6e, 0x6d, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x42, - 0x4c, 0x5a, 0x4a, 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, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x85, 0x01, 0x0a, 0x1c, 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, 0x65, 0x63, + 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3e, 0x0a, 0x13, 0x72, 0x65, 0x61, 0x63, 0x68, + 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4e, 0x65, + 0x74, 0x49, 0x50, 0x52, 0x12, 0x72, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x23, 0x0a, 0x0b, 0x4d, 0x65, 0x74, 0x61, 0x4b, + 0x65, 0x79, 0x53, 0x70, 0x65, 0x63, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xa2, 0x01, 0x0a, + 0x0f, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x53, 0x70, 0x65, 0x63, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x12, 0x27, 0x0a, 0x0f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x66, 0x69, 0x6c, 0x65, 0x73, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, + 0x64, 0x22, 0xf5, 0x01, 0x0a, 0x14, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x53, 0x70, 0x65, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x7a, 0x6f, + 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x7a, 0x6f, 0x6e, 0x65, 0x12, 0x23, + 0x0a, 0x0d, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x70, 0x6f, 0x74, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x04, 0x73, 0x70, 0x6f, 0x74, 0x22, 0x3c, 0x0a, 0x0e, 0x55, 0x6e, 0x6d, + 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x42, 0x4c, 0x5a, 0x4a, 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, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -855,33 +919,36 @@ func file_resource_definitions_runtime_runtime_proto_rawDescGZIP() []byte { return file_resource_definitions_runtime_runtime_proto_rawDescData } -var file_resource_definitions_runtime_runtime_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_resource_definitions_runtime_runtime_proto_msgTypes = make([]protoimpl.MessageInfo, 13) var file_resource_definitions_runtime_runtime_proto_goTypes = []interface{}{ - (*DevicesStatusSpec)(nil), // 0: talos.resource.definitions.runtime.DevicesStatusSpec - (*EventSinkConfigSpec)(nil), // 1: talos.resource.definitions.runtime.EventSinkConfigSpec - (*KernelModuleSpecSpec)(nil), // 2: talos.resource.definitions.runtime.KernelModuleSpecSpec - (*KernelParamSpecSpec)(nil), // 3: talos.resource.definitions.runtime.KernelParamSpecSpec - (*KernelParamStatusSpec)(nil), // 4: talos.resource.definitions.runtime.KernelParamStatusSpec - (*KmsgLogConfigSpec)(nil), // 5: talos.resource.definitions.runtime.KmsgLogConfigSpec - (*MachineStatusSpec)(nil), // 6: talos.resource.definitions.runtime.MachineStatusSpec - (*MachineStatusStatus)(nil), // 7: talos.resource.definitions.runtime.MachineStatusStatus - (*MetaKeySpec)(nil), // 8: talos.resource.definitions.runtime.MetaKeySpec - (*MountStatusSpec)(nil), // 9: talos.resource.definitions.runtime.MountStatusSpec - (*PlatformMetadataSpec)(nil), // 10: talos.resource.definitions.runtime.PlatformMetadataSpec - (*UnmetCondition)(nil), // 11: talos.resource.definitions.runtime.UnmetCondition - (*common.URL)(nil), // 12: common.URL - (enums.RuntimeMachineStage)(0), // 13: talos.resource.definitions.enums.RuntimeMachineStage + (*DevicesStatusSpec)(nil), // 0: talos.resource.definitions.runtime.DevicesStatusSpec + (*EventSinkConfigSpec)(nil), // 1: talos.resource.definitions.runtime.EventSinkConfigSpec + (*KernelModuleSpecSpec)(nil), // 2: talos.resource.definitions.runtime.KernelModuleSpecSpec + (*KernelParamSpecSpec)(nil), // 3: talos.resource.definitions.runtime.KernelParamSpecSpec + (*KernelParamStatusSpec)(nil), // 4: talos.resource.definitions.runtime.KernelParamStatusSpec + (*KmsgLogConfigSpec)(nil), // 5: talos.resource.definitions.runtime.KmsgLogConfigSpec + (*MachineStatusSpec)(nil), // 6: talos.resource.definitions.runtime.MachineStatusSpec + (*MachineStatusStatus)(nil), // 7: talos.resource.definitions.runtime.MachineStatusStatus + (*MaintenanceServiceConfigSpec)(nil), // 8: talos.resource.definitions.runtime.MaintenanceServiceConfigSpec + (*MetaKeySpec)(nil), // 9: talos.resource.definitions.runtime.MetaKeySpec + (*MountStatusSpec)(nil), // 10: talos.resource.definitions.runtime.MountStatusSpec + (*PlatformMetadataSpec)(nil), // 11: talos.resource.definitions.runtime.PlatformMetadataSpec + (*UnmetCondition)(nil), // 12: talos.resource.definitions.runtime.UnmetCondition + (*common.URL)(nil), // 13: common.URL + (enums.RuntimeMachineStage)(0), // 14: talos.resource.definitions.enums.RuntimeMachineStage + (*common.NetIP)(nil), // 15: common.NetIP } var file_resource_definitions_runtime_runtime_proto_depIdxs = []int32{ - 12, // 0: talos.resource.definitions.runtime.KmsgLogConfigSpec.destinations:type_name -> common.URL - 13, // 1: talos.resource.definitions.runtime.MachineStatusSpec.stage:type_name -> talos.resource.definitions.enums.RuntimeMachineStage + 13, // 0: talos.resource.definitions.runtime.KmsgLogConfigSpec.destinations:type_name -> common.URL + 14, // 1: talos.resource.definitions.runtime.MachineStatusSpec.stage:type_name -> talos.resource.definitions.enums.RuntimeMachineStage 7, // 2: talos.resource.definitions.runtime.MachineStatusSpec.status:type_name -> talos.resource.definitions.runtime.MachineStatusStatus - 11, // 3: talos.resource.definitions.runtime.MachineStatusStatus.unmet_conditions:type_name -> talos.resource.definitions.runtime.UnmetCondition - 4, // [4:4] is the sub-list for method output_type - 4, // [4:4] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name + 12, // 3: talos.resource.definitions.runtime.MachineStatusStatus.unmet_conditions:type_name -> talos.resource.definitions.runtime.UnmetCondition + 15, // 4: talos.resource.definitions.runtime.MaintenanceServiceConfigSpec.reachable_addresses:type_name -> common.NetIP + 5, // [5:5] is the sub-list for method output_type + 5, // [5:5] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name } func init() { file_resource_definitions_runtime_runtime_proto_init() } @@ -987,7 +1054,7 @@ func file_resource_definitions_runtime_runtime_proto_init() { } } file_resource_definitions_runtime_runtime_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MetaKeySpec); i { + switch v := v.(*MaintenanceServiceConfigSpec); i { case 0: return &v.state case 1: @@ -999,7 +1066,7 @@ func file_resource_definitions_runtime_runtime_proto_init() { } } file_resource_definitions_runtime_runtime_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MountStatusSpec); i { + switch v := v.(*MetaKeySpec); i { case 0: return &v.state case 1: @@ -1011,7 +1078,7 @@ func file_resource_definitions_runtime_runtime_proto_init() { } } file_resource_definitions_runtime_runtime_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PlatformMetadataSpec); i { + switch v := v.(*MountStatusSpec); i { case 0: return &v.state case 1: @@ -1023,6 +1090,18 @@ func file_resource_definitions_runtime_runtime_proto_init() { } } file_resource_definitions_runtime_runtime_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PlatformMetadataSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_resource_definitions_runtime_runtime_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*UnmetCondition); i { case 0: return &v.state @@ -1041,7 +1120,7 @@ func file_resource_definitions_runtime_runtime_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_resource_definitions_runtime_runtime_proto_rawDesc, NumEnums: 0, - NumMessages: 12, + NumMessages: 13, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/machinery/api/resource/definitions/runtime/runtime_vtproto.pb.go b/pkg/machinery/api/resource/definitions/runtime/runtime_vtproto.pb.go index 6f767de48..384464538 100644 --- a/pkg/machinery/api/resource/definitions/runtime/runtime_vtproto.pb.go +++ b/pkg/machinery/api/resource/definitions/runtime/runtime_vtproto.pb.go @@ -422,6 +422,70 @@ func (m *MachineStatusStatus) MarshalToSizedBufferVT(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *MaintenanceServiceConfigSpec) 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 *MaintenanceServiceConfigSpec) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *MaintenanceServiceConfigSpec) 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.ReachableAddresses) > 0 { + for iNdEx := len(m.ReachableAddresses) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.ReachableAddresses[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.ReachableAddresses[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = encodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.ListenAddress) > 0 { + i -= len(m.ListenAddress) + copy(dAtA[i:], m.ListenAddress) + i = encodeVarint(dAtA, i, uint64(len(m.ListenAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *MetaKeySpec) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil @@ -828,6 +892,32 @@ func (m *MachineStatusStatus) SizeVT() (n int) { return n } +func (m *MaintenanceServiceConfigSpec) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ListenAddress) + if l > 0 { + n += 1 + l + sov(uint64(l)) + } + if len(m.ReachableAddresses) > 0 { + for _, e := range m.ReachableAddresses { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + sov(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + func (m *MetaKeySpec) SizeVT() (n int) { if m == nil { return 0 @@ -1749,6 +1839,131 @@ func (m *MachineStatusStatus) UnmarshalVT(dAtA []byte) error { } return nil } +func (m *MaintenanceServiceConfigSpec) 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 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: MaintenanceServiceConfigSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MaintenanceServiceConfigSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ListenAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 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 ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ListenAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReachableAddresses", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ReachableAddresses = append(m.ReachableAddresses, &common.NetIP{}) + if unmarshal, ok := interface{}(m.ReachableAddresses[len(m.ReachableAddresses)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ReachableAddresses[len(m.ReachableAddresses)-1]); err != nil { + return err + } + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return 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 *MetaKeySpec) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/pkg/machinery/api/resource/definitions/secrets/secrets.pb.go b/pkg/machinery/api/resource/definitions/secrets/secrets.pb.go index de3cdedd0..48d9d7665 100644 --- a/pkg/machinery/api/resource/definitions/secrets/secrets.pb.go +++ b/pkg/machinery/api/resource/definitions/secrets/secrets.pb.go @@ -623,6 +623,110 @@ func (x *KubernetesRootSpec) GetApiServerIps() []*common.NetIP { return nil } +// MaintenanceRootSpec describes maintenance service CA. +type MaintenanceRootSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ca *common.PEMEncodedCertificateAndKey `protobuf:"bytes,1,opt,name=ca,proto3" json:"ca,omitempty"` +} + +func (x *MaintenanceRootSpec) Reset() { + *x = MaintenanceRootSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MaintenanceRootSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MaintenanceRootSpec) ProtoMessage() {} + +func (x *MaintenanceRootSpec) ProtoReflect() protoreflect.Message { + mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MaintenanceRootSpec.ProtoReflect.Descriptor instead. +func (*MaintenanceRootSpec) Descriptor() ([]byte, []int) { + return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{8} +} + +func (x *MaintenanceRootSpec) GetCa() *common.PEMEncodedCertificateAndKey { + if x != nil { + return x.Ca + } + return nil +} + +// MaintenanceServiceCertsSpec describes maintenance service certs secrets. +type MaintenanceServiceCertsSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ca *common.PEMEncodedCertificateAndKey `protobuf:"bytes,1,opt,name=ca,proto3" json:"ca,omitempty"` + Server *common.PEMEncodedCertificateAndKey `protobuf:"bytes,2,opt,name=server,proto3" json:"server,omitempty"` +} + +func (x *MaintenanceServiceCertsSpec) Reset() { + *x = MaintenanceServiceCertsSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MaintenanceServiceCertsSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MaintenanceServiceCertsSpec) ProtoMessage() {} + +func (x *MaintenanceServiceCertsSpec) ProtoReflect() protoreflect.Message { + mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MaintenanceServiceCertsSpec.ProtoReflect.Descriptor instead. +func (*MaintenanceServiceCertsSpec) Descriptor() ([]byte, []int) { + return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{9} +} + +func (x *MaintenanceServiceCertsSpec) GetCa() *common.PEMEncodedCertificateAndKey { + if x != nil { + return x.Ca + } + return nil +} + +func (x *MaintenanceServiceCertsSpec) GetServer() *common.PEMEncodedCertificateAndKey { + if x != nil { + return x.Server + } + return nil +} + // OSRootSpec describes operating system CA. type OSRootSpec struct { state protoimpl.MessageState @@ -638,7 +742,7 @@ type OSRootSpec struct { func (x *OSRootSpec) Reset() { *x = OSRootSpec{} if protoimpl.UnsafeEnabled { - mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[8] + mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -651,7 +755,7 @@ func (x *OSRootSpec) String() string { func (*OSRootSpec) ProtoMessage() {} func (x *OSRootSpec) ProtoReflect() protoreflect.Message { - mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[8] + mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -664,7 +768,7 @@ func (x *OSRootSpec) ProtoReflect() protoreflect.Message { // Deprecated: Use OSRootSpec.ProtoReflect.Descriptor instead. func (*OSRootSpec) Descriptor() ([]byte, []int) { - return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{8} + return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{10} } func (x *OSRootSpec) GetCa() *common.PEMEncodedCertificateAndKey { @@ -708,7 +812,7 @@ type TrustdCertsSpec struct { func (x *TrustdCertsSpec) Reset() { *x = TrustdCertsSpec{} if protoimpl.UnsafeEnabled { - mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[9] + mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -721,7 +825,7 @@ func (x *TrustdCertsSpec) String() string { func (*TrustdCertsSpec) ProtoMessage() {} func (x *TrustdCertsSpec) ProtoReflect() protoreflect.Message { - mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[9] + mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -734,7 +838,7 @@ func (x *TrustdCertsSpec) ProtoReflect() protoreflect.Message { // Deprecated: Use TrustdCertsSpec.ProtoReflect.Descriptor instead. func (*TrustdCertsSpec) Descriptor() ([]byte, []int) { - return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{9} + return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{11} } func (x *TrustdCertsSpec) GetCa() *common.PEMEncodedCertificateAndKey { @@ -887,32 +991,46 @@ var file_resource_definitions_secrets_secrets_proto_rawDesc = []byte{ 0x6f, 0x6e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x33, 0x0a, 0x0e, 0x61, 0x70, 0x69, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x70, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x50, 0x52, - 0x0c, 0x61, 0x70, 0x69, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x70, 0x73, 0x22, 0xb4, 0x01, - 0x0a, 0x0a, 0x4f, 0x53, 0x52, 0x6f, 0x6f, 0x74, 0x53, 0x70, 0x65, 0x63, 0x12, 0x33, 0x0a, 0x02, - 0x63, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x50, 0x45, 0x4d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x6e, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x02, 0x63, - 0x61, 0x12, 0x2f, 0x0a, 0x0c, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x73, 0x61, 0x6e, 0x69, 0x5f, 0x70, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x50, 0x52, 0x0a, 0x63, 0x65, 0x72, 0x74, 0x53, 0x61, 0x6e, 0x69, - 0x50, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x73, 0x61, 0x6e, 0x64, 0x6e, - 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x63, - 0x65, 0x72, 0x74, 0x53, 0x61, 0x6e, 0x64, 0x6e, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x14, - 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x83, 0x01, 0x0a, 0x0f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x64, 0x43, - 0x65, 0x72, 0x74, 0x73, 0x53, 0x70, 0x65, 0x63, 0x12, 0x33, 0x0a, 0x02, 0x63, 0x61, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x45, - 0x4d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x41, 0x6e, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x02, 0x63, 0x61, 0x12, 0x3b, 0x0a, - 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x45, 0x4d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, - 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x6e, 0x64, 0x4b, - 0x65, 0x79, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x4c, 0x5a, 0x4a, 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, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x0c, 0x61, 0x70, 0x69, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x70, 0x73, 0x22, 0x4a, 0x0a, + 0x13, 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x6f, 0x6f, 0x74, + 0x53, 0x70, 0x65, 0x63, 0x12, 0x33, 0x0a, 0x02, 0x63, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x45, 0x4d, 0x45, 0x6e, 0x63, + 0x6f, 0x64, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, + 0x6e, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x02, 0x63, 0x61, 0x22, 0x8f, 0x01, 0x0a, 0x1b, 0x4d, 0x61, + 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x43, 0x65, 0x72, 0x74, 0x73, 0x53, 0x70, 0x65, 0x63, 0x12, 0x33, 0x0a, 0x02, 0x63, 0x61, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, + 0x45, 0x4d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x41, 0x6e, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x02, 0x63, 0x61, 0x12, 0x3b, + 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x45, 0x4d, 0x45, 0x6e, 0x63, 0x6f, 0x64, + 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x6e, 0x64, + 0x4b, 0x65, 0x79, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0xb4, 0x01, 0x0a, 0x0a, + 0x4f, 0x53, 0x52, 0x6f, 0x6f, 0x74, 0x53, 0x70, 0x65, 0x63, 0x12, 0x33, 0x0a, 0x02, 0x63, 0x61, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x50, 0x45, 0x4d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x6e, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x02, 0x63, 0x61, 0x12, + 0x2f, 0x0a, 0x0c, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x73, 0x61, 0x6e, 0x69, 0x5f, 0x70, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4e, + 0x65, 0x74, 0x49, 0x50, 0x52, 0x0a, 0x63, 0x65, 0x72, 0x74, 0x53, 0x61, 0x6e, 0x69, 0x50, 0x73, + 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x73, 0x61, 0x6e, 0x64, 0x6e, 0x73, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x65, 0x72, + 0x74, 0x53, 0x61, 0x6e, 0x64, 0x6e, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x22, 0x83, 0x01, 0x0a, 0x0f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x64, 0x43, 0x65, 0x72, + 0x74, 0x73, 0x53, 0x70, 0x65, 0x63, 0x12, 0x33, 0x0a, 0x02, 0x63, 0x61, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x45, 0x4d, 0x45, + 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x41, 0x6e, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x02, 0x63, 0x61, 0x12, 0x3b, 0x0a, 0x06, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x45, 0x4d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x6e, 0x64, 0x4b, 0x65, 0x79, + 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x4c, 0x5a, 0x4a, 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, 0x73, + 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -927,7 +1045,7 @@ func file_resource_definitions_secrets_secrets_proto_rawDescGZIP() []byte { return file_resource_definitions_secrets_secrets_proto_rawDescData } -var file_resource_definitions_secrets_secrets_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_resource_definitions_secrets_secrets_proto_msgTypes = make([]protoimpl.MessageInfo, 12) var file_resource_definitions_secrets_secrets_proto_goTypes = []interface{}{ (*APICertsSpec)(nil), // 0: talos.resource.definitions.secrets.APICertsSpec (*CertSANSpec)(nil), // 1: talos.resource.definitions.secrets.CertSANSpec @@ -937,43 +1055,48 @@ var file_resource_definitions_secrets_secrets_proto_goTypes = []interface{}{ (*KubernetesCertsSpec)(nil), // 5: talos.resource.definitions.secrets.KubernetesCertsSpec (*KubernetesDynamicCertsSpec)(nil), // 6: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec (*KubernetesRootSpec)(nil), // 7: talos.resource.definitions.secrets.KubernetesRootSpec - (*OSRootSpec)(nil), // 8: talos.resource.definitions.secrets.OSRootSpec - (*TrustdCertsSpec)(nil), // 9: talos.resource.definitions.secrets.TrustdCertsSpec - (*common.PEMEncodedCertificateAndKey)(nil), // 10: common.PEMEncodedCertificateAndKey - (*common.NetIP)(nil), // 11: common.NetIP - (*common.URL)(nil), // 12: common.URL - (*common.PEMEncodedKey)(nil), // 13: common.PEMEncodedKey + (*MaintenanceRootSpec)(nil), // 8: talos.resource.definitions.secrets.MaintenanceRootSpec + (*MaintenanceServiceCertsSpec)(nil), // 9: talos.resource.definitions.secrets.MaintenanceServiceCertsSpec + (*OSRootSpec)(nil), // 10: talos.resource.definitions.secrets.OSRootSpec + (*TrustdCertsSpec)(nil), // 11: talos.resource.definitions.secrets.TrustdCertsSpec + (*common.PEMEncodedCertificateAndKey)(nil), // 12: common.PEMEncodedCertificateAndKey + (*common.NetIP)(nil), // 13: common.NetIP + (*common.URL)(nil), // 14: common.URL + (*common.PEMEncodedKey)(nil), // 15: common.PEMEncodedKey } var file_resource_definitions_secrets_secrets_proto_depIdxs = []int32{ - 10, // 0: talos.resource.definitions.secrets.APICertsSpec.ca:type_name -> common.PEMEncodedCertificateAndKey - 10, // 1: talos.resource.definitions.secrets.APICertsSpec.client:type_name -> common.PEMEncodedCertificateAndKey - 10, // 2: talos.resource.definitions.secrets.APICertsSpec.server:type_name -> common.PEMEncodedCertificateAndKey - 11, // 3: talos.resource.definitions.secrets.CertSANSpec.i_ps:type_name -> common.NetIP - 10, // 4: talos.resource.definitions.secrets.EtcdCertsSpec.etcd:type_name -> common.PEMEncodedCertificateAndKey - 10, // 5: talos.resource.definitions.secrets.EtcdCertsSpec.etcd_peer:type_name -> common.PEMEncodedCertificateAndKey - 10, // 6: talos.resource.definitions.secrets.EtcdCertsSpec.etcd_admin:type_name -> common.PEMEncodedCertificateAndKey - 10, // 7: talos.resource.definitions.secrets.EtcdCertsSpec.etcd_api_server:type_name -> common.PEMEncodedCertificateAndKey - 10, // 8: talos.resource.definitions.secrets.EtcdRootSpec.etcd_ca:type_name -> common.PEMEncodedCertificateAndKey - 12, // 9: talos.resource.definitions.secrets.KubeletSpec.endpoint:type_name -> common.URL - 10, // 10: talos.resource.definitions.secrets.KubeletSpec.ca:type_name -> common.PEMEncodedCertificateAndKey - 10, // 11: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec.api_server:type_name -> common.PEMEncodedCertificateAndKey - 10, // 12: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec.api_server_kubelet_client:type_name -> common.PEMEncodedCertificateAndKey - 10, // 13: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec.front_proxy:type_name -> common.PEMEncodedCertificateAndKey - 12, // 14: talos.resource.definitions.secrets.KubernetesRootSpec.endpoint:type_name -> common.URL - 12, // 15: talos.resource.definitions.secrets.KubernetesRootSpec.local_endpoint:type_name -> common.URL - 10, // 16: talos.resource.definitions.secrets.KubernetesRootSpec.ca:type_name -> common.PEMEncodedCertificateAndKey - 13, // 17: talos.resource.definitions.secrets.KubernetesRootSpec.service_account:type_name -> common.PEMEncodedKey - 10, // 18: talos.resource.definitions.secrets.KubernetesRootSpec.aggregator_ca:type_name -> common.PEMEncodedCertificateAndKey - 11, // 19: talos.resource.definitions.secrets.KubernetesRootSpec.api_server_ips:type_name -> common.NetIP - 10, // 20: talos.resource.definitions.secrets.OSRootSpec.ca:type_name -> common.PEMEncodedCertificateAndKey - 11, // 21: talos.resource.definitions.secrets.OSRootSpec.cert_sani_ps:type_name -> common.NetIP - 10, // 22: talos.resource.definitions.secrets.TrustdCertsSpec.ca:type_name -> common.PEMEncodedCertificateAndKey - 10, // 23: talos.resource.definitions.secrets.TrustdCertsSpec.server:type_name -> common.PEMEncodedCertificateAndKey - 24, // [24:24] is the sub-list for method output_type - 24, // [24:24] is the sub-list for method input_type - 24, // [24:24] is the sub-list for extension type_name - 24, // [24:24] is the sub-list for extension extendee - 0, // [0:24] is the sub-list for field type_name + 12, // 0: talos.resource.definitions.secrets.APICertsSpec.ca:type_name -> common.PEMEncodedCertificateAndKey + 12, // 1: talos.resource.definitions.secrets.APICertsSpec.client:type_name -> common.PEMEncodedCertificateAndKey + 12, // 2: talos.resource.definitions.secrets.APICertsSpec.server:type_name -> common.PEMEncodedCertificateAndKey + 13, // 3: talos.resource.definitions.secrets.CertSANSpec.i_ps:type_name -> common.NetIP + 12, // 4: talos.resource.definitions.secrets.EtcdCertsSpec.etcd:type_name -> common.PEMEncodedCertificateAndKey + 12, // 5: talos.resource.definitions.secrets.EtcdCertsSpec.etcd_peer:type_name -> common.PEMEncodedCertificateAndKey + 12, // 6: talos.resource.definitions.secrets.EtcdCertsSpec.etcd_admin:type_name -> common.PEMEncodedCertificateAndKey + 12, // 7: talos.resource.definitions.secrets.EtcdCertsSpec.etcd_api_server:type_name -> common.PEMEncodedCertificateAndKey + 12, // 8: talos.resource.definitions.secrets.EtcdRootSpec.etcd_ca:type_name -> common.PEMEncodedCertificateAndKey + 14, // 9: talos.resource.definitions.secrets.KubeletSpec.endpoint:type_name -> common.URL + 12, // 10: talos.resource.definitions.secrets.KubeletSpec.ca:type_name -> common.PEMEncodedCertificateAndKey + 12, // 11: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec.api_server:type_name -> common.PEMEncodedCertificateAndKey + 12, // 12: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec.api_server_kubelet_client:type_name -> common.PEMEncodedCertificateAndKey + 12, // 13: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec.front_proxy:type_name -> common.PEMEncodedCertificateAndKey + 14, // 14: talos.resource.definitions.secrets.KubernetesRootSpec.endpoint:type_name -> common.URL + 14, // 15: talos.resource.definitions.secrets.KubernetesRootSpec.local_endpoint:type_name -> common.URL + 12, // 16: talos.resource.definitions.secrets.KubernetesRootSpec.ca:type_name -> common.PEMEncodedCertificateAndKey + 15, // 17: talos.resource.definitions.secrets.KubernetesRootSpec.service_account:type_name -> common.PEMEncodedKey + 12, // 18: talos.resource.definitions.secrets.KubernetesRootSpec.aggregator_ca:type_name -> common.PEMEncodedCertificateAndKey + 13, // 19: talos.resource.definitions.secrets.KubernetesRootSpec.api_server_ips:type_name -> common.NetIP + 12, // 20: talos.resource.definitions.secrets.MaintenanceRootSpec.ca:type_name -> common.PEMEncodedCertificateAndKey + 12, // 21: talos.resource.definitions.secrets.MaintenanceServiceCertsSpec.ca:type_name -> common.PEMEncodedCertificateAndKey + 12, // 22: talos.resource.definitions.secrets.MaintenanceServiceCertsSpec.server:type_name -> common.PEMEncodedCertificateAndKey + 12, // 23: talos.resource.definitions.secrets.OSRootSpec.ca:type_name -> common.PEMEncodedCertificateAndKey + 13, // 24: talos.resource.definitions.secrets.OSRootSpec.cert_sani_ps:type_name -> common.NetIP + 12, // 25: talos.resource.definitions.secrets.TrustdCertsSpec.ca:type_name -> common.PEMEncodedCertificateAndKey + 12, // 26: talos.resource.definitions.secrets.TrustdCertsSpec.server:type_name -> common.PEMEncodedCertificateAndKey + 27, // [27:27] is the sub-list for method output_type + 27, // [27:27] is the sub-list for method input_type + 27, // [27:27] is the sub-list for extension type_name + 27, // [27:27] is the sub-list for extension extendee + 0, // [0:27] is the sub-list for field type_name } func init() { file_resource_definitions_secrets_secrets_proto_init() } @@ -1079,7 +1202,7 @@ func file_resource_definitions_secrets_secrets_proto_init() { } } file_resource_definitions_secrets_secrets_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*OSRootSpec); i { + switch v := v.(*MaintenanceRootSpec); i { case 0: return &v.state case 1: @@ -1091,6 +1214,30 @@ func file_resource_definitions_secrets_secrets_proto_init() { } } file_resource_definitions_secrets_secrets_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MaintenanceServiceCertsSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_resource_definitions_secrets_secrets_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OSRootSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_resource_definitions_secrets_secrets_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TrustdCertsSpec); i { case 0: return &v.state @@ -1109,7 +1256,7 @@ func file_resource_definitions_secrets_secrets_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_resource_definitions_secrets_secrets_proto_rawDesc, NumEnums: 0, - NumMessages: 10, + NumMessages: 12, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/machinery/api/resource/definitions/secrets/secrets_vtproto.pb.go b/pkg/machinery/api/resource/definitions/secrets/secrets_vtproto.pb.go index ad7a91168..8580c3670 100644 --- a/pkg/machinery/api/resource/definitions/secrets/secrets_vtproto.pb.go +++ b/pkg/machinery/api/resource/definitions/secrets/secrets_vtproto.pb.go @@ -839,6 +839,138 @@ func (m *KubernetesRootSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *MaintenanceRootSpec) 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 *MaintenanceRootSpec) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *MaintenanceRootSpec) 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 m.Ca != nil { + if vtmsg, ok := interface{}(m.Ca).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Ca) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = encodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MaintenanceServiceCertsSpec) 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 *MaintenanceServiceCertsSpec) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *MaintenanceServiceCertsSpec) 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 m.Server != nil { + if vtmsg, ok := interface{}(m.Server).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Server) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = encodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x12 + } + if m.Ca != nil { + if vtmsg, ok := interface{}(m.Ca).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Ca) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = encodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *OSRootSpec) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil @@ -1370,6 +1502,56 @@ func (m *KubernetesRootSpec) SizeVT() (n int) { return n } +func (m *MaintenanceRootSpec) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Ca != nil { + if size, ok := interface{}(m.Ca).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(m.Ca) + } + n += 1 + l + sov(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *MaintenanceServiceCertsSpec) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Ca != nil { + if size, ok := interface{}(m.Ca).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(m.Ca) + } + n += 1 + l + sov(uint64(l)) + } + if m.Server != nil { + if size, ok := interface{}(m.Server).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(m.Server) + } + n += 1 + l + sov(uint64(l)) + } + n += len(m.unknownFields) + return n +} + func (m *OSRootSpec) SizeVT() (n int) { if m == nil { return 0 @@ -3212,6 +3394,240 @@ func (m *KubernetesRootSpec) UnmarshalVT(dAtA []byte) error { } return nil } +func (m *MaintenanceRootSpec) 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 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: MaintenanceRootSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MaintenanceRootSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Ca", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Ca == nil { + m.Ca = &common.PEMEncodedCertificateAndKey{} + } + if unmarshal, ok := interface{}(m.Ca).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Ca); err != nil { + return err + } + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return 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 *MaintenanceServiceCertsSpec) 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 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: MaintenanceServiceCertsSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MaintenanceServiceCertsSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Ca", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Ca == nil { + m.Ca = &common.PEMEncodedCertificateAndKey{} + } + if unmarshal, ok := interface{}(m.Ca).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Ca); err != nil { + return err + } + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Server", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Server == nil { + m.Server = &common.PEMEncodedCertificateAndKey{} + } + if unmarshal, ok := interface{}(m.Server).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Server); err != nil { + return err + } + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return 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 *OSRootSpec) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/pkg/machinery/config/container/container.go b/pkg/machinery/config/container/container.go index c527316d4..840dd32ac 100644 --- a/pkg/machinery/config/container/container.go +++ b/pkg/machinery/config/container/container.go @@ -226,16 +226,22 @@ func (container *Container) Validate(mode validation.RuntimeMode, opt ...validat warnings, err = container.v1alpha1Config.Validate(mode, opt...) } + var multiErr *multierror.Error + + if err != nil { + multiErr = multierror.Append(multiErr, err) + } + for _, doc := range container.documents { if validatableDoc, ok := doc.(config.Validator); ok { docWarnings, docErr := validatableDoc.Validate(mode, opt...) warnings = append(warnings, docWarnings...) - err = multierror.Append(err, docErr) + multiErr = multierror.Append(multiErr, docErr) } } - return warnings, err + return warnings, multiErr.ErrorOrNil() } // RedactSecrets returns a copy of the Provider with all secrets replaced with the given string. diff --git a/pkg/machinery/config/container/container_test.go b/pkg/machinery/config/container/container_test.go index 9167f72d9..be831fb1d 100644 --- a/pkg/machinery/config/container/container_test.go +++ b/pkg/machinery/config/container/container_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/siderolabs/talos/pkg/machinery/config/config" "github.com/siderolabs/talos/pkg/machinery/config/configloader" "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/siderolink" @@ -19,6 +20,8 @@ import ( ) func TestNew(t *testing.T) { + t.Parallel() + v1alpha1Cfg := &v1alpha1.Config{ MachineConfig: &v1alpha1.MachineConfig{ MachineFeatures: &v1alpha1.FeaturesConfig{ @@ -42,6 +45,7 @@ func TestNew(t *testing.T) { assert.Equal(t, "topsecret", cfg.Cluster().Secret()) assert.Equal(t, "https://siderolink.api/join?jointoken=secret&user=alice", cfg.SideroLink().APIUrl().String()) assert.Same(t, v1alpha1Cfg, cfg.RawV1Alpha1()) + assert.Equal(t, []config.Document{v1alpha1Cfg, sideroLinkCfg}, cfg.Documents()) bytes, err := cfg.Bytes() require.NoError(t, err) @@ -58,6 +62,8 @@ func TestNew(t *testing.T) { } func TestNewDuplicate(t *testing.T) { + t.Parallel() + v1alpha1Cfg1 := &v1alpha1.Config{} v1alpha1Cfg2 := &v1alpha1.Config{} @@ -71,6 +77,88 @@ func TestNewDuplicate(t *testing.T) { assert.EqualError(t, err, "duplicate document: SideroLinkConfig/") } +func TestValidate(t *testing.T) { + t.Parallel() + + sideroLinkCfg := siderolink.NewConfigV1Alpha1() + sideroLinkCfg.APIUrlConfig.URL = must(url.Parse("https://siderolink.api/?jointoken=secret&user=alice")) + + invalidSideroLinkCfg := siderolink.NewConfigV1Alpha1() + + v1alpha1Cfg := &v1alpha1.Config{ + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: must(url.Parse("https://localhost:6443")), + }, + }, + }, + MachineConfig: &v1alpha1.MachineConfig{ + MachineType: "worker", + }, + } + + invalidV1alpha1Config := &v1alpha1.Config{} + + for _, tt := range []struct { + name string + documents []config.Document + + expectedError string + expecetedWarnings []string + }{ + { + name: "empty", + }, + { + name: "multi-doc", + documents: []config.Document{sideroLinkCfg, v1alpha1Cfg}, + }, + { + name: "only siderolink", + documents: []config.Document{sideroLinkCfg}, + }, + { + name: "only v1alpha1", + documents: []config.Document{v1alpha1Cfg}, + }, + { + name: "invalid siderolink", + documents: []config.Document{invalidSideroLinkCfg}, + expectedError: "1 error occurred:\n\t* apiUrl is required\n\n", + }, + { + name: "invalid v1alpha1", + documents: []config.Document{invalidV1alpha1Config}, + expectedError: "1 error occurred:\n\t* machine instructions are required\n\n", + }, + { + name: "invalid multi-doc", + documents: []config.Document{invalidSideroLinkCfg, invalidV1alpha1Config}, + expectedError: "2 errors occurred:\n\t* machine instructions are required\n\t* apiUrl is required\n\n", + }, + } { + tt := tt + + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + ctr, err := container.New(tt.documents...) + require.NoError(t, err) + + warnings, err := ctr.Validate(validationMode{}) + + if tt.expectedError == "" { + require.NoError(t, err) + } else { + require.EqualError(t, err, tt.expectedError) + } + + require.Equal(t, tt.expecetedWarnings, warnings) + }) + } +} + func must[T any](t T, err error) T { if err != nil { panic(err) @@ -78,3 +166,13 @@ func must[T any](t T, err error) T { return t } + +type validationMode struct{} + +func (validationMode) String() string { + return "" +} + +func (validationMode) RequiresInstall() bool { + return false +} diff --git a/pkg/machinery/constants/constants.go b/pkg/machinery/constants/constants.go index f44e0cac1..e1f9ca034 100644 --- a/pkg/machinery/constants/constants.go +++ b/pkg/machinery/constants/constants.go @@ -866,6 +866,9 @@ const ( // MetaValuesEnvVar is the name of the environment variable to store encoded meta values for the disk image (installer). MetaValuesEnvVar = "INSTALLER_META_BASE64" + + // MaintenanceServiceCommonName is the CN of the maintenance service server certificate. + MaintenanceServiceCommonName = "maintenance-service.talos.dev" ) // See https://linux.die.net/man/3/klogctl diff --git a/pkg/machinery/resources/config/machine_config.go b/pkg/machinery/resources/config/machine_config.go index 412d782ef..bf73f0a85 100644 --- a/pkg/machinery/resources/config/machine_config.go +++ b/pkg/machinery/resources/config/machine_config.go @@ -21,6 +21,9 @@ const MachineConfigType = resource.Type("MachineConfigs.config.talos.dev") // V1Alpha1ID is the ID of V1Alpha1 resource (singleton). const V1Alpha1ID = resource.ID("v1alpha1") +// MaintenanceID is the ID of the config submitted in the maintenance mode. +const MaintenanceID = resource.ID("maintenance") + // MachineConfig resource holds v1alpha Talos configuration. type MachineConfig struct { md resource.Metadata @@ -38,8 +41,13 @@ func (s *v1alpha1Spec) MarshalYAMLBytes() ([]byte, error) { // NewMachineConfig initializes a V1Alpha1 resource. func NewMachineConfig(spec config.Provider) *MachineConfig { + return NewMachineConfigWithID(spec, V1Alpha1ID) +} + +// NewMachineConfigWithID initializes a MachineConfig resource. +func NewMachineConfigWithID(spec config.Provider, id resource.ID) *MachineConfig { r := &MachineConfig{ - md: resource.NewMetadata(NamespaceName, MachineConfigType, V1Alpha1ID, resource.VersionUndefined), + md: resource.NewMetadata(NamespaceName, MachineConfigType, id, resource.VersionUndefined), spec: &v1alpha1Spec{ cfg: spec, }, diff --git a/pkg/machinery/resources/runtime/deep_copy.generated.go b/pkg/machinery/resources/runtime/deep_copy.generated.go index 273e43da1..388a8c584 100644 --- a/pkg/machinery/resources/runtime/deep_copy.generated.go +++ b/pkg/machinery/resources/runtime/deep_copy.generated.go @@ -2,11 +2,12 @@ // 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 DevicesStatusSpec -type EventSinkConfigSpec -type KernelModuleSpecSpec -type KernelParamSpecSpec -type KernelParamStatusSpec -type KmsgLogConfigSpec -type MachineStatusSpec -type MetaKeySpec -type MountStatusSpec -type PlatformMetadataSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT. +// Code generated by "deep-copy -type DevicesStatusSpec -type EventSinkConfigSpec -type KernelModuleSpecSpec -type KernelParamSpecSpec -type KernelParamStatusSpec -type KmsgLogConfigSpec -type MaintenanceServiceConfigSpec -type MaintenanceServiceRequestSpec -type MachineStatusSpec -type MetaKeySpec -type MountStatusSpec -type PlatformMetadataSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT. package runtime import ( + "net/netip" "net/url" ) @@ -64,6 +65,22 @@ func (o KmsgLogConfigSpec) DeepCopy() KmsgLogConfigSpec { return cp } +// DeepCopy generates a deep copy of MaintenanceServiceConfigSpec. +func (o MaintenanceServiceConfigSpec) DeepCopy() MaintenanceServiceConfigSpec { + var cp MaintenanceServiceConfigSpec = o + if o.ReachableAddresses != nil { + cp.ReachableAddresses = make([]netip.Addr, len(o.ReachableAddresses)) + copy(cp.ReachableAddresses, o.ReachableAddresses) + } + return cp +} + +// DeepCopy generates a deep copy of MaintenanceServiceRequestSpec. +func (o MaintenanceServiceRequestSpec) DeepCopy() MaintenanceServiceRequestSpec { + var cp MaintenanceServiceRequestSpec = o + return cp +} + // DeepCopy generates a deep copy of MachineStatusSpec. func (o MachineStatusSpec) DeepCopy() MachineStatusSpec { var cp MachineStatusSpec = o diff --git a/pkg/machinery/resources/runtime/maintenance_config.go b/pkg/machinery/resources/runtime/maintenance_config.go new file mode 100644 index 000000000..b3c247612 --- /dev/null +++ b/pkg/machinery/resources/runtime/maintenance_config.go @@ -0,0 +1,62 @@ +// 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 runtime + +import ( + "net/netip" + + "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" +) + +// MaintenanceServiceConfigType is type of MaintenanceConfig resource. +const MaintenanceServiceConfigType = resource.Type("MaintenanceServiceConfigs.runtime.talos.dev") + +// MaintenanceServiceConfig resource holds configuration for maintenance service API. +type MaintenanceServiceConfig = typed.Resource[MaintenanceServiceConfigSpec, MaintenanceServiceConfigExtension] + +// MaintenanceServiceConfigID is a resource ID for MaintenanceConfig. +const MaintenanceServiceConfigID resource.ID = "maintenance" + +// MaintenanceServiceConfigSpec describes configuration for maintenance service API. +// +//gotagsrewrite:gen +type MaintenanceServiceConfigSpec struct { + ListenAddress string `yaml:"listenAddress" protobuf:"1"` + ReachableAddresses []netip.Addr `yaml:"reachableAddresses" protobuf:"2"` +} + +// NewMaintenanceServiceConfig initializes a MaintenanceConfig resource. +func NewMaintenanceServiceConfig() *MaintenanceServiceConfig { + return typed.NewResource[MaintenanceServiceConfigSpec, MaintenanceServiceConfigExtension]( + resource.NewMetadata(NamespaceName, MaintenanceServiceConfigType, MaintenanceServiceConfigID, resource.VersionUndefined), + MaintenanceServiceConfigSpec{}, + ) +} + +// MaintenanceServiceConfigExtension is auxiliary resource data for MaintenanceConfig. +type MaintenanceServiceConfigExtension struct{} + +// ResourceDefinition implements meta.ResourceDefinitionProvider interface. +func (MaintenanceServiceConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec { + return meta.ResourceDefinitionSpec{ + Type: MaintenanceServiceConfigType, + Aliases: []resource.Type{}, + DefaultNamespace: NamespaceName, + } +} + +func init() { + proto.RegisterDefaultTypes() + + err := protobuf.RegisterDynamic[MaintenanceServiceConfigSpec](MaintenanceServiceConfigType, &MaintenanceServiceConfig{}) + if err != nil { + panic(err) + } +} diff --git a/pkg/machinery/resources/runtime/maintenance_request.go b/pkg/machinery/resources/runtime/maintenance_request.go new file mode 100644 index 000000000..b313aa8fc --- /dev/null +++ b/pkg/machinery/resources/runtime/maintenance_request.go @@ -0,0 +1,57 @@ +// 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 runtime + +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" +) + +// MaintenanceServiceRequestType is type of MaintenanceServiceConfig resource. +const MaintenanceServiceRequestType = resource.Type("MaintenanceServiceRequests.runtime.talos.dev") + +// MaintenanceServiceRequest resource indicates that the maintenance service should run. +type MaintenanceServiceRequest = typed.Resource[MaintenanceServiceRequestSpec, MaintenanceServiceRequestExtension] + +// MaintenanceServiceRequestID is a resource ID for MaintenanceConfig. +const MaintenanceServiceRequestID resource.ID = "maintenance" + +// MaintenanceServiceRequestSpec indicates that maintenance service API should be started. +// +//gotagsrewrite:gen +type MaintenanceServiceRequestSpec struct{} + +// NewMaintenanceServiceRequest initializes a MaintenanceConfig resource. +func NewMaintenanceServiceRequest() *MaintenanceServiceRequest { + return typed.NewResource[MaintenanceServiceRequestSpec, MaintenanceServiceRequestExtension]( + resource.NewMetadata(NamespaceName, MaintenanceServiceRequestType, MaintenanceServiceRequestID, resource.VersionUndefined), + MaintenanceServiceRequestSpec{}, + ) +} + +// MaintenanceServiceRequestExtension is auxiliary resource data for MaintenanceConfig. +type MaintenanceServiceRequestExtension struct{} + +// ResourceDefinition implements meta.ResourceDefinitionProvider interface. +func (MaintenanceServiceRequestExtension) ResourceDefinition() meta.ResourceDefinitionSpec { + return meta.ResourceDefinitionSpec{ + Type: MaintenanceServiceRequestType, + Aliases: []resource.Type{}, + DefaultNamespace: NamespaceName, + } +} + +func init() { + proto.RegisterDefaultTypes() + + err := protobuf.RegisterDynamic[MaintenanceServiceRequestSpec](MaintenanceServiceRequestType, &MaintenanceServiceRequest{}) + if err != nil { + panic(err) + } +} diff --git a/pkg/machinery/resources/runtime/runtime.go b/pkg/machinery/resources/runtime/runtime.go index 6f5b93fe3..05232e0e8 100644 --- a/pkg/machinery/resources/runtime/runtime.go +++ b/pkg/machinery/resources/runtime/runtime.go @@ -5,4 +5,4 @@ package runtime //nolint:lll -//go:generate deep-copy -type DevicesStatusSpec -type EventSinkConfigSpec -type KernelModuleSpecSpec -type KernelParamSpecSpec -type KernelParamStatusSpec -type KmsgLogConfigSpec -type MachineStatusSpec -type MetaKeySpec -type MountStatusSpec -type PlatformMetadataSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go . +//go:generate deep-copy -type DevicesStatusSpec -type EventSinkConfigSpec -type KernelModuleSpecSpec -type KernelParamSpecSpec -type KernelParamStatusSpec -type KmsgLogConfigSpec -type MaintenanceServiceConfigSpec -type MaintenanceServiceRequestSpec -type MachineStatusSpec -type MetaKeySpec -type MountStatusSpec -type PlatformMetadataSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go . diff --git a/pkg/machinery/resources/runtime/runtime_test.go b/pkg/machinery/resources/runtime/runtime_test.go index 8d81e7f37..5dc8cac59 100644 --- a/pkg/machinery/resources/runtime/runtime_test.go +++ b/pkg/machinery/resources/runtime/runtime_test.go @@ -33,6 +33,8 @@ func TestRegisterResource(t *testing.T) { &runtime.KernelParamStatus{}, &runtime.KmsgLogConfig{}, &runtime.MachineStatus{}, + &runtime.MaintenanceServiceConfig{}, + &runtime.MaintenanceServiceRequest{}, &runtime.MetaKey{}, &runtime.MountStatus{}, &runtime.PlatformMetadata{}, diff --git a/pkg/machinery/resources/secrets/cert_sans.go b/pkg/machinery/resources/secrets/cert_sans.go index e50147749..7284ed25c 100644 --- a/pkg/machinery/resources/secrets/cert_sans.go +++ b/pkg/machinery/resources/secrets/cert_sans.go @@ -24,6 +24,9 @@ const CertSANType = resource.Type("CertSANs.secrets.talos.dev") // CertSANAPIID is a resource ID of singleton instance for the Talos API. const CertSANAPIID = resource.ID("api") +// CertSANMaintenanceID is a resource ID of singleton instance for the Talos Maintenance API. +const CertSANMaintenanceID = resource.ID("maintenance") + // CertSANKubernetesID is a resource ID of singleton instance for the Kubernetes API Server. const CertSANKubernetesID = resource.ID("k8s") diff --git a/pkg/machinery/resources/secrets/deep_copy.generated.go b/pkg/machinery/resources/secrets/deep_copy.generated.go index de9c7feb8..1acd87583 100644 --- a/pkg/machinery/resources/secrets/deep_copy.generated.go +++ b/pkg/machinery/resources/secrets/deep_copy.generated.go @@ -2,7 +2,7 @@ // 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 APICertsSpec -type CertSANSpec -type EtcdCertsSpec -type EtcdRootSpec -type KubeletSpec -type KubernetesCertsSpec -type KubernetesDynamicCertsSpec -type KubernetesRootSpec -type OSRootSpec -type TrustdCertsSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT. +// Code generated by "deep-copy -type APICertsSpec -type CertSANSpec -type EtcdCertsSpec -type EtcdRootSpec -type KubeletSpec -type KubernetesCertsSpec -type KubernetesDynamicCertsSpec -type KubernetesRootSpec -type MaintenanceServiceCertsSpec -type MaintenanceRootSpec -type OSRootSpec -type TrustdCertsSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT. package secrets @@ -144,6 +144,27 @@ func (o KubernetesRootSpec) DeepCopy() KubernetesRootSpec { return cp } +// DeepCopy generates a deep copy of MaintenanceServiceCertsSpec. +func (o MaintenanceServiceCertsSpec) DeepCopy() MaintenanceServiceCertsSpec { + var cp MaintenanceServiceCertsSpec = o + if o.CA != nil { + cp.CA = o.CA.DeepCopy() + } + if o.Server != nil { + cp.Server = o.Server.DeepCopy() + } + return cp +} + +// DeepCopy generates a deep copy of MaintenanceRootSpec. +func (o MaintenanceRootSpec) DeepCopy() MaintenanceRootSpec { + var cp MaintenanceRootSpec = o + if o.CA != nil { + cp.CA = o.CA.DeepCopy() + } + return cp +} + // DeepCopy generates a deep copy of OSRootSpec. func (o OSRootSpec) DeepCopy() OSRootSpec { var cp OSRootSpec = o diff --git a/pkg/machinery/resources/secrets/maintenance.go b/pkg/machinery/resources/secrets/maintenance.go new file mode 100644 index 000000000..ed35febe5 --- /dev/null +++ b/pkg/machinery/resources/secrets/maintenance.go @@ -0,0 +1,61 @@ +// 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 secrets //nolint:dupl + +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/crypto/x509" + + "github.com/siderolabs/talos/pkg/machinery/proto" +) + +// MaintenanceServiceCertsType is type of MaintenanceCerts resource. +const MaintenanceServiceCertsType = resource.Type("MaintenanceServiceCertificates.secrets.talos.dev") + +// MaintenanceServiceCertsID is a resource ID of singleton instance. +const MaintenanceServiceCertsID = resource.ID("maintenance") + +// MaintenanceServiceCerts contains Maintenance Service generated secrets. +type MaintenanceServiceCerts = typed.Resource[MaintenanceServiceCertsSpec, MaintenanceCertsExtension] + +// MaintenanceServiceCertsSpec describes maintenance service certs secrets. +// +//gotagsrewrite:gen +type MaintenanceServiceCertsSpec struct { + CA *x509.PEMEncodedCertificateAndKey `yaml:"ca" protobuf:"1"` // only cert is passed, without key + Server *x509.PEMEncodedCertificateAndKey `yaml:"server" protobuf:"2"` +} + +// NewMaintenanceServiceCerts initializes an MaintenanceCerts resource. +func NewMaintenanceServiceCerts() *MaintenanceServiceCerts { + return typed.NewResource[MaintenanceServiceCertsSpec, MaintenanceCertsExtension]( + resource.NewMetadata(NamespaceName, MaintenanceServiceCertsType, MaintenanceServiceCertsID, resource.VersionUndefined), + MaintenanceServiceCertsSpec{}, + ) +} + +// MaintenanceCertsExtension provides auxiliary methods for MaintenanceCerts. +type MaintenanceCertsExtension struct{} + +// ResourceDefinition implements meta.ResourceDefinitionProvider interface. +func (MaintenanceCertsExtension) ResourceDefinition() meta.ResourceDefinitionSpec { + return meta.ResourceDefinitionSpec{ + Type: MaintenanceServiceCertsType, + Aliases: []resource.Type{}, + DefaultNamespace: NamespaceName, + Sensitivity: meta.Sensitive, + } +} + +func init() { + proto.RegisterDefaultTypes() + + if err := protobuf.RegisterDynamic[MaintenanceServiceCertsSpec](MaintenanceServiceCertsType, &MaintenanceServiceCerts{}); err != nil { + panic(err) + } +} diff --git a/pkg/machinery/resources/secrets/maintenance_root.go b/pkg/machinery/resources/secrets/maintenance_root.go new file mode 100644 index 000000000..75c919ac3 --- /dev/null +++ b/pkg/machinery/resources/secrets/maintenance_root.go @@ -0,0 +1,60 @@ +// 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 secrets + +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/crypto/x509" + + "github.com/siderolabs/talos/pkg/machinery/proto" +) + +// MaintenanceRootType is type of MaintenanceRoot secret resource. +const MaintenanceRootType = resource.Type("MaintenanceRootSecrets.secrets.talos.dev") + +// MaintenanceRootID is the Resource ID for MaintenanceRoot. +const MaintenanceRootID = resource.ID("maintenance") + +// MaintenanceRoot contains root secrets for the maintenance service. +type MaintenanceRoot = typed.Resource[MaintenanceRootSpec, MaintenanceRootExtension] + +// MaintenanceRootSpec describes maintenance service CA. +// +//gotagsrewrite:gen +type MaintenanceRootSpec struct { + CA *x509.PEMEncodedCertificateAndKey `yaml:"ca" protobuf:"1"` +} + +// NewMaintenanceRoot initializes a MaintenanceRoot resource. +func NewMaintenanceRoot(id resource.ID) *MaintenanceRoot { + return typed.NewResource[MaintenanceRootSpec, MaintenanceRootExtension]( + resource.NewMetadata(NamespaceName, MaintenanceRootType, id, resource.VersionUndefined), + MaintenanceRootSpec{}, + ) +} + +// MaintenanceRootExtension provides auxiliary methods for MaintenanceRoot. +type MaintenanceRootExtension struct{} + +// ResourceDefinition implements meta.ResourceDefinitionProvider interface. +func (MaintenanceRootExtension) ResourceDefinition() meta.ResourceDefinitionSpec { + return meta.ResourceDefinitionSpec{ + Type: MaintenanceRootType, + Aliases: []resource.Type{}, + DefaultNamespace: NamespaceName, + Sensitivity: meta.Sensitive, + } +} + +func init() { + proto.RegisterDefaultTypes() + + if err := protobuf.RegisterDynamic[MaintenanceRootSpec](MaintenanceRootType, &MaintenanceRoot{}); err != nil { + panic(err) + } +} diff --git a/pkg/machinery/resources/secrets/secrets.go b/pkg/machinery/resources/secrets/secrets.go index 27f85d07b..a182f4139 100644 --- a/pkg/machinery/resources/secrets/secrets.go +++ b/pkg/machinery/resources/secrets/secrets.go @@ -11,4 +11,4 @@ import "github.com/cosi-project/runtime/pkg/resource" const NamespaceName resource.Namespace = "secrets" //nolint:lll -//go:generate deep-copy -type APICertsSpec -type CertSANSpec -type EtcdCertsSpec -type EtcdRootSpec -type KubeletSpec -type KubernetesCertsSpec -type KubernetesDynamicCertsSpec -type KubernetesRootSpec -type OSRootSpec -type TrustdCertsSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go . +//go:generate deep-copy -type APICertsSpec -type CertSANSpec -type EtcdCertsSpec -type EtcdRootSpec -type KubeletSpec -type KubernetesCertsSpec -type KubernetesDynamicCertsSpec -type KubernetesRootSpec -type MaintenanceServiceCertsSpec -type MaintenanceRootSpec -type OSRootSpec -type TrustdCertsSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go . diff --git a/pkg/machinery/resources/secrets/secrets_test.go b/pkg/machinery/resources/secrets/secrets_test.go index 593b6ba90..adf4c6ced 100644 --- a/pkg/machinery/resources/secrets/secrets_test.go +++ b/pkg/machinery/resources/secrets/secrets_test.go @@ -33,6 +33,8 @@ func TestRegisterResource(t *testing.T) { &secrets.Kubernetes{}, &secrets.KubernetesDynamicCerts{}, &secrets.KubernetesRoot{}, + &secrets.MaintenanceServiceCerts{}, + &secrets.MaintenanceRoot{}, &secrets.OSRoot{}, &secrets.Trustd{}, } { diff --git a/pkg/machinery/resources/secrets/trustd.go b/pkg/machinery/resources/secrets/trustd.go index 586c73862..1f176cc5e 100644 --- a/pkg/machinery/resources/secrets/trustd.go +++ b/pkg/machinery/resources/secrets/trustd.go @@ -2,7 +2,7 @@ // 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 secrets +package secrets //nolint:dupl import ( "github.com/cosi-project/runtime/pkg/resource" diff --git a/pkg/machinery/resources/siderolink/siderolink.go b/pkg/machinery/resources/siderolink/siderolink.go index a4ce62780..907070242 100644 --- a/pkg/machinery/resources/siderolink/siderolink.go +++ b/pkg/machinery/resources/siderolink/siderolink.go @@ -57,6 +57,7 @@ func (ConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec { JSONPath: `{.apiEndpoint}`, }, }, + Sensitivity: meta.Sensitive, } } diff --git a/website/content/v1.5/reference/api.md b/website/content/v1.5/reference/api.md index 1d6f9b14d..b852f15cf 100644 --- a/website/content/v1.5/reference/api.md +++ b/website/content/v1.5/reference/api.md @@ -195,6 +195,7 @@ description: Talos gRPC API reference. - [KmsgLogConfigSpec](#talos.resource.definitions.runtime.KmsgLogConfigSpec) - [MachineStatusSpec](#talos.resource.definitions.runtime.MachineStatusSpec) - [MachineStatusStatus](#talos.resource.definitions.runtime.MachineStatusStatus) + - [MaintenanceServiceConfigSpec](#talos.resource.definitions.runtime.MaintenanceServiceConfigSpec) - [MetaKeySpec](#talos.resource.definitions.runtime.MetaKeySpec) - [MountStatusSpec](#talos.resource.definitions.runtime.MountStatusSpec) - [PlatformMetadataSpec](#talos.resource.definitions.runtime.PlatformMetadataSpec) @@ -209,6 +210,8 @@ description: Talos gRPC API reference. - [KubernetesCertsSpec](#talos.resource.definitions.secrets.KubernetesCertsSpec) - [KubernetesDynamicCertsSpec](#talos.resource.definitions.secrets.KubernetesDynamicCertsSpec) - [KubernetesRootSpec](#talos.resource.definitions.secrets.KubernetesRootSpec) + - [MaintenanceRootSpec](#talos.resource.definitions.secrets.MaintenanceRootSpec) + - [MaintenanceServiceCertsSpec](#talos.resource.definitions.secrets.MaintenanceServiceCertsSpec) - [OSRootSpec](#talos.resource.definitions.secrets.OSRootSpec) - [TrustdCertsSpec](#talos.resource.definitions.secrets.TrustdCertsSpec) @@ -3549,6 +3552,22 @@ MachineStatusStatus describes machine current status at the stage. + + +### MaintenanceServiceConfigSpec +MaintenanceServiceConfigSpec describes configuration for maintenance service API. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| listen_address | [string](#string) | | | +| reachable_addresses | [common.NetIP](#common.NetIP) | repeated | | + + + + + + ### MetaKeySpec @@ -3784,6 +3803,37 @@ KubernetesRootSpec describes root Kubernetes secrets. + + +### MaintenanceRootSpec +MaintenanceRootSpec describes maintenance service CA. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| ca | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) | | | + + + + + + + + +### MaintenanceServiceCertsSpec +MaintenanceServiceCertsSpec describes maintenance service certs secrets. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| ca | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) | | | +| server | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) | | | + + + + + + ### OSRootSpec