diff --git a/cmd/talosctl/cmd/mgmt/cluster/create.go b/cmd/talosctl/cmd/mgmt/cluster/create.go index 3ce8d60fb..99fd6f173 100644 --- a/cmd/talosctl/cmd/mgmt/cluster/create.go +++ b/cmd/talosctl/cmd/mgmt/cluster/create.go @@ -32,12 +32,12 @@ import ( "github.com/siderolabs/talos/pkg/images" clientconfig "github.com/siderolabs/talos/pkg/machinery/client/config" "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/bundle" "github.com/siderolabs/talos/pkg/machinery/config/configpatcher" "github.com/siderolabs/talos/pkg/machinery/config/encoder" + "github.com/siderolabs/talos/pkg/machinery/config/generate" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/bundle" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/nethelpers" "github.com/siderolabs/talos/pkg/provision" @@ -333,7 +333,7 @@ func create(ctx context.Context, flags *pflag.FlagSet) (err error) { configBundleOpts = append(configBundleOpts, bundle.WithExistingConfigs(inputDir)) } else { - genOptions := []generate.GenOption{ + genOptions := []generate.Option{ generate.WithInstallImage(nodeInstallImage), generate.WithDebug(configDebug), generate.WithDNSDomain(dnsDomain), @@ -530,7 +530,7 @@ func create(ctx context.Context, flags *pflag.FlagSet) (err error) { return err } - configBundle, err := bundle.NewConfigBundle(configBundleOpts...) + configBundle, err := bundle.NewBundle(configBundleOpts...) if err != nil { return err } diff --git a/cmd/talosctl/cmd/mgmt/debug/air-gapped.go b/cmd/talosctl/cmd/mgmt/debug/air-gapped.go index b788b746c..8560a32f2 100644 --- a/cmd/talosctl/cmd/mgmt/debug/air-gapped.go +++ b/cmd/talosctl/cmd/mgmt/debug/air-gapped.go @@ -96,7 +96,7 @@ func generateConfigPatch(caPEM []byte) error { }, } - patchBytes, err := patch.EncodeBytes(encoder.WithComments(encoder.CommentsDisabled)) + patchBytes, err := encoder.NewEncoder(patch, encoder.WithComments(encoder.CommentsDisabled)).Encode() if err != nil { return err } diff --git a/cmd/talosctl/cmd/mgmt/gen/config.go b/cmd/talosctl/cmd/mgmt/gen/config.go index 37ffae3ee..731303f40 100644 --- a/cmd/talosctl/cmd/mgmt/gen/config.go +++ b/cmd/talosctl/cmd/mgmt/gen/config.go @@ -20,12 +20,13 @@ import ( "github.com/siderolabs/talos/cmd/talosctl/pkg/mgmt/helpers" "github.com/siderolabs/talos/pkg/images" "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/bundle" "github.com/siderolabs/talos/pkg/machinery/config/configpatcher" "github.com/siderolabs/talos/pkg/machinery/config/encoder" + "github.com/siderolabs/talos/pkg/machinery/config/generate" + "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/bundle" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/constants" ) @@ -91,7 +92,7 @@ setup, usually involving a load balancer, use the IP and port of the load balanc switch genConfigCmdFlags.configVersion { case "v1alpha1": - return writeV1Alpha1Config(args) + return writeConfig(args) default: return fmt.Errorf("unknown config version: %q", genConfigCmdFlags.configVersion) } @@ -115,17 +116,17 @@ func fixControlPlaneEndpoint(u *url.URL) *url.URL { return u } -// V1Alpha1Config generates the Talos config bundle +// GenerateConfigBundle generates the Talos config bundle // -// V1Alpha1Config is useful for integration with external tooling options. -func V1Alpha1Config(genOptions []generate.GenOption, +// GenerateConfigBundle is useful for integration with external tooling options. +func GenerateConfigBundle(genOptions []generate.Option, clusterName string, endpoint string, kubernetesVersion string, configPatch []string, configPatchControlPlane []string, configPatchWorker []string, -) (*bundle.ConfigBundle, error) { +) (*bundle.Bundle, error) { configBundleOpts := []bundle.Option{ bundle.WithInputOptions( &bundle.InputOptions{ @@ -160,7 +161,7 @@ func V1Alpha1Config(genOptions []generate.GenOption, return nil, err } - configBundle, err := bundle.NewConfigBundle(configBundleOpts...) + configBundle, err := bundle.NewBundle(configBundleOpts...) if err != nil { return nil, fmt.Errorf("failed to generate config bundle: %w", err) } @@ -172,7 +173,7 @@ func V1Alpha1Config(genOptions []generate.GenOption, } //nolint:gocyclo -func writeV1Alpha1Config(args []string) error { +func writeConfig(args []string) error { if err := validateFlags(); err != nil { return err } @@ -182,7 +183,7 @@ func writeV1Alpha1Config(args []string) error { return err } - var genOptions []generate.GenOption //nolint:prealloc + var genOptions []generate.Option //nolint:prealloc for _, registryMirror := range genConfigCmdFlags.registryMirrors { components := strings.SplitN(registryMirror, "=", 2) @@ -213,7 +214,14 @@ func writeV1Alpha1Config(args []string) error { } if genConfigCmdFlags.withSecrets != "" { - genOptions = append(genOptions, generate.WithSecrets(genConfigCmdFlags.withSecrets)) + var secretsBundle *secrets.Bundle + + secretsBundle, err = secrets.LoadBundle(genConfigCmdFlags.withSecrets) + if err != nil { + return fmt.Errorf("failed to load secrets bundle: %w", err) + } + + genOptions = append(genOptions, generate.WithSecretsBundle(secretsBundle)) } genOptions = append(genOptions, @@ -234,7 +242,7 @@ func writeV1Alpha1Config(args []string) error { commentsFlags |= encoder.CommentsExamples } - configBundle, err := V1Alpha1Config( + configBundle, err := GenerateConfigBundle( genOptions, args[0], args[1], @@ -280,7 +288,7 @@ func validateFlags() error { } // nolint:gocyclo -func writeConfigBundle(configBundle *bundle.ConfigBundle, outputPaths configOutputPaths, commentsFlags encoder.CommentsFlags) error { +func writeConfigBundle(configBundle *bundle.Bundle, outputPaths configOutputPaths, commentsFlags encoder.CommentsFlags) error { outputTypesSet := slices.ToSet(genConfigCmdFlags.outputTypes) if _, ok := outputTypesSet[controlPlaneOutputType]; ok { diff --git a/cmd/talosctl/cmd/mgmt/gen/secrets.go b/cmd/talosctl/cmd/mgmt/gen/secrets.go index a92518bdb..4a634fe11 100644 --- a/cmd/talosctl/cmd/mgmt/gen/secrets.go +++ b/cmd/talosctl/cmd/mgmt/gen/secrets.go @@ -7,12 +7,13 @@ package gen import ( "fmt" "os" + "time" "github.com/spf13/cobra" "gopkg.in/yaml.v3" "github.com/siderolabs/talos/pkg/machinery/config" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" + "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets" ) var genSecretsCmdFlags struct { @@ -30,7 +31,7 @@ var genSecretsCmd = &cobra.Command{ Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { var ( - secretsBundle *generate.SecretsBundle + secretsBundle *secrets.Bundle versionContract *config.VersionContract err error ) @@ -43,7 +44,7 @@ var genSecretsCmd = &cobra.Command{ } if genSecretsCmdFlags.fromKubernetesPki != "" { - secretsBundle, err = generate.NewSecretsBundleFromKubernetesPKI(genSecretsCmdFlags.fromKubernetesPki, + secretsBundle, err = secrets.NewBundleFromKubernetesPKI(genSecretsCmdFlags.fromKubernetesPki, genSecretsCmdFlags.kubernetesBootstrapToken, versionContract) if err != nil { return fmt.Errorf("failed to create secrets bundle: %w", err) @@ -52,8 +53,8 @@ var genSecretsCmd = &cobra.Command{ return writeSecretsBundleToFile(secretsBundle) } - secretsBundle, err = generate.NewSecretsBundle(generate.NewClock(), - generate.WithVersionContract(versionContract), + secretsBundle, err = secrets.NewBundle(secrets.NewFixedClock(time.Now()), + versionContract, ) if err != nil { return fmt.Errorf("failed to create secrets bundle: %w", err) @@ -63,7 +64,7 @@ var genSecretsCmd = &cobra.Command{ }, } -func writeSecretsBundleToFile(bundle *generate.SecretsBundle) error { +func writeSecretsBundleToFile(bundle *secrets.Bundle) error { bundleBytes, err := yaml.Marshal(bundle) if err != nil { return err diff --git a/cmd/talosctl/cmd/mgmt/root.go b/cmd/talosctl/cmd/mgmt/root.go index ac84d0ea1..b19254bad 100644 --- a/cmd/talosctl/cmd/mgmt/root.go +++ b/cmd/talosctl/cmd/mgmt/root.go @@ -20,7 +20,7 @@ var Commands []*cobra.Command // GenV1Alpha1Config generates the Talos config bundle // // Kept with this name in this package for backwards-compatibility. -var GenV1Alpha1Config = gen.V1Alpha1Config +var GenV1Alpha1Config = gen.GenerateConfigBundle func addCommand(cmd *cobra.Command) { Commands = append(Commands, cmd) diff --git a/cmd/talosctl/cmd/talos/health.go b/cmd/talosctl/cmd/talos/health.go index 668a20937..03345c916 100644 --- a/cmd/talosctl/cmd/talos/health.go +++ b/cmd/talosctl/cmd/talos/health.go @@ -21,7 +21,7 @@ import ( "github.com/siderolabs/talos/pkg/cluster/sonobuoy" clusterapi "github.com/siderolabs/talos/pkg/machinery/api/cluster" "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" clusterres "github.com/siderolabs/talos/pkg/machinery/resources/cluster" ) diff --git a/cmd/talosctl/cmd/talos/images.go b/cmd/talosctl/cmd/talos/images.go index 58f43f70a..ccaa83e95 100644 --- a/cmd/talosctl/cmd/talos/images.go +++ b/cmd/talosctl/cmd/talos/images.go @@ -10,6 +10,7 @@ import ( "github.com/spf13/cobra" "github.com/siderolabs/talos/pkg/images" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" ) @@ -19,7 +20,7 @@ var imagesCmd = &cobra.Command{ Short: "List the default images used by Talos", Long: ``, RunE: func(cmd *cobra.Command, args []string) error { - images := images.List(&v1alpha1.Config{ + images := images.List(container.NewV1Alpha1(&v1alpha1.Config{ MachineConfig: &v1alpha1.MachineConfig{ MachineKubelet: &v1alpha1.KubeletConfig{}, }, @@ -31,7 +32,7 @@ var imagesCmd = &cobra.Command{ CoreDNSConfig: &v1alpha1.CoreDNS{}, ProxyConfig: &v1alpha1.ProxyConfig{}, }, - }) + })) fmt.Printf("%s\n", images.Flannel) fmt.Printf("%s\n", images.FlannelCNI) diff --git a/cmd/talosctl/pkg/mgmt/helpers/wireguard.go b/cmd/talosctl/pkg/mgmt/helpers/wireguard.go index 6519a4913..76e10936d 100644 --- a/cmd/talosctl/pkg/mgmt/helpers/wireguard.go +++ b/cmd/talosctl/pkg/mgmt/helpers/wireguard.go @@ -14,6 +14,7 @@ import ( "golang.zx2c4.com/wireguard/wgctrl/wgtypes" "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" ) @@ -112,5 +113,5 @@ func (w *WireguardConfigBundle) PatchConfig(ip fmt.Stringer, cfg config.Provider config.MachineConfig.MachineNetwork.NetworkInterfaces = append(config.MachineConfig.MachineNetwork.NetworkInterfaces, device) - return config, nil + return container.New(config) } diff --git a/internal/app/machined/internal/server/v1alpha1/v1alpha1_cluster.go b/internal/app/machined/internal/server/v1alpha1/v1alpha1_cluster.go index e8214b203..f57d46896 100644 --- a/internal/app/machined/internal/server/v1alpha1/v1alpha1_cluster.go +++ b/internal/app/machined/internal/server/v1alpha1/v1alpha1_cluster.go @@ -24,7 +24,7 @@ import ( "github.com/siderolabs/talos/pkg/conditions" "github.com/siderolabs/talos/pkg/grpc/middleware/authz" clusterapi "github.com/siderolabs/talos/pkg/machinery/api/cluster" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" clusterres "github.com/siderolabs/talos/pkg/machinery/resources/cluster" ) diff --git a/internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go b/internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go index 73b72ed01..25231afc5 100644 --- a/internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go +++ b/internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go @@ -79,9 +79,9 @@ import ( "github.com/siderolabs/talos/pkg/machinery/api/storage" timeapi "github.com/siderolabs/talos/pkg/machinery/api/time" clientconfig "github.com/siderolabs/talos/pkg/machinery/client/config" + "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets" + machinetype "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" - machinetype "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/nethelpers" etcdresource "github.com/siderolabs/talos/pkg/machinery/resources/etcd" @@ -2140,11 +2140,11 @@ func (s *Server) GenerateClientConfiguration(ctx context.Context, in *machine.Ge return nil, status.Error(codes.InvalidArgument, "crt_ttl should be positive") } - ca := s.Controller.Runtime().Config().Machine().Security().CA() - roles, _ := role.Parse(in.Roles) - cert, err := generate.NewAdminCertificateAndKey(time.Now(), ca, roles, crtTTL) + secretsBundle := secrets.NewBundleFromConfig(secrets.NewFixedClock(time.Now()), s.Controller.Runtime().Config()) + + cert, err := secretsBundle.GenerateTalosAPIClientCertificate(roles) if err != nil { return nil, err } @@ -2155,7 +2155,7 @@ func (s *Server) GenerateClientConfiguration(ctx context.Context, in *machine.Ge contextName = strings.TrimPrefix(r[0], role.Prefix) + "@" + contextName } - talosconfig := clientconfig.NewConfig(contextName, nil, ca.Crt, cert) + talosconfig := clientconfig.NewConfig(contextName, nil, secretsBundle.Certs.OS.Crt, cert) b, err := talosconfig.Bytes() if err != nil { @@ -2165,7 +2165,7 @@ func (s *Server) GenerateClientConfiguration(ctx context.Context, in *machine.Ge reply := &machine.GenerateClientConfigurationResponse{ Messages: []*machine.GenerateClientConfiguration{ { - Ca: ca.Crt, + Ca: secretsBundle.Certs.OS.Crt, Crt: cert.Crt, Key: cert.Key, Talosconfig: b, diff --git a/internal/app/machined/internal/server/v1alpha1/v1alpha1_time_test.go b/internal/app/machined/internal/server/v1alpha1/v1alpha1_time_test.go index 025c619a7..3520915f7 100644 --- a/internal/app/machined/internal/server/v1alpha1/v1alpha1_time_test.go +++ b/internal/app/machined/internal/server/v1alpha1/v1alpha1_time_test.go @@ -21,6 +21,7 @@ import ( "github.com/siderolabs/talos/pkg/grpc/factory" timeapi "github.com/siderolabs/talos/pkg/machinery/api/time" "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" ) @@ -39,13 +40,13 @@ type mockConfigProvider struct { } func (provider *mockConfigProvider) Config() config.Config { - return &v1alpha1.Config{ + return container.NewV1Alpha1(&v1alpha1.Config{ MachineConfig: &v1alpha1.MachineConfig{ MachineTime: &v1alpha1.TimeConfig{ TimeServers: []string{provider.timeServer}, }, }, - } + }) } func (suite *TimedSuite) TestTime() { diff --git a/internal/app/machined/pkg/controllers/cluster/affiliate_merge_test.go b/internal/app/machined/pkg/controllers/cluster/affiliate_merge_test.go index 4cf23e8f4..2ae8184b3 100644 --- a/internal/app/machined/pkg/controllers/cluster/affiliate_merge_test.go +++ b/internal/app/machined/pkg/controllers/cluster/affiliate_merge_test.go @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/suite" clusterctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/cluster" ) diff --git a/internal/app/machined/pkg/controllers/cluster/cluster_test.go b/internal/app/machined/pkg/controllers/cluster/cluster_test.go index 7de0dd44e..2c897f670 100644 --- a/internal/app/machined/pkg/controllers/cluster/cluster_test.go +++ b/internal/app/machined/pkg/controllers/cluster/cluster_test.go @@ -19,8 +19,6 @@ import ( "github.com/stretchr/testify/suite" "github.com/siderolabs/talos/pkg/logging" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/resources/config" ) type ClusterSuite struct { @@ -94,21 +92,6 @@ func (suite *ClusterSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - err := suite.state.Create( - context.Background(), config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - }, - ), - ) - if state.IsConflictError(err) { - err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) - } - - suite.Assert().NoError(err) } func (suite *ClusterSuite) State() state.State { return suite.state } diff --git a/internal/app/machined/pkg/controllers/cluster/config_test.go b/internal/app/machined/pkg/controllers/cluster/config_test.go index 33f59c199..b37c29e20 100644 --- a/internal/app/machined/pkg/controllers/cluster/config_test.go +++ b/internal/app/machined/pkg/controllers/cluster/config_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/suite" clusterctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/resources/cluster" "github.com/siderolabs/talos/pkg/machinery/resources/config" @@ -29,7 +30,7 @@ func (suite *ConfigSuite) TestReconcileConfig() { suite.startRuntime() - cfg := config.NewMachineConfig(&v1alpha1.Config{ + cfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{ ConfigVersion: "v1alpha1", ClusterConfig: &v1alpha1.ClusterConfig{ ClusterID: "cluster1", @@ -38,7 +39,7 @@ func (suite *ConfigSuite) TestReconcileConfig() { DiscoveryEnabled: pointer.To(true), }, }, - }) + })) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -71,7 +72,7 @@ func (suite *ConfigSuite) TestReconcileConfigCustom() { suite.startRuntime() - cfg := config.NewMachineConfig(&v1alpha1.Config{ + cfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{ ConfigVersion: "v1alpha1", ClusterConfig: &v1alpha1.ClusterConfig{ ClusterID: "cluster1", @@ -88,7 +89,7 @@ func (suite *ConfigSuite) TestReconcileConfigCustom() { }, }, }, - }) + })) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -117,7 +118,7 @@ func (suite *ConfigSuite) TestReconcileConfigCustomInsecure() { suite.startRuntime() - cfg := config.NewMachineConfig(&v1alpha1.Config{ + cfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{ ConfigVersion: "v1alpha1", ClusterConfig: &v1alpha1.ClusterConfig{ ClusterID: "cluster1", @@ -134,7 +135,7 @@ func (suite *ConfigSuite) TestReconcileConfigCustomInsecure() { }, }, }, - }) + })) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -163,11 +164,11 @@ func (suite *ConfigSuite) TestReconcileDisabled() { suite.startRuntime() - cfg := config.NewMachineConfig(&v1alpha1.Config{ + cfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{ ConfigVersion: "v1alpha1", MachineConfig: &v1alpha1.MachineConfig{}, ClusterConfig: &v1alpha1.ClusterConfig{}, - }) + })) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) diff --git a/internal/app/machined/pkg/controllers/cluster/discovery_service.go b/internal/app/machined/pkg/controllers/cluster/discovery_service.go index 2bb0a6b9c..7681f64fb 100644 --- a/internal/app/machined/pkg/controllers/cluster/discovery_service.go +++ b/internal/app/machined/pkg/controllers/cluster/discovery_service.go @@ -23,7 +23,7 @@ import ( "github.com/siderolabs/go-pointer" "go.uber.org/zap" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/proto" "github.com/siderolabs/talos/pkg/machinery/resources/cluster" "github.com/siderolabs/talos/pkg/machinery/resources/config" diff --git a/internal/app/machined/pkg/controllers/cluster/discovery_service_test.go b/internal/app/machined/pkg/controllers/cluster/discovery_service_test.go index 4920de355..8ced5c676 100644 --- a/internal/app/machined/pkg/controllers/cluster/discovery_service_test.go +++ b/internal/app/machined/pkg/controllers/cluster/discovery_service_test.go @@ -26,7 +26,7 @@ import ( clusterctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster" "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" "github.com/siderolabs/talos/pkg/logging" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/proto" "github.com/siderolabs/talos/pkg/machinery/resources/cluster" diff --git a/internal/app/machined/pkg/controllers/cluster/endpoint.go b/internal/app/machined/pkg/controllers/cluster/endpoint.go index 1fdc686bf..1f8d518d9 100644 --- a/internal/app/machined/pkg/controllers/cluster/endpoint.go +++ b/internal/app/machined/pkg/controllers/cluster/endpoint.go @@ -15,7 +15,7 @@ import ( "github.com/cosi-project/runtime/pkg/resource" "go.uber.org/zap" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/cluster" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" ) diff --git a/internal/app/machined/pkg/controllers/cluster/endpoint_test.go b/internal/app/machined/pkg/controllers/cluster/endpoint_test.go index b6152dbb8..19efdf852 100644 --- a/internal/app/machined/pkg/controllers/cluster/endpoint_test.go +++ b/internal/app/machined/pkg/controllers/cluster/endpoint_test.go @@ -15,7 +15,7 @@ import ( "github.com/stretchr/testify/suite" clusterctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/cluster" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" ) diff --git a/internal/app/machined/pkg/controllers/cluster/local_affiliate_test.go b/internal/app/machined/pkg/controllers/cluster/local_affiliate_test.go index 4ce90f9f8..d360689da 100644 --- a/internal/app/machined/pkg/controllers/cluster/local_affiliate_test.go +++ b/internal/app/machined/pkg/controllers/cluster/local_affiliate_test.go @@ -17,7 +17,7 @@ import ( clusteradapter "github.com/siderolabs/talos/internal/app/machined/pkg/adapters/cluster" kubespanadapter "github.com/siderolabs/talos/internal/app/machined/pkg/adapters/kubespan" clusterctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/cluster" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" diff --git a/internal/app/machined/pkg/controllers/cluster/member_test.go b/internal/app/machined/pkg/controllers/cluster/member_test.go index d4748643e..4427ff94d 100644 --- a/internal/app/machined/pkg/controllers/cluster/member_test.go +++ b/internal/app/machined/pkg/controllers/cluster/member_test.go @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/suite" clusterctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/cluster" ) diff --git a/internal/app/machined/pkg/controllers/config/machine_type.go b/internal/app/machined/pkg/controllers/config/machine_type.go index d44e1c55f..0083f2511 100644 --- a/internal/app/machined/pkg/controllers/config/machine_type.go +++ b/internal/app/machined/pkg/controllers/config/machine_type.go @@ -14,7 +14,7 @@ import ( "github.com/siderolabs/go-pointer" "go.uber.org/zap" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/config" ) diff --git a/internal/app/machined/pkg/controllers/cri/seccomp_profile_test.go b/internal/app/machined/pkg/controllers/cri/seccomp_profile_test.go index 78b04318b..2404a9d4e 100644 --- a/internal/app/machined/pkg/controllers/cri/seccomp_profile_test.go +++ b/internal/app/machined/pkg/controllers/cri/seccomp_profile_test.go @@ -14,13 +14,14 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cri" "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/resources/config" criseccompresource "github.com/siderolabs/talos/pkg/machinery/resources/cri" ) func (suite *CRISeccompProfileSuite) TestReconcileSeccompProfile() { - cfg := config.NewMachineConfig(&v1alpha1.Config{ + cfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{ MachineConfig: &v1alpha1.MachineConfig{ MachineSeccompProfiles: []*v1alpha1.MachineSeccompProfile{ { @@ -41,7 +42,7 @@ func (suite *CRISeccompProfileSuite) TestReconcileSeccompProfile() { }, }, }, - }) + })) suite.Require().NoError(suite.State().Create(suite.Ctx(), cfg)) @@ -108,7 +109,7 @@ func (suite *CRISeccompProfileSuite) TestReconcileSeccompProfile() { }) // test deletion - cfg = config.NewMachineConfig(&v1alpha1.Config{ + cfg = config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{ MachineConfig: &v1alpha1.MachineConfig{ MachineSeccompProfiles: []*v1alpha1.MachineSeccompProfile{ { @@ -121,7 +122,7 @@ func (suite *CRISeccompProfileSuite) TestReconcileSeccompProfile() { }, }, }, - }) + })) ctest.UpdateWithConflicts(suite, cfg, func(mc *config.MachineConfig) error { return nil }) diff --git a/internal/app/machined/pkg/controllers/etcd/config_test.go b/internal/app/machined/pkg/controllers/etcd/config_test.go index ee3ecf4c5..7043f96ee 100644 --- a/internal/app/machined/pkg/controllers/etcd/config_test.go +++ b/internal/app/machined/pkg/controllers/etcd/config_test.go @@ -15,8 +15,9 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" etcdctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/etcd" + "github.com/siderolabs/talos/pkg/machinery/config/container" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/etcd" ) @@ -148,7 +149,7 @@ func (suite *ConfigSuite) TestReconcile() { }, } { suite.Run(tt.name, func() { - cfg := &v1alpha1.Config{ + cfg := container.NewV1Alpha1(&v1alpha1.Config{ ClusterConfig: &v1alpha1.ClusterConfig{ EtcdConfig: tt.etcdConfig, }, @@ -157,7 +158,7 @@ func (suite *ConfigSuite) TestReconcile() { NetworkInterfaces: tt.networkConfig, }, }, - } + }) machineConfig := config.NewMachineConfig(cfg) suite.Require().NoError(suite.State().Create(suite.Ctx(), machineConfig)) diff --git a/internal/app/machined/pkg/controllers/files/etcfile_test.go b/internal/app/machined/pkg/controllers/files/etcfile_test.go index a577c507c..e167a848f 100644 --- a/internal/app/machined/pkg/controllers/files/etcfile_test.go +++ b/internal/app/machined/pkg/controllers/files/etcfile_test.go @@ -153,11 +153,12 @@ func (suite *EtcFileSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError(suite.state.Create(context.Background(), files.NewEtcFileSpec(files.NamespaceName, "bar"))) } func TestEtcFileSuite(t *testing.T) { + if os.Geteuid() != 0 { + t.Skip("requires root") + } + suite.Run(t, new(EtcFileSuite)) } diff --git a/internal/app/machined/pkg/controllers/hardware/hardware_test.go b/internal/app/machined/pkg/controllers/hardware/hardware_test.go index 2a58c09c5..c4e5f818b 100644 --- a/internal/app/machined/pkg/controllers/hardware/hardware_test.go +++ b/internal/app/machined/pkg/controllers/hardware/hardware_test.go @@ -19,8 +19,6 @@ import ( "github.com/stretchr/testify/suite" "github.com/siderolabs/talos/pkg/logging" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/resources/config" ) type HardwareSuite struct { @@ -84,19 +82,4 @@ func (suite *HardwareSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - err := suite.state.Create( - context.Background(), config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - }, - ), - ) - if state.IsConflictError(err) { - err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) - } - - suite.Assert().NoError(err) } diff --git a/internal/app/machined/pkg/controllers/k8s/address_filter_test.go b/internal/app/machined/pkg/controllers/k8s/address_filter_test.go index 057e51397..9e3b76881 100644 --- a/internal/app/machined/pkg/controllers/k8s/address_filter_test.go +++ b/internal/app/machined/pkg/controllers/k8s/address_filter_test.go @@ -24,6 +24,7 @@ import ( k8sctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" @@ -91,27 +92,29 @@ func (suite *K8sAddressFilterSuite) TestReconcile() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, - }, - ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ - ServiceSubnet: []string{ - "10.200.0.0/22", - "fd40:10:200::/112", - }, - PodSubnet: []string{ - "10.32.0.0/12", - "fd00:10:32::/102", + ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ + ServiceSubnet: []string{ + "10.200.0.0/22", + "fd40:10:200::/112", + }, + PodSubnet: []string{ + "10.32.0.0/12", + "fd00:10:32::/102", + }, }, }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) diff --git a/internal/app/machined/pkg/controllers/k8s/control_plane_static_pod_test.go b/internal/app/machined/pkg/controllers/k8s/control_plane_static_pod_test.go index f7db76168..6954f0957 100644 --- a/internal/app/machined/pkg/controllers/k8s/control_plane_static_pod_test.go +++ b/internal/app/machined/pkg/controllers/k8s/control_plane_static_pod_test.go @@ -631,14 +631,6 @@ func (suite *ControlPlaneStaticPodSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError( - suite.state.Create( - context.Background(), - k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, "-"), - ), - ) } func TestControlPlaneStaticPodSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/k8s/control_plane_test.go b/internal/app/machined/pkg/controllers/k8s/control_plane_test.go index a6d7a05e4..6afca6cf8 100644 --- a/internal/app/machined/pkg/controllers/k8s/control_plane_test.go +++ b/internal/app/machined/pkg/controllers/k8s/control_plane_test.go @@ -20,8 +20,9 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" k8sctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s" + "github.com/siderolabs/talos/pkg/machinery/config/container" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" @@ -54,17 +55,19 @@ func (suite *K8sControlPlaneSuite) TestReconcileDefaults() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, }, }, - }, + ), ) suite.setupMachine(cfg) @@ -96,17 +99,19 @@ func (suite *K8sControlPlaneSuite) TestReconcileTransitionWorker() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, }, }, - }, + ), ) suite.setupMachine(cfg) @@ -131,21 +136,23 @@ func (suite *K8sControlPlaneSuite) TestReconcileIPv6() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, + }, + ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ + PodSubnet: []string{constants.DefaultIPv6PodNet}, + ServiceSubnet: []string{constants.DefaultIPv6ServiceNet}, }, }, - ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ - PodSubnet: []string{constants.DefaultIPv6PodNet}, - ServiceSubnet: []string{constants.DefaultIPv6ServiceNet}, - }, }, - }, + ), ) suite.setupMachine(cfg) @@ -163,21 +170,23 @@ func (suite *K8sControlPlaneSuite) TestReconcileDualStack() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, + }, + ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ + PodSubnet: []string{constants.DefaultIPv4PodNet, constants.DefaultIPv6PodNet}, + ServiceSubnet: []string{constants.DefaultIPv4ServiceNet, constants.DefaultIPv6ServiceNet}, }, }, - ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ - PodSubnet: []string{constants.DefaultIPv4PodNet, constants.DefaultIPv6PodNet}, - ServiceSubnet: []string{constants.DefaultIPv4ServiceNet, constants.DefaultIPv6ServiceNet}, - }, }, - }, + ), ) suite.setupMachine(cfg) @@ -195,29 +204,31 @@ func (suite *K8sControlPlaneSuite) TestReconcileExtraVolumes() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, - }, - }, - APIServerConfig: &v1alpha1.APIServerConfig{ - ExtraVolumesConfig: []v1alpha1.VolumeMountConfig{ - { - VolumeHostPath: "/var/lib", - VolumeMountPath: "/var/foo/", + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, }, - { - VolumeHostPath: "/var/lib/a.foo", - VolumeMountPath: "/var/foo/b.foo", + }, + APIServerConfig: &v1alpha1.APIServerConfig{ + ExtraVolumesConfig: []v1alpha1.VolumeMountConfig{ + { + VolumeHostPath: "/var/lib", + VolumeMountPath: "/var/foo/", + }, + { + VolumeHostPath: "/var/lib/a.foo", + VolumeMountPath: "/var/foo/b.foo", + }, }, }, }, }, - }, + ), ) suite.setupMachine(cfg) @@ -251,22 +262,24 @@ func (suite *K8sControlPlaneSuite) TestReconcileEnvironment() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, - }, - APIServerConfig: &v1alpha1.APIServerConfig{ - EnvConfig: v1alpha1.Env{ - "HTTP_PROXY": "foo", + APIServerConfig: &v1alpha1.APIServerConfig{ + EnvConfig: v1alpha1.Env{ + "HTTP_PROXY": "foo", + }, }, }, }, - }, + ), ) suite.setupMachine(cfg) @@ -289,24 +302,26 @@ func (suite *K8sControlPlaneSuite) TestReconcileExternalCloudProvider() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, - }, - ExternalCloudProviderConfig: &v1alpha1.ExternalCloudProviderConfig{ - ExternalEnabled: pointer.To(true), - ExternalManifests: []string{ - "https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml", - "https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml", + ExternalCloudProviderConfig: &v1alpha1.ExternalCloudProviderConfig{ + ExternalEnabled: pointer.To(true), + ExternalManifests: []string{ + "https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml", + "https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml", + }, }, }, }, - }, + ), ) suite.setupMachine(cfg) @@ -351,30 +366,32 @@ func (suite *K8sControlPlaneSuite) TestReconcileInlineManifests() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, - }, - ClusterInlineManifests: v1alpha1.ClusterInlineManifests{ - { - InlineManifestName: "namespace-ci", - InlineManifestContents: strings.TrimSpace( - ` + ClusterInlineManifests: v1alpha1.ClusterInlineManifests{ + { + InlineManifestName: "namespace-ci", + InlineManifestContents: strings.TrimSpace( + ` apiVersion: v1 kind: Namespace metadata: name: ci `, - ), + ), + }, }, }, }, - }, + ), ) suite.setupMachine(cfg) diff --git a/internal/app/machined/pkg/controllers/k8s/endpoint.go b/internal/app/machined/pkg/controllers/k8s/endpoint.go index 8795882c3..89dc7b323 100644 --- a/internal/app/machined/pkg/controllers/k8s/endpoint.go +++ b/internal/app/machined/pkg/controllers/k8s/endpoint.go @@ -28,7 +28,7 @@ import ( "github.com/siderolabs/talos/pkg/conditions" "github.com/siderolabs/talos/pkg/kubernetes" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" diff --git a/internal/app/machined/pkg/controllers/k8s/extra_manifest_test.go b/internal/app/machined/pkg/controllers/k8s/extra_manifest_test.go index fa888356f..fa9f40c2e 100644 --- a/internal/app/machined/pkg/controllers/k8s/extra_manifest_test.go +++ b/internal/app/machined/pkg/controllers/k8s/extra_manifest_test.go @@ -29,7 +29,6 @@ import ( "github.com/siderolabs/talos/pkg/logging" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" "github.com/siderolabs/talos/pkg/machinery/resources/network" - "github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1" ) type ExtraManifestSuite struct { @@ -155,9 +154,6 @@ func (suite *ExtraManifestSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError(suite.state.Create(context.Background(), v1alpha1.NewService("foo"))) } func TestExtraManifestSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/k8s/kubelet_config_test.go b/internal/app/machined/pkg/controllers/k8s/kubelet_config_test.go index dff785c39..023791871 100644 --- a/internal/app/machined/pkg/controllers/k8s/kubelet_config_test.go +++ b/internal/app/machined/pkg/controllers/k8s/kubelet_config_test.go @@ -25,6 +25,7 @@ import ( k8sctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/config" @@ -83,46 +84,48 @@ func (suite *KubeletConfigSuite) TestReconcile() { suite.createStaticPodServerStatus() cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineKubelet: &v1alpha1.KubeletConfig{ - KubeletImage: "kubelet", - KubeletClusterDNS: []string{"10.0.0.1"}, - KubeletExtraArgs: map[string]string{ - "enable-feature": "foo", - }, - KubeletExtraMounts: []v1alpha1.ExtraMount{ - { - Mount: specs.Mount{ - Destination: "/tmp", - Source: "/var", - Type: "tmpfs", + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineKubelet: &v1alpha1.KubeletConfig{ + KubeletImage: "kubelet", + KubeletClusterDNS: []string{"10.0.0.1"}, + KubeletExtraArgs: map[string]string{ + "enable-feature": "foo", + }, + KubeletExtraMounts: []v1alpha1.ExtraMount{ + { + Mount: specs.Mount{ + Destination: "/tmp", + Source: "/var", + Type: "tmpfs", + }, }, }, + KubeletExtraConfig: v1alpha1.Unstructured{ + Object: map[string]interface{}{ + "serverTLSBootstrap": true, + }, + }, + KubeletDefaultRuntimeSeccompProfileEnabled: pointer.To(true), }, - KubeletExtraConfig: v1alpha1.Unstructured{ - Object: map[string]interface{}{ - "serverTLSBootstrap": true, + }, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, }, }, - KubeletDefaultRuntimeSeccompProfileEnabled: pointer.To(true), - }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + ExternalCloudProviderConfig: &v1alpha1.ExternalCloudProviderConfig{ + ExternalEnabled: pointer.To(true), + }, + ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ + DNSDomain: "service.svc", }, }, - ExternalCloudProviderConfig: &v1alpha1.ExternalCloudProviderConfig{ - ExternalEnabled: pointer.To(true), - }, - ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ - DNSDomain: "service.svc", - }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -190,24 +193,26 @@ func (suite *KubeletConfigSuite) TestReconcileDefaults() { suite.createStaticPodServerStatus() cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineKubelet: &v1alpha1.KubeletConfig{ - KubeletImage: "kubelet", - }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineKubelet: &v1alpha1.KubeletConfig{ + KubeletImage: "kubelet", }, }, - ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ - ServiceSubnet: []string{constants.DefaultIPv4ServiceNet}, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, + }, + ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ + ServiceSubnet: []string{constants.DefaultIPv4ServiceNet}, + }, }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) diff --git a/internal/app/machined/pkg/controllers/k8s/manifest_test.go b/internal/app/machined/pkg/controllers/k8s/manifest_test.go index a250414cc..7ebe96778 100644 --- a/internal/app/machined/pkg/controllers/k8s/manifest_test.go +++ b/internal/app/machined/pkg/controllers/k8s/manifest_test.go @@ -353,9 +353,6 @@ func (suite *ManifestSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError(suite.state.Create(context.Background(), secrets.NewKubernetesRoot("-"))) } func TestManifestSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/k8s/node_label_spec_test.go b/internal/app/machined/pkg/controllers/k8s/node_label_spec_test.go index 6abd80b96..2a602d046 100644 --- a/internal/app/machined/pkg/controllers/k8s/node_label_spec_test.go +++ b/internal/app/machined/pkg/controllers/k8s/node_label_spec_test.go @@ -23,8 +23,9 @@ import ( k8sctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/config/container" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" ) @@ -102,11 +103,12 @@ func (suite *NodeLabelsSuite) setupMachineType() { func mcWithNodeLabels(labels map[string]string) *config.MachineConfig { return config.NewMachineConfig( - &v1alpha1.Config{ - MachineConfig: &v1alpha1.MachineConfig{ - MachineNodeLabels: labels, - }, - }) + container.NewV1Alpha1( + &v1alpha1.Config{ + MachineConfig: &v1alpha1.MachineConfig{ + MachineNodeLabels: labels, + }, + })) } func (suite *NodeLabelsSuite) createNodeLabelsConfig(labels map[string]string) { diff --git a/internal/app/machined/pkg/controllers/k8s/nodeip_config_test.go b/internal/app/machined/pkg/controllers/k8s/nodeip_config_test.go index 02f7500db..655c9309c 100644 --- a/internal/app/machined/pkg/controllers/k8s/nodeip_config_test.go +++ b/internal/app/machined/pkg/controllers/k8s/nodeip_config_test.go @@ -23,6 +23,7 @@ import ( k8sctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/config" @@ -71,44 +72,46 @@ func (suite *NodeIPConfigSuite) TestReconcileWithSubnets() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineKubelet: &v1alpha1.KubeletConfig{ - KubeletNodeIP: &v1alpha1.KubeletNodeIPConfig{ - KubeletNodeIPValidSubnets: []string{"10.0.0.0/24"}, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineKubelet: &v1alpha1.KubeletConfig{ + KubeletNodeIP: &v1alpha1.KubeletNodeIPConfig{ + KubeletNodeIPValidSubnets: []string{"10.0.0.0/24"}, + }, }, - }, - MachineNetwork: &v1alpha1.NetworkConfig{ - NetworkInterfaces: []*v1alpha1.Device{ - { - DeviceVIPConfig: &v1alpha1.DeviceVIPConfig{ - SharedIP: "1.2.3.4", - }, - DeviceVlans: []*v1alpha1.Vlan{ - { - VlanID: 100, - VlanVIP: &v1alpha1.DeviceVIPConfig{ - SharedIP: "5.6.7.8", + MachineNetwork: &v1alpha1.NetworkConfig{ + NetworkInterfaces: []*v1alpha1.Device{ + { + DeviceVIPConfig: &v1alpha1.DeviceVIPConfig{ + SharedIP: "1.2.3.4", + }, + DeviceVlans: []*v1alpha1.Vlan{ + { + VlanID: 100, + VlanVIP: &v1alpha1.DeviceVIPConfig{ + SharedIP: "5.6.7.8", + }, }, }, }, }, }, }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, + }, + ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ + ServiceSubnet: []string{constants.DefaultIPv4ServiceNet}, + PodSubnet: []string{constants.DefaultIPv4PodNet}, }, }, - ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ - ServiceSubnet: []string{constants.DefaultIPv4ServiceNet}, - PodSubnet: []string{constants.DefaultIPv4PodNet}, - }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -152,21 +155,23 @@ func (suite *NodeIPConfigSuite) TestReconcileDefaults() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, + }, + ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ + ServiceSubnet: []string{constants.DefaultIPv4ServiceNet, constants.DefaultIPv6ServiceNet}, + PodSubnet: []string{constants.DefaultIPv4PodNet, constants.DefaultIPv6PodNet}, }, }, - ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ - ServiceSubnet: []string{constants.DefaultIPv4ServiceNet, constants.DefaultIPv6ServiceNet}, - PodSubnet: []string{constants.DefaultIPv4PodNet, constants.DefaultIPv6PodNet}, - }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) diff --git a/internal/app/machined/pkg/controllers/k8s/nodename_test.go b/internal/app/machined/pkg/controllers/k8s/nodename_test.go index 87cec5883..2aae3cddf 100644 --- a/internal/app/machined/pkg/controllers/k8s/nodename_test.go +++ b/internal/app/machined/pkg/controllers/k8s/nodename_test.go @@ -25,6 +25,7 @@ import ( k8sctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" @@ -102,17 +103,19 @@ func (suite *NodenameSuite) TestDefault() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -137,21 +140,23 @@ func (suite *NodenameSuite) TestFQDN() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineKubelet: &v1alpha1.KubeletConfig{ - KubeletRegisterWithFQDN: pointer.To(true), + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineKubelet: &v1alpha1.KubeletConfig{ + KubeletRegisterWithFQDN: pointer.To(true), + }, }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -177,28 +182,6 @@ func (suite *NodenameSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - err := suite.state.Create( - context.Background(), config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - }, - ), - ) - if state.IsConflictError(err) { - err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) - } - - suite.Require().NoError(err) - - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewHostnameStatus(network.NamespaceName, "bar"), - ), - ) } func TestNodenameSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/k8s/static_endpoint_test.go b/internal/app/machined/pkg/controllers/k8s/static_endpoint_test.go index ad86e9f2c..6b0fe4885 100644 --- a/internal/app/machined/pkg/controllers/k8s/static_endpoint_test.go +++ b/internal/app/machined/pkg/controllers/k8s/static_endpoint_test.go @@ -16,6 +16,7 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" k8sctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" @@ -30,17 +31,19 @@ func (suite *StaticEndpointControllerSuite) TestReconcile() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, }, }, - }, + ), ) suite.Require().NoError(suite.State().Create(suite.Ctx(), cfg)) diff --git a/internal/app/machined/pkg/controllers/k8s/static_pod_config_test.go b/internal/app/machined/pkg/controllers/k8s/static_pod_config_test.go index ff242f55d..76b6d8550 100644 --- a/internal/app/machined/pkg/controllers/k8s/static_pod_config_test.go +++ b/internal/app/machined/pkg/controllers/k8s/static_pod_config_test.go @@ -23,6 +23,7 @@ import ( k8sctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" @@ -100,32 +101,33 @@ func (suite *StaticPodConfigSuite) assertNoResource(md resource.Metadata) func() func (suite *StaticPodConfigSuite) TestReconcile() { cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachinePods: []v1alpha1.Unstructured{ - { - Object: map[string]interface{}{ - "apiVersion": "v1", - "kind": "pod", - "metadata": map[string]interface{}{ - "name": "nginx", - }, - "spec": map[string]interface{}{ - "containers": []interface{}{ - map[string]interface{}{ - "name": "nginx", - "image": "nginx", + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachinePods: []v1alpha1.Unstructured{ + { + Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "pod", + "metadata": map[string]interface{}{ + "name": "nginx", + }, + "spec": map[string]interface{}{ + "containers": []interface{}{ + map[string]interface{}{ + "name": "nginx", + "image": "nginx", + }, }, }, }, }, }, }, + ClusterConfig: &v1alpha1.ClusterConfig{}, }, - ClusterConfig: &v1alpha1.ClusterConfig{}, - }, - ) + )) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) diff --git a/internal/app/machined/pkg/controllers/kubeaccess/config_test.go b/internal/app/machined/pkg/controllers/kubeaccess/config_test.go index 9a85fb972..19ee03e60 100644 --- a/internal/app/machined/pkg/controllers/kubeaccess/config_test.go +++ b/internal/app/machined/pkg/controllers/kubeaccess/config_test.go @@ -14,8 +14,9 @@ import ( "github.com/stretchr/testify/suite" kubeaccessctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/kubeaccess" + "github.com/siderolabs/talos/pkg/machinery/config/container" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/kubeaccess" ) @@ -34,7 +35,7 @@ func (suite *ConfigSuite) TestReconcileConfig() { suite.Require().NoError(suite.state.Create(suite.ctx, machineType)) - cfg := config.NewMachineConfig(&v1alpha1.Config{ + cfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{ ConfigVersion: "v1alpha1", MachineConfig: &v1alpha1.MachineConfig{ MachineFeatures: &v1alpha1.FeaturesConfig{ @@ -45,7 +46,7 @@ func (suite *ConfigSuite) TestReconcileConfig() { }, }, }, - }) + })) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -77,10 +78,10 @@ func (suite *ConfigSuite) TestReconcileDisabled() { suite.Require().NoError(suite.state.Create(suite.ctx, machineType)) - cfg := config.NewMachineConfig(&v1alpha1.Config{ + cfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{ ConfigVersion: "v1alpha1", MachineConfig: &v1alpha1.MachineConfig{}, - }) + })) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -112,7 +113,7 @@ func (suite *ConfigSuite) TestReconcileWorker() { suite.Require().NoError(suite.state.Create(suite.ctx, machineType)) - cfg := config.NewMachineConfig(&v1alpha1.Config{ + cfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{ ConfigVersion: "v1alpha1", MachineConfig: &v1alpha1.MachineConfig{ MachineFeatures: &v1alpha1.FeaturesConfig{ @@ -123,7 +124,7 @@ func (suite *ConfigSuite) TestReconcileWorker() { }, }, }, - }) + })) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) diff --git a/internal/app/machined/pkg/controllers/kubeaccess/kubeaccess_test.go b/internal/app/machined/pkg/controllers/kubeaccess/kubeaccess_test.go index faa77f3b5..f8aa3e83a 100644 --- a/internal/app/machined/pkg/controllers/kubeaccess/kubeaccess_test.go +++ b/internal/app/machined/pkg/controllers/kubeaccess/kubeaccess_test.go @@ -19,8 +19,6 @@ import ( "github.com/stretchr/testify/suite" "github.com/siderolabs/talos/pkg/logging" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/resources/config" ) type KubeaccessSuite struct { @@ -94,19 +92,4 @@ func (suite *KubeaccessSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - err := suite.state.Create( - context.Background(), config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - }, - ), - ) - if state.IsConflictError(err) { - err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) - } - - suite.Assert().NoError(err) } diff --git a/internal/app/machined/pkg/controllers/kubeaccess/serviceaccount/crd_controller.go b/internal/app/machined/pkg/controllers/kubeaccess/serviceaccount/crd_controller.go index 3cb07e8ec..9b6850bbe 100644 --- a/internal/app/machined/pkg/controllers/kubeaccess/serviceaccount/crd_controller.go +++ b/internal/app/machined/pkg/controllers/kubeaccess/serviceaccount/crd_controller.go @@ -43,7 +43,7 @@ import ( "k8s.io/client-go/util/workqueue" clientconfig "github.com/siderolabs/talos/pkg/machinery/client/config" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" + "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/role" ) @@ -639,7 +639,7 @@ func (t *CRDController) newSecret(talosSA *unstructured.Unstructured, roles role func (t *CRDController) generateTalosconfig(roles role.Set) ([]byte, error) { var newCert *x509.PEMEncodedCertificateAndKey - newCert, err := generate.NewAdminCertificateAndKey(time.Now(), t.talosCA, roles, certTTL) + newCert, err := secrets.NewAdminCertificateAndKey(time.Now(), t.talosCA, roles, certTTL) if err != nil { return nil, err } diff --git a/internal/app/machined/pkg/controllers/kubespan/config_test.go b/internal/app/machined/pkg/controllers/kubespan/config_test.go index e0a38ba02..8a0e80f73 100644 --- a/internal/app/machined/pkg/controllers/kubespan/config_test.go +++ b/internal/app/machined/pkg/controllers/kubespan/config_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/suite" kubespanctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/kubespan" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/kubespan" @@ -27,20 +28,22 @@ func (suite *ConfigSuite) TestReconcileConfig() { suite.startRuntime() - cfg := config.NewMachineConfig(&v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineNetwork: &v1alpha1.NetworkConfig{ - NetworkKubeSpan: &v1alpha1.NetworkKubeSpan{ - KubeSpanEnabled: pointer.To(true), + cfg := config.NewMachineConfig( + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineNetwork: &v1alpha1.NetworkConfig{ + NetworkKubeSpan: &v1alpha1.NetworkKubeSpan{ + KubeSpanEnabled: pointer.To(true), + }, + }, }, - }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{ - ClusterID: "8XuV9TZHW08DOk3bVxQjH9ih_TBKjnh-j44tsCLSBzo=", - ClusterSecret: "I+1In7fLnpcRIjUmEoeugZnSyFoTF6MztLxICL5Yu0s=", - }, - }) + ClusterConfig: &v1alpha1.ClusterConfig{ + ClusterID: "8XuV9TZHW08DOk3bVxQjH9ih_TBKjnh-j44tsCLSBzo=", + ClusterSecret: "I+1In7fLnpcRIjUmEoeugZnSyFoTF6MztLxICL5Yu0s=", + }, + })) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -69,11 +72,13 @@ func (suite *ConfigSuite) TestReconcileDisabled() { suite.startRuntime() - cfg := config.NewMachineConfig(&v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - ClusterConfig: &v1alpha1.ClusterConfig{}, - }) + cfg := config.NewMachineConfig( + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + ClusterConfig: &v1alpha1.ClusterConfig{}, + })) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) diff --git a/internal/app/machined/pkg/controllers/kubespan/endpoint_test.go b/internal/app/machined/pkg/controllers/kubespan/endpoint_test.go index 6fb48c8ab..4d4765c3d 100644 --- a/internal/app/machined/pkg/controllers/kubespan/endpoint_test.go +++ b/internal/app/machined/pkg/controllers/kubespan/endpoint_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/suite" kubespanctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/kubespan" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/cluster" "github.com/siderolabs/talos/pkg/machinery/resources/kubespan" ) diff --git a/internal/app/machined/pkg/controllers/kubespan/kubespan_test.go b/internal/app/machined/pkg/controllers/kubespan/kubespan_test.go index df5a9b122..ebbeba50f 100644 --- a/internal/app/machined/pkg/controllers/kubespan/kubespan_test.go +++ b/internal/app/machined/pkg/controllers/kubespan/kubespan_test.go @@ -22,8 +22,6 @@ import ( "github.com/stretchr/testify/suite" "github.com/siderolabs/talos/pkg/logging" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/resources/config" ) type KubeSpanSuite struct { @@ -131,19 +129,4 @@ func (suite *KubeSpanSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - err := suite.state.Create( - context.Background(), config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - }, - ), - ) - if state.IsConflictError(err) { - err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) - } - - suite.Assert().NoError(err) } diff --git a/internal/app/machined/pkg/controllers/kubespan/manager_test.go b/internal/app/machined/pkg/controllers/kubespan/manager_test.go index 06efd6e2e..f68e2e722 100644 --- a/internal/app/machined/pkg/controllers/kubespan/manager_test.go +++ b/internal/app/machined/pkg/controllers/kubespan/manager_test.go @@ -480,5 +480,9 @@ func asUDP(addr netip.AddrPort) *net.UDPAddr { } func TestManagerSuite(t *testing.T) { + if os.Geteuid() != 0 { + t.Skip("requires root") + } + suite.Run(t, new(ManagerSuite)) } diff --git a/internal/app/machined/pkg/controllers/kubespan/nftables_test.go b/internal/app/machined/pkg/controllers/kubespan/nftables_test.go index f9aaafc62..fef62f1ef 100644 --- a/internal/app/machined/pkg/controllers/kubespan/nftables_test.go +++ b/internal/app/machined/pkg/controllers/kubespan/nftables_test.go @@ -5,6 +5,7 @@ package kubespan_test import ( "net/netip" + "os" "testing" "github.com/stretchr/testify/assert" @@ -16,6 +17,10 @@ import ( ) func TestNfTables(t *testing.T) { + if os.Geteuid() != 0 { + t.Skip("requires root") + } + // use a different mark to avoid conflicts with running kubespan mgr := kubespan.NewNfTablesManager( constants.KubeSpanDefaultFirewallMark<<1, diff --git a/internal/app/machined/pkg/controllers/kubespan/peer_spec_test.go b/internal/app/machined/pkg/controllers/kubespan/peer_spec_test.go index ba919dc1d..da0f6843a 100644 --- a/internal/app/machined/pkg/controllers/kubespan/peer_spec_test.go +++ b/internal/app/machined/pkg/controllers/kubespan/peer_spec_test.go @@ -15,7 +15,7 @@ import ( clusteradapter "github.com/siderolabs/talos/internal/app/machined/pkg/adapters/cluster" kubespanctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/kubespan" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/cluster" "github.com/siderolabs/talos/pkg/machinery/resources/config" diff --git a/internal/app/machined/pkg/controllers/kubespan/routing_rules_test.go b/internal/app/machined/pkg/controllers/kubespan/routing_rules_test.go index 4933b5cde..0e9ca81cc 100644 --- a/internal/app/machined/pkg/controllers/kubespan/routing_rules_test.go +++ b/internal/app/machined/pkg/controllers/kubespan/routing_rules_test.go @@ -4,6 +4,7 @@ package kubespan_test import ( + "os" "testing" "github.com/stretchr/testify/assert" @@ -13,6 +14,10 @@ import ( ) func TestRoutingRules(t *testing.T) { + if os.Geteuid() != 0 { + t.Skip("requires root") + } + // use a different table/mark to avoid conflicts with running kubespan mgr := kubespan.NewRulesManager(constants.KubeSpanDefaultRoutingTable+10, constants.KubeSpanDefaultForceFirewallMark<<1, constants.KubeSpanDefaultFirewallMask<<1) diff --git a/internal/app/machined/pkg/controllers/network/address_config_test.go b/internal/app/machined/pkg/controllers/network/address_config_test.go index 494ec904d..946bf555e 100644 --- a/internal/app/machined/pkg/controllers/network/address_config_test.go +++ b/internal/app/machined/pkg/controllers/network/address_config_test.go @@ -28,6 +28,7 @@ import ( netctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/nethelpers" "github.com/siderolabs/talos/pkg/machinery/resources/config" @@ -162,61 +163,63 @@ func (suite *AddressConfigSuite) TestMachineConfiguration() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineNetwork: &v1alpha1.NetworkConfig{ - NetworkInterfaces: []*v1alpha1.Device{ - { - DeviceInterface: "eth3", - DeviceCIDR: "192.168.0.24/28", - }, - { - DeviceIgnore: pointer.To(true), - DeviceInterface: "eth4", - DeviceCIDR: "192.168.0.24/28", - }, - { - DeviceInterface: "eth2", - DeviceCIDR: "2001:470:6d:30e:8ed2:b60c:9d2f:803a/64", - }, - { - DeviceInterface: "eth5", - DeviceCIDR: "10.5.0.7", - }, - { - DeviceInterface: "eth6", - DeviceAddresses: []string{ - "10.5.0.8", - "2001:470:6d:30e:8ed2:b60c:9d2f:803b/64", + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineNetwork: &v1alpha1.NetworkConfig{ + NetworkInterfaces: []*v1alpha1.Device{ + { + DeviceInterface: "eth3", + DeviceCIDR: "192.168.0.24/28", }, - }, - { - DeviceInterface: "eth0", - DeviceVlans: []*v1alpha1.Vlan{ - { - VlanID: 24, - VlanCIDR: "10.0.0.1/8", + { + DeviceIgnore: pointer.To(true), + DeviceInterface: "eth4", + DeviceCIDR: "192.168.0.24/28", + }, + { + DeviceInterface: "eth2", + DeviceCIDR: "2001:470:6d:30e:8ed2:b60c:9d2f:803a/64", + }, + { + DeviceInterface: "eth5", + DeviceCIDR: "10.5.0.7", + }, + { + DeviceInterface: "eth6", + DeviceAddresses: []string{ + "10.5.0.8", + "2001:470:6d:30e:8ed2:b60c:9d2f:803b/64", }, - { - VlanID: 25, - VlanAddresses: []string{ - "11.0.0.1/8", + }, + { + DeviceInterface: "eth0", + DeviceVlans: []*v1alpha1.Vlan{ + { + VlanID: 24, + VlanCIDR: "10.0.0.1/8", + }, + { + VlanID: 25, + VlanAddresses: []string{ + "11.0.0.1/8", + }, }, }, }, }, }, }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -240,21 +243,6 @@ func (suite *AddressConfigSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - err := suite.state.Create( - context.Background(), config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - }, - ), - ) - if state.IsConflictError(err) { - err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) - } - - suite.Require().NoError(err) } func TestAddressConfigSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/address_merge_test.go b/internal/app/machined/pkg/controllers/network/address_merge_test.go index 98a25afb3..9f365f079 100644 --- a/internal/app/machined/pkg/controllers/network/address_merge_test.go +++ b/internal/app/machined/pkg/controllers/network/address_merge_test.go @@ -273,14 +273,6 @@ func (suite *AddressMergeSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewAddressSpec(network.ConfigNamespaceName, "bar"), - ), - ) } func TestAddressMergeSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/address_spec_test.go b/internal/app/machined/pkg/controllers/network/address_spec_test.go index 98a856380..5d5b3cb5c 100644 --- a/internal/app/machined/pkg/controllers/network/address_spec_test.go +++ b/internal/app/machined/pkg/controllers/network/address_spec_test.go @@ -12,6 +12,7 @@ import ( "math/rand" "net" "net/netip" + "os" "sync" "testing" "time" @@ -244,16 +245,12 @@ func (suite *AddressSpecSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewAddressSpec(network.NamespaceName, "bar"), - ), - ) } func TestAddressSpecSuite(t *testing.T) { + if os.Geteuid() != 0 { + t.Skip("requires root") + } + suite.Run(t, new(AddressSpecSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/device_config_test.go b/internal/app/machined/pkg/controllers/network/device_config_test.go index e964cd294..8d76b5aa9 100644 --- a/internal/app/machined/pkg/controllers/network/device_config_test.go +++ b/internal/app/machined/pkg/controllers/network/device_config_test.go @@ -18,6 +18,8 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" netctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network" + configs "github.com/siderolabs/talos/pkg/machinery/config/config" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/nethelpers" "github.com/siderolabs/talos/pkg/machinery/resources/config" @@ -29,7 +31,7 @@ type DeviceConfigSpecSuite struct { } func (suite *DeviceConfigSpecSuite) TestDeviceConfigs() { - cfgProvider := &v1alpha1.Config{ + cfgProvider := container.NewV1Alpha1(&v1alpha1.Config{ ConfigVersion: "v1alpha1", MachineConfig: &v1alpha1.MachineConfig{ MachineNetwork: &v1alpha1.NetworkConfig{ @@ -54,13 +56,13 @@ func (suite *DeviceConfigSpecSuite) TestDeviceConfigs() { }, }, }, - } + }) cfg := config.NewMachineConfig(cfgProvider) - devices := map[string]*v1alpha1.Device{} - for index, item := range cfgProvider.MachineConfig.MachineNetwork.NetworkInterfaces { - devices[fmt.Sprintf("%s/%03d", item.DeviceInterface, index)] = item + devices := map[string]configs.Device{} + for index, item := range cfgProvider.Machine().Network().Devices() { + devices[fmt.Sprintf("%s/%03d", item.Interface(), index)] = item } suite.Require().NoError(suite.State().Create(suite.Ctx(), cfg)) @@ -75,7 +77,7 @@ func (suite *DeviceConfigSpecSuite) TestDeviceConfigs() { func (suite *DeviceConfigSpecSuite) TestSelectors() { kernelDriver := "thedriver" - cfgProvider := &v1alpha1.Config{ + cfgProvider := container.NewV1Alpha1(&v1alpha1.Config{ ConfigVersion: "v1alpha1", MachineConfig: &v1alpha1.MachineConfig{ MachineNetwork: &v1alpha1.NetworkConfig{ @@ -90,7 +92,7 @@ func (suite *DeviceConfigSpecSuite) TestSelectors() { }, }, }, - } + }) cfg := config.NewMachineConfig(cfgProvider) suite.Require().NoError(suite.State().Create(suite.Ctx(), cfg)) @@ -111,7 +113,7 @@ func (suite *DeviceConfigSpecSuite) TestSelectors() { } func (suite *DeviceConfigSpecSuite) TestBondSelectors() { - cfgProvider := &v1alpha1.Config{ + cfgProvider := container.NewV1Alpha1(&v1alpha1.Config{ ConfigVersion: "v1alpha1", MachineConfig: &v1alpha1.MachineConfig{ MachineNetwork: &v1alpha1.NetworkConfig{ @@ -135,7 +137,7 @@ func (suite *DeviceConfigSpecSuite) TestBondSelectors() { }, }, }, - } + }) cfg := config.NewMachineConfig(cfgProvider) suite.Require().NoError(suite.State().Create(suite.Ctx(), cfg)) diff --git a/internal/app/machined/pkg/controllers/network/etcfile_test.go b/internal/app/machined/pkg/controllers/network/etcfile_test.go index c01bc1353..1a35c72de 100644 --- a/internal/app/machined/pkg/controllers/network/etcfile_test.go +++ b/internal/app/machined/pkg/controllers/network/etcfile_test.go @@ -25,6 +25,7 @@ import ( netctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/files" @@ -66,30 +67,32 @@ func (suite *EtcFileConfigSuite) SetupTest() { suite.Require().NoError(err) suite.cfg = config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineNetwork: &v1alpha1.NetworkConfig{ - ExtraHostEntries: []*v1alpha1.ExtraHost{ - { - HostIP: "10.0.0.1", - HostAliases: []string{"a", "b"}, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineNetwork: &v1alpha1.NetworkConfig{ + ExtraHostEntries: []*v1alpha1.ExtraHost{ + { + HostIP: "10.0.0.1", + HostAliases: []string{"a", "b"}, + }, + { + HostIP: "10.0.0.2", + HostAliases: []string{"c", "d"}, + }, }, - { - HostIP: "10.0.0.2", - HostAliases: []string{"c", "d"}, + }, + }, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, }, }, }, }, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, - }, - }, - }, - }, + ), ) suite.defaultAddress = network.NewNodeAddress(network.NamespaceName, network.NodeAddressDefaultID) @@ -182,14 +185,16 @@ func (suite *EtcFileConfigSuite) TestNoExtraHosts() { func (suite *EtcFileConfigSuite) TestNoSearchDomain() { cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineNetwork: &v1alpha1.NetworkConfig{ - NetworkDisableSearchDomain: pointer.To(true), + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineNetwork: &v1alpha1.NetworkConfig{ + NetworkDisableSearchDomain: pointer.To(true), + }, }, }, - }, + ), ) suite.testFiles( []resource.Resource{cfg, suite.defaultAddress, suite.hostnameStatus, suite.resolverStatus}, @@ -230,40 +235,6 @@ func (suite *EtcFileConfigSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - err := suite.state.Create( - context.Background(), config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - }, - ), - ) - if state.IsConflictError(err) { - err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) - } - - suite.Require().NoError(err) - - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewHostnameStatus(network.NamespaceName, "bar"), - ), - ) - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewResolverStatus(network.NamespaceName, "bar"), - ), - ) - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewNodeAddress(network.NamespaceName, "bar"), - ), - ) } func TestEtcFileConfigSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/hardware_addr_test.go b/internal/app/machined/pkg/controllers/network/hardware_addr_test.go index 2cf07c384..70521479f 100644 --- a/internal/app/machined/pkg/controllers/network/hardware_addr_test.go +++ b/internal/app/machined/pkg/controllers/network/hardware_addr_test.go @@ -146,14 +146,6 @@ func (suite *HardwareAddrSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewLinkStatus(network.NamespaceName, "bar"), - ), - ) } func TestHardwareAddrSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/hostname_config_test.go b/internal/app/machined/pkg/controllers/network/hostname_config_test.go index 3aed3cc94..7678cc414 100644 --- a/internal/app/machined/pkg/controllers/network/hostname_config_test.go +++ b/internal/app/machined/pkg/controllers/network/hostname_config_test.go @@ -31,6 +31,7 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" netctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/resources/cluster" "github.com/siderolabs/talos/pkg/machinery/resources/config" @@ -116,7 +117,7 @@ func (suite *HostnameConfigSuite) TestDefaultIPBasedHostname() { suite.startRuntime() - cfg := config.NewMachineConfig(&v1alpha1.Config{ConfigVersion: "v1alpha1"}) + cfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{ConfigVersion: "v1alpha1"})) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) defaultAddress := network.NewNodeAddress(network.NamespaceName, network.NodeAddressDefaultID) @@ -141,14 +142,16 @@ func (suite *HostnameConfigSuite) TestDefaultStableHostname() { suite.startRuntime() cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineFeatures: &v1alpha1.FeaturesConfig{ - StableHostname: pointer.To(true), + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineFeatures: &v1alpha1.FeaturesConfig{ + StableHostname: pointer.To(true), + }, }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -198,21 +201,23 @@ func (suite *HostnameConfigSuite) TestMachineConfiguration() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineNetwork: &v1alpha1.NetworkConfig{ - NetworkHostname: "foo", + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineNetwork: &v1alpha1.NetworkConfig{ + NetworkHostname: "foo", + }, }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -228,7 +233,7 @@ func (suite *HostnameConfigSuite) TestMachineConfiguration() { ) ctest.UpdateWithConflicts(suite, cfg, func(r *config.MachineConfig) error { - r.Config().(*v1alpha1.Config).MachineConfig.MachineNetwork.NetworkHostname = strings.Repeat("a", 128) + r.Container().RawV1Alpha1().MachineConfig.MachineNetwork.NetworkHostname = strings.Repeat("a", 128) return nil }) @@ -249,28 +254,6 @@ func (suite *HostnameConfigSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - err := suite.state.Create( - context.Background(), config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - }, - ), - ) - if state.IsConflictError(err) { - err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) - } - - suite.Require().NoError(err) - - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewNodeAddress(network.NamespaceName, "bar"), - ), - ) } func TestHostnameConfigSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/hostname_merge_test.go b/internal/app/machined/pkg/controllers/network/hostname_merge_test.go index c2296ef4d..dd9771432 100644 --- a/internal/app/machined/pkg/controllers/network/hostname_merge_test.go +++ b/internal/app/machined/pkg/controllers/network/hostname_merge_test.go @@ -124,14 +124,6 @@ func (suite *HostnameMergeSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewHostnameSpec(network.ConfigNamespaceName, "bar"), - ), - ) } func TestHostnameMergeSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/hostname_spec_test.go b/internal/app/machined/pkg/controllers/network/hostname_spec_test.go index e8ae1953e..53c6c3cd6 100644 --- a/internal/app/machined/pkg/controllers/network/hostname_spec_test.go +++ b/internal/app/machined/pkg/controllers/network/hostname_spec_test.go @@ -117,14 +117,6 @@ func (suite *HostnameSpecSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewHostnameSpec(network.NamespaceName, "bar"), - ), - ) } func TestHostnameSpecSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/link_config_test.go b/internal/app/machined/pkg/controllers/network/link_config_test.go index 050e5180f..66a704d29 100644 --- a/internal/app/machined/pkg/controllers/network/link_config_test.go +++ b/internal/app/machined/pkg/controllers/network/link_config_test.go @@ -28,6 +28,7 @@ import ( netctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/nethelpers" "github.com/siderolabs/talos/pkg/machinery/resources/config" @@ -150,101 +151,103 @@ func (suite *LinkConfigSuite) TestMachineConfiguration() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineNetwork: &v1alpha1.NetworkConfig{ - NetworkInterfaces: []*v1alpha1.Device{ - { - DeviceInterface: "eth0", - DeviceVlans: []*v1alpha1.Vlan{ - { - VlanID: 24, - VlanMTU: 1000, - VlanAddresses: []string{ - "10.0.0.1/8", - }, - }, - { - VlanID: 48, - VlanAddresses: []string{ - "10.0.0.2/8", - }, - }, - }, - }, - { - DeviceInterface: "eth1", - DeviceAddresses: []string{"192.168.0.24/28"}, - }, - { - DeviceInterface: "eth1", - DeviceMTU: 9001, - }, - { - DeviceIgnore: pointer.To(true), - DeviceInterface: "eth2", - DeviceAddresses: []string{"192.168.0.24/28"}, - }, - { - DeviceInterface: "eth2", - }, - { - DeviceInterface: "bond0", - DeviceBond: &v1alpha1.Bond{ - BondInterfaces: []string{"eth2", "eth3"}, - BondMode: "balance-xor", - }, - }, - { - DeviceInterface: "bond1", - DeviceBond: &v1alpha1.Bond{ - BondDeviceSelectors: []v1alpha1.NetworkDeviceSelector{{ - NetworkDeviceKernelDriver: kernelDriver, - }}, - BondMode: "balance-xor", - }, - }, - { - DeviceInterface: "eth4", - DeviceAddresses: []string{"192.168.0.42/24"}, - }, - { - DeviceInterface: "eth5", - DeviceAddresses: []string{"192.168.0.43/24"}, - }, - { - DeviceInterface: "br0", - DeviceBridge: &v1alpha1.Bridge{ - BridgedInterfaces: []string{"eth4", "eth5"}, - BridgeSTP: &v1alpha1.STP{ - STPEnabled: pointer.To(false), - }, - }, - }, - { - DeviceInterface: "br0", - DeviceBridge: &v1alpha1.Bridge{ - BridgeSTP: &v1alpha1.STP{ - STPEnabled: pointer.To(true), - }, - }, - }, - { - DeviceInterface: "dummy0", - DeviceDummy: pointer.To(true), - }, - { - DeviceInterface: "wireguard0", - DeviceWireguardConfig: &v1alpha1.DeviceWireguardConfig{ - WireguardPrivateKey: "ABC", - WireguardPeers: []*v1alpha1.DeviceWireguardPeer{ + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineNetwork: &v1alpha1.NetworkConfig{ + NetworkInterfaces: []*v1alpha1.Device{ + { + DeviceInterface: "eth0", + DeviceVlans: []*v1alpha1.Vlan{ { - WireguardPublicKey: "DEF", - WireguardEndpoint: "10.0.0.1:3000", - WireguardAllowedIPs: []string{ - "10.2.3.0/24", - "10.2.4.0/24", + VlanID: 24, + VlanMTU: 1000, + VlanAddresses: []string{ + "10.0.0.1/8", + }, + }, + { + VlanID: 48, + VlanAddresses: []string{ + "10.0.0.2/8", + }, + }, + }, + }, + { + DeviceInterface: "eth1", + DeviceAddresses: []string{"192.168.0.24/28"}, + }, + { + DeviceInterface: "eth1", + DeviceMTU: 9001, + }, + { + DeviceIgnore: pointer.To(true), + DeviceInterface: "eth2", + DeviceAddresses: []string{"192.168.0.24/28"}, + }, + { + DeviceInterface: "eth2", + }, + { + DeviceInterface: "bond0", + DeviceBond: &v1alpha1.Bond{ + BondInterfaces: []string{"eth2", "eth3"}, + BondMode: "balance-xor", + }, + }, + { + DeviceInterface: "bond1", + DeviceBond: &v1alpha1.Bond{ + BondDeviceSelectors: []v1alpha1.NetworkDeviceSelector{{ + NetworkDeviceKernelDriver: kernelDriver, + }}, + BondMode: "balance-xor", + }, + }, + { + DeviceInterface: "eth4", + DeviceAddresses: []string{"192.168.0.42/24"}, + }, + { + DeviceInterface: "eth5", + DeviceAddresses: []string{"192.168.0.43/24"}, + }, + { + DeviceInterface: "br0", + DeviceBridge: &v1alpha1.Bridge{ + BridgedInterfaces: []string{"eth4", "eth5"}, + BridgeSTP: &v1alpha1.STP{ + STPEnabled: pointer.To(false), + }, + }, + }, + { + DeviceInterface: "br0", + DeviceBridge: &v1alpha1.Bridge{ + BridgeSTP: &v1alpha1.STP{ + STPEnabled: pointer.To(true), + }, + }, + }, + { + DeviceInterface: "dummy0", + DeviceDummy: pointer.To(true), + }, + { + DeviceInterface: "wireguard0", + DeviceWireguardConfig: &v1alpha1.DeviceWireguardConfig{ + WireguardPrivateKey: "ABC", + WireguardPeers: []*v1alpha1.DeviceWireguardPeer{ + { + WireguardPublicKey: "DEF", + WireguardEndpoint: "10.0.0.1:3000", + WireguardAllowedIPs: []string{ + "10.2.3.0/24", + "10.2.4.0/24", + }, }, }, }, @@ -252,15 +255,15 @@ func (suite *LinkConfigSuite) TestMachineConfiguration() { }, }, }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -393,48 +396,50 @@ func (suite *LinkConfigSuite) TestDefaultUp() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineNetwork: &v1alpha1.NetworkConfig{ - NetworkInterfaces: []*v1alpha1.Device{ - { - DeviceInterface: "eth0", - DeviceVlans: []*v1alpha1.Vlan{ - { - VlanID: 24, - VlanAddresses: []string{ - "10.0.0.1/8", + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineNetwork: &v1alpha1.NetworkConfig{ + NetworkInterfaces: []*v1alpha1.Device{ + { + DeviceInterface: "eth0", + DeviceVlans: []*v1alpha1.Vlan{ + { + VlanID: 24, + VlanAddresses: []string{ + "10.0.0.1/8", + }, }, - }, - { - VlanID: 48, - VlanAddresses: []string{ - "10.0.0.2/8", + { + VlanID: 48, + VlanAddresses: []string{ + "10.0.0.2/8", + }, }, }, }, - }, - { - DeviceInterface: "bond0", - DeviceBond: &v1alpha1.Bond{ - BondInterfaces: []string{ - "eth3", - "eth4", + { + DeviceInterface: "bond0", + DeviceBond: &v1alpha1.Bond{ + BondInterfaces: []string{ + "eth3", + "eth4", + }, }, }, }, }, }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -472,28 +477,6 @@ func (suite *LinkConfigSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - err := suite.state.Create( - context.Background(), config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - }, - ), - ) - if state.IsConflictError(err) { - err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) - } - - suite.Require().NoError(err) - - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewLinkStatus(network.NamespaceName, "bar"), - ), - ) } func TestLinkConfigSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/link_merge_test.go b/internal/app/machined/pkg/controllers/network/link_merge_test.go index fbe185479..47428c629 100644 --- a/internal/app/machined/pkg/controllers/network/link_merge_test.go +++ b/internal/app/machined/pkg/controllers/network/link_merge_test.go @@ -373,14 +373,6 @@ func (suite *LinkMergeSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewLinkSpec(network.ConfigNamespaceName, "bar"), - ), - ) } func TestLinkMergeSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/link_spec_test.go b/internal/app/machined/pkg/controllers/network/link_spec_test.go index 88b903f7e..43dca4a5b 100644 --- a/internal/app/machined/pkg/controllers/network/link_spec_test.go +++ b/internal/app/machined/pkg/controllers/network/link_spec_test.go @@ -11,6 +11,7 @@ import ( "log" "math/rand" "net/netip" + "os" "sync" "testing" "time" @@ -891,12 +892,13 @@ func (suite *LinkSpecSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError(suite.state.Create(context.Background(), network.NewLinkSpec(network.NamespaceName, "bar"))) } func TestLinkSpecSuite(t *testing.T) { + if os.Geteuid() != 0 { + t.Skip("requires root") + } + suite.Run(t, new(LinkSpecSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/link_status_test.go b/internal/app/machined/pkg/controllers/network/link_status_test.go index f09c7966f..4517afcc4 100644 --- a/internal/app/machined/pkg/controllers/network/link_status_test.go +++ b/internal/app/machined/pkg/controllers/network/link_status_test.go @@ -12,6 +12,7 @@ import ( "log" "math/rand" "net" + "os" "strings" "sync" "testing" @@ -200,6 +201,10 @@ func (suite *LinkStatusSuite) TestLoopbackInterface() { } func (suite *LinkStatusSuite) TestDummyInterface() { + if os.Geteuid() != 0 { + suite.T().Skip("requires root") + } + dummyInterface := suite.uniqueDummyInterface() conn, err := rtnetlink.Dial(nil) @@ -287,6 +292,10 @@ func (suite *LinkStatusSuite) TestDummyInterface() { } func (suite *LinkStatusSuite) TestBridgeInterface() { + if os.Geteuid() != 0 { + suite.T().Skip("requires root") + } + bridgeInterface := suite.uniqueDummyInterface() conn, err := rtnetlink.Dial(nil) @@ -352,14 +361,6 @@ func (suite *LinkStatusSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewLinkRefresh(network.NamespaceName, "bar"), - ), - ) } func TestLinkStatusSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/node_address_test.go b/internal/app/machined/pkg/controllers/network/node_address_test.go index b59a5c911..9b28d31e8 100644 --- a/internal/app/machined/pkg/controllers/network/node_address_test.go +++ b/internal/app/machined/pkg/controllers/network/node_address_test.go @@ -471,20 +471,6 @@ func (suite *NodeAddressSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewAddressStatus(network.NamespaceName, "bar"), - ), - ) - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewLinkStatus(network.NamespaceName, "bar"), - ), - ) } func TestNodeAddressSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/operator_config_test.go b/internal/app/machined/pkg/controllers/network/operator_config_test.go index 2cd044562..a5e394a5c 100644 --- a/internal/app/machined/pkg/controllers/network/operator_config_test.go +++ b/internal/app/machined/pkg/controllers/network/operator_config_test.go @@ -27,6 +27,7 @@ import ( netctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/nethelpers" "github.com/siderolabs/talos/pkg/machinery/resources/config" @@ -227,64 +228,66 @@ func (suite *OperatorConfigSuite) TestMachineConfigurationDHCP4() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineNetwork: &v1alpha1.NetworkConfig{ - NetworkInterfaces: []*v1alpha1.Device{ - { - DeviceInterface: "eth0", - }, - { - DeviceInterface: "eth1", - DeviceDHCP: pointer.To(true), - }, - { - DeviceIgnore: pointer.To(true), - DeviceInterface: "eth2", - DeviceDHCP: pointer.To(true), - }, - { - DeviceInterface: "eth3", - DeviceDHCP: pointer.To(true), - DeviceDHCPOptions: &v1alpha1.DHCPOptions{ - DHCPIPv4: pointer.To(true), - DHCPRouteMetric: 256, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineNetwork: &v1alpha1.NetworkConfig{ + NetworkInterfaces: []*v1alpha1.Device{ + { + DeviceInterface: "eth0", }, - }, - { - DeviceInterface: "eth4", - DeviceVlans: []*v1alpha1.Vlan{ - { - VlanID: 25, - VlanDHCP: pointer.To(true), + { + DeviceInterface: "eth1", + DeviceDHCP: pointer.To(true), + }, + { + DeviceIgnore: pointer.To(true), + DeviceInterface: "eth2", + DeviceDHCP: pointer.To(true), + }, + { + DeviceInterface: "eth3", + DeviceDHCP: pointer.To(true), + DeviceDHCPOptions: &v1alpha1.DHCPOptions{ + DHCPIPv4: pointer.To(true), + DHCPRouteMetric: 256, }, - { - VlanID: 26, - }, - { - VlanID: 27, - VlanDHCPOptions: &v1alpha1.DHCPOptions{ - DHCPRouteMetric: 256, + }, + { + DeviceInterface: "eth4", + DeviceVlans: []*v1alpha1.Vlan{ + { + VlanID: 25, + VlanDHCP: pointer.To(true), + }, + { + VlanID: 26, + }, + { + VlanID: 27, + VlanDHCPOptions: &v1alpha1.DHCPOptions{ + DHCPRouteMetric: 256, + }, }, }, }, + { + DeviceInterface: "eth5", + DeviceDHCP: pointer.To(true), + }, }, - { - DeviceInterface: "eth5", - DeviceDHCP: pointer.To(true), + }, + }, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, }, }, }, }, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, - }, - }, - }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -344,44 +347,46 @@ func (suite *OperatorConfigSuite) TestMachineConfigurationDHCP6() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineNetwork: &v1alpha1.NetworkConfig{ - NetworkInterfaces: []*v1alpha1.Device{ - { - DeviceInterface: "eth1", - DeviceDHCP: pointer.To(true), - DeviceDHCPOptions: &v1alpha1.DHCPOptions{ - DHCPIPv4: pointer.To(true), + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineNetwork: &v1alpha1.NetworkConfig{ + NetworkInterfaces: []*v1alpha1.Device{ + { + DeviceInterface: "eth1", + DeviceDHCP: pointer.To(true), + DeviceDHCPOptions: &v1alpha1.DHCPOptions{ + DHCPIPv4: pointer.To(true), + }, }, - }, - { - DeviceInterface: "eth2", - DeviceDHCP: pointer.To(true), - DeviceDHCPOptions: &v1alpha1.DHCPOptions{ - DHCPIPv6: pointer.To(true), + { + DeviceInterface: "eth2", + DeviceDHCP: pointer.To(true), + DeviceDHCPOptions: &v1alpha1.DHCPOptions{ + DHCPIPv6: pointer.To(true), + }, }, - }, - { - DeviceInterface: "eth3", - DeviceDHCP: pointer.To(true), - DeviceDHCPOptions: &v1alpha1.DHCPOptions{ - DHCPIPv6: pointer.To(true), - DHCPRouteMetric: 512, + { + DeviceInterface: "eth3", + DeviceDHCP: pointer.To(true), + DeviceDHCPOptions: &v1alpha1.DHCPOptions{ + DHCPIPv6: pointer.To(true), + DHCPRouteMetric: 512, + }, }, }, }, }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -424,28 +429,6 @@ func (suite *OperatorConfigSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - err := suite.state.Create( - context.Background(), config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - }, - ), - ) - if state.IsConflictError(err) { - err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) - } - - suite.Require().NoError(err) - - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewLinkStatus(network.ConfigNamespaceName, "bar"), - ), - ) } func TestOperatorConfigSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/operator_merge_test.go b/internal/app/machined/pkg/controllers/network/operator_merge_test.go index 2935b5952..da93f9056 100644 --- a/internal/app/machined/pkg/controllers/network/operator_merge_test.go +++ b/internal/app/machined/pkg/controllers/network/operator_merge_test.go @@ -309,14 +309,6 @@ func (suite *OperatorMergeSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewOperatorSpec(network.ConfigNamespaceName, "bar"), - ), - ) } func TestOperatorMergeSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/operator_spec_test.go b/internal/app/machined/pkg/controllers/network/operator_spec_test.go index 50813df61..550a80d76 100644 --- a/internal/app/machined/pkg/controllers/network/operator_spec_test.go +++ b/internal/app/machined/pkg/controllers/network/operator_spec_test.go @@ -546,14 +546,6 @@ func (suite *OperatorSpecSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewOperatorSpec(network.NamespaceName, "bar"), - ), - ) } func TestOperatorSpecSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/operator_vip_config_test.go b/internal/app/machined/pkg/controllers/network/operator_vip_config_test.go index b0774120f..97c8148e4 100644 --- a/internal/app/machined/pkg/controllers/network/operator_vip_config_test.go +++ b/internal/app/machined/pkg/controllers/network/operator_vip_config_test.go @@ -25,6 +25,7 @@ import ( netctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/network" @@ -81,48 +82,50 @@ func (suite *OperatorVIPConfigSuite) TestMachineConfigurationVIP() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineNetwork: &v1alpha1.NetworkConfig{ - NetworkInterfaces: []*v1alpha1.Device{ - { - DeviceInterface: "eth1", - DeviceDHCP: pointer.To(true), - DeviceVIPConfig: &v1alpha1.DeviceVIPConfig{ - SharedIP: "2.3.4.5", + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineNetwork: &v1alpha1.NetworkConfig{ + NetworkInterfaces: []*v1alpha1.Device{ + { + DeviceInterface: "eth1", + DeviceDHCP: pointer.To(true), + DeviceVIPConfig: &v1alpha1.DeviceVIPConfig{ + SharedIP: "2.3.4.5", + }, }, - }, - { - DeviceInterface: "eth2", - DeviceDHCP: pointer.To(true), - DeviceVIPConfig: &v1alpha1.DeviceVIPConfig{ - SharedIP: "fd7a:115c:a1e0:ab12:4843:cd96:6277:2302", + { + DeviceInterface: "eth2", + DeviceDHCP: pointer.To(true), + DeviceVIPConfig: &v1alpha1.DeviceVIPConfig{ + SharedIP: "fd7a:115c:a1e0:ab12:4843:cd96:6277:2302", + }, }, - }, - { - DeviceInterface: "eth3", - DeviceDHCP: pointer.To(true), - DeviceVlans: []*v1alpha1.Vlan{ - { - VlanID: 26, - VlanVIP: &v1alpha1.DeviceVIPConfig{ - SharedIP: "5.5.4.4", + { + DeviceInterface: "eth3", + DeviceDHCP: pointer.To(true), + DeviceVlans: []*v1alpha1.Vlan{ + { + VlanID: 26, + VlanVIP: &v1alpha1.DeviceVIPConfig{ + SharedIP: "5.5.4.4", + }, }, }, }, }, }, }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -160,28 +163,6 @@ func (suite *OperatorVIPConfigSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - err := suite.state.Create( - context.Background(), config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - }, - ), - ) - if state.IsConflictError(err) { - err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) - } - - suite.Require().NoError(err) - - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewLinkStatus(network.ConfigNamespaceName, "bar"), - ), - ) } func TestOperatorVIPConfigSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/resolver_config_test.go b/internal/app/machined/pkg/controllers/network/resolver_config_test.go index b1cc54bea..0e4142861 100644 --- a/internal/app/machined/pkg/controllers/network/resolver_config_test.go +++ b/internal/app/machined/pkg/controllers/network/resolver_config_test.go @@ -29,6 +29,7 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" netctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/config" @@ -148,21 +149,23 @@ func (suite *ResolverConfigSuite) TestMachineConfiguration() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineNetwork: &v1alpha1.NetworkConfig{ - NameServers: []string{"2.2.2.2", "3.3.3.3"}, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineNetwork: &v1alpha1.NetworkConfig{ + NameServers: []string{"2.2.2.2", "3.3.3.3"}, + }, }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -181,7 +184,7 @@ func (suite *ResolverConfigSuite) TestMachineConfiguration() { ) ctest.UpdateWithConflicts(suite, cfg, func(r *config.MachineConfig) error { - r.Config().(*v1alpha1.Config).MachineConfig.MachineNetwork.NameServers = nil + r.Container().RawV1Alpha1().MachineConfig.MachineNetwork.NameServers = nil return nil }) @@ -201,21 +204,6 @@ func (suite *ResolverConfigSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - err := suite.state.Create( - context.Background(), config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - }, - ), - ) - if state.IsConflictError(err) { - err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) - } - - suite.Require().NoError(err) } func TestResolverConfigSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/resolver_merge_test.go b/internal/app/machined/pkg/controllers/network/resolver_merge_test.go index 2e452befc..7ccad21fb 100644 --- a/internal/app/machined/pkg/controllers/network/resolver_merge_test.go +++ b/internal/app/machined/pkg/controllers/network/resolver_merge_test.go @@ -125,14 +125,6 @@ func (suite *ResolverMergeSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewResolverSpec(network.ConfigNamespaceName, "bar"), - ), - ) } func TestResolverMergeSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/resolver_spec_test.go b/internal/app/machined/pkg/controllers/network/resolver_spec_test.go index 4935e1a89..9d4c44f66 100644 --- a/internal/app/machined/pkg/controllers/network/resolver_spec_test.go +++ b/internal/app/machined/pkg/controllers/network/resolver_spec_test.go @@ -113,14 +113,6 @@ func (suite *ResolverSpecSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewResolverSpec(network.NamespaceName, "bar"), - ), - ) } func TestResolverSpecSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/route_config_test.go b/internal/app/machined/pkg/controllers/network/route_config_test.go index b2b09bb32..0a694043a 100644 --- a/internal/app/machined/pkg/controllers/network/route_config_test.go +++ b/internal/app/machined/pkg/controllers/network/route_config_test.go @@ -26,6 +26,7 @@ import ( netctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/nethelpers" "github.com/siderolabs/talos/pkg/machinery/resources/config" @@ -144,84 +145,86 @@ func (suite *RouteConfigSuite) TestMachineConfiguration() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineNetwork: &v1alpha1.NetworkConfig{ - NetworkInterfaces: []*v1alpha1.Device{ - { - DeviceInterface: "eth3", - DeviceAddresses: []string{"192.168.0.24/28"}, - DeviceRoutes: []*v1alpha1.Route{ - { - RouteNetwork: "192.168.0.0/18", - RouteGateway: "192.168.0.25", - RouteMetric: 25, - }, - { - RouteNetwork: "169.254.254.254/32", - }, - }, - }, - { - DeviceIgnore: pointer.To(true), - DeviceInterface: "eth4", - DeviceAddresses: []string{"192.168.0.24/28"}, - DeviceRoutes: []*v1alpha1.Route{ - { - RouteNetwork: "192.168.0.0/18", - RouteGateway: "192.168.0.26", - RouteMetric: 25, - }, - }, - }, - { - DeviceInterface: "eth2", - DeviceAddresses: []string{"2001:470:6d:30e:8ed2:b60c:9d2f:803a/64"}, - DeviceRoutes: []*v1alpha1.Route{ - { - RouteGateway: "2001:470:6d:30e:8ed2:b60c:9d2f:803b", - }, - }, - }, - { - DeviceInterface: "eth0", - DeviceVlans: []*v1alpha1.Vlan{ - { - VlanID: 24, - VlanAddresses: []string{ - "10.0.0.1/8", + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineNetwork: &v1alpha1.NetworkConfig{ + NetworkInterfaces: []*v1alpha1.Device{ + { + DeviceInterface: "eth3", + DeviceAddresses: []string{"192.168.0.24/28"}, + DeviceRoutes: []*v1alpha1.Route{ + { + RouteNetwork: "192.168.0.0/18", + RouteGateway: "192.168.0.25", + RouteMetric: 25, }, - VlanRoutes: []*v1alpha1.Route{ - { - RouteNetwork: "10.0.3.0/24", - RouteGateway: "10.0.3.1", + { + RouteNetwork: "169.254.254.254/32", + }, + }, + }, + { + DeviceIgnore: pointer.To(true), + DeviceInterface: "eth4", + DeviceAddresses: []string{"192.168.0.24/28"}, + DeviceRoutes: []*v1alpha1.Route{ + { + RouteNetwork: "192.168.0.0/18", + RouteGateway: "192.168.0.26", + RouteMetric: 25, + }, + }, + }, + { + DeviceInterface: "eth2", + DeviceAddresses: []string{"2001:470:6d:30e:8ed2:b60c:9d2f:803a/64"}, + DeviceRoutes: []*v1alpha1.Route{ + { + RouteGateway: "2001:470:6d:30e:8ed2:b60c:9d2f:803b", + }, + }, + }, + { + DeviceInterface: "eth0", + DeviceVlans: []*v1alpha1.Vlan{ + { + VlanID: 24, + VlanAddresses: []string{ + "10.0.0.1/8", + }, + VlanRoutes: []*v1alpha1.Route{ + { + RouteNetwork: "10.0.3.0/24", + RouteGateway: "10.0.3.1", + }, }, }, }, }, - }, - { - DeviceInterface: "eth1", - DeviceRoutes: []*v1alpha1.Route{ - { - RouteNetwork: "192.244.0.0/24", - RouteGateway: "192.244.0.1", - RouteSource: "192.244.0.10", + { + DeviceInterface: "eth1", + DeviceRoutes: []*v1alpha1.Route{ + { + RouteNetwork: "192.244.0.0/24", + RouteGateway: "192.244.0.1", + RouteSource: "192.244.0.10", + }, }, }, }, }, }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -271,21 +274,6 @@ func (suite *RouteConfigSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - err := suite.state.Create( - context.Background(), config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - }, - ), - ) - if state.IsConflictError(err) { - err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) - } - - suite.Require().NoError(err) } func TestRouteConfigSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/route_merge_test.go b/internal/app/machined/pkg/controllers/network/route_merge_test.go index 64859301e..8425ceeb8 100644 --- a/internal/app/machined/pkg/controllers/network/route_merge_test.go +++ b/internal/app/machined/pkg/controllers/network/route_merge_test.go @@ -352,14 +352,6 @@ func (suite *RouteMergeSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewRouteSpec(network.ConfigNamespaceName, "bar"), - ), - ) } func TestRouteMergeSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/route_spec_test.go b/internal/app/machined/pkg/controllers/network/route_spec_test.go index 8a18b93f0..126e58285 100644 --- a/internal/app/machined/pkg/controllers/network/route_spec_test.go +++ b/internal/app/machined/pkg/controllers/network/route_spec_test.go @@ -12,6 +12,7 @@ import ( "math/rand" "net" "net/netip" + "os" "sync" "testing" "time" @@ -558,11 +559,12 @@ func (suite *RouteSpecSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError(suite.state.Create(context.Background(), network.NewRouteSpec(network.NamespaceName, "bar"))) } func TestRouteSpecSuite(t *testing.T) { + if os.Geteuid() != 0 { + t.Skip("requires root") + } + suite.Run(t, new(RouteSpecSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/timeserver_config_test.go b/internal/app/machined/pkg/controllers/network/timeserver_config_test.go index 38dd90e02..f0397ed97 100644 --- a/internal/app/machined/pkg/controllers/network/timeserver_config_test.go +++ b/internal/app/machined/pkg/controllers/network/timeserver_config_test.go @@ -28,6 +28,7 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" netctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/config" @@ -140,21 +141,23 @@ func (suite *TimeServerConfigSuite) TestMachineConfiguration() { suite.Require().NoError(err) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineTime: &v1alpha1.TimeConfig{ - TimeServers: []string{"za.pool.ntp.org", "pool.ntp.org"}, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineTime: &v1alpha1.TimeConfig{ + TimeServers: []string{"za.pool.ntp.org", "pool.ntp.org"}, + }, }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, }, }, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -168,7 +171,7 @@ func (suite *TimeServerConfigSuite) TestMachineConfiguration() { ) ctest.UpdateWithConflicts(suite, cfg, func(r *config.MachineConfig) error { - r.Config().(*v1alpha1.Config).MachineConfig.MachineTime = nil + r.Container().RawV1Alpha1().MachineConfig.MachineTime = nil return nil }) @@ -188,21 +191,6 @@ func (suite *TimeServerConfigSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - err := suite.state.Create( - context.Background(), config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - }, - ), - ) - if state.IsConflictError(err) { - err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) - } - - suite.Require().NoError(err) } func TestTimeServerConfigSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/timeserver_merge_test.go b/internal/app/machined/pkg/controllers/network/timeserver_merge_test.go index 7901db669..cc7f130a0 100644 --- a/internal/app/machined/pkg/controllers/network/timeserver_merge_test.go +++ b/internal/app/machined/pkg/controllers/network/timeserver_merge_test.go @@ -124,14 +124,6 @@ func (suite *TimeServerMergeSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewTimeServerSpec(network.ConfigNamespaceName, "bar"), - ), - ) } func TestTimeServerMergeSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/network/timeserver_spec_test.go b/internal/app/machined/pkg/controllers/network/timeserver_spec_test.go index 0533c0f8f..a0624efbb 100644 --- a/internal/app/machined/pkg/controllers/network/timeserver_spec_test.go +++ b/internal/app/machined/pkg/controllers/network/timeserver_spec_test.go @@ -112,14 +112,6 @@ func (suite *TimeServerSpecSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - suite.Assert().NoError( - suite.state.Create( - context.Background(), - network.NewTimeServerSpec(network.NamespaceName, "bar"), - ), - ) } func TestTimeServerSpecSuite(t *testing.T) { diff --git a/internal/app/machined/pkg/controllers/runtime/common_test.go b/internal/app/machined/pkg/controllers/runtime/common_test.go index 508b577d6..8fd46ce2f 100644 --- a/internal/app/machined/pkg/controllers/runtime/common_test.go +++ b/internal/app/machined/pkg/controllers/runtime/common_test.go @@ -20,8 +20,6 @@ import ( "github.com/stretchr/testify/suite" "github.com/siderolabs/talos/pkg/logging" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/resources/config" ) const ( @@ -90,19 +88,4 @@ func (suite *RuntimeSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - err := suite.state.Create( - context.Background(), config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - }, - ), - ) - if state.IsConflictError(err) { - err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) - } - - suite.Assert().NoError(err) } diff --git a/internal/app/machined/pkg/controllers/runtime/kernel_module_config_test.go b/internal/app/machined/pkg/controllers/runtime/kernel_module_config_test.go index ba862e45a..1b4d83ba3 100644 --- a/internal/app/machined/pkg/controllers/runtime/kernel_module_config_test.go +++ b/internal/app/machined/pkg/controllers/runtime/kernel_module_config_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/suite" runtimecontrollers "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/resources/config" runtimeresource "github.com/siderolabs/talos/pkg/machinery/resources/runtime" @@ -28,22 +29,26 @@ func (suite *KernelModuleConfigSuite) TestReconcileConfig() { suite.startRuntime() - cfg := config.NewMachineConfig(&v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineKernel: &v1alpha1.KernelConfig{ - KernelModules: []*v1alpha1.KernelModuleConfig{ - { - ModuleName: "brtfs", - }, - { - ModuleName: "e1000", + cfg := config.NewMachineConfig( + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineKernel: &v1alpha1.KernelConfig{ + KernelModules: []*v1alpha1.KernelModuleConfig{ + { + ModuleName: "brtfs", + }, + { + ModuleName: "e1000", + }, + }, }, }, + ClusterConfig: &v1alpha1.ClusterConfig{}, }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{}, - }) + ), + ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -59,13 +64,17 @@ func (suite *KernelModuleConfigSuite) TestReconcileConfig() { )) old := cfg.Metadata().Version() - cfg = config.NewMachineConfig(&v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineKernel: nil, - }, - ClusterConfig: &v1alpha1.ClusterConfig{}, - }) + cfg = config.NewMachineConfig( + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineKernel: nil, + }, + ClusterConfig: &v1alpha1.ClusterConfig{}, + }, + ), + ) cfg.Metadata().SetVersion(old) suite.Require().NoError(suite.state.Update(suite.ctx, cfg)) diff --git a/internal/app/machined/pkg/controllers/runtime/kernel_param_config_test.go b/internal/app/machined/pkg/controllers/runtime/kernel_param_config_test.go index d995b7e6c..99c2f4d3f 100644 --- a/internal/app/machined/pkg/controllers/runtime/kernel_param_config_test.go +++ b/internal/app/machined/pkg/controllers/runtime/kernel_param_config_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/suite" runtimecontrollers "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/resources/config" runtimeresource "github.com/siderolabs/talos/pkg/machinery/resources/runtime" @@ -31,18 +32,22 @@ func (suite *KernelParamConfigSuite) TestReconcileConfig() { value := "500000" valueSysfs := "600000" - cfg := config.NewMachineConfig(&v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineSysctls: map[string]string{ - fsFileMax: value, + cfg := config.NewMachineConfig( + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineSysctls: map[string]string{ + fsFileMax: value, + }, + MachineSysfs: map[string]string{ + fsFileMax: valueSysfs, + }, + }, + ClusterConfig: &v1alpha1.ClusterConfig{}, }, - MachineSysfs: map[string]string{ - fsFileMax: valueSysfs, - }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{}, - }) + ), + ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -73,16 +78,20 @@ func (suite *KernelParamConfigSuite) TestReconcileConfig() { )) old := cfg.Metadata().Version() - cfg = config.NewMachineConfig(&v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineSysctls: map[string]string{}, - MachineSysfs: map[string]string{ - fsFileMax: valueSysfs, + cfg = config.NewMachineConfig( + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineSysctls: map[string]string{}, + MachineSysfs: map[string]string{ + fsFileMax: valueSysfs, + }, + }, + ClusterConfig: &v1alpha1.ClusterConfig{}, }, - }, - ClusterConfig: &v1alpha1.ClusterConfig{}, - }) + ), + ) cfg.Metadata().SetVersion(old) suite.Require().NoError(suite.state.Update(suite.ctx, cfg)) diff --git a/internal/app/machined/pkg/controllers/runtime/kernel_param_spec_test.go b/internal/app/machined/pkg/controllers/runtime/kernel_param_spec_test.go index 81346222e..7fa23fde6 100644 --- a/internal/app/machined/pkg/controllers/runtime/kernel_param_spec_test.go +++ b/internal/app/machined/pkg/controllers/runtime/kernel_param_spec_test.go @@ -6,6 +6,7 @@ package runtime_test import ( "fmt" + "os" "strings" "testing" "time" @@ -108,5 +109,9 @@ func (suite *KernelParamSpecSuite) TestParamsUnsupported() { } func TestKernelParamSpecSuite(t *testing.T) { + if os.Geteuid() != 0 { + t.Skip("skipping test because it requires root privileges") + } + suite.Run(t, new(KernelParamSpecSuite)) } diff --git a/internal/app/machined/pkg/controllers/runtime/kmsg_log_test.go b/internal/app/machined/pkg/controllers/runtime/kmsg_log_test.go index 977757fa6..724fe448f 100644 --- a/internal/app/machined/pkg/controllers/runtime/kmsg_log_test.go +++ b/internal/app/machined/pkg/controllers/runtime/kmsg_log_test.go @@ -10,6 +10,7 @@ import ( "log" "net" "net/netip" + "os" "sync" "testing" "time" @@ -172,5 +173,9 @@ func (suite *KmsgLogDeliverySuite) TearDownTest() { } func TestKmsgLogDeliverySuite(t *testing.T) { + if os.Geteuid() != 0 { + t.Skip("requires root") + } + suite.Run(t, new(KmsgLogDeliverySuite)) } diff --git a/internal/app/machined/pkg/controllers/runtime/machine_status.go b/internal/app/machined/pkg/controllers/runtime/machine_status.go index 996a9a10c..5a734e78b 100644 --- a/internal/app/machined/pkg/controllers/runtime/machine_status.go +++ b/internal/app/machined/pkg/controllers/runtime/machine_status.go @@ -21,7 +21,7 @@ import ( v1alpha1runtime "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" "github.com/siderolabs/talos/pkg/machinery/api/common" machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" "github.com/siderolabs/talos/pkg/machinery/resources/network" diff --git a/internal/app/machined/pkg/controllers/runtime/machine_status_test.go b/internal/app/machined/pkg/controllers/runtime/machine_status_test.go index 939eca939..96c2fe629 100644 --- a/internal/app/machined/pkg/controllers/runtime/machine_status_test.go +++ b/internal/app/machined/pkg/controllers/runtime/machine_status_test.go @@ -18,7 +18,7 @@ import ( runtimectrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime" v1alpha1runtime "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/network" "github.com/siderolabs/talos/pkg/machinery/resources/runtime" diff --git a/internal/app/machined/pkg/controllers/secrets/api.go b/internal/app/machined/pkg/controllers/secrets/api.go index dca9a86a1..c885b8036 100644 --- a/internal/app/machined/pkg/controllers/secrets/api.go +++ b/internal/app/machined/pkg/controllers/secrets/api.go @@ -18,7 +18,7 @@ import ( "go.uber.org/zap" "github.com/siderolabs/talos/pkg/grpc/gen" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" "github.com/siderolabs/talos/pkg/machinery/resources/network" diff --git a/internal/app/machined/pkg/controllers/secrets/api_test.go b/internal/app/machined/pkg/controllers/secrets/api_test.go index 064ab711e..136f30cb5 100644 --- a/internal/app/machined/pkg/controllers/secrets/api_test.go +++ b/internal/app/machined/pkg/controllers/secrets/api_test.go @@ -20,7 +20,7 @@ import ( "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/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/network" "github.com/siderolabs/talos/pkg/machinery/resources/secrets" diff --git a/internal/app/machined/pkg/controllers/secrets/kubelet_test.go b/internal/app/machined/pkg/controllers/secrets/kubelet_test.go index bdb46dafc..83db48c8f 100644 --- a/internal/app/machined/pkg/controllers/secrets/kubelet_test.go +++ b/internal/app/machined/pkg/controllers/secrets/kubelet_test.go @@ -18,6 +18,7 @@ import ( "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/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/secrets" @@ -47,19 +48,21 @@ func (suite *KubeletSuite) TestReconcile() { k8sCA := x509.NewCertificateAndKeyFromCertificateAuthority(ca) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - ClusterConfig: &v1alpha1.ClusterConfig{ - ControlPlane: &v1alpha1.ControlPlaneConfig{ - Endpoint: &v1alpha1.Endpoint{ - URL: u, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + ClusterConfig: &v1alpha1.ClusterConfig{ + ControlPlane: &v1alpha1.ControlPlaneConfig{ + Endpoint: &v1alpha1.Endpoint{ + URL: u, + }, }, + ClusterCA: k8sCA, + BootstrapToken: "abc.def", }, - ClusterCA: k8sCA, - BootstrapToken: "abc.def", }, - }, + ), ) suite.Require().NoError(suite.State().Create(suite.Ctx(), cfg)) diff --git a/internal/app/machined/pkg/controllers/secrets/kubernetes_dynamic_certs_test.go b/internal/app/machined/pkg/controllers/secrets/kubernetes_dynamic_certs_test.go index 756cf7477..97fd344fe 100644 --- a/internal/app/machined/pkg/controllers/secrets/kubernetes_dynamic_certs_test.go +++ b/internal/app/machined/pkg/controllers/secrets/kubernetes_dynamic_certs_test.go @@ -21,7 +21,7 @@ import ( "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/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/network" diff --git a/internal/app/machined/pkg/controllers/secrets/kubernetes_test.go b/internal/app/machined/pkg/controllers/secrets/kubernetes_test.go index da51a0ce4..039e742f0 100644 --- a/internal/app/machined/pkg/controllers/secrets/kubernetes_test.go +++ b/internal/app/machined/pkg/controllers/secrets/kubernetes_test.go @@ -20,7 +20,7 @@ import ( "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/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/secrets" timeresource "github.com/siderolabs/talos/pkg/machinery/resources/time" diff --git a/internal/app/machined/pkg/controllers/secrets/root.go b/internal/app/machined/pkg/controllers/secrets/root.go index a9ab178ac..f170f63b8 100644 --- a/internal/app/machined/pkg/controllers/secrets/root.go +++ b/internal/app/machined/pkg/controllers/secrets/root.go @@ -17,7 +17,7 @@ import ( "go.uber.org/zap" talosconfig "github.com/siderolabs/talos/pkg/machinery/config" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/secrets" diff --git a/internal/app/machined/pkg/controllers/secrets/trustd_test.go b/internal/app/machined/pkg/controllers/secrets/trustd_test.go index f4a908ae5..f05bab476 100644 --- a/internal/app/machined/pkg/controllers/secrets/trustd_test.go +++ b/internal/app/machined/pkg/controllers/secrets/trustd_test.go @@ -20,7 +20,7 @@ import ( "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/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/network" "github.com/siderolabs/talos/pkg/machinery/resources/secrets" diff --git a/internal/app/machined/pkg/controllers/siderolink/config.go b/internal/app/machined/pkg/controllers/siderolink/config.go index c87910fa7..e1e42acc6 100644 --- a/internal/app/machined/pkg/controllers/siderolink/config.go +++ b/internal/app/machined/pkg/controllers/siderolink/config.go @@ -11,6 +11,7 @@ import ( "github.com/cosi-project/runtime/pkg/controller" "github.com/cosi-project/runtime/pkg/safe" "github.com/cosi-project/runtime/pkg/state" + "github.com/siderolabs/go-pointer" "github.com/siderolabs/go-procfs/procfs" "go.uber.org/zap" @@ -31,7 +32,14 @@ func (ctrl *ConfigController) Name() string { // Inputs implements controller.Controller interface. func (ctrl *ConfigController) Inputs() []controller.Input { - return nil + return []controller.Input{ + { + Namespace: config.NamespaceName, + Type: config.MachineConfigType, + ID: pointer.To(config.V1Alpha1ID), + Kind: controller.InputWeak, + }, + } } // Outputs implements controller.Controller interface. @@ -53,16 +61,21 @@ func (ctrl *ConfigController) Run(ctx context.Context, r controller.Runtime, _ * case <-r.EventCh(): } - if err := ctrl.updateConfig(ctx, r); err != nil { + cfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID) + if err != nil && !state.IsNotFoundError(err) { + return err + } + + if err := ctrl.updateConfig(ctx, r, cfg); err != nil { return fmt.Errorf("failed to update config: %w", err) } } } -func (ctrl *ConfigController) updateConfig(ctx context.Context, r controller.Runtime) error { +func (ctrl *ConfigController) updateConfig(ctx context.Context, r controller.Runtime, machineConfig *config.MachineConfig) error { cfg := siderolink.NewConfig(config.NamespaceName, siderolink.ConfigID) - endpoint := ctrl.apiEndpoint() + endpoint := ctrl.apiEndpoint(machineConfig) if endpoint == "" { err := r.Destroy(ctx, cfg.Metadata()) if err != nil && !state.IsNotFoundError(err) { @@ -79,7 +92,11 @@ func (ctrl *ConfigController) updateConfig(ctx context.Context, r controller.Run }) } -func (ctrl *ConfigController) apiEndpoint() string { +func (ctrl *ConfigController) apiEndpoint(machineConfig *config.MachineConfig) string { + if machineConfig != nil && machineConfig.Config().SideroLink() != nil && machineConfig.Config().SideroLink().APIUrl() != nil { + return machineConfig.Config().SideroLink().APIUrl().String() + } + if ctrl.Cmdline == nil || ctrl.Cmdline.Get(constants.KernelParamSideroLink).First() == nil { return "" } diff --git a/internal/app/machined/pkg/controllers/siderolink/config_test.go b/internal/app/machined/pkg/controllers/siderolink/config_test.go new file mode 100644 index 000000000..cdc259b12 --- /dev/null +++ b/internal/app/machined/pkg/controllers/siderolink/config_test.go @@ -0,0 +1,65 @@ +// 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 siderolink_test + +import ( + "net/url" + "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" + siderolinkctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/siderolink" + "github.com/siderolabs/talos/pkg/machinery/config/container" + "github.com/siderolabs/talos/pkg/machinery/config/types/meta" + siderolinkcfg "github.com/siderolabs/talos/pkg/machinery/config/types/siderolink" + "github.com/siderolabs/talos/pkg/machinery/resources/config" + "github.com/siderolabs/talos/pkg/machinery/resources/siderolink" +) + +type ConfigSuite struct { + ctest.DefaultSuite +} + +func TestConfigSuite(t *testing.T) { + suite.Run(t, &ConfigSuite{ + DefaultSuite: ctest.DefaultSuite{ + AfterSetup: func(suite *ctest.DefaultSuite) { + suite.Require().NoError(suite.Runtime().RegisterController(&siderolinkctrl.ConfigController{})) + }, + }, + }) +} + +func (suite *ConfigSuite) TestConfig() { + rtestutils.AssertNoResource[*siderolink.Config](suite.Ctx(), suite.T(), suite.State(), siderolink.ConfigID) + + siderolinkConfig := &siderolinkcfg.ConfigV1Alpha1{ + APIUrlConfig: meta.URL{ + URL: must(url.Parse("https://api.sidero.dev")), + }, + } + + cfg, err := container.New(siderolinkConfig) + suite.Require().NoError(err) + + suite.Require().NoError(suite.State().Create(suite.Ctx(), config.NewMachineConfig(cfg))) + + rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{siderolink.ConfigID}, + func(c *siderolink.Config, assert *assert.Assertions) { + assert.Equal("https://api.sidero.dev", c.TypedSpec().APIEndpoint) + }) +} + +func must[T any](t T, err error) T { + if err != nil { + panic(err) + } + + return t +} diff --git a/internal/app/machined/pkg/controllers/time/sync_test.go b/internal/app/machined/pkg/controllers/time/sync_test.go index d5e052680..f55531aa2 100644 --- a/internal/app/machined/pkg/controllers/time/sync_test.go +++ b/internal/app/machined/pkg/controllers/time/sync_test.go @@ -28,6 +28,7 @@ import ( timectrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/time" v1alpha1runtime "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" "github.com/siderolabs/talos/pkg/logging" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/config" @@ -167,15 +168,17 @@ func (suite *SyncSuite) TestReconcileSyncDisabled() { ) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineTime: &v1alpha1.TimeConfig{ - TimeDisabled: pointer.To(true), + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineTime: &v1alpha1.TimeConfig{ + TimeDisabled: pointer.To(true), + }, }, + ClusterConfig: &v1alpha1.ClusterConfig{}, }, - ClusterConfig: &v1alpha1.ClusterConfig{}, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -212,11 +215,13 @@ func (suite *SyncSuite) TestReconcileSyncDefaultConfig() { suite.Require().NoError(suite.state.Create(suite.ctx, timeServers)) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - ClusterConfig: &v1alpha1.ClusterConfig{}, - }, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + ClusterConfig: &v1alpha1.ClusterConfig{}, + }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -267,11 +272,13 @@ func (suite *SyncSuite) TestReconcileSyncChangeConfig() { ) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - ClusterConfig: &v1alpha1.ClusterConfig{}, - }, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + ClusterConfig: &v1alpha1.ClusterConfig{}, + }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -359,7 +366,7 @@ func (suite *SyncSuite) TestReconcileSyncChangeConfig() { ) ctest.UpdateWithConflicts(suite, cfg, func(r *config.MachineConfig) error { - r.Config().(*v1alpha1.Config).MachineConfig.MachineTime = &v1alpha1.TimeConfig{ + r.Container().RawV1Alpha1().MachineConfig.MachineTime = &v1alpha1.TimeConfig{ TimeDisabled: pointer.To(true), } @@ -412,15 +419,17 @@ func (suite *SyncSuite) TestReconcileSyncBootTimeout() { ) cfg := config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{ - MachineTime: &v1alpha1.TimeConfig{ - TimeBootTimeout: 5 * time.Second, + container.NewV1Alpha1( + &v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{ + MachineTime: &v1alpha1.TimeConfig{ + TimeBootTimeout: 5 * time.Second, + }, }, + ClusterConfig: &v1alpha1.ClusterConfig{}, }, - ClusterConfig: &v1alpha1.ClusterConfig{}, - }, + ), ) suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) @@ -446,21 +455,6 @@ func (suite *SyncSuite) TearDownTest() { suite.ctxCancel() suite.wg.Wait() - - // trigger updates in resources to stop watch loops - err := suite.state.Create( - context.Background(), config.NewMachineConfig( - &v1alpha1.Config{ - ConfigVersion: "v1alpha1", - MachineConfig: &v1alpha1.MachineConfig{}, - }, - ), - ) - if state.IsConflictError(err) { - err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) - } - - suite.Assert().NoError(err) } func (suite *SyncSuite) newMockSyncer(logger *zap.Logger, servers []string) timectrl.NTPSyncer { diff --git a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go index 71ced0fe5..0ecb3f627 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go @@ -12,7 +12,7 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" ) 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 7ad01be59..6481abe99 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go @@ -70,8 +70,8 @@ import ( machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" "github.com/siderolabs/talos/pkg/machinery/config/config" "github.com/siderolabs/talos/pkg/machinery/config/configloader" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/kernel" resourcefiles "github.com/siderolabs/talos/pkg/machinery/resources/files" diff --git a/internal/app/machined/pkg/system/runner/goroutine/goroutine_test.go b/internal/app/machined/pkg/system/runner/goroutine/goroutine_test.go index 4a581e3f5..afa6d238c 100644 --- a/internal/app/machined/pkg/system/runner/goroutine/goroutine_test.go +++ b/internal/app/machined/pkg/system/runner/goroutine/goroutine_test.go @@ -23,6 +23,7 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/system/events" "github.com/siderolabs/talos/internal/app/machined/pkg/system/runner" "github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/goroutine" + "github.com/siderolabs/talos/pkg/machinery/config/container" v1alpha1cfg "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" ) @@ -47,9 +48,10 @@ func (suite *GoroutineSuite) SetupSuite() { suite.loggingManager = logging.NewFileLoggingManager(suite.tmpDir) s, err := v1alpha1.NewState() - suite.Assert().NoError(err) + suite.Require().NoError(err) - cfg := &v1alpha1cfg.Config{} + cfg, err := container.New(&v1alpha1cfg.Config{}) + suite.Require().NoError(err) e := v1alpha1.NewEvents(100, 10) @@ -165,5 +167,7 @@ func (suite *GoroutineSuite) TestRunLogs() { } func TestGoroutineSuite(t *testing.T) { + t.Setenv("PLATFORM", "metal") + suite.Run(t, new(GoroutineSuite)) } diff --git a/internal/app/machined/pkg/system/runner/process/process_test.go b/internal/app/machined/pkg/system/runner/process/process_test.go index b2255c766..f8f18980e 100644 --- a/internal/app/machined/pkg/system/runner/process/process_test.go +++ b/internal/app/machined/pkg/system/runner/process/process_test.go @@ -220,6 +220,10 @@ func (suite *ProcessSuite) TestStopSigKill() { } func TestProcessSuite(t *testing.T) { + if _, err := os.Stat("/sbin/wrapperd"); err != nil { + t.Skip("wrapperd not found") + } + for _, runReaper := range []bool{true, false} { func(runReaper bool) { t.Run(fmt.Sprintf("runReaper=%v", runReaper), func(t *testing.T) { suite.Run(t, &ProcessSuite{runReaper: runReaper}) }) diff --git a/internal/app/machined/pkg/system/services/etcd.go b/internal/app/machined/pkg/system/services/etcd.go index 2140c9186..3b5727eb0 100644 --- a/internal/app/machined/pkg/system/services/etcd.go +++ b/internal/app/machined/pkg/system/services/etcd.go @@ -46,7 +46,7 @@ import ( "github.com/siderolabs/talos/pkg/filetree" "github.com/siderolabs/talos/pkg/logging" machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/nethelpers" etcdresource "github.com/siderolabs/talos/pkg/machinery/resources/etcd" diff --git a/internal/app/machined/pkg/system/services/kubelet.go b/internal/app/machined/pkg/system/services/kubelet.go index 36d9d57cf..098d04e67 100644 --- a/internal/app/machined/pkg/system/services/kubelet.go +++ b/internal/app/machined/pkg/system/services/kubelet.go @@ -29,7 +29,7 @@ import ( "github.com/siderolabs/talos/internal/pkg/containers/image" "github.com/siderolabs/talos/internal/pkg/environment" "github.com/siderolabs/talos/pkg/conditions" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" "github.com/siderolabs/talos/pkg/machinery/resources/network" diff --git a/internal/app/maintenance/server/server.go b/internal/app/maintenance/server/server.go index 646534373..ae1d3f9dd 100644 --- a/internal/app/maintenance/server/server.go +++ b/internal/app/maintenance/server/server.go @@ -28,7 +28,7 @@ import ( "github.com/siderolabs/talos/pkg/machinery/api/machine" "github.com/siderolabs/talos/pkg/machinery/api/storage" "github.com/siderolabs/talos/pkg/machinery/config/configloader" - v1alpha1machine "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + v1alpha1machine "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/version" ) diff --git a/internal/app/trustd/internal/reg/reg_test.go b/internal/app/trustd/internal/reg/reg_test.go index 5b077085a..d3c97a5ff 100644 --- a/internal/app/trustd/internal/reg/reg_test.go +++ b/internal/app/trustd/internal/reg/reg_test.go @@ -22,7 +22,7 @@ import ( "github.com/siderolabs/talos/internal/app/trustd/internal/reg" "github.com/siderolabs/talos/pkg/machinery/api/security" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" + gensecrets "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets" "github.com/siderolabs/talos/pkg/machinery/resources/secrets" "github.com/siderolabs/talos/pkg/machinery/role" ) @@ -33,7 +33,7 @@ func TestCertificate(t *testing.T) { resources := state.WrapCore(namespaced.NewState(inmem.Build)) - ca, err := generate.NewTalosCA(time.Now()) + ca, err := gensecrets.NewTalosCA(time.Now()) require.NoError(t, err) osRoot := secrets.NewOSRoot(secrets.OSRootID) diff --git a/internal/integration/api/apid.go b/internal/integration/api/apid.go index ffc568047..616ebbbc9 100644 --- a/internal/integration/api/apid.go +++ b/internal/integration/api/apid.go @@ -14,7 +14,7 @@ import ( "github.com/siderolabs/talos/internal/integration/base" "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // ApidSuite verifies Discovery API. diff --git a/internal/integration/api/apply-config.go b/internal/integration/api/apply-config.go index f214c2b68..394031994 100644 --- a/internal/integration/api/apply-config.go +++ b/internal/integration/api/apply-config.go @@ -26,8 +26,9 @@ import ( machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" "github.com/siderolabs/talos/pkg/machinery/client" "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/container" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/constants" mc "github.com/siderolabs/talos/pkg/machinery/resources/config" ) @@ -109,7 +110,10 @@ func (suite *ApplyConfigSuite) TestApply() { cfg.MachineConfig.MachineSysctls[applyConfigTestSysctl] = applyConfigTestSysctlVal - cfgDataOut, err := cfg.Bytes() + provider, err = container.New(cfg) + suite.Require().NoError(err) + + cfgDataOut, err := provider.Bytes() suite.Assert().Nilf(err, "failed to marshal updated machine config data (node %q): %w", node, err) suite.AssertRebooted( @@ -176,7 +180,10 @@ func (suite *ApplyConfigSuite) TestApplyWithoutReboot() { cfg.MachineConfig.MachineSysctls[applyConfigNoRebootTestSysctl] = applyConfigNoRebootTestSysctlVal - cfgDataOut, err := cfg.Bytes() + provider, err = container.New(cfg) + suite.Require().NoError(err) + + cfgDataOut, err := provider.Bytes() suite.Require().NoError(err, "failed to marshal updated machine config data (node %q)", node) _, err = suite.Client.ApplyConfiguration( @@ -205,7 +212,10 @@ func (suite *ApplyConfigSuite) TestApplyWithoutReboot() { // revert back delete(cfg.MachineConfig.MachineSysctls, applyConfigNoRebootTestSysctl) - cfgDataOut, err = cfg.Bytes() + provider, err = container.New(cfg) + suite.Require().NoError(err) + + cfgDataOut, err = provider.Bytes() suite.Require().NoError(err, "failed to marshal updated machine config data (node %q)", node) _, err = suite.Client.ApplyConfiguration( @@ -303,7 +313,7 @@ func (suite *ApplyConfigSuite) TestApplyConfigRotateEncryptionSecrets() { for _, keys := range keySets { cfg.EncryptionKeys = keys - data, err := machineConfig.Bytes() + data, err := container.NewV1Alpha1(machineConfig).Bytes() suite.Require().NoError(err) suite.AssertRebooted( @@ -386,7 +396,10 @@ func (suite *ApplyConfigSuite) TestApplyNoReboot() { // this won't be possible without a reboot cfg.MachineConfig.MachineType = "controlplane" - cfgDataOut, err := cfg.Bytes() + provider, err = container.New(cfg) + suite.Require().NoError(err) + + cfgDataOut, err := provider.Bytes() suite.Assert().Nilf(err, "failed to marshal updated machine config data (node %q): %w", node, err) _, err = suite.Client.ApplyConfiguration( @@ -429,7 +442,10 @@ func (suite *ApplyConfigSuite) TestApplyDryRun() { // this won't be possible without a reboot cfg.MachineConfig.MachineType = "controlplane" - cfgDataOut, err := cfg.Bytes() + provider, err = container.New(cfg) + suite.Require().NoError(err) + + cfgDataOut, err := provider.Bytes() suite.Assert().Nilf(err, "failed to marshal updated machine config data (node %q): %w", node, err) reply, err := suite.Client.ApplyConfiguration( @@ -486,7 +502,7 @@ func (suite *ApplyConfigSuite) TestApplyTry() { }, ) - cfgDataOut, err := cfg.Bytes() + cfgDataOut, err := container.NewV1Alpha1(cfg).Bytes() suite.Assert().Nilf(err, "failed to marshal updated machine config data (node %q): %s", node, err) _, err = suite.Client.ApplyConfiguration( diff --git a/internal/integration/api/etcd-recover.go b/internal/integration/api/etcd-recover.go index 03c012fef..1345abf17 100644 --- a/internal/integration/api/etcd-recover.go +++ b/internal/integration/api/etcd-recover.go @@ -21,7 +21,7 @@ import ( "github.com/siderolabs/talos/internal/integration/base" machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" ) diff --git a/internal/integration/api/etcd.go b/internal/integration/api/etcd.go index e7e84a5e5..0ac7f204e 100644 --- a/internal/integration/api/etcd.go +++ b/internal/integration/api/etcd.go @@ -18,7 +18,7 @@ import ( "github.com/siderolabs/talos/internal/integration/base" machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/etcd" "github.com/siderolabs/talos/pkg/machinery/resources/network" diff --git a/internal/integration/api/events.go b/internal/integration/api/events.go index 529ab8f95..1f420d288 100644 --- a/internal/integration/api/events.go +++ b/internal/integration/api/events.go @@ -12,7 +12,7 @@ import ( "github.com/siderolabs/talos/internal/integration/base" "github.com/siderolabs/talos/pkg/machinery/client" - machinetype "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + machinetype "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // EventsSuite verifies Events API. diff --git a/internal/integration/api/generate-config.go b/internal/integration/api/generate-config.go index 399e0cde9..25d602f67 100644 --- a/internal/integration/api/generate-config.go +++ b/internal/integration/api/generate-config.go @@ -17,7 +17,7 @@ import ( "github.com/siderolabs/talos/pkg/machinery/client" clientconfig "github.com/siderolabs/talos/pkg/machinery/client/config" "github.com/siderolabs/talos/pkg/machinery/config/configloader" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" ) diff --git a/internal/integration/api/node-labels.go b/internal/integration/api/node-labels.go index df4c7079d..561079a2d 100644 --- a/internal/integration/api/node-labels.go +++ b/internal/integration/api/node-labels.go @@ -17,7 +17,8 @@ import ( "github.com/siderolabs/talos/internal/integration/base" machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/container" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // NodeLabelsSuite verifies updating node labels via machine config. @@ -167,7 +168,7 @@ func (suite *NodeLabelsSuite) setNodeLabels(nodeIP string, nodeLabels map[string nodeConfigRaw.MachineConfig.MachineNodeLabels = nodeLabels - bytes, err := nodeConfigRaw.Bytes() + bytes, err := container.NewV1Alpha1(nodeConfigRaw).Bytes() suite.Require().NoError(err) _, err = suite.Client.ApplyConfiguration(nodeCtx, &machineapi.ApplyConfigurationRequest{ diff --git a/internal/integration/api/reboot.go b/internal/integration/api/reboot.go index e32e9d029..4b37991bc 100644 --- a/internal/integration/api/reboot.go +++ b/internal/integration/api/reboot.go @@ -17,7 +17,7 @@ import ( "github.com/siderolabs/talos/internal/integration/base" "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // RebootSuite ... diff --git a/internal/integration/api/reset.go b/internal/integration/api/reset.go index 447f45f27..6ff0ee162 100644 --- a/internal/integration/api/reset.go +++ b/internal/integration/api/reset.go @@ -19,7 +19,7 @@ import ( machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" "github.com/siderolabs/talos/pkg/machinery/api/storage" "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" ) diff --git a/internal/integration/api/resources.go b/internal/integration/api/resources.go index 8bf5c4f79..6d15b5a41 100644 --- a/internal/integration/api/resources.go +++ b/internal/integration/api/resources.go @@ -19,7 +19,7 @@ import ( "github.com/siderolabs/talos/internal/integration/base" "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1" ) diff --git a/internal/integration/api/serviceaccount.go b/internal/integration/api/serviceaccount.go index 3f74148cf..f14635254 100644 --- a/internal/integration/api/serviceaccount.go +++ b/internal/integration/api/serviceaccount.go @@ -24,8 +24,9 @@ import ( machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" "github.com/siderolabs/talos/pkg/machinery/client" "github.com/siderolabs/talos/pkg/machinery/client/config" + "github.com/siderolabs/talos/pkg/machinery/config/container" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/constants" ) @@ -261,7 +262,7 @@ func (suite *ServiceAccountSuite) configureAPIAccess( nodeConfigRaw.MachineConfig.MachineFeatures.KubernetesTalosAPIAccessConfig = &accessConfig - bytes, err := nodeConfigRaw.Bytes() + bytes, err := container.NewV1Alpha1(nodeConfigRaw).Bytes() if err != nil { return err } diff --git a/internal/integration/api/update-endpoint.go b/internal/integration/api/update-endpoint.go index 8487e8bf9..f2d39f2e6 100644 --- a/internal/integration/api/update-endpoint.go +++ b/internal/integration/api/update-endpoint.go @@ -17,7 +17,8 @@ import ( "github.com/siderolabs/talos/internal/integration/base" machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/container" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // UpdateEndpointSuite verifies UpdateEndpoint API. @@ -105,7 +106,7 @@ func (suite *UpdateEndpointSuite) updateEndpointURL(nodeIP string, newURL string oldURL = endpoint.URL.String() endpoint.URL = newEndpointURL - bytes, err := nodeConfigRaw.Bytes() + bytes, err := container.NewV1Alpha1(nodeConfigRaw).Bytes() suite.Require().NoError(err) _, err = suite.Client.ApplyConfiguration(nodeCtx, &machineapi.ApplyConfigurationRequest{ diff --git a/internal/integration/api/update-hostname.go b/internal/integration/api/update-hostname.go index b8527c4ba..22750193d 100644 --- a/internal/integration/api/update-hostname.go +++ b/internal/integration/api/update-hostname.go @@ -19,7 +19,8 @@ import ( "github.com/siderolabs/talos/internal/integration/base" machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/container" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // UpdateHostnameSuite verifies UpdateHostname API. @@ -146,7 +147,7 @@ func (suite *UpdateHostnameSuite) updateHostname(nodeCtx context.Context, newHos nodeConfigRaw.MachineConfig.MachineNetwork.NetworkHostname = newHostname - bytes, err := nodeConfigRaw.Bytes() + bytes, err := container.NewV1Alpha1(nodeConfigRaw).Bytes() if err != nil { return err } diff --git a/internal/integration/base/api.go b/internal/integration/base/api.go index 8eea1e18c..74a01df25 100644 --- a/internal/integration/base/api.go +++ b/internal/integration/base/api.go @@ -30,7 +30,7 @@ import ( clientconfig "github.com/siderolabs/talos/pkg/machinery/client/config" "github.com/siderolabs/talos/pkg/machinery/config" "github.com/siderolabs/talos/pkg/machinery/config/configloader" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/provision" "github.com/siderolabs/talos/pkg/provision/access" diff --git a/internal/integration/base/cli.go b/internal/integration/base/cli.go index 845842787..796598f42 100644 --- a/internal/integration/base/cli.go +++ b/internal/integration/base/cli.go @@ -21,7 +21,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/siderolabs/talos/pkg/cluster" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" ) diff --git a/internal/integration/base/cluster.go b/internal/integration/base/cluster.go index 4758eb267..0257591ed 100644 --- a/internal/integration/base/cluster.go +++ b/internal/integration/base/cluster.go @@ -10,7 +10,7 @@ import ( "github.com/siderolabs/gen/slices" "github.com/siderolabs/talos/pkg/cluster" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) type infoWrapper struct { diff --git a/internal/integration/cli/config.go b/internal/integration/cli/config.go index 9708c97f6..7d53ca652 100644 --- a/internal/integration/cli/config.go +++ b/internal/integration/cli/config.go @@ -16,7 +16,7 @@ import ( "github.com/siderolabs/talos/internal/integration/base" machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" clientconfig "github.com/siderolabs/talos/pkg/machinery/client/config" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // TalosconfigSuite checks `talosctl config`. diff --git a/internal/integration/cli/containers.go b/internal/integration/cli/containers.go index d429cba6c..c2904fe82 100644 --- a/internal/integration/cli/containers.go +++ b/internal/integration/cli/containers.go @@ -10,7 +10,7 @@ import ( "regexp" "github.com/siderolabs/talos/internal/integration/base" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // ContainersSuite verifies dmesg command. diff --git a/internal/integration/cli/etcd.go b/internal/integration/cli/etcd.go index ac9a1681f..f45f57b6d 100644 --- a/internal/integration/cli/etcd.go +++ b/internal/integration/cli/etcd.go @@ -13,7 +13,7 @@ import ( "strings" "github.com/siderolabs/talos/internal/integration/base" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // EtcdSuite verifies etcd command. diff --git a/internal/integration/cli/gen.go b/internal/integration/cli/gen.go index 7fc4d6313..b0bdbc22c 100644 --- a/internal/integration/cli/gen.go +++ b/internal/integration/cli/gen.go @@ -13,12 +13,13 @@ import ( "path/filepath" "regexp" "strings" + "time" "gopkg.in/yaml.v3" "github.com/siderolabs/talos/internal/integration/base" "github.com/siderolabs/talos/pkg/machinery/config/configloader" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" + "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets" ) // GenSuite verifies gen command. @@ -261,19 +262,19 @@ func (suite *GenSuite) TestSecretsWithPKIDirAndToken() { secretsYaml, err := os.ReadFile(path) suite.Assert().NoError(err) - var secrets generate.SecretsBundle + var secretsBundle secrets.Bundle - err = yaml.Unmarshal(secretsYaml, &secrets) + err = yaml.Unmarshal(secretsYaml, &secretsBundle) suite.Assert().NoError(err) - suite.Assert().Equal("test-token", secrets.Secrets.BootstrapToken, "bootstrap token does not match") - suite.Assert().Equal(pkiCACrt, secrets.Certs.K8s.Crt, "k8s ca cert does not match") - suite.Assert().Equal(pkiCAKey, secrets.Certs.K8s.Key, "k8s ca key does not match") - suite.Assert().Equal(pkiFrontProxyCACrt, secrets.Certs.K8sAggregator.Crt, "k8s aggregator ca cert does not match") - suite.Assert().Equal(pkiFrontProxyCAKey, secrets.Certs.K8sAggregator.Key, "k8s aggregator ca key does not match") - suite.Assert().Equal(pkiSAKey, secrets.Certs.K8sServiceAccount.Key, "k8s service account key does not match") - suite.Assert().Equal(pkiEtcdCACrt, secrets.Certs.Etcd.Crt, "etcd ca cert does not match") - suite.Assert().Equal(pkiEtcdCAKey, secrets.Certs.Etcd.Key, "etcd ca key does not match") + suite.Assert().Equal("test-token", secretsBundle.Secrets.BootstrapToken, "bootstrap token does not match") + suite.Assert().Equal(pkiCACrt, secretsBundle.Certs.K8s.Crt, "k8s ca cert does not match") + suite.Assert().Equal(pkiCAKey, secretsBundle.Certs.K8s.Key, "k8s ca key does not match") + suite.Assert().Equal(pkiFrontProxyCACrt, secretsBundle.Certs.K8sAggregator.Crt, "k8s aggregator ca cert does not match") + suite.Assert().Equal(pkiFrontProxyCAKey, secretsBundle.Certs.K8sAggregator.Key, "k8s aggregator ca key does not match") + suite.Assert().Equal(pkiSAKey, secretsBundle.Certs.K8sServiceAccount.Key, "k8s service account key does not match") + suite.Assert().Equal(pkiEtcdCACrt, secretsBundle.Certs.Etcd.Crt, "etcd ca cert does not match") + suite.Assert().Equal(pkiEtcdCAKey, secretsBundle.Certs.Etcd.Key, "etcd ca key does not match") } // TestConfigWithSecrets tests the gen config command with secrets provided. @@ -292,7 +293,7 @@ func (suite *GenSuite) TestConfigWithSecrets() { config, err := configloader.NewFromFile("controlplane.yaml") suite.Assert().NoError(err) - configSecretsBundle := generate.NewSecretsBundleFromConfig(generate.NewClock(), config) + configSecretsBundle := secrets.NewBundleFromConfig(secrets.NewFixedClock(time.Now()), config) configSecretsBundleBytes, err := yaml.Marshal(configSecretsBundle) suite.Assert().NoError(err) diff --git a/internal/integration/cli/health.go b/internal/integration/cli/health.go index 892b4d5d6..33b99b4bb 100644 --- a/internal/integration/cli/health.go +++ b/internal/integration/cli/health.go @@ -15,7 +15,7 @@ import ( "gopkg.in/yaml.v3" "github.com/siderolabs/talos/internal/integration/base" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/cluster" ) diff --git a/internal/integration/cli/jsonpath.go b/internal/integration/cli/jsonpath.go index d364506d7..27dde35e8 100644 --- a/internal/integration/cli/jsonpath.go +++ b/internal/integration/cli/jsonpath.go @@ -13,7 +13,7 @@ import ( "github.com/siderolabs/go-retry/retry" "github.com/siderolabs/talos/internal/integration/base" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // JSONPathSuite verifies dmesg command. diff --git a/internal/integration/cli/kubeconfig.go b/internal/integration/cli/kubeconfig.go index 9305592af..0c1bfbe8a 100644 --- a/internal/integration/cli/kubeconfig.go +++ b/internal/integration/cli/kubeconfig.go @@ -14,7 +14,7 @@ import ( "k8s.io/client-go/tools/clientcmd" "github.com/siderolabs/talos/internal/integration/base" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // KubeconfigSuite verifies dmesg command. diff --git a/internal/integration/cli/list.go b/internal/integration/cli/list.go index 6aa13178c..655fce1b8 100644 --- a/internal/integration/cli/list.go +++ b/internal/integration/cli/list.go @@ -16,7 +16,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/siderolabs/talos/internal/integration/base" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // ListSuite verifies dmesg command. diff --git a/internal/integration/cli/patch.go b/internal/integration/cli/patch.go index c3df7056f..5cbf8c91c 100644 --- a/internal/integration/cli/patch.go +++ b/internal/integration/cli/patch.go @@ -11,7 +11,7 @@ import ( "fmt" "github.com/siderolabs/talos/internal/integration/base" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" ) diff --git a/internal/integration/cli/pcap.go b/internal/integration/cli/pcap.go index 95f62d051..10d526f47 100644 --- a/internal/integration/cli/pcap.go +++ b/internal/integration/cli/pcap.go @@ -8,7 +8,7 @@ package cli import ( "github.com/siderolabs/talos/internal/integration/base" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // PcapSuite verifies etcd command. diff --git a/internal/integration/cli/reboot.go b/internal/integration/cli/reboot.go index e68bc3307..a48d7951b 100644 --- a/internal/integration/cli/reboot.go +++ b/internal/integration/cli/reboot.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/go-multierror" "github.com/siderolabs/talos/internal/integration/base" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // RebootSuite tests reboot command. diff --git a/internal/integration/cli/restart.go b/internal/integration/cli/restart.go index f5f1c69b4..89b857a33 100644 --- a/internal/integration/cli/restart.go +++ b/internal/integration/cli/restart.go @@ -12,7 +12,7 @@ import ( "time" "github.com/siderolabs/talos/internal/integration/base" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // RestartSuite verifies dmesg command. diff --git a/internal/integration/cli/stats.go b/internal/integration/cli/stats.go index 1d5d00512..c7ad7a5a8 100644 --- a/internal/integration/cli/stats.go +++ b/internal/integration/cli/stats.go @@ -10,7 +10,7 @@ import ( "regexp" "github.com/siderolabs/talos/internal/integration/base" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // StatsSuite verifies dmesg command. diff --git a/internal/integration/cli/support.go b/internal/integration/cli/support.go index 46de3ffa3..773975083 100644 --- a/internal/integration/cli/support.go +++ b/internal/integration/cli/support.go @@ -13,7 +13,7 @@ import ( "strings" "github.com/siderolabs/talos/internal/integration/base" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // SupportSuite verifies support command. diff --git a/internal/integration/provision/upgrade.go b/internal/integration/provision/upgrade.go index b05a10d98..257483357 100644 --- a/internal/integration/provision/upgrade.go +++ b/internal/integration/provision/upgrade.go @@ -37,10 +37,10 @@ import ( talosclient "github.com/siderolabs/talos/pkg/machinery/client" clientconfig "github.com/siderolabs/talos/pkg/machinery/client/config" "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/bundle" + "github.com/siderolabs/talos/pkg/machinery/config/generate" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/bundle" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/nethelpers" "github.com/siderolabs/talos/pkg/provision" @@ -232,7 +232,7 @@ type UpgradeSuite struct { provisioner provision.Provisioner - configBundle *bundle.ConfigBundle + configBundle *bundle.Bundle clusterAccess *access.Adapter controlPlaneEndpoint string @@ -402,7 +402,7 @@ func (suite *UpgradeSuite) setupCluster() { versionContract, err := config.ParseContractFromVersion(suite.spec.SourceVersion) suite.Require().NoError(err) - suite.configBundle, err = bundle.NewConfigBundle( + suite.configBundle, err = bundle.NewBundle( bundle.WithInputOptions( &bundle.InputOptions{ ClusterName: clusterName, diff --git a/internal/pkg/configuration/configuration.go b/internal/pkg/configuration/configuration.go index fe52c09d8..d428726d7 100644 --- a/internal/pkg/configuration/configuration.go +++ b/internal/pkg/configuration/configuration.go @@ -10,6 +10,7 @@ import ( "fmt" "net/url" "os" + "time" "github.com/siderolabs/gen/slices" "github.com/siderolabs/go-pointer" @@ -17,9 +18,10 @@ import ( "github.com/siderolabs/talos/pkg/machinery/api/machine" "github.com/siderolabs/talos/pkg/machinery/config" "github.com/siderolabs/talos/pkg/machinery/config/configloader" + "github.com/siderolabs/talos/pkg/machinery/config/generate" + "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets" + v1alpha1machine "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" - v1alpha1machine "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/constants" ) @@ -37,7 +39,7 @@ func Generate(ctx context.Context, in *machine.GenerateConfigurationRequest) (re case "v1alpha1": machineType := v1alpha1machine.Type(in.MachineConfig.Type) - options := []generate.GenOption{} + options := []generate.Option{} if in.MachineConfig.NetworkConfig != nil { networkConfig := &v1alpha1.NetworkConfig{ @@ -107,34 +109,35 @@ func Generate(ctx context.Context, in *machine.GenerateConfigurationRequest) (re cfgBytes []byte taloscfgBytes []byte baseConfig config.Provider - secrets *generate.SecretsBundle + secretsBundle *secrets.Bundle ) baseConfig, err = configloader.NewFromFile(constants.ConfigPath) - clock := generate.NewClock() + clock := secrets.NewFixedClock(time.Now()) if in.OverrideTime != nil { - clock.SetFixedTimestamp(in.OverrideTime.AsTime()) + clock = secrets.NewFixedClock(in.OverrideTime.AsTime()) } switch { case os.IsNotExist(err): - secrets, err = generate.NewSecretsBundle(clock) + secretsBundle, err = secrets.NewBundle(clock, config.TalosVersionCurrent) if err != nil { return nil, err } case err != nil: return nil, err default: - secrets = generate.NewSecretsBundleFromConfig(clock, baseConfig) + secretsBundle = secrets.NewBundleFromConfig(clock, baseConfig) } + options = append(options, generate.WithSecretsBundle(secretsBundle)) + input, err = generate.NewInput( in.ClusterConfig.Name, in.ClusterConfig.ControlPlane.Endpoint, in.MachineConfig.KubernetesVersion, - secrets, options..., ) @@ -142,10 +145,7 @@ func Generate(ctx context.Context, in *machine.GenerateConfigurationRequest) (re return nil, err } - c, err = generate.Config( - machineType, - input, - ) + c, err = input.Config(machineType) if err != nil { return nil, err @@ -157,7 +157,7 @@ func Generate(ctx context.Context, in *machine.GenerateConfigurationRequest) (re return nil, err } - talosconfig, err := generate.Talosconfig(input, options...) + talosconfig, err := input.Talosconfig() if err != nil { return nil, err } diff --git a/internal/pkg/dashboard/components/kubernetesinfo.go b/internal/pkg/dashboard/components/kubernetesinfo.go index e002d621f..a8d468eb7 100644 --- a/internal/pkg/dashboard/components/kubernetesinfo.go +++ b/internal/pkg/dashboard/components/kubernetesinfo.go @@ -13,7 +13,7 @@ import ( "github.com/siderolabs/talos/internal/pkg/dashboard/apidata" "github.com/siderolabs/talos/internal/pkg/dashboard/resourcedata" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/config" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" ) diff --git a/internal/pkg/discovery/registry/kubernetes.go b/internal/pkg/discovery/registry/kubernetes.go index 1d1497f90..8272530a8 100644 --- a/internal/pkg/discovery/registry/kubernetes.go +++ b/internal/pkg/discovery/registry/kubernetes.go @@ -26,7 +26,7 @@ import ( "k8s.io/client-go/tools/cache" "github.com/siderolabs/talos/pkg/kubernetes" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/cluster" ) diff --git a/internal/pkg/discovery/registry/kubernetes_test.go b/internal/pkg/discovery/registry/kubernetes_test.go index ae1b8a881..0c53e1c5b 100644 --- a/internal/pkg/discovery/registry/kubernetes_test.go +++ b/internal/pkg/discovery/registry/kubernetes_test.go @@ -13,7 +13,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/siderolabs/talos/internal/pkg/discovery/registry" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/cluster" ) diff --git a/internal/pkg/environment/environment_test.go b/internal/pkg/environment/environment_test.go index ae2e94702..35500f814 100644 --- a/internal/pkg/environment/environment_test.go +++ b/internal/pkg/environment/environment_test.go @@ -9,9 +9,11 @@ import ( "github.com/siderolabs/go-procfs/procfs" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/siderolabs/talos/internal/pkg/environment" "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" ) @@ -67,11 +69,14 @@ func TestGet(t *testing.T) { var cfg config.Config if test.cfg != nil { - cfg = &v1alpha1.Config{ + var err error + + cfg, err = container.New(&v1alpha1.Config{ MachineConfig: &v1alpha1.MachineConfig{ MachineEnv: test.cfg, }, - } + }) + require.NoError(t, err) } result := environment.GetCmdline(cmdline, cfg) diff --git a/internal/pkg/etcd/etcd.go b/internal/pkg/etcd/etcd.go index ca185e390..6febc8f40 100644 --- a/internal/pkg/etcd/etcd.go +++ b/internal/pkg/etcd/etcd.go @@ -24,7 +24,7 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/system" "github.com/siderolabs/talos/pkg/machinery/config" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/nethelpers" etcdresource "github.com/siderolabs/talos/pkg/machinery/resources/etcd" diff --git a/internal/pkg/tui/installer/state.go b/internal/pkg/tui/installer/state.go index 0f949f9cb..69cb598f6 100644 --- a/internal/pkg/tui/installer/state.go +++ b/internal/pkg/tui/installer/state.go @@ -17,8 +17,8 @@ import ( "github.com/siderolabs/talos/internal/pkg/tui/components" "github.com/siderolabs/talos/pkg/images" machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/nethelpers" ) diff --git a/pkg/cluster/bootstrap.go b/pkg/cluster/bootstrap.go index 8bb97bab5..765e6f901 100644 --- a/pkg/cluster/bootstrap.go +++ b/pkg/cluster/bootstrap.go @@ -19,7 +19,7 @@ import ( machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // APIBootstrapper bootstraps cluster via Talos API. diff --git a/pkg/cluster/check/default.go b/pkg/cluster/check/default.go index a741e3d8c..fd5a63d2a 100644 --- a/pkg/cluster/check/default.go +++ b/pkg/cluster/check/default.go @@ -9,7 +9,7 @@ import ( "time" "github.com/siderolabs/talos/pkg/conditions" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // DefaultClusterChecks returns a set of default Talos cluster readiness checks. diff --git a/pkg/cluster/check/discovery.go b/pkg/cluster/check/discovery.go index 869c79961..18e5ed38a 100644 --- a/pkg/cluster/check/discovery.go +++ b/pkg/cluster/check/discovery.go @@ -12,7 +12,7 @@ import ( "github.com/siderolabs/gen/slices" "github.com/siderolabs/talos/pkg/cluster" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" clussterres "github.com/siderolabs/talos/pkg/machinery/resources/cluster" ) diff --git a/pkg/cluster/check/etcd.go b/pkg/cluster/check/etcd.go index d9d7ebc20..e1c921d0d 100644 --- a/pkg/cluster/check/etcd.go +++ b/pkg/cluster/check/etcd.go @@ -17,7 +17,7 @@ import ( "github.com/siderolabs/talos/pkg/cluster" machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // EtcdConsistentAssertion checks that etcd membership is consistent across nodes. diff --git a/pkg/cluster/check/kubernetes.go b/pkg/cluster/check/kubernetes.go index eceed6d52..1dd18579f 100644 --- a/pkg/cluster/check/kubernetes.go +++ b/pkg/cluster/check/kubernetes.go @@ -19,7 +19,7 @@ import ( "github.com/siderolabs/talos/pkg/cluster" "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" ) diff --git a/pkg/cluster/check/nodes.go b/pkg/cluster/check/nodes.go index f1477083b..2b0e0a5bf 100644 --- a/pkg/cluster/check/nodes.go +++ b/pkg/cluster/check/nodes.go @@ -17,7 +17,7 @@ import ( "google.golang.org/grpc/codes" "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/runtime" "github.com/siderolabs/talos/pkg/minimal" diff --git a/pkg/cluster/check/options.go b/pkg/cluster/check/options.go index 3d51f4f3c..b309d3b53 100644 --- a/pkg/cluster/check/options.go +++ b/pkg/cluster/check/options.go @@ -4,7 +4,7 @@ package check -import "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" +import "github.com/siderolabs/talos/pkg/machinery/config/machine" // Option represents functional option. type Option func(o *Options) error diff --git a/pkg/cluster/check/service.go b/pkg/cluster/check/service.go index 395ea73df..157a7ca76 100644 --- a/pkg/cluster/check/service.go +++ b/pkg/cluster/check/service.go @@ -14,7 +14,7 @@ import ( "github.com/siderolabs/talos/pkg/cluster" "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // ErrServiceNotFound is an error that indicates that a service was not found. diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index df01c96fe..9ef9a2fad 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -19,7 +19,7 @@ import ( k8s "github.com/siderolabs/talos/pkg/kubernetes" "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // ClientProvider builds Talos client by endpoint. diff --git a/pkg/cluster/kubernetes/patch.go b/pkg/cluster/kubernetes/patch.go index 44c1af557..670c98b91 100644 --- a/pkg/cluster/kubernetes/patch.go +++ b/pkg/cluster/kubernetes/patch.go @@ -46,7 +46,7 @@ func patchNodeConfig(ctx context.Context, cluster UpgradeProvider, node string, return fmt.Errorf("error patching config: %w", err) } - cfgBytes, err := cfg.Bytes() + cfgBytes, err := mc.Container().EncodeBytes() if err != nil { return fmt.Errorf("error serializing config: %w", err) } diff --git a/pkg/cluster/kubernetes/talos_managed.go b/pkg/cluster/kubernetes/talos_managed.go index 394f785e7..a15dccc26 100644 --- a/pkg/cluster/kubernetes/talos_managed.go +++ b/pkg/cluster/kubernetes/talos_managed.go @@ -24,8 +24,8 @@ import ( "github.com/siderolabs/talos/pkg/cluster" "github.com/siderolabs/talos/pkg/kubernetes" "github.com/siderolabs/talos/pkg/machinery/client" + machinetype "github.com/siderolabs/talos/pkg/machinery/config/machine" v1alpha1config "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - machinetype "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" ) diff --git a/pkg/cluster/provision.go b/pkg/cluster/provision.go index bc4502279..f79cf868c 100644 --- a/pkg/cluster/provision.go +++ b/pkg/cluster/provision.go @@ -7,7 +7,7 @@ package cluster import ( "net/netip" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/provision" ) diff --git a/pkg/kubernetes/kubernetes.go b/pkg/kubernetes/kubernetes.go index 2c1d3529d..ad2524bef 100644 --- a/pkg/kubernetes/kubernetes.go +++ b/pkg/kubernetes/kubernetes.go @@ -32,7 +32,7 @@ import ( restclient "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/secrets" ) diff --git a/pkg/machinery/config/bundle/bundle.go b/pkg/machinery/config/bundle/bundle.go new file mode 100644 index 000000000..5135da9ef --- /dev/null +++ b/pkg/machinery/config/bundle/bundle.go @@ -0,0 +1,263 @@ +// 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 bundle provides a set of machine configuration files. +package bundle + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + clientconfig "github.com/siderolabs/talos/pkg/machinery/client/config" + "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/configloader" + "github.com/siderolabs/talos/pkg/machinery/config/configpatcher" + "github.com/siderolabs/talos/pkg/machinery/config/encoder" + "github.com/siderolabs/talos/pkg/machinery/config/generate" + "github.com/siderolabs/talos/pkg/machinery/config/machine" +) + +// Bundle defines a set of machine configuration files. +type Bundle struct { + InitCfg config.Provider + ControlPlaneCfg config.Provider + WorkerCfg config.Provider + TalosCfg *clientconfig.Config +} + +// NewBundle returns a new bundle of configuration files. +// +//nolint:gocyclo,cyclop +func NewBundle(opts ...Option) (*Bundle, error) { + options := DefaultOptions() + + for _, opt := range opts { + if err := opt(&options); err != nil { + return nil, err + } + } + + bundle := &Bundle{} + + // Configs already exist, we'll pull them in. + if options.ExistingConfigs != "" { + if options.InputOptions != nil { + return bundle, fmt.Errorf("both existing config path and input options specified") + } + + // Pull existing machine configs of each type + for _, configType := range []machine.Type{machine.TypeInit, machine.TypeControlPlane, machine.TypeWorker} { + data, err := os.ReadFile(filepath.Join(options.ExistingConfigs, strings.ToLower(configType.String())+".yaml")) + if err != nil { + if configType == machine.TypeInit && os.IsNotExist(err) { + continue + } + + return bundle, err + } + + unmarshalledConfig, err := configloader.NewFromBytes(data) + if err != nil { + return nil, err + } + + switch configType { + case machine.TypeInit: + bundle.InitCfg = unmarshalledConfig + case machine.TypeControlPlane: + bundle.ControlPlaneCfg = unmarshalledConfig + case machine.TypeWorker: + bundle.WorkerCfg = unmarshalledConfig + case machine.TypeUnknown: + fallthrough + default: + panic("unreachable") + } + } + + if err := bundle.applyPatches(options); err != nil { + return nil, err + } + + // Pull existing talosconfig + talosConfig, err := os.Open(filepath.Join(options.ExistingConfigs, "talosconfig")) + if err != nil { + return bundle, err + } + + defer talosConfig.Close() //nolint:errcheck + + if bundle.TalosCfg, err = clientconfig.ReadFrom(talosConfig); err != nil { + return bundle, err + } + + return bundle, nil + } + + // Handle generating net-new configs + if options.Verbose { + fmt.Fprintln(os.Stderr, "generating PKI and tokens") + } + + if options.InputOptions == nil { + return nil, fmt.Errorf("no WithInputOptions is defined") + } + + input, err := generate.NewInput( + options.InputOptions.ClusterName, + options.InputOptions.Endpoint, + options.InputOptions.KubeVersion, + options.InputOptions.GenOptions..., + ) + if err != nil { + return bundle, err + } + + for _, configType := range []machine.Type{machine.TypeInit, machine.TypeControlPlane, machine.TypeWorker} { + var generatedConfig config.Provider + + generatedConfig, err = input.Config(configType) + if err != nil { + return bundle, err + } + + switch configType { + case machine.TypeInit: + bundle.InitCfg = generatedConfig + case machine.TypeControlPlane: + bundle.ControlPlaneCfg = generatedConfig + case machine.TypeWorker: + bundle.WorkerCfg = generatedConfig + case machine.TypeUnknown: + fallthrough + default: + panic("unreachable") + } + } + + if err = bundle.applyPatches(options); err != nil { + return nil, err + } + + bundle.TalosCfg, err = input.Talosconfig() + if err != nil { + return bundle, err + } + + return bundle, nil +} + +// Init implements the ProviderBundle interface. +func (bundle *Bundle) Init() config.Provider { + return bundle.InitCfg +} + +// ControlPlane implements the ProviderBundle interface. +func (bundle *Bundle) ControlPlane() config.Provider { + return bundle.ControlPlaneCfg +} + +// Worker implements the ProviderBundle interface. +func (bundle *Bundle) Worker() config.Provider { + return bundle.WorkerCfg +} + +// TalosConfig implements the ProviderBundle interface. +func (bundle *Bundle) TalosConfig() *clientconfig.Config { + return bundle.TalosCfg +} + +// Write config files to output directory. +func (bundle *Bundle) Write(outputDir string, commentsFlags encoder.CommentsFlags, types ...machine.Type) error { + for _, t := range types { + name := strings.ToLower(t.String()) + ".yaml" + fullFilePath := filepath.Join(outputDir, name) + + bytes, err := bundle.Serialize(commentsFlags, t) + if err != nil { + return err + } + + if err = os.WriteFile(fullFilePath, bytes, 0o644); err != nil { + return err + } + + fmt.Fprintf(os.Stderr, "created %s\n", fullFilePath) + } + + return nil +} + +// Serialize returns the config for the provided machine type as bytes. +func (bundle *Bundle) Serialize(commentsFlags encoder.CommentsFlags, machineType machine.Type) ([]byte, error) { + switch machineType { + case machine.TypeInit: + return bundle.Init().EncodeBytes(encoder.WithComments(commentsFlags)) + case machine.TypeControlPlane: + return bundle.ControlPlane().EncodeBytes(encoder.WithComments(commentsFlags)) + case machine.TypeWorker: + return bundle.Worker().EncodeBytes(encoder.WithComments(commentsFlags)) + case machine.TypeUnknown: + fallthrough + default: + return nil, fmt.Errorf("unexpected machine type %v", machineType) + } +} + +// ApplyPatches patches every config type with a patch. +func (bundle *Bundle) ApplyPatches(patches []configpatcher.Patch, patchControlPlane, patchWorker bool) error { + if len(patches) == 0 { + return nil + } + + apply := func(in config.Provider) (config.Provider, error) { + patched, err := configpatcher.Apply(configpatcher.WithConfig(in), patches) + if err != nil { + return nil, err + } + + return patched.Config() + } + + var err error + + if patchControlPlane { + bundle.InitCfg, err = apply(bundle.InitCfg) + if err != nil { + return err + } + + bundle.ControlPlaneCfg, err = apply(bundle.ControlPlaneCfg) + if err != nil { + return err + } + } + + if patchWorker { + bundle.WorkerCfg, err = apply(bundle.WorkerCfg) + if err != nil { + return err + } + } + + return nil +} + +func (bundle *Bundle) applyPatches(options Options) error { + if err := bundle.ApplyPatches(options.Patches, true, true); err != nil { + return fmt.Errorf("error patching configs: %w", err) + } + + if err := bundle.ApplyPatches(options.PatchesControlPlane, true, false); err != nil { + return fmt.Errorf("error patching control plane configs: %w", err) + } + + if err := bundle.ApplyPatches(options.PatchesWorker, false, true); err != nil { + return fmt.Errorf("error patching worker config: %w", err) + } + + return nil +} diff --git a/pkg/machinery/config/types/v1alpha1/bundle/bundle_test.go b/pkg/machinery/config/bundle/bundle_test.go similarity index 88% rename from pkg/machinery/config/types/v1alpha1/bundle/bundle_test.go rename to pkg/machinery/config/bundle/bundle_test.go index fce456261..25a7862d6 100644 --- a/pkg/machinery/config/types/v1alpha1/bundle/bundle_test.go +++ b/pkg/machinery/config/bundle/bundle_test.go @@ -12,11 +12,11 @@ import ( "github.com/stretchr/testify/require" "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/bundle" "github.com/siderolabs/talos/pkg/machinery/config/configloader" "github.com/siderolabs/talos/pkg/machinery/config/configpatcher" "github.com/siderolabs/talos/pkg/machinery/config/encoder" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/bundle" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) func TestGenerateConfig(t *testing.T) { @@ -35,7 +35,7 @@ func TestGenerateConfig(t *testing.T) { configBundleOpts = append(configBundleOpts, bundle.WithPatch(patches)) - configBundle, err := bundle.NewConfigBundle(configBundleOpts...) + configBundle, err := bundle.NewBundle(configBundleOpts...) require.NoError(t, err) tempDir := t.TempDir() diff --git a/pkg/machinery/config/bundle/options.go b/pkg/machinery/config/bundle/options.go new file mode 100644 index 000000000..48f859b6a --- /dev/null +++ b/pkg/machinery/config/bundle/options.go @@ -0,0 +1,93 @@ +// 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 bundle + +import ( + "github.com/siderolabs/talos/pkg/machinery/config/configpatcher" + "github.com/siderolabs/talos/pkg/machinery/config/generate" +) + +// Option controls config options specific to config bundle generation. +type Option func(o *Options) error + +// InputOptions holds necessary params for generating an input. +type InputOptions struct { + ClusterName string + Endpoint string + KubeVersion string + GenOptions []generate.Option +} + +// Options describes generate parameters. +type Options struct { + ExistingConfigs string // path to existing config files + Verbose bool // whether to write any logs during generate + InputOptions *InputOptions + + Patches []configpatcher.Patch + PatchesControlPlane []configpatcher.Patch + PatchesWorker []configpatcher.Patch +} + +// DefaultOptions returns default options. +func DefaultOptions() Options { + return Options{ + Verbose: true, + } +} + +// WithExistingConfigs sets the path to existing config files. +func WithExistingConfigs(configPath string) Option { + return func(o *Options) error { + o.ExistingConfigs = configPath + + return nil + } +} + +// WithInputOptions allows passing in of various params for net-new input generation. +func WithInputOptions(inputOpts *InputOptions) Option { + return func(o *Options) error { + o.InputOptions = inputOpts + + return nil + } +} + +// WithVerbose allows setting verbose logging. +func WithVerbose(verbose bool) Option { + return func(o *Options) error { + o.Verbose = verbose + + return nil + } +} + +// WithPatch allows patching every config in a bundle with a patch. +func WithPatch(patch []configpatcher.Patch) Option { + return func(o *Options) error { + o.Patches = append(o.Patches, patch...) + + return nil + } +} + +// WithPatchControlPlane allows patching init and controlplane config in a bundle with a patch. +func WithPatchControlPlane(patch []configpatcher.Patch) Option { + return func(o *Options) error { + o.PatchesControlPlane = append(o.PatchesControlPlane, patch...) + + return nil + } +} + +// WithPatchWorker allows patching worker config in a bundle with a patch. +func WithPatchWorker(patch []configpatcher.Patch) Option { + return func(o *Options) error { + o.PatchesWorker = append(o.PatchesWorker, patch...) + + return nil + } +} diff --git a/pkg/machinery/config/config/config.go b/pkg/machinery/config/config/config.go index b82696ed8..84ea7e6b9 100644 --- a/pkg/machinery/config/config/config.go +++ b/pkg/machinery/config/config/config.go @@ -11,4 +11,5 @@ type Config interface { Persist() bool Machine() MachineConfig Cluster() ClusterConfig + SideroLink() SideroLinkConfig } diff --git a/pkg/machinery/config/config/document.go b/pkg/machinery/config/config/document.go new file mode 100644 index 000000000..0960c66e4 --- /dev/null +++ b/pkg/machinery/config/config/document.go @@ -0,0 +1,17 @@ +// 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 config + +// Document is a configuration document. +type Document interface { + // Clone returns a deep copy of the document. + Clone() Document +} + +// SecretDocument is a configuration document that contains secrets. +type SecretDocument interface { + // Redact does in-place replacement of secrets with the given string. + Redact(replacement string) +} diff --git a/pkg/machinery/config/config/machine.go b/pkg/machinery/config/config/machine.go index deb215ec1..ea2f7539e 100644 --- a/pkg/machinery/config/config/machine.go +++ b/pkg/machinery/config/config/machine.go @@ -13,7 +13,7 @@ import ( "github.com/opencontainers/runtime-spec/specs-go" "github.com/siderolabs/crypto/x509" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // MachineConfig defines the requirements for a config that pertains to machine diff --git a/pkg/machinery/config/config/siderolink.go b/pkg/machinery/config/config/siderolink.go new file mode 100644 index 000000000..38bf79866 --- /dev/null +++ b/pkg/machinery/config/config/siderolink.go @@ -0,0 +1,12 @@ +// 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 config + +import "net/url" + +// SideroLinkConfig defines the interface to access SideroLink configuration. +type SideroLinkConfig interface { + APIUrl() *url.URL +} diff --git a/pkg/machinery/config/config/validate.go b/pkg/machinery/config/config/validate.go new file mode 100644 index 000000000..bd244b5cf --- /dev/null +++ b/pkg/machinery/config/config/validate.go @@ -0,0 +1,15 @@ +// 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 config + +import "github.com/siderolabs/talos/pkg/machinery/config/validation" + +// Validator is the interface to validate configuration. +// +// Validator might be implemented by a Container and a single Document. +type Validator interface { + // Validate checks configuration and returns warnings and fatal errors (as multierror). + Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) +} diff --git a/pkg/machinery/config/configloader/configloader.go b/pkg/machinery/config/configloader/configloader.go index 37f13cb36..01ef5873d 100644 --- a/pkg/machinery/config/configloader/configloader.go +++ b/pkg/machinery/config/configloader/configloader.go @@ -8,71 +8,57 @@ package configloader import ( "bytes" "errors" - "fmt" "io" "os" "github.com/siderolabs/talos/pkg/machinery/config" "github.com/siderolabs/talos/pkg/machinery/config/configloader/internal/decoder" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" + "github.com/siderolabs/talos/pkg/machinery/config/container" + _ "github.com/siderolabs/talos/pkg/machinery/config/types" //nolint:revive ) // ErrNoConfig is returned when no configuration was found in the input. var ErrNoConfig = errors.New("config not found") // newConfig initializes and returns a Configurator. -func newConfig(source []byte) (config config.Provider, err error) { - dec := decoder.NewDecoder(source) +func newConfig(r io.Reader) (config config.Provider, err error) { + dec := decoder.NewDecoder() - manifests, err := dec.Decode() + var buf bytes.Buffer + + // preserve the original contents + r = io.TeeReader(r, &buf) + + manifests, err := dec.Decode(r) if err != nil { return nil, err } - // Look for the older flat v1alpha1 file first, since we have to handle it in - // a special way. - for _, manifest := range manifests { - if talosconfig, ok := manifest.(*v1alpha1.Config); ok { - return v1alpha1.WrapReadonly(talosconfig, source), nil - } + if len(manifests) == 0 { + return nil, ErrNoConfig } - return nil, ErrNoConfig + return container.NewReadonly(buf.Bytes(), manifests...) } // NewFromFile will take a filepath and attempt to parse a config file from it. func NewFromFile(filepath string) (config.Provider, error) { - source, err := fromFile(filepath) + f, err := os.Open(filepath) if err != nil { return nil, err } - return newConfig(source) + defer f.Close() //nolint:errcheck + + return newConfig(f) } // NewFromStdin initializes a config provider by reading from stdin. func NewFromStdin() (config.Provider, error) { - buf := bytes.NewBuffer(nil) - - _, err := io.Copy(buf, os.Stdin) - if err != nil { - return nil, err - } - - config, err := NewFromBytes(buf.Bytes()) - if err != nil { - return nil, fmt.Errorf("failed load config from stdin: %w", err) - } - - return config, nil + return newConfig(os.Stdin) } // NewFromBytes will take a byteslice and attempt to parse a config file from it. func NewFromBytes(source []byte) (config.Provider, error) { - return newConfig(source) -} - -// fromFile is a convenience function that reads the config from disk. -func fromFile(p string) ([]byte, error) { - return os.ReadFile(p) + return newConfig(bytes.NewReader(source)) } diff --git a/pkg/machinery/config/configloader/configloader_test.go b/pkg/machinery/config/configloader/configloader_test.go index 248c3e852..404d1a258 100644 --- a/pkg/machinery/config/configloader/configloader_test.go +++ b/pkg/machinery/config/configloader/configloader_test.go @@ -19,6 +19,10 @@ import ( func callMethods(t testing.TB, obj reflect.Value, chain ...string) { t.Helper() + if obj.Kind() == reflect.Interface && obj.IsNil() { + return + } + typ := obj.Type() for i := 0; i < obj.NumMethod(); i++ { diff --git a/pkg/machinery/config/configloader/internal/decoder/decoder.go b/pkg/machinery/config/configloader/internal/decoder/decoder.go index 3e6526565..179042b33 100644 --- a/pkg/machinery/config/configloader/internal/decoder/decoder.go +++ b/pkg/machinery/config/configloader/internal/decoder/decoder.go @@ -6,34 +6,24 @@ package decoder import ( - "bytes" "errors" "fmt" "io" yaml "gopkg.in/yaml.v3" + "github.com/siderolabs/talos/pkg/machinery/config/config" "github.com/siderolabs/talos/pkg/machinery/config/internal/registry" ) -var ( - // ErrMissingVersion indicates that the manifest is missing a version. - ErrMissingVersion = errors.New("missing version") - // ErrMissingKind indicates that the manifest is missing a kind. - ErrMissingKind = errors.New("missing kind") - // ErrMissingSpec indicates that the manifest is missing a spec. - ErrMissingSpec = errors.New("missing spec") - // ErrMissingSpecConent indicates that the manifest spec is empty. - ErrMissingSpecConent = errors.New("missing spec content") -) +// ErrMissingKind indicates that the manifest is missing a kind. +var ErrMissingKind = errors.New("missing kind") const ( // ManifestVersionKey is the string indicating a manifest's version. ManifestVersionKey = "version" // ManifestKindKey is the string indicating a manifest's kind. ManifestKindKey = "kind" - // ManifestSpecKey represents a manifest's spec. - ManifestSpecKey = "spec" // ManifestDeprecatedKeyMachine represents the deprecated v1alpha1 manifest. ManifestDeprecatedKeyMachine = "machine" // ManifestDeprecatedKeyCluster represents the deprecated v1alpha1 manifest. @@ -45,27 +35,19 @@ const ( ) // Decoder represents a multi-doc YAML decoder. -type Decoder struct { - source []byte -} +type Decoder struct{} // Decode decodes all known manifests. -func (d *Decoder) Decode() ([]interface{}, error) { - return d.decode() +func (d *Decoder) Decode(r io.Reader) ([]config.Document, error) { + return parse(r) } // NewDecoder initializes and returns a `Decoder`. -func NewDecoder(source []byte) *Decoder { - return &Decoder{ - source: source, - } +func NewDecoder() *Decoder { + return &Decoder{} } -func (d *Decoder) decode() ([]interface{}, error) { - return parse(d.source) -} - -func parse(source []byte) (decoded []interface{}, err error) { +func parse(r io.Reader) (decoded []config.Document, err error) { // Recover from yaml.v3 panics because we rely on machine configuration loading _a lot_. defer func() { if p := recover(); p != nil { @@ -73,9 +55,7 @@ func parse(source []byte) (decoded []interface{}, err error) { } }() - decoded = []interface{}{} - - r := bytes.NewReader(source) + decoded = []config.Document{} dec := yaml.NewDecoder(r) @@ -98,7 +78,7 @@ func parse(source []byte) (decoded []interface{}, err error) { } for _, manifest := range manifests.Content { - var target interface{} + var target config.Document if target, err = decode(manifest); err != nil { return nil, err @@ -110,11 +90,10 @@ func parse(source []byte) (decoded []interface{}, err error) { } //nolint:gocyclo,cyclop -func decode(manifest *yaml.Node) (target interface{}, err error) { +func decode(manifest *yaml.Node) (target config.Document, err error) { var ( version string kind string - spec *yaml.Node ) for i, node := range manifest.Content { @@ -135,58 +114,33 @@ func decode(manifest *yaml.Node) (target interface{}, err error) { if err = manifest.Content[i+1].Decode(&version); err != nil { return nil, fmt.Errorf("version decode: %w", err) } - case ManifestSpecKey: - if len(manifest.Content) < i+1 { - return nil, fmt.Errorf("missing manifest content") - } - - spec = manifest.Content[i+1] case ManifestDeprecatedKeyMachine, ManifestDeprecatedKeyCluster, ManifestDeprecatedKeyDebug, ManifestDeprecatedKeyPersist: - if target, err = registry.New("v1alpha1", ""); err != nil { - return nil, fmt.Errorf("new deprecated config: %w", err) - } - - if err = manifest.Decode(target); err != nil { - return nil, fmt.Errorf("deprecated decode: %w", err) - } - - if err = checkUnknownKeys(target, manifest); err != nil { - return nil, err - } - - return target, nil + version = "v1alpha1" } } - if kind == "" { - return nil, ErrMissingKind + switch { + case version == "v1alpha1" && kind == "": + target, err = registry.New("v1alpha1", "") + case kind == "": + err = ErrMissingKind + default: + target, err = registry.New(kind, version) } - if version == "" { - return nil, ErrMissingVersion + if err != nil { + return nil, err } - if spec == nil { - return nil, ErrMissingSpec + if err = manifest.Decode(target); err != nil { + return nil, fmt.Errorf("error decoding %s to %T: %w", kind, target, err) } - if spec.Content == nil { - return nil, ErrMissingSpecConent - } - - if target, err = registry.New(kind, version); err != nil { - return nil, fmt.Errorf("new config: %w", err) - } - - if err = spec.Decode(target); err != nil { - return nil, fmt.Errorf("spec decode: %w", err) - } - - if err = checkUnknownKeys(target, spec); err != nil { + if err = checkUnknownKeys(target, manifest); err != nil { return nil, err } diff --git a/pkg/machinery/config/configloader/internal/decoder/decoder_test.go b/pkg/machinery/config/configloader/internal/decoder/decoder_test.go index 3e91ff73b..1a2f61b97 100644 --- a/pkg/machinery/config/configloader/internal/decoder/decoder_test.go +++ b/pkg/machinery/config/configloader/internal/decoder/decoder_test.go @@ -5,6 +5,7 @@ package decoder_test import ( + "bytes" "os" "path/filepath" "testing" @@ -12,30 +13,65 @@ 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/internal/decoder" "github.com/siderolabs/talos/pkg/machinery/config/internal/registry" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" ) +type Meta struct { + Kind string `yaml:"kind"` + Version string `yaml:"version,omitempty"` +} + type Mock struct { + Meta Test bool `yaml:"test"` } +func (m *Mock) Clone() config.Document { + return m +} + type MockV2 struct { + Meta Slice []Mock `yaml:"slice"` Map map[string]*Mock `yaml:"map"` } +func (m *MockV2) Clone() config.Document { + return m +} + type MockV3 struct { + Meta Omit bool `yaml:"omit,omitempty"` } +func (m *MockV3) Clone() config.Document { + return m +} + +type KubeletConfig struct { + Meta + v1alpha1.KubeletConfig `yaml:",inline"` +} + +func (m *KubeletConfig) Clone() config.Document { + return m +} + type MockUnstructured struct { + Meta Pods []v1alpha1.Unstructured `yaml:"pods,omitempty"` } +func (m *MockUnstructured) Clone() config.Document { + return m +} + func init() { - registry.Register("mock", func(version string) any { + registry.Register("mock", func(version string) config.Document { switch version { case "v1alpha2": return &MockV2{} @@ -46,11 +82,11 @@ func init() { return &Mock{} }) - registry.Register("kubelet", func(string) any { - return &v1alpha1.KubeletConfig{} + registry.Register("kubelet", func(string) config.Document { + return &KubeletConfig{} }) - registry.Register("unstructured", func(string) any { + registry.Register("unstructured", func(string) config.Document { return &MockUnstructured{} }) } @@ -61,7 +97,7 @@ func TestDecoder(t *testing.T) { tests := []struct { name string source []byte - expected []interface{} + expected []config.Document expectedErr string }{ { @@ -69,10 +105,9 @@ func TestDecoder(t *testing.T) { source: []byte(`--- kind: mock version: v1alpha1 -spec: - test: true +test: true `), - expected: []interface{}{ + expected: []config.Document{ &Mock{ Test: true, }, @@ -82,9 +117,8 @@ spec: { name: "missing kind", source: []byte(`--- -version: v1alpha1 -spec: - test: true +version: v1alpha2 +test: true `), expected: nil, expectedErr: "missing kind", @@ -93,53 +127,12 @@ spec: name: "empty kind", source: []byte(`--- kind: -version: v1alpha1 -spec: - test: true +version: v1alpha2 +test: true `), expected: nil, expectedErr: "missing kind", }, - { - name: "missing version", - source: []byte(`--- -kind: mock -spec: - test: true -`), - expected: nil, - expectedErr: "missing version", - }, - { - name: "empty version", - source: []byte(`--- -kind: mock -version: -spec: - test: true -`), - expected: nil, - expectedErr: "missing version", - }, - { - name: "missing spec", - source: []byte(`--- -kind: mock -version: v1alpha1 -`), - expected: nil, - expectedErr: "missing spec", - }, - { - name: "empty spec", - source: []byte(`--- -kind: mock -version: v1alpha1 -spec: -`), - expected: nil, - expectedErr: "missing spec content", - }, { name: "tab instead of spaces", source: []byte(`--- @@ -156,9 +149,8 @@ spec: source: []byte(`--- kind: mock version: v1alpha1 -spec: - test: true - extra: fail +test: true +extra: fail `), expected: nil, expectedErr: "unknown keys found during decoding:\nextra: fail\n", @@ -168,11 +160,10 @@ spec: source: []byte(`--- kind: mock version: v1alpha2 -spec: - map: - first: - test: true - extra: me +map: + first: + test: true + extra: me `), expected: nil, expectedErr: "unknown keys found during decoding:\nmap:\n first:\n extra: me\n", @@ -182,12 +173,11 @@ spec: source: []byte(`--- kind: mock version: v1alpha2 -spec: - slice: - - test: true - not: working - more: extra - fields: here +slice: + - test: true + not: working + more: extra + fields: here `), expected: nil, expectedErr: "unknown keys found during decoding:\nslice:\n - fields: here\n more: extra\n not: working\n", @@ -197,11 +187,10 @@ spec: source: []byte(`--- kind: mock version: v1alpha2 -spec: - map: - second: - a: - b: {} +map: + second: + a: + b: {} `), expected: nil, expectedErr: "unknown keys found during decoding:\nmap:\n second:\n a:\n b: {}\n", @@ -211,16 +200,15 @@ spec: source: []byte(`--- kind: mock version: v1alpha2 -spec: - slice: - - test: true - map: - first: - test: true - second: - test: false +slice: + - test: true +map: + first: + test: true + second: + test: false `), - expected: []interface{}{ + expected: []config.Document{ &MockV2{ Map: map[string]*Mock{ "first": { @@ -242,14 +230,13 @@ spec: source: []byte(`--- kind: kubelet version: v1alpha1 -spec: - extraMounts: - - destination: /var/local - options: - - rbind - - rshared - - rw - source: /var/local +extraMounts: + - destination: /var/local + options: + - rbind + - rshared + - rw + source: /var/local `), expected: nil, expectedErr: "", @@ -259,8 +246,7 @@ spec: source: []byte(`--- kind: mock version: v1alpha3 -spec: - omit: false +omit: false `), expected: nil, expectedErr: "", @@ -276,14 +262,13 @@ spec: source: []byte(`--- kind: unstructured version: v1alpha1 -spec: - pods: - - destination: /var/local - options: - - rbind - - rw - source: /var/local - something: 1.34 +pods: + - destination: /var/local + options: + - rbind + - rw + source: /var/local + something: 1.34 `), expected: nil, expectedErr: "", @@ -293,8 +278,7 @@ spec: source: []byte(`--- kind: mock version: v1alpha3 -spec: - omit: false +omit: false `), }, } @@ -305,8 +289,8 @@ spec: t.Run(tt.name, func(t *testing.T) { t.Parallel() - d := decoder.NewDecoder(tt.source) - actual, err := d.Decode() + d := decoder.NewDecoder() + actual, err := d.Decode(bytes.NewReader(tt.source)) if tt.expected != nil { assert.Equal(t, tt.expected, actual) } @@ -334,8 +318,8 @@ func TestDecoderV1Alpha1Config(t *testing.T) { contents, err := os.ReadFile(file) require.NoError(t, err) - d := decoder.NewDecoder(contents) - _, err = d.Decode() + d := decoder.NewDecoder() + _, err = d.Decode(bytes.NewReader(contents)) assert.NoError(t, err) }) @@ -349,8 +333,8 @@ func BenchmarkDecoderV1Alpha1Config(b *testing.B) { require.NoError(b, err) for i := 0; i < b.N; i++ { - d := decoder.NewDecoder(contents) - _, err = d.Decode() + d := decoder.NewDecoder() + _, err = d.Decode(bytes.NewReader(contents)) assert.NoError(b, err) } diff --git a/pkg/machinery/config/configpatcher/strategic.go b/pkg/machinery/config/configpatcher/strategic.go index 7daab73d3..ca2eb8c5b 100644 --- a/pkg/machinery/config/configpatcher/strategic.go +++ b/pkg/machinery/config/configpatcher/strategic.go @@ -6,6 +6,7 @@ package configpatcher import ( "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/merge" ) @@ -15,6 +16,8 @@ type StrategicMergePatch struct { } // StrategicMerge performs strategic merge config patching. +// +// TODO: this will drop any extra non-v1alpha1 documents. func StrategicMerge(cfg config.Provider, patch StrategicMergePatch) (config.Provider, error) { left := cfg.RawV1Alpha1() right := patch.RawV1Alpha1() @@ -23,5 +26,5 @@ func StrategicMerge(cfg config.Provider, patch StrategicMergePatch) (config.Prov return nil, err } - return left, nil + return container.New(left) } diff --git a/pkg/machinery/config/container/container.go b/pkg/machinery/config/container/container.go new file mode 100644 index 000000000..1e0143ade --- /dev/null +++ b/pkg/machinery/config/container/container.go @@ -0,0 +1,236 @@ +// 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 container implements a wrapper which wraps all configuration documents into a single container. +package container + +import ( + "bytes" + "fmt" + + "github.com/hashicorp/go-multierror" + "github.com/siderolabs/gen/slices" + + coreconfig "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/config" + "github.com/siderolabs/talos/pkg/machinery/config/encoder" + "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" + "github.com/siderolabs/talos/pkg/machinery/config/validation" +) + +// Container wraps all configuration documents into a single container. +type Container struct { + v1alpha1Config *v1alpha1.Config + documents []config.Document + bytes []byte + readonly bool +} + +var _ coreconfig.Provider = &Container{} + +// New creates a container out of the list of documents. +func New(documents ...config.Document) (*Container, error) { + container := &Container{ + documents: make([]config.Document, 0, len(documents)), + } + + for _, doc := range documents { + switch d := doc.(type) { + case *v1alpha1.Config: + if container.v1alpha1Config != nil { + return nil, fmt.Errorf("duplicate v1alpha1.Config") + } + + container.v1alpha1Config = d + default: + // TODO: we should check for some uniqueness of multi-docs (?) + container.documents = append(container.documents, d) + } + } + + return container, nil +} + +// NewReadonly creates a read-only container which preserves byte representation of contents. +func NewReadonly(bytes []byte, documents ...config.Document) (*Container, error) { + c, err := New(documents...) + if err != nil { + return nil, err + } + + c.bytes = bytes + c.readonly = true + + return c, nil +} + +// NewV1Alpha1 creates a container with (only) v1alpha1.Config document. +func NewV1Alpha1(config *v1alpha1.Config) *Container { + return &Container{ + v1alpha1Config: config, + } +} + +// Clone the container. +// +// Cloned container is not readonly. +func (container *Container) Clone() coreconfig.Provider { + return &Container{ + v1alpha1Config: container.v1alpha1Config.DeepCopy(), + documents: slices.Map(container.documents, config.Document.Clone), + } +} + +// Readonly implements config.Container interface. +func (container *Container) Readonly() bool { + return container.readonly +} + +// Debug implements config.Config interface. +func (container *Container) Debug() bool { + if container.v1alpha1Config == nil { + return false + } + + return container.v1alpha1Config.Debug() +} + +// Persist implements config.Config interface. +func (container *Container) Persist() bool { + if container.v1alpha1Config == nil { + return false + } + + return container.v1alpha1Config.Persist() +} + +// Machine implements config.Config interface. +func (container *Container) Machine() config.MachineConfig { + if container.v1alpha1Config == nil { + return nil + } + + return container.v1alpha1Config.Machine() +} + +// Cluster implements config.Config interface. +func (container *Container) Cluster() config.ClusterConfig { + if container.v1alpha1Config == nil { + return nil + } + + return container.v1alpha1Config.Cluster() +} + +// SideroLink implements config.Config interface. +func (container *Container) SideroLink() config.SideroLinkConfig { + for _, doc := range container.documents { + if c, ok := doc.(config.SideroLinkConfig); ok { + return c + } + } + + return nil +} + +// Bytes returns source YAML representation (if available) or does default encoding. +func (container *Container) Bytes() ([]byte, error) { + if !container.readonly { + return container.EncodeBytes() + } + + if container.bytes == nil { + panic("container.Bytes() called on a readonly container without bytes") + } + + return container.bytes, nil +} + +// EncodeString configuration to YAML using the provided options. +func (container *Container) EncodeString(encoderOptions ...encoder.Option) (string, error) { + b, err := container.EncodeBytes(encoderOptions...) + if err != nil { + return "", err + } + + return string(b), nil +} + +// EncodeBytes configuration to YAML using the provided options. +func (container *Container) EncodeBytes(encoderOptions ...encoder.Option) ([]byte, error) { + var buf bytes.Buffer + + if container.v1alpha1Config != nil { + b, err := encoder.NewEncoder(container.v1alpha1Config, encoderOptions...).Encode() + if err != nil { + return nil, err + } + + buf.Write(b) + } + + for _, doc := range container.documents { + if buf.Len() > 0 { + buf.Write([]byte("---\n")) + } + + b, err := encoder.NewEncoder(doc, encoderOptions...).Encode() + if err != nil { + return nil, err + } + + buf.Write(b) + } + + return buf.Bytes(), nil +} + +// Validate checks configuration and returns warnings and fatal errors (as multierror). +func (container *Container) Validate(mode validation.RuntimeMode, opt ...validation.Option) ([]string, error) { + var ( + warnings []string + err error + ) + + if container.v1alpha1Config != nil { + warnings, err = container.v1alpha1Config.Validate(mode, opt...) + } + + 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) + } + } + + return warnings, err +} + +// RedactSecrets returns a copy of the Provider with all secrets replaced with the given string. +func (container *Container) RedactSecrets(replacement string) coreconfig.Provider { + clone := container.Clone().(*Container) //nolint:forcetypeassert,errcheck + + if clone.v1alpha1Config != nil { + clone.v1alpha1Config.Redact(replacement) + } + + for _, doc := range clone.documents { + if secretDoc, ok := doc.(config.SecretDocument); ok { + secretDoc.Redact(replacement) + } + } + + return clone +} + +// RawV1Alpha1 returns internal config representation. +func (container *Container) RawV1Alpha1() *v1alpha1.Config { + if container.readonly { + return container.v1alpha1Config.DeepCopy() + } + + return container.v1alpha1Config +} diff --git a/pkg/machinery/config/container/container_test.go b/pkg/machinery/config/container/container_test.go new file mode 100644 index 000000000..9291340de --- /dev/null +++ b/pkg/machinery/config/container/container_test.go @@ -0,0 +1,66 @@ +// 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 container_test + +import ( + "net/url" + "testing" + + "github.com/siderolabs/go-pointer" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "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" + "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" +) + +func TestNew(t *testing.T) { + v1alpha1Cfg := &v1alpha1.Config{ + MachineConfig: &v1alpha1.MachineConfig{ + MachineFeatures: &v1alpha1.FeaturesConfig{ + RBAC: pointer.To(true), + }, + }, + ClusterConfig: &v1alpha1.ClusterConfig{ + ClusterSecret: "topsecret", + }, + } + + sideroLinkCfg := siderolink.NewConfigV1Alpha1() + sideroLinkCfg.APIUrlConfig.URL = must(url.Parse("https://siderolink.api/join?jointoken=secret&user=alice")) + + cfg, err := container.New(v1alpha1Cfg, sideroLinkCfg) + require.NoError(t, err) + + assert.False(t, cfg.Readonly()) + assert.False(t, cfg.Debug()) + assert.True(t, cfg.Machine().Features().RBACEnabled()) + 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()) + + bytes, err := cfg.Bytes() + require.NoError(t, err) + + cfgBack, err := configloader.NewFromBytes(bytes) + require.NoError(t, err) + + assert.True(t, cfgBack.Readonly()) + assert.NotEqual(t, v1alpha1Cfg, cfgBack.RawV1Alpha1()) + + cfgRedacted := cfg.RedactSecrets("REDACTED") + assert.Equal(t, "REDACTED", cfgRedacted.Cluster().Secret()) + assert.Equal(t, "https://siderolink.api/join?jointoken=REDACTED&user=alice", cfgRedacted.SideroLink().APIUrl().String()) +} + +func must[T any](t T, err error) T { + if err != nil { + panic(err) + } + + return t +} diff --git a/pkg/machinery/config/types/v1alpha1/generate/controlplane.go b/pkg/machinery/config/generate/controlplane.go similarity index 52% rename from pkg/machinery/config/types/v1alpha1/generate/controlplane.go rename to pkg/machinery/config/generate/controlplane.go index 7a9e00c73..4d125455b 100644 --- a/pkg/machinery/config/types/v1alpha1/generate/controlplane.go +++ b/pkg/machinery/config/generate/controlplane.go @@ -5,17 +5,18 @@ package generate import ( + "github.com/siderolabs/talos/pkg/machinery/config/config" + "github.com/siderolabs/talos/pkg/machinery/config/machine" v1alpha1 "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" ) -func controlPlaneUd(in *Input) (*v1alpha1.Config, error) { - config, err := initUd(in) +func (in *Input) controlPlane() ([]config.Document, error) { + docs, err := in.init() if err != nil { return nil, err } - config.MachineConfig.MachineType = machine.TypeControlPlane.String() + docs[0].(*v1alpha1.Config).MachineConfig.MachineType = machine.TypeControlPlane.String() - return config, nil + return docs, nil } diff --git a/pkg/machinery/config/types/v1alpha1/generate/example_test.go b/pkg/machinery/config/generate/example_test.go similarity index 82% rename from pkg/machinery/config/types/v1alpha1/generate/example_test.go rename to pkg/machinery/config/generate/example_test.go index 855ae05d9..47c6ed6d3 100644 --- a/pkg/machinery/config/types/v1alpha1/generate/example_test.go +++ b/pkg/machinery/config/generate/example_test.go @@ -7,11 +7,12 @@ package generate_test import ( "log" "os" + "time" "github.com/siderolabs/talos/pkg/machinery/config" - v1alpha1 "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/generate" + "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" ) @@ -46,13 +47,17 @@ func Example() { // generate the cluster-wide secrets once and use it for every node machine configuration // secrets can be stashed for future use by marshaling the structure to YAML or JSON - secrets, err := generate.NewSecretsBundle(generate.NewClock(), generate.WithVersionContract(versionContract)) + secretsBundle, err := secrets.NewBundle(secrets.NewFixedClock(time.Now()), versionContract) if err != nil { log.Fatalf("failed to generate secrets bundle: %s", err) } - input, err := generate.NewInput(clusterName, controlPlaneEndpoint, kubernetesVersion, secrets, + input, err := generate.NewInput(clusterName, controlPlaneEndpoint, kubernetesVersion, generate.WithVersionContract(versionContract), + generate.WithSecretsBundle(secretsBundle), + generate.WithEndpointList( + []string{"172.0.0.1", "172.0.0.2", "172.20.0.3"}, // list of control plane node IP addresses + ), // there are many more generate options available which allow to tweak generated config programmatically ) if err != nil { @@ -61,18 +66,18 @@ func Example() { // generate the machine config for each node of the cluster using the secrets for _, node := range []string{"machine1", "machine2"} { - var cfg *v1alpha1.Config + var cfg config.Provider // generate the machine config for the node, using the right machine type: // * machine.TypeConrolPlane for control plane nodes // * machine.TypeWorker for worker nodes - cfg, err = generate.Config(machine.TypeControlPlane, input) + cfg, err = input.Config(machine.TypeControlPlane) if err != nil { log.Fatalf("failed to generate config for node %q: %s", node, err) } // config can be tweaked at this point to add machine-specific configuration, e.g.: - cfg.MachineConfig.MachineInstall.InstallDisk = "/dev/sdb" + cfg.RawV1Alpha1().MachineConfig.MachineInstall.InstallDisk = "/dev/sdb" // marshal the config to YAML var marshaledCfg []byte @@ -89,9 +94,7 @@ func Example() { } // generate the client Talos configuration (for API access, e.g. talosctl) - clientCfg, err := generate.Talosconfig(input, generate.WithEndpointList( - []string{"172.0.0.1", "172.0.0.2", "172.20.0.3"}, // list of control plane node IP addresses - )) + clientCfg, err := input.Talosconfig() if err != nil { log.Fatalf("failed to generate client config: %s", err) } diff --git a/pkg/machinery/config/generate/generate.go b/pkg/machinery/config/generate/generate.go new file mode 100644 index 000000000..86d6826a1 --- /dev/null +++ b/pkg/machinery/config/generate/generate.go @@ -0,0 +1,152 @@ +// 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 generate provides Talos machine configuration generation and client config generation. +// +// Please see the example for more information on using this package. +package generate + +import ( + "errors" + "net/netip" + "net/url" + "time" + + "github.com/siderolabs/gen/slices" + "github.com/siderolabs/go-pointer" + + coreconfig "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/config" + "github.com/siderolabs/talos/pkg/machinery/config/container" + "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets" + "github.com/siderolabs/talos/pkg/machinery/config/machine" + "github.com/siderolabs/talos/pkg/machinery/constants" +) + +// Input holds info about certs, ips, and node type. +// +//nolint:maligned +type Input struct { + Options Options + + // ControlplaneEndpoint is the canonical address of the kubernetes control + // plane. It can be a DNS name, the IP address of a load balancer, or + // (default) the IP address of the first controlplane node. It is NOT + // multi-valued. It may optionally specify the port. + ControlPlaneEndpoint string + + AdditionalSubjectAltNames []string + AdditionalMachineCertSANs []string + + ClusterName string + PodNet []string + ServiceNet []string + KubernetesVersion string +} + +// GetAPIServerSANs returns the formatted list of Subject Alt Name addresses for the API Server. +func (in *Input) GetAPIServerSANs() []string { + list := []string{} + + endpointURL, err := url.Parse(in.ControlPlaneEndpoint) + if err == nil { + list = append(list, endpointURL.Hostname()) + } + + list = append(list, in.AdditionalSubjectAltNames...) + + return list +} + +// NewInput prepares a new Input struct to perform machine config generation. +func NewInput(clustername, endpoint, kubernetesVersion string, opts ...Option) (*Input, error) { + input := &Input{ + ClusterName: clustername, + ControlPlaneEndpoint: endpoint, + KubernetesVersion: kubernetesVersion, + } + input.Options = DefaultOptions() + + for _, opt := range opts { + if err := opt(&input.Options); err != nil { + return nil, err + } + } + + var podNet, serviceNet string + + if addr, addrErr := netip.ParseAddr(endpoint); addrErr == nil && addr.Is6() { + podNet = constants.DefaultIPv6PodNet + serviceNet = constants.DefaultIPv6ServiceNet + } else { + podNet = constants.DefaultIPv4PodNet + serviceNet = constants.DefaultIPv4ServiceNet + } + + if input.Options.SecretsBundle == nil { + var err error + + input.Options.SecretsBundle, err = secrets.NewBundle(secrets.NewFixedClock(time.Now()), input.Options.VersionContract) + if err != nil { + return nil, err + } + } + + additionalSubjectAltNames := slices.Clone(input.Options.AdditionalSubjectAltNames) + + if !input.Options.VersionContract.SupportsDynamicCertSANs() { + additionalSubjectAltNames = append(additionalSubjectAltNames, input.Options.EndpointList...) + } + + if input.Options.DiscoveryEnabled == nil { + input.Options.DiscoveryEnabled = pointer.To(input.Options.VersionContract.ClusterDiscoveryEnabled()) + } + + input.ClusterName = clustername + input.KubernetesVersion = kubernetesVersion + input.AdditionalMachineCertSANs = additionalSubjectAltNames + input.AdditionalSubjectAltNames = additionalSubjectAltNames + input.PodNet = []string{podNet} + input.ServiceNet = []string{serviceNet} + input.ControlPlaneEndpoint = endpoint + input.KubernetesVersion = kubernetesVersion + + return input, nil +} + +// Config returns the talos config for a given node type. +func (in *Input) Config(t machine.Type) (coreconfig.Provider, error) { + var ( + documents []config.Document + err error + ) + + switch t { + case machine.TypeInit: + documents, err = in.init() + case machine.TypeControlPlane: + documents, err = in.controlPlane() + case machine.TypeWorker: + documents, err = in.worker() + case machine.TypeUnknown: + fallthrough + default: + return nil, errors.New("failed to determine config type to generate") + } + + if err != nil { + return nil, err + } + + return container.New(documents...) +} + +// emptyIf returns empty string if the 2nd argument is empty string, otherwise returns the first argument. +func emptyIf(str, check string) string { + if check == "" { + return "" + } + + return str +} diff --git a/pkg/machinery/config/generate/generate_test.go b/pkg/machinery/config/generate/generate_test.go new file mode 100644 index 000000000..b8ed50b5d --- /dev/null +++ b/pkg/machinery/config/generate/generate_test.go @@ -0,0 +1,181 @@ +// 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 generate_test + +import ( + "crypto/x509" + "fmt" + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/siderolabs/talos/pkg/machinery/client" + "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/generate" + "github.com/siderolabs/talos/pkg/machinery/config/machine" + "github.com/siderolabs/talos/pkg/machinery/constants" + "github.com/siderolabs/talos/pkg/machinery/role" +) + +type GenerateSuite struct { + suite.Suite + + input *generate.Input + genOptions []generate.Option + + versionContract *config.VersionContract +} + +func TestGenerateSuite(t *testing.T) { + t.Parallel() + + for _, tt := range []struct { + label string + genOptions []generate.Option + }{ + { + label: "current", + }, + { + label: "1.5", + genOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion1_5)}, + }, + { + label: "1.4", + genOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion1_4)}, + }, + { + label: "1.3", + genOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion1_3)}, + }, + { + label: "1.2", + genOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion1_2)}, + }, + { + label: "1.1", + genOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion1_1)}, + }, + { + label: "1.0", + genOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion1_0)}, + }, + { + label: "0.14", + genOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion0_14)}, + }, + { + label: "0.13", + genOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion0_13)}, + }, + { + label: "0.12", + genOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion0_12)}, + }, + { + label: "0.11", + genOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion0_11)}, + }, + { + label: "0.10", + genOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion0_10)}, + }, + { + label: "0.9", + genOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion0_9)}, + }, + { + label: "0.8", + genOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion0_8)}, + }, + } { + tt := tt + + t.Run(tt.label, func(t *testing.T) { + t.Parallel() + + suite.Run(t, &GenerateSuite{ + genOptions: tt.genOptions, + }) + }) + } +} + +func (suite *GenerateSuite) SetupSuite() { + var err error + suite.input, err = generate.NewInput("test", "https://10.0.1.5", constants.DefaultKubernetesVersion, suite.genOptions...) + suite.Require().NoError(err) + + var opts generate.Options + + for _, opt := range suite.genOptions { + suite.Require().NoError(opt(&opts)) + } + + suite.versionContract = suite.input.Options.VersionContract +} + +func (suite *GenerateSuite) TestGenerateInitSuccess() { + cfg, err := suite.input.Config(machine.TypeInit) + suite.Require().NoError(err) + + if suite.versionContract.SupportsRBACFeature() { + suite.True(cfg.Machine().Features().RBACEnabled()) + } else { + suite.False(cfg.Machine().Features().RBACEnabled()) + } +} + +func (suite *GenerateSuite) TestGenerateControlPlaneSuccess() { + cfg, err := suite.input.Config(machine.TypeControlPlane) + suite.Require().NoError(err) + + _, err = cfg.Validate(runtimeMode{false}) + suite.Require().NoError(err) + + if suite.versionContract.SupportsRBACFeature() { + suite.True(cfg.Machine().Features().RBACEnabled()) + } else { + suite.False(cfg.Machine().Features().RBACEnabled()) + } +} + +func (suite *GenerateSuite) TestGenerateWorkerSuccess() { + cfg, err := suite.input.Config(machine.TypeWorker) + suite.Require().NoError(err) + + if suite.versionContract.SupportsRBACFeature() { + suite.True(cfg.Machine().Features().RBACEnabled()) + } else { + suite.False(cfg.Machine().Features().RBACEnabled()) + } +} + +func (suite *GenerateSuite) TestGenerateTalosconfigSuccess() { + cfg, err := suite.input.Talosconfig() + suite.Require().NoError(err) + + creds, err := client.CertificateFromConfigContext(cfg.Contexts[cfg.Context]) + suite.Require().NoError(err) + suite.Require().Nil(creds.Leaf) + suite.Require().Len(creds.Certificate, 1) + + cert, err := x509.ParseCertificate(creds.Certificate[0]) + suite.Require().NoError(err) + + suite.Equal([]string{string(role.Admin)}, cert.Subject.Organization) +} + +type runtimeMode struct { + requiresInstall bool +} + +func (m runtimeMode) String() string { + return fmt.Sprintf("runtimeMode(%v)", m.requiresInstall) +} + +func (m runtimeMode) RequiresInstall() bool { + return m.requiresInstall +} diff --git a/pkg/machinery/config/types/v1alpha1/generate/init.go b/pkg/machinery/config/generate/init.go similarity index 61% rename from pkg/machinery/config/types/v1alpha1/generate/init.go rename to pkg/machinery/config/generate/init.go index e16a21c24..22eef147b 100644 --- a/pkg/machinery/config/types/v1alpha1/generate/init.go +++ b/pkg/machinery/config/generate/init.go @@ -10,22 +10,23 @@ import ( "github.com/siderolabs/go-pointer" + "github.com/siderolabs/talos/pkg/machinery/config/config" + "github.com/siderolabs/talos/pkg/machinery/config/machine" v1alpha1 "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/constants" ) //nolint:gocyclo,cyclop -func initUd(in *Input) (*v1alpha1.Config, error) { - config := &v1alpha1.Config{ +func (in *Input) init() ([]config.Document, error) { + v1alpha1Config := &v1alpha1.Config{ ConfigVersion: "v1alpha1", - ConfigDebug: pointer.To(in.Debug), - ConfigPersist: pointer.To(in.Persist), + ConfigDebug: pointer.To(in.Options.Debug), + ConfigPersist: pointer.To(in.Options.Persist), } networkConfig := &v1alpha1.NetworkConfig{} - for _, opt := range in.NetworkConfigOptions { + for _, opt := range in.Options.NetworkConfigOptions { if err := opt(machine.TypeControlPlane, networkConfig); err != nil { return nil, err } @@ -37,47 +38,47 @@ func initUd(in *Input) (*v1alpha1.Config, error) { KubeletImage: emptyIf(fmt.Sprintf("%s:v%s", constants.KubeletImage, in.KubernetesVersion), in.KubernetesVersion), }, MachineNetwork: networkConfig, - MachineCA: in.Certs.OS, + MachineCA: in.Options.SecretsBundle.Certs.OS, MachineCertSANs: in.AdditionalMachineCertSANs, - MachineToken: in.TrustdInfo.Token, + MachineToken: in.Options.SecretsBundle.TrustdInfo.Token, MachineInstall: &v1alpha1.InstallConfig{ - InstallDisk: in.InstallDisk, - InstallImage: in.InstallImage, + InstallDisk: in.Options.InstallDisk, + InstallImage: in.Options.InstallImage, InstallBootloader: pointer.To(true), InstallWipe: pointer.To(false), - InstallExtraKernelArgs: in.InstallExtraKernelArgs, + InstallExtraKernelArgs: in.Options.InstallExtraKernelArgs, }, MachineRegistries: v1alpha1.RegistriesConfig{ - RegistryMirrors: in.RegistryMirrors, - RegistryConfig: in.RegistryConfig, + RegistryMirrors: in.Options.RegistryMirrors, + RegistryConfig: in.Options.RegistryConfig, }, - MachineDisks: in.MachineDisks, - MachineSystemDiskEncryption: in.SystemDiskEncryptionConfig, - MachineSysctls: in.Sysctls, + MachineDisks: in.Options.MachineDisks, + MachineSystemDiskEncryption: in.Options.SystemDiskEncryptionConfig, + MachineSysctls: in.Options.Sysctls, MachineFeatures: &v1alpha1.FeaturesConfig{}, } - if in.VersionContract.SupportsRBACFeature() { + if in.Options.VersionContract.SupportsRBACFeature() { machine.MachineFeatures.RBAC = pointer.To(true) } - if in.VersionContract.StableHostnameEnabled() { + if in.Options.VersionContract.StableHostnameEnabled() { machine.MachineFeatures.StableHostname = pointer.To(true) } - if in.VersionContract.ApidExtKeyUsageCheckEnabled() { + if in.Options.VersionContract.ApidExtKeyUsageCheckEnabled() { machine.MachineFeatures.ApidCheckExtKeyUsage = pointer.To(true) } - if in.VersionContract.DiskQuotaSupportEnabled() { + if in.Options.VersionContract.DiskQuotaSupportEnabled() { machine.MachineFeatures.DiskQuotaSupport = pointer.To(true) } - if in.VersionContract.KubeletDefaultRuntimeSeccompProfileEnabled() { + if in.Options.VersionContract.KubeletDefaultRuntimeSeccompProfileEnabled() { machine.MachineKubelet.KubeletDefaultRuntimeSeccompProfileEnabled = pointer.To(true) } - if in.VersionContract.KubeletManifestsDirectoryDisabled() { + if in.Options.VersionContract.KubeletManifestsDirectoryDisabled() { machine.MachineKubelet.KubeletDisableManifestsDirectory = pointer.To(true) } @@ -85,12 +86,12 @@ func initUd(in *Input) (*v1alpha1.Config, error) { controlPlaneURL, err := url.Parse(in.ControlPlaneEndpoint) if err != nil { - return config, err + return nil, err } var admissionControlConfig []*v1alpha1.AdmissionPluginConfig - if in.VersionContract.PodSecurityAdmissionEnabled() { + if in.Options.VersionContract.PodSecurityAdmissionEnabled() { admissionControlConfig = append(admissionControlConfig, &v1alpha1.AdmissionPluginConfig{ PluginName: "PodSecurity", @@ -119,17 +120,17 @@ func initUd(in *Input) (*v1alpha1.Config, error) { var auditPolicyConfig v1alpha1.Unstructured - if in.VersionContract.APIServerAuditPolicySupported() { + if in.Options.VersionContract.APIServerAuditPolicySupported() { auditPolicyConfig = v1alpha1.APIServerDefaultAuditPolicy } cluster := &v1alpha1.ClusterConfig{ - ClusterID: in.ClusterID, + ClusterID: in.Options.SecretsBundle.Cluster.ID, ClusterName: in.ClusterName, - ClusterSecret: in.ClusterSecret, + ClusterSecret: in.Options.SecretsBundle.Cluster.Secret, ControlPlane: &v1alpha1.ControlPlaneConfig{ Endpoint: &v1alpha1.Endpoint{URL: controlPlaneURL}, - LocalAPIServerPort: in.LocalAPIServerPort, + LocalAPIServerPort: in.Options.LocalAPIServerPort, }, APIServerConfig: &v1alpha1.APIServerConfig{ CertSANs: certSANs, @@ -147,56 +148,56 @@ func initUd(in *Input) (*v1alpha1.Config, error) { ContainerImage: emptyIf(fmt.Sprintf("%s:v%s", constants.KubernetesSchedulerImage, in.KubernetesVersion), in.KubernetesVersion), }, EtcdConfig: &v1alpha1.EtcdConfig{ - RootCA: in.Certs.Etcd, + RootCA: in.Options.SecretsBundle.Certs.Etcd, }, ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ - DNSDomain: in.ServiceDomain, + DNSDomain: in.Options.DNSDomain, PodSubnet: in.PodNet, ServiceSubnet: in.ServiceNet, - CNI: in.CNIConfig, + CNI: in.Options.CNIConfig, }, - ClusterCA: in.Certs.K8s, - ClusterAggregatorCA: in.Certs.K8sAggregator, - ClusterServiceAccount: in.Certs.K8sServiceAccount, - BootstrapToken: in.Secrets.BootstrapToken, + ClusterCA: in.Options.SecretsBundle.Certs.K8s, + ClusterAggregatorCA: in.Options.SecretsBundle.Certs.K8sAggregator, + ClusterServiceAccount: in.Options.SecretsBundle.Certs.K8sServiceAccount, + BootstrapToken: in.Options.SecretsBundle.Secrets.BootstrapToken, ExtraManifests: []string{}, ClusterInlineManifests: v1alpha1.ClusterInlineManifests{}, } - if in.AllowSchedulingOnControlPlanes { - if in.VersionContract.KubernetesAllowSchedulingOnControlPlanes() { - cluster.AllowSchedulingOnControlPlanes = pointer.To(in.AllowSchedulingOnControlPlanes) + if in.Options.AllowSchedulingOnControlPlanes { + if in.Options.VersionContract.KubernetesAllowSchedulingOnControlPlanes() { + cluster.AllowSchedulingOnControlPlanes = pointer.To(in.Options.AllowSchedulingOnControlPlanes) } else { // backwards compatibility for Talos versions older than 1.2 - cluster.AllowSchedulingOnMasters = pointer.To(in.AllowSchedulingOnControlPlanes) //nolint:staticcheck + cluster.AllowSchedulingOnMasters = pointer.To(in.Options.AllowSchedulingOnControlPlanes) //nolint:staticcheck } } - if in.DiscoveryEnabled { + if in.Options.DiscoveryEnabled != nil { cluster.ClusterDiscoveryConfig = &v1alpha1.ClusterDiscoveryConfig{ - DiscoveryEnabled: pointer.To(in.DiscoveryEnabled), + DiscoveryEnabled: pointer.To(*in.Options.DiscoveryEnabled), } - if in.VersionContract.KubernetesDiscoveryBackendDisabled() { + if in.Options.VersionContract.KubernetesDiscoveryBackendDisabled() { cluster.ClusterDiscoveryConfig.DiscoveryRegistries.RegistryKubernetes.RegistryDisabled = pointer.To(true) } } - if !in.VersionContract.PodSecurityPolicyEnabled() { + if !in.Options.VersionContract.PodSecurityPolicyEnabled() { cluster.APIServerConfig.DisablePodSecurityPolicyConfig = pointer.To(true) } - if in.VersionContract.SecretboxEncryptionSupported() { - cluster.ClusterSecretboxEncryptionSecret = in.Secrets.SecretboxEncryptionSecret + if in.Options.VersionContract.SecretboxEncryptionSupported() { + cluster.ClusterSecretboxEncryptionSecret = in.Options.SecretsBundle.Secrets.SecretboxEncryptionSecret } else { - cluster.ClusterAESCBCEncryptionSecret = in.Secrets.AESCBCEncryptionSecret + cluster.ClusterAESCBCEncryptionSecret = in.Options.SecretsBundle.Secrets.AESCBCEncryptionSecret } if machine.MachineRegistries.RegistryMirrors == nil { machine.MachineRegistries.RegistryMirrors = map[string]*v1alpha1.RegistryMirrorConfig{} } - if in.VersionContract.KubernetesAlternateImageRegistries() { + if in.Options.VersionContract.KubernetesAlternateImageRegistries() { if _, ok := machine.MachineRegistries.RegistryMirrors["k8s.gcr.io"]; !ok { machine.MachineRegistries.RegistryMirrors["k8s.gcr.io"] = &v1alpha1.RegistryMirrorConfig{ MirrorEndpoints: []string{ @@ -207,8 +208,8 @@ func initUd(in *Input) (*v1alpha1.Config, error) { } } - config.MachineConfig = machine - config.ClusterConfig = cluster + v1alpha1Config.MachineConfig = machine + v1alpha1Config.ClusterConfig = cluster - return config, nil + return []config.Document{v1alpha1Config}, nil } diff --git a/pkg/machinery/config/generate/options.go b/pkg/machinery/config/generate/options.go new file mode 100644 index 000000000..e1969c425 --- /dev/null +++ b/pkg/machinery/config/generate/options.go @@ -0,0 +1,301 @@ +// 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 generate + +import ( + "github.com/siderolabs/go-pointer" + + "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets" + v1alpha1 "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" + "github.com/siderolabs/talos/pkg/machinery/role" +) + +// Option controls generate options specific to input generation. +type Option func(o *Options) error + +// WithEndpointList specifies endpoints to use when accessing Talos cluster. +func WithEndpointList(endpoints []string) Option { + return func(o *Options) error { + o.EndpointList = endpoints + + return nil + } +} + +// WithLocalAPIServerPort specifies the local API server port for the cluster. +func WithLocalAPIServerPort(port int) Option { + return func(o *Options) error { + o.LocalAPIServerPort = port + + return nil + } +} + +// WithInstallDisk specifies install disk to use in Talos cluster. +func WithInstallDisk(disk string) Option { + return func(o *Options) error { + o.InstallDisk = disk + + return nil + } +} + +// WithAdditionalSubjectAltNames specifies additional SANs. +func WithAdditionalSubjectAltNames(sans []string) Option { + return func(o *Options) error { + o.AdditionalSubjectAltNames = sans + + return nil + } +} + +// WithInstallImage specifies install container image to use in Talos cluster. +func WithInstallImage(imageRef string) Option { + return func(o *Options) error { + o.InstallImage = imageRef + + return nil + } +} + +// WithInstallExtraKernelArgs specifies extra kernel arguments to pass to the installer. +func WithInstallExtraKernelArgs(args []string) Option { + return func(o *Options) error { + o.InstallExtraKernelArgs = append(o.InstallExtraKernelArgs, args...) + + return nil + } +} + +// WithNetworkOptions adds network config generation option. +func WithNetworkOptions(opts ...v1alpha1.NetworkConfigOption) Option { + return func(o *Options) error { + o.NetworkConfigOptions = append(o.NetworkConfigOptions, opts...) + + return nil + } +} + +// WithRegistryMirror configures registry mirror endpoint(s). +func WithRegistryMirror(host string, endpoints ...string) Option { + return func(o *Options) error { + if o.RegistryMirrors == nil { + o.RegistryMirrors = make(map[string]*v1alpha1.RegistryMirrorConfig) + } + + o.RegistryMirrors[host] = &v1alpha1.RegistryMirrorConfig{MirrorEndpoints: endpoints} + + return nil + } +} + +// WithRegistryCACert specifies the certificate of the certificate authority which signed certificate of the registry. +func WithRegistryCACert(host, cacert string) Option { + return func(o *Options) error { + if o.RegistryConfig == nil { + o.RegistryConfig = make(map[string]*v1alpha1.RegistryConfig) + } + + if _, ok := o.RegistryConfig[host]; !ok { + o.RegistryConfig[host] = &v1alpha1.RegistryConfig{} + } + + if o.RegistryConfig[host].RegistryTLS == nil { + o.RegistryConfig[host].RegistryTLS = &v1alpha1.RegistryTLSConfig{} + } + + o.RegistryConfig[host].RegistryTLS.TLSCA = v1alpha1.Base64Bytes(cacert) + + return nil + } +} + +// WithRegistryInsecureSkipVerify marks registry host to skip TLS verification. +func WithRegistryInsecureSkipVerify(host string) Option { + return func(o *Options) error { + if o.RegistryConfig == nil { + o.RegistryConfig = make(map[string]*v1alpha1.RegistryConfig) + } + + if _, ok := o.RegistryConfig[host]; !ok { + o.RegistryConfig[host] = &v1alpha1.RegistryConfig{} + } + + if o.RegistryConfig[host].RegistryTLS == nil { + o.RegistryConfig[host].RegistryTLS = &v1alpha1.RegistryTLSConfig{} + } + + o.RegistryConfig[host].RegistryTLS.TLSInsecureSkipVerify = pointer.To(true) + + return nil + } +} + +// WithDNSDomain specifies domain name to use in Talos cluster. +func WithDNSDomain(dnsDomain string) Option { + return func(o *Options) error { + o.DNSDomain = dnsDomain + + return nil + } +} + +// WithDebug enables verbose logging to console for all services. +func WithDebug(enable bool) Option { + return func(o *Options) error { + o.Debug = enable + + return nil + } +} + +// WithPersist enables persistence of machine config across reboots. +func WithPersist(enable bool) Option { + return func(o *Options) error { + o.Persist = enable + + return nil + } +} + +// WithClusterCNIConfig specifies custom cluster CNI config. +func WithClusterCNIConfig(config *v1alpha1.CNIConfig) Option { + return func(o *Options) error { + o.CNIConfig = config + + return nil + } +} + +// WithUserDisks generates user partitions config. +func WithUserDisks(disks []*v1alpha1.MachineDisk) Option { + return func(o *Options) error { + o.MachineDisks = disks + + return nil + } +} + +// WithAllowSchedulingOnControlPlanes specifies AllowSchedulingOnControlPlane flag. +func WithAllowSchedulingOnControlPlanes(enabled bool) Option { + return func(o *Options) error { + o.AllowSchedulingOnControlPlanes = enabled + + return nil + } +} + +// WithVersionContract specifies version contract to use when generating. +func WithVersionContract(versionContract *config.VersionContract) Option { + return func(o *Options) error { + o.VersionContract = versionContract + + return nil + } +} + +// WithSystemDiskEncryption specifies encryption settings for the system disk partitions. +func WithSystemDiskEncryption(cfg *v1alpha1.SystemDiskEncryptionConfig) Option { + return func(o *Options) error { + o.SystemDiskEncryptionConfig = cfg + + return nil + } +} + +// WithRoles specifies user roles. +func WithRoles(roles role.Set) Option { + return func(o *Options) error { + o.Roles = roles + + return nil + } +} + +// WithClusterDiscovery enables cluster discovery feature. +func WithClusterDiscovery(enabled bool) Option { + return func(o *Options) error { + o.DiscoveryEnabled = pointer.To(enabled) + + return nil + } +} + +// WithSysctls merges list of sysctls with new values. +func WithSysctls(params map[string]string) Option { + return func(o *Options) error { + if o.Sysctls == nil { + o.Sysctls = make(map[string]string) + } + + for k, v := range params { + o.Sysctls[k] = v + } + + return nil + } +} + +// WithSecretsBundle specifies custom secrets bundle. +func WithSecretsBundle(bundle *secrets.Bundle) Option { + return func(o *Options) error { + o.SecretsBundle = bundle + + return nil + } +} + +// Options describes generate parameters. +type Options struct { + VersionContract *config.VersionContract + + // Custom secrets bundle. + SecretsBundle *secrets.Bundle + + // Base settings. + Debug bool + Persist bool + + // Machine settings: install. + InstallDisk string + InstallImage string + InstallExtraKernelArgs []string + + // Machine disks. + MachineDisks []*v1alpha1.MachineDisk + SystemDiskEncryptionConfig *v1alpha1.SystemDiskEncryptionConfig + + // Machine network settings. + NetworkConfigOptions []v1alpha1.NetworkConfigOption + + // Machine sysctls. + Sysctls map[string]string + + // Machine registries. + RegistryMirrors map[string]*v1alpha1.RegistryMirrorConfig + RegistryConfig map[string]*v1alpha1.RegistryConfig + + // Cluster settings. + DNSDomain string + CNIConfig *v1alpha1.CNIConfig + AllowSchedulingOnControlPlanes bool + LocalAPIServerPort int + AdditionalSubjectAltNames []string + DiscoveryEnabled *bool + + // Client options. + Roles role.Set + EndpointList []string +} + +// DefaultOptions returns default options. +func DefaultOptions() Options { + return Options{ + DNSDomain: "cluster.local", + Persist: true, + Roles: role.MakeSet(role.Admin), + } +} diff --git a/pkg/machinery/config/generate/secrets/bundle.go b/pkg/machinery/config/generate/secrets/bundle.go new file mode 100644 index 000000000..42925ae6d --- /dev/null +++ b/pkg/machinery/config/generate/secrets/bundle.go @@ -0,0 +1,356 @@ +// 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 ( + "encoding/base64" + "fmt" + "os" + "path/filepath" + + "github.com/siderolabs/crypto/x509" + "gopkg.in/yaml.v3" + + "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/internal/cis" + "github.com/siderolabs/talos/pkg/machinery/constants" + "github.com/siderolabs/talos/pkg/machinery/role" +) + +// NewBundle creates secrets bundle generating all secrets. +func NewBundle(clock Clock, versionContract *config.VersionContract) (*Bundle, error) { + bundle := &Bundle{ + Clock: clock, + } + + err := bundle.populate(versionContract) + if err != nil { + return nil, err + } + + return bundle, nil +} + +// LoadBundle loads secrets bundle from the given file. +func LoadBundle(path string) (*Bundle, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + + defer f.Close() //nolint: errcheck + + bundle := &Bundle{ + Clock: NewClock(), + } + + decoder := yaml.NewDecoder(f) + if err = decoder.Decode(&bundle); err != nil { + return nil, err + } + + return bundle, nil +} + +// NewBundleFromKubernetesPKI creates secrets bundle by reading the contents +// of a Kubernetes PKI directory (typically `/etc/kubernetes/pki`) and using the provided bootstrapToken as input. +// +//nolint:gocyclo +func NewBundleFromKubernetesPKI(pkiDir, bootstrapToken string, versionContract *config.VersionContract) (*Bundle, error) { + dirStat, err := os.Stat(pkiDir) + if err != nil { + return nil, err + } + + if !dirStat.IsDir() { + return nil, fmt.Errorf("%q is not a directory", pkiDir) + } + + var ( + ca *x509.PEMEncodedCertificateAndKey + etcdCA *x509.PEMEncodedCertificateAndKey + aggregatorCA *x509.PEMEncodedCertificateAndKey + sa *x509.PEMEncodedKey + ) + + ca, err = x509.NewCertificateAndKeyFromFiles(filepath.Join(pkiDir, "ca.crt"), filepath.Join(pkiDir, "ca.key")) + if err != nil { + return nil, err + } + + err = validatePEMEncodedCertificateAndKey(ca) + if err != nil { + return nil, err + } + + etcdDir := filepath.Join(pkiDir, "etcd") + + etcdCA, err = x509.NewCertificateAndKeyFromFiles(filepath.Join(etcdDir, "ca.crt"), filepath.Join(etcdDir, "ca.key")) + if err != nil { + return nil, err + } + + err = validatePEMEncodedCertificateAndKey(etcdCA) + if err != nil { + return nil, err + } + + aggregatorCACrtPath := filepath.Join(pkiDir, "front-proxy-ca.crt") + _, err = os.Stat(aggregatorCACrtPath) + + aggregatorCAFound := err == nil + if aggregatorCAFound && !versionContract.SupportsAggregatorCA() { + return nil, fmt.Errorf("aggregator CA found in pki dir but is not supported by the requested version") + } + + if versionContract.SupportsAggregatorCA() { + aggregatorCA, err = x509.NewCertificateAndKeyFromFiles(aggregatorCACrtPath, filepath.Join(pkiDir, "front-proxy-ca.key")) + if err != nil { + return nil, err + } + + err = validatePEMEncodedCertificateAndKey(aggregatorCA) + if err != nil { + return nil, err + } + } + + saKeyPath := filepath.Join(pkiDir, "sa.key") + _, err = os.Stat(saKeyPath) + + saKeyFound := err == nil + if saKeyFound && !versionContract.SupportsServiceAccount() { + return nil, fmt.Errorf("service account key found in pki dir but is not supported by the requested version") + } + + if versionContract.SupportsServiceAccount() { + var saBytes []byte + + saBytes, err = os.ReadFile(filepath.Join(pkiDir, "sa.key")) + if err != nil { + return nil, err + } + + sa = &x509.PEMEncodedKey{ + Key: saBytes, + } + + _, err = sa.GetKey() + if err != nil { + return nil, err + } + } + + bundle := &Bundle{ + Secrets: &Secrets{ + BootstrapToken: bootstrapToken, + }, + Certs: &Certs{ + Etcd: etcdCA, + K8s: ca, + K8sAggregator: aggregatorCA, + K8sServiceAccount: sa, + }, + } + + err = bundle.populate(versionContract) + if err != nil { + return nil, err + } + + return bundle, nil +} + +// NewBundleFromConfig creates secrets bundle using existing config. +func NewBundleFromConfig(clock Clock, c config.Config) *Bundle { + certs := &Certs{ + K8s: c.Cluster().CA(), + K8sAggregator: c.Cluster().AggregatorCA(), + K8sServiceAccount: c.Cluster().ServiceAccount(), + Etcd: c.Cluster().Etcd().CA(), + OS: c.Machine().Security().CA(), + } + + cluster := &Cluster{ + ID: c.Cluster().ID(), + Secret: c.Cluster().Secret(), + } + + trustd := &TrustdInfo{ + Token: c.Machine().Security().Token(), + } + + bootstrapToken := fmt.Sprintf( + "%s.%s", + c.Cluster().Token().ID(), + c.Cluster().Token().Secret(), + ) + + secrets := &Secrets{ + AESCBCEncryptionSecret: c.Cluster().AESCBCEncryptionSecret(), + SecretboxEncryptionSecret: c.Cluster().SecretboxEncryptionSecret(), + BootstrapToken: bootstrapToken, + } + + return &Bundle{ + Clock: clock, + Cluster: cluster, + Secrets: secrets, + TrustdInfo: trustd, + Certs: certs, + } +} + +// populate fills all the missing fields in the secrets bundle. +// +//nolint:gocyclo,cyclop +func (bundle *Bundle) populate(versionContract *config.VersionContract) error { + if bundle.Clock == nil { + bundle.Clock = NewClock() + } + + if bundle.Certs == nil { + bundle.Certs = &Certs{} + } + + if bundle.Certs.Etcd == nil { + etcd, err := NewEtcdCA(bundle.Clock.Now(), versionContract) + if err != nil { + return err + } + + bundle.Certs.Etcd = &x509.PEMEncodedCertificateAndKey{ + Crt: etcd.CrtPEM, + Key: etcd.KeyPEM, + } + } + + if bundle.Certs.K8s == nil { + kubernetesCA, err := NewKubernetesCA(bundle.Clock.Now(), versionContract) + if err != nil { + return err + } + + bundle.Certs.K8s = &x509.PEMEncodedCertificateAndKey{ + Crt: kubernetesCA.CrtPEM, + Key: kubernetesCA.KeyPEM, + } + } + + if versionContract.SupportsAggregatorCA() && bundle.Certs.K8sAggregator == nil { + aggregatorCA, err := NewAggregatorCA(bundle.Clock.Now(), versionContract) + if err != nil { + return err + } + + bundle.Certs.K8sAggregator = &x509.PEMEncodedCertificateAndKey{ + Crt: aggregatorCA.CrtPEM, + Key: aggregatorCA.KeyPEM, + } + } + + if versionContract.SupportsServiceAccount() && bundle.Certs.K8sServiceAccount == nil { + serviceAccount, err := x509.NewECDSAKey() + if err != nil { + return err + } + + bundle.Certs.K8sServiceAccount = &x509.PEMEncodedKey{ + Key: serviceAccount.KeyPEM, + } + } + + if bundle.Certs.OS == nil { + talosCA, err := NewTalosCA(bundle.Clock.Now()) + if err != nil { + return err + } + + bundle.Certs.OS = &x509.PEMEncodedCertificateAndKey{ + Crt: talosCA.CrtPEM, + Key: talosCA.KeyPEM, + } + } + + if bundle.Secrets == nil { + bundle.Secrets = &Secrets{} + } + + if bundle.Secrets.BootstrapToken == "" { + token, err := genToken(6, 16) + if err != nil { + return err + } + + bundle.Secrets.BootstrapToken = token + } + + if versionContract.Greater(config.TalosVersion1_2) { + if bundle.Secrets.SecretboxEncryptionSecret == "" { + secretboxEncryptionSecret, err := cis.CreateEncryptionToken() + if err != nil { + return err + } + + bundle.Secrets.SecretboxEncryptionSecret = secretboxEncryptionSecret + } + } else { + if bundle.Secrets.AESCBCEncryptionSecret == "" { + aesCBCEncryptionSecret, err := cis.CreateEncryptionToken() + if err != nil { + return err + } + + bundle.Secrets.AESCBCEncryptionSecret = aesCBCEncryptionSecret + } + } + + if bundle.TrustdInfo == nil { + bundle.TrustdInfo = &TrustdInfo{} + } + + if bundle.TrustdInfo.Token == "" { + token, err := genToken(6, 16) + if err != nil { + return err + } + + bundle.TrustdInfo.Token = token + } + + if bundle.Cluster == nil { + bundle.Cluster = &Cluster{} + } + + if bundle.Cluster.ID == "" { + clusterID, err := randBytes(constants.DefaultClusterIDSize) + if err != nil { + return fmt.Errorf("failed to generate cluster ID: %w", err) + } + + bundle.Cluster.ID = base64.URLEncoding.EncodeToString(clusterID) + } + + if bundle.Cluster.Secret == "" { + clusterSecret, err := randBytes(constants.DefaultClusterSecretSize) + if err != nil { + return fmt.Errorf("failed to generate cluster secret: %w", err) + } + + bundle.Cluster.Secret = base64.StdEncoding.EncodeToString(clusterSecret) + } + + return nil +} + +// GenerateTalosAPIClientCertificate generates the admin certificate. +func (bundle *Bundle) GenerateTalosAPIClientCertificate(roles role.Set) (*x509.PEMEncodedCertificateAndKey, error) { + return NewAdminCertificateAndKey( + bundle.Clock.Now(), + bundle.Certs.OS, + roles, + CAValidityTime, + ) +} diff --git a/pkg/machinery/config/generate/secrets/ca.go b/pkg/machinery/config/generate/secrets/ca.go new file mode 100644 index 000000000..a9cd0591e --- /dev/null +++ b/pkg/machinery/config/generate/secrets/ca.go @@ -0,0 +1,113 @@ +// 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 ( + stdx509 "crypto/x509" + "time" + + "github.com/siderolabs/crypto/x509" + + "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/role" +) + +// NewEtcdCA generates a CA for the Etcd PKI. +// +//nolint:dupl +func NewEtcdCA(currentTime time.Time, contract *config.VersionContract) (ca *x509.CertificateAuthority, err error) { + opts := []x509.Option{ + x509.Organization("etcd"), + x509.NotAfter(currentTime.Add(CAValidityTime)), + x509.NotBefore(currentTime), + } + + if !contract.SupportsECDSAKeys() { + opts = append(opts, x509.RSA(true)) + } else { + if contract.SupportsECDSASHA256() { + opts = append(opts, x509.ECDSA(true)) + } else { + opts = append(opts, x509.ECDSASHA512(true)) + } + } + + return x509.NewSelfSignedCertificateAuthority(opts...) +} + +// NewKubernetesCA generates a CA for the Kubernetes PKI. +// +//nolint:dupl +func NewKubernetesCA(currentTime time.Time, contract *config.VersionContract) (ca *x509.CertificateAuthority, err error) { + opts := []x509.Option{ + x509.Organization("kubernetes"), + x509.NotAfter(currentTime.Add(CAValidityTime)), + x509.NotBefore(currentTime), + } + + if !contract.SupportsECDSAKeys() { + opts = append(opts, x509.RSA(true)) + } else { + if contract.SupportsECDSASHA256() { + opts = append(opts, x509.ECDSA(true)) + } else { + opts = append(opts, x509.ECDSASHA512(true)) + } + } + + return x509.NewSelfSignedCertificateAuthority(opts...) +} + +// NewAggregatorCA generates a CA for the Kubernetes aggregator/front-proxy. +func NewAggregatorCA(currentTime time.Time, contract *config.VersionContract) (ca *x509.CertificateAuthority, err error) { + opts := []x509.Option{ + x509.ECDSA(true), + x509.CommonName("front-proxy"), + x509.NotAfter(currentTime.Add(CAValidityTime)), + x509.NotBefore(currentTime), + } + + if contract.SupportsECDSASHA256() { + opts = append(opts, x509.ECDSA(true)) + } else { + opts = append(opts, x509.ECDSASHA512(true)) + } + + return x509.NewSelfSignedCertificateAuthority(opts...) +} + +// NewTalosCA generates a CA for the Talos PKI. +func NewTalosCA(currentTime time.Time) (ca *x509.CertificateAuthority, err error) { + opts := []x509.Option{ + x509.Organization("talos"), + x509.NotAfter(currentTime.Add(CAValidityTime)), + x509.NotBefore(currentTime), + } + + return x509.NewSelfSignedCertificateAuthority(opts...) +} + +// NewAdminCertificateAndKey generates the admin Talos certificate and key. +func NewAdminCertificateAndKey(currentTime time.Time, ca *x509.PEMEncodedCertificateAndKey, roles role.Set, ttl time.Duration) (p *x509.PEMEncodedCertificateAndKey, err error) { + opts := []x509.Option{ + x509.Organization(roles.Strings()...), + x509.NotAfter(currentTime.Add(ttl)), + x509.NotBefore(currentTime), + x509.KeyUsage(stdx509.KeyUsageDigitalSignature), + x509.ExtKeyUsage([]stdx509.ExtKeyUsage{stdx509.ExtKeyUsageClientAuth}), + } + + talosCA, err := x509.NewCertificateAuthorityFromCertificateAndKey(ca) + if err != nil { + return nil, err + } + + keyPair, err := x509.NewKeyPair(talosCA, opts...) + if err != nil { + return nil, err + } + + return x509.NewCertificateAndKeyFromKeyPair(keyPair), nil +} diff --git a/pkg/machinery/config/generate/secrets/clock.go b/pkg/machinery/config/generate/secrets/clock.go new file mode 100644 index 000000000..f3716d6a1 --- /dev/null +++ b/pkg/machinery/config/generate/secrets/clock.go @@ -0,0 +1,45 @@ +// 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 "time" + +// Clock system clock. +type Clock interface { + Now() time.Time +} + +// SystemClock is a real system clock, but the time returned can be made fixed. +type SystemClock struct { + fixedTime time.Time +} + +// NewClock creates new SystemClock. +func NewClock() *SystemClock { + return &SystemClock{} +} + +// NewFixedClock creates new SystemClock with fixed time. +func NewFixedClock(t time.Time) *SystemClock { + return &SystemClock{ + fixedTime: t, + } +} + +// Now implements Clock. +func (c *SystemClock) Now() time.Time { + if c.fixedTime.IsZero() { + return time.Now() + } + + return c.fixedTime +} + +// SetFixedTimestamp freezes the clock by setting a timestamp. +// +// Deprecated: use NewFixedClock instead. +func (c *SystemClock) SetFixedTimestamp(t time.Time) { + c.fixedTime = t +} diff --git a/pkg/machinery/config/generate/secrets/generate_test.go b/pkg/machinery/config/generate/secrets/generate_test.go new file mode 100644 index 000000000..44be802dc --- /dev/null +++ b/pkg/machinery/config/generate/secrets/generate_test.go @@ -0,0 +1,75 @@ +// 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" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/generate" + "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets" + "github.com/siderolabs/talos/pkg/machinery/config/machine" + "github.com/siderolabs/talos/pkg/machinery/constants" +) + +func TestNewBundle(t *testing.T) { + t.Parallel() + + for _, test := range []struct { + name string + versionContract *config.VersionContract + }{ + { + name: "v0.8", + versionContract: config.TalosVersion0_8, + }, + { + name: "v0.9", + versionContract: config.TalosVersion0_9, + }, + { + name: "v1.0", + versionContract: config.TalosVersion1_0, + }, + { + name: "v1.3", + versionContract: config.TalosVersion1_3, + }, + { + name: "current", + versionContract: config.TalosVersionCurrent, + }, + } { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + _, err := secrets.NewBundle(secrets.NewFixedClock(time.Now()), test.versionContract) + require.NoError(t, err) + }) + } +} + +func TestNewBundleFromConfig(t *testing.T) { + t.Parallel() + + bundle, err := secrets.NewBundle(secrets.NewFixedClock(time.Now()), config.TalosVersionCurrent) + require.NoError(t, err) + + input, err := generate.NewInput("test", "https://localhost:6443", constants.DefaultKubernetesVersion, generate.WithSecretsBundle(bundle)) + require.NoError(t, err) + + cfg, err := input.Config(machine.TypeControlPlane) + require.NoError(t, err) + + bundle2 := secrets.NewBundleFromConfig(bundle.Clock, cfg) + + assert.Equal(t, bundle, bundle2) +} diff --git a/pkg/machinery/config/generate/secrets/marshal_test.go b/pkg/machinery/config/generate/secrets/marshal_test.go new file mode 100644 index 000000000..dac8535a9 --- /dev/null +++ b/pkg/machinery/config/generate/secrets/marshal_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 ( + "os" + "path/filepath" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" + + "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets" +) + +func TestMarshalUnmarshal(t *testing.T) { + t.Parallel() + + bundle, err := secrets.NewBundle(secrets.NewFixedClock(time.Now()), config.TalosVersionCurrent) + require.NoError(t, err) + + dir := t.TempDir() + path := filepath.Join(dir, "secrets.yaml") + + f, err := os.Create(path) + require.NoError(t, err) + + require.NoError(t, yaml.NewEncoder(f).Encode(bundle)) + + require.NoError(t, f.Close()) + + bundle2, err := secrets.LoadBundle(path) + require.NoError(t, err) + + bundle2.Clock = bundle.Clock + + assert.Equal(t, bundle, bundle2) +} + +func TestUnmarshalStable(t *testing.T) { + t.Parallel() + + bundle, err := secrets.LoadBundle("testdata/secrets.yaml") + require.NoError(t, err) + + assert.NotNil(t, bundle.Certs) + assert.NotNil(t, bundle.Certs.Etcd) + assert.NotNil(t, bundle.Certs.K8s) + assert.NotNil(t, bundle.Certs.K8sAggregator) + assert.NotNil(t, bundle.Certs.K8sServiceAccount) + + assert.NotNil(t, bundle.Cluster) + assert.NotEmpty(t, bundle.Cluster.ID) + assert.NotEmpty(t, bundle.Cluster.Secret) + + assert.NotNil(t, bundle.Secrets) + assert.NotEmpty(t, bundle.Secrets.BootstrapToken) + assert.NotEmpty(t, bundle.Secrets.SecretboxEncryptionSecret) + + assert.NotNil(t, bundle.TrustdInfo) + assert.NotEmpty(t, bundle.TrustdInfo.Token) +} diff --git a/pkg/machinery/config/generate/secrets/secrets.go b/pkg/machinery/config/generate/secrets/secrets.go new file mode 100644 index 000000000..08ab0414d --- /dev/null +++ b/pkg/machinery/config/generate/secrets/secrets.go @@ -0,0 +1,63 @@ +// 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 provides types and methods to handle base machine configuration secrets. +package secrets + +import ( + "time" + + "github.com/siderolabs/crypto/x509" +) + +// CAValidityTime is the default validity time for CA certificates. +const CAValidityTime = 87600 * time.Hour + +// Bundle contains all cluster secrets required to generate machine configuration. +// +// NB: this structure is marhsalled/unmarshalled to/from JSON in various projects, so +// we need to keep representation compatible. +type Bundle struct { + Clock Clock `yaml:"-" json:"-"` + Cluster *Cluster `json:"Cluster"` + Secrets *Secrets `json:"Secrets"` + TrustdInfo *TrustdInfo `json:"TrustdInfo"` + Certs *Certs `json:"Certs"` +} + +// Certs holds the base64 encoded keys and certificates. +type Certs struct { + // Admin is Talos admin talosconfig client certificate and key. + // + // Deprecated: should not be used anymore. + Admin *x509.PEMEncodedCertificateAndKey `json:"Admin,omitempty" yaml:",omitempty"` + // Etcd is etcd CA certificate and key. + Etcd *x509.PEMEncodedCertificateAndKey `json:"Etcd"` + // K8s is Kubernetes CA certificate and key. + K8s *x509.PEMEncodedCertificateAndKey `json:"K8s"` + // K8sAggregator is Kubernetes aggregator CA certificate and key. + K8sAggregator *x509.PEMEncodedCertificateAndKey `json:"K8sAggregator"` + // K8sServiceAccount is Kubernetes service account key. + K8sServiceAccount *x509.PEMEncodedKey `json:"K8sServiceAccount"` + // OS is Talos API CA certificate and key. + OS *x509.PEMEncodedCertificateAndKey `json:"OS"` +} + +// Cluster holds Talos cluster-wide secrets. +type Cluster struct { + ID string `json:"Id"` + Secret string `json:"Secret"` +} + +// Secrets holds the sensitive kubeadm data. +type Secrets struct { + BootstrapToken string `json:"BootstrapToken"` + AESCBCEncryptionSecret string `json:"AESCBCEncryptionSecret,omitempty" yaml:",omitempty"` + SecretboxEncryptionSecret string `json:"SecretboxEncryptionSecret,omitempty" yaml:",omitempty"` +} + +// TrustdInfo holds the trustd credentials. +type TrustdInfo struct { + Token string `json:"Token"` +} diff --git a/pkg/machinery/config/generate/secrets/testdata/secrets.yaml b/pkg/machinery/config/generate/secrets/testdata/secrets.yaml new file mode 100644 index 000000000..12511480f --- /dev/null +++ b/pkg/machinery/config/generate/secrets/testdata/secrets.yaml @@ -0,0 +1,23 @@ +cluster: + id: cgvhCbucls-WqkESDTRqykFgb4hROI4cBpgB0YJLLtM= + secret: Wiu0qx68V3MKhFDr8+OFwGCNOOPBiQCDsLpRa3MdxEQ= +secrets: + bootstraptoken: 2psnp2.lry8e9gycdix3bpa + secretboxencryptionsecret: 6zWBpno849HlD5jeuTmGToFYP+z8lgkJa0fhHobv7mE= +trustdinfo: + token: oamejv.9tk1nhuwnlc2nghf +certs: + etcd: + crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmRENDQVNPZ0F3SUJBZ0lRQ0tGUmRhOVIvY3dIQXo4U1ZHU3I5ekFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TURVeU5URXlNVFEwTWxvWERUTXpNRFV5TWpFeU1UUTBNbG93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkdjUEQ5S2xIa09WCkJhcTFKSXhPaE56UXpHNDgvUG1hRmNTaExZckR1WkZ2MkY3NWd2bmkrbDU5RENTR3h4S3VncnJiZlQzempjSUoKdWRQblN6VEI2eVdqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVb2ZLdXhqa0pyL3hSCkRwQmNKYmlaR3dTRVhKSXdDZ1lJS29aSXpqMEVBd0lEUndBd1JBSWdHZ2VzU2NmOUh0ZHRGdEVGVEJlK2pkRFgKTDZUT3UwazRaQ3lmelNtY0JGMENJSDFNeDRTUmx0TGRHaE43aitZNU00aTJzT2liZHBCN0xFOCtQRW9RM081eQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVLb0RIa3I4bnFHQmVsWkRYWkpoVVdySkUrNEx2L0ViZEFrbjZ3TnJ1QkNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFWnc4UDBxVWVRNVVGcXJVa2pFNkUzTkRNYmp6OCtab1Z4S0V0aXNPNWtXL1lYdm1DK2VMNgpYbjBNSkliSEVxNkN1dHQ5UGZPTndnbTUwK2RMTk1IckpRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= + k8s: + crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRTkEvQ2JmWWRJaE5wRXVaQlgwWEFWVEFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNRFV5TlRFeU1UUTBNbG9YRFRNek1EVXlNakV5TVRRMApNbG93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCRUJHWDRoamtDbE5sSnBWNFJUZEVjSjJUcFVOTGlON2pQYnFzQkxIWFM2QWJBQWVDY2l0cHFLaWlUenQKaWdaTE5tdWlvL3ZOL1MxUkxaTTQ1TzFIVVBxallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVVIS2NNVExRMWlCQloxL2Qvd0JBNjRsL0UrdW93Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnSFgwZXBmd3gKaUxDSGxUeks5Y0pjSjgzOGlOU3VPSmFoZllNcFJXMU5nUkVDSVFDOG5EUm9IUFRKNVpNN3lPRWNycURoR3FVVAp3YWVoMXRFTS83aDYyNWxGaHc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUhteWM0SzhmN0doWlQwdkVOcUNPbDE0L3FPM0g1LytiaUM2ZU1aL3JkYzNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUUVaZmlHT1FLVTJVbWxYaEZOMFJ3blpPbFEwdUkzdU05dXF3RXNkZExvQnNBQjRKeUsybQpvcUtKUE8yS0JrczJhNktqKzgzOUxWRXRremprN1VkUStnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= + k8saggregator: + crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZRENDQVFXZ0F3SUJBZ0lRRnMwdklHTVN6MXA1TnFkdnpOY3k2VEFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1EVXlOVEV5TVRRME1sb1hEVE16TURVeU1qRXlNVFEwTWxvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCSnhZUXlKWUR1dkwvcEYwT1phbHRYc2NoQk9Oc3F3SmJUTW1HN2FMZ1NjNjZKU05yT3dmCkZrSCtSdmdiNFhoOUJiTHpsMEhaWDNTVFAzYStkancvYUJpallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV5cFJHdXVtK0lPM3pCbHJITk5KT2x2ZlhiTnd3Q2dZSUtvWkl6ajBFQXdJRFNRQXdSZ0loCkFKUWVERjhydk8yS2J4QWRlUHF0NmxoOTdDNjlDdzcvUitkY0hUZ1ZtWUFMQWlFQXJ0Yjg0TkxGejlXSzdqa3IKQ2FzR3lrSEdPUHY1THFhUFhXVUJCY3Z4MTc0PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUZxQnZKQytUVWtRUTZxTTJYRU9leFE5Nklsc1VkU0NBaC9MZmJndWhzUnJvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFbkZoRElsZ082OHYra1hRNWxxVzFleHlFRTQyeXJBbHRNeVlidG91Qkp6cm9sSTJzN0I4VwpRZjVHK0J2aGVIMEZzdk9YUWRsZmRKTS9kcjUyUEQ5b0dBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= + k8sserviceaccount: + key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUY3b0ZsaXYrTVZ3Zzc4dUVla3JaMktsVS82ZVJ6RUw2OGUzTWNkWk82STZvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFbHROcm00eDNpQy9vMmVGTDZyWVJjcTVtbExjTHhFVW5NQVJkVnpXeFVpbUpwZHVYeGhuSQpXSXloeTAzenUyRC9qSWlOeVlFR3llMjFUSTFVRFpwNUdRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= + os: + crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBaHQrSExpc1Flc2wyQVZRdDByVUpxakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qTXdOVEkxTVRJeE5EUXlXaGNOTXpNd05USXlNVEl4TkRReVdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUdFT3RQV3YvZlc5WVkyV21LVmJqcENKaStkbXhlWlBqUXpICjZvdHp0MWRYbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkxxU3UrREt1V1Jkbyt6NApMSDBjdG9mZUg4OUFNQVVHQXl0bGNBTkJBRnFabUp3ajZ6bTYrZm1SWldsaTBqQldVMElvckhxZGkrYXZzU3lxCkRPQlRPbVplYkFLQ2NqTEVMNGxoQWNhNk81ZVc1U0xVVVJxVUliUktwKzRjZ0FzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJT0VTT0dBNjE1RktsTEJDWlVsZlhyVUFmQ3NZTFY1dE0wN0pvbjU0d1RDSwotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K diff --git a/pkg/machinery/config/generate/secrets/utils.go b/pkg/machinery/config/generate/secrets/utils.go new file mode 100644 index 000000000..f5cff3116 --- /dev/null +++ b/pkg/machinery/config/generate/secrets/utils.go @@ -0,0 +1,96 @@ +// 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 ( + "bufio" + "crypto/rand" + "fmt" + "io" + + "github.com/siderolabs/crypto/x509" +) + +func randBytes(size int) ([]byte, error) { + buf := make([]byte, size) + + n, err := io.ReadFull(rand.Reader, buf) + if err != nil { + return nil, fmt.Errorf("failed to read from random generator: %w", err) + } + + if n != size { + return nil, fmt.Errorf("failed to generate sufficient number of random bytes (%d != %d)", n, size) + } + + return buf, nil +} + +func validatePEMEncodedCertificateAndKey(certs *x509.PEMEncodedCertificateAndKey) error { + _, err := certs.GetKey() + if err != nil { + return err + } + + _, err = certs.GetCert() + + return err +} + +// randBootstrapTokenString returns a random string consisting of the characters in +// validBootstrapTokenChars, with the length customized by the parameter. +func randBootstrapTokenString(length int) (string, error) { + // validBootstrapTokenChars defines the characters a bootstrap token can consist of + const validBootstrapTokenChars = "0123456789abcdefghijklmnopqrstuvwxyz" + + // len("0123456789abcdefghijklmnopqrstuvwxyz") = 36 which doesn't evenly divide + // the possible values of a byte: 256 mod 36 = 4. Discard any random bytes we + // read that are >= 252 so the bytes we evenly divide the character set. + const maxByteValue = 252 + + var ( + b byte + err error + token = make([]byte, length) + ) + + reader := bufio.NewReaderSize(rand.Reader, length*2) + + for i := range token { + for { + if b, err = reader.ReadByte(); err != nil { + return "", err + } + + if b < maxByteValue { + break + } + } + + token[i] = validBootstrapTokenChars[int(b)%len(validBootstrapTokenChars)] + } + + return string(token), err +} + +// genToken will generate a token of the format abc.123 (like kubeadm/trustd), where the length of the first string (before the dot) +// and length of the second string (after dot) are specified as inputs. +func genToken(lenFirst, lenSecond int) (string, error) { + var err error + + tokenTemp := make([]string, 2) + + tokenTemp[0], err = randBootstrapTokenString(lenFirst) + if err != nil { + return "", err + } + + tokenTemp[1], err = randBootstrapTokenString(lenSecond) + if err != nil { + return "", err + } + + return tokenTemp[0] + "." + tokenTemp[1], nil +} diff --git a/pkg/machinery/config/generate/talosconfig.go b/pkg/machinery/config/generate/talosconfig.go new file mode 100644 index 000000000..9e20c9abe --- /dev/null +++ b/pkg/machinery/config/generate/talosconfig.go @@ -0,0 +1,19 @@ +// 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 generate + +import ( + clientconfig "github.com/siderolabs/talos/pkg/machinery/client/config" +) + +// Talosconfig returns the talos admin Talos config. +func (in *Input) Talosconfig() (*clientconfig.Config, error) { + clientcert, err := in.Options.SecretsBundle.GenerateTalosAPIClientCertificate(in.Options.Roles) + if err != nil { + return nil, err + } + + return clientconfig.NewConfig(in.ClusterName, in.Options.EndpointList, in.Options.SecretsBundle.Certs.OS.Crt, clientcert), nil +} diff --git a/pkg/machinery/config/types/v1alpha1/generate/worker.go b/pkg/machinery/config/generate/worker.go similarity index 55% rename from pkg/machinery/config/types/v1alpha1/generate/worker.go rename to pkg/machinery/config/generate/worker.go index 64e0ef534..8fe45c816 100644 --- a/pkg/machinery/config/types/v1alpha1/generate/worker.go +++ b/pkg/machinery/config/generate/worker.go @@ -11,22 +11,23 @@ import ( "github.com/siderolabs/crypto/x509" "github.com/siderolabs/go-pointer" + "github.com/siderolabs/talos/pkg/machinery/config/config" + "github.com/siderolabs/talos/pkg/machinery/config/machine" v1alpha1 "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/constants" ) //nolint:gocyclo -func workerUd(in *Input) (*v1alpha1.Config, error) { - config := &v1alpha1.Config{ +func (in *Input) worker() ([]config.Document, error) { + v1alpha1Config := &v1alpha1.Config{ ConfigVersion: "v1alpha1", - ConfigDebug: pointer.To(in.Debug), - ConfigPersist: pointer.To(in.Persist), + ConfigDebug: pointer.To(in.Options.Debug), + ConfigPersist: pointer.To(in.Options.Persist), } networkConfig := &v1alpha1.NetworkConfig{} - for _, opt := range in.NetworkConfigOptions { + for _, opt := range in.Options.NetworkConfigOptions { if err := opt(machine.TypeWorker, networkConfig); err != nil { return nil, err } @@ -34,81 +35,81 @@ func workerUd(in *Input) (*v1alpha1.Config, error) { machine := &v1alpha1.MachineConfig{ MachineType: machine.TypeWorker.String(), - MachineToken: in.TrustdInfo.Token, + MachineToken: in.Options.SecretsBundle.TrustdInfo.Token, MachineCertSANs: in.AdditionalMachineCertSANs, MachineKubelet: &v1alpha1.KubeletConfig{ KubeletImage: emptyIf(fmt.Sprintf("%s:v%s", constants.KubeletImage, in.KubernetesVersion), in.KubernetesVersion), }, MachineNetwork: networkConfig, - MachineCA: &x509.PEMEncodedCertificateAndKey{Crt: in.Certs.OS.Crt}, + MachineCA: &x509.PEMEncodedCertificateAndKey{Crt: in.Options.SecretsBundle.Certs.OS.Crt}, MachineInstall: &v1alpha1.InstallConfig{ - InstallDisk: in.InstallDisk, - InstallImage: in.InstallImage, + InstallDisk: in.Options.InstallDisk, + InstallImage: in.Options.InstallImage, InstallBootloader: pointer.To(true), InstallWipe: pointer.To(false), - InstallExtraKernelArgs: in.InstallExtraKernelArgs, + InstallExtraKernelArgs: in.Options.InstallExtraKernelArgs, }, MachineRegistries: v1alpha1.RegistriesConfig{ - RegistryMirrors: in.RegistryMirrors, - RegistryConfig: in.RegistryConfig, + RegistryMirrors: in.Options.RegistryMirrors, + RegistryConfig: in.Options.RegistryConfig, }, - MachineDisks: in.MachineDisks, - MachineSystemDiskEncryption: in.SystemDiskEncryptionConfig, - MachineSysctls: in.Sysctls, + MachineDisks: in.Options.MachineDisks, + MachineSystemDiskEncryption: in.Options.SystemDiskEncryptionConfig, + MachineSysctls: in.Options.Sysctls, MachineFeatures: &v1alpha1.FeaturesConfig{}, } - if in.VersionContract.SupportsRBACFeature() { + if in.Options.VersionContract.SupportsRBACFeature() { machine.MachineFeatures.RBAC = pointer.To(true) } - if in.VersionContract.StableHostnameEnabled() { + if in.Options.VersionContract.StableHostnameEnabled() { machine.MachineFeatures.StableHostname = pointer.To(true) } - if in.VersionContract.ApidExtKeyUsageCheckEnabled() { + if in.Options.VersionContract.ApidExtKeyUsageCheckEnabled() { machine.MachineFeatures.ApidCheckExtKeyUsage = pointer.To(true) } - if in.VersionContract.DiskQuotaSupportEnabled() { + if in.Options.VersionContract.DiskQuotaSupportEnabled() { machine.MachineFeatures.DiskQuotaSupport = pointer.To(true) } - if in.VersionContract.KubeletDefaultRuntimeSeccompProfileEnabled() { + if in.Options.VersionContract.KubeletDefaultRuntimeSeccompProfileEnabled() { machine.MachineKubelet.KubeletDefaultRuntimeSeccompProfileEnabled = pointer.To(true) } - if in.VersionContract.KubeletManifestsDirectoryDisabled() { + if in.Options.VersionContract.KubeletManifestsDirectoryDisabled() { machine.MachineKubelet.KubeletDisableManifestsDirectory = pointer.To(true) } controlPlaneURL, err := url.Parse(in.ControlPlaneEndpoint) if err != nil { - return config, err + return nil, err } cluster := &v1alpha1.ClusterConfig{ - ClusterID: in.ClusterID, - ClusterSecret: in.ClusterSecret, - ClusterCA: &x509.PEMEncodedCertificateAndKey{Crt: in.Certs.K8s.Crt}, - BootstrapToken: in.Secrets.BootstrapToken, + ClusterID: in.Options.SecretsBundle.Cluster.ID, + ClusterSecret: in.Options.SecretsBundle.Cluster.Secret, + ClusterCA: &x509.PEMEncodedCertificateAndKey{Crt: in.Options.SecretsBundle.Certs.K8s.Crt}, + BootstrapToken: in.Options.SecretsBundle.Secrets.BootstrapToken, ControlPlane: &v1alpha1.ControlPlaneConfig{ Endpoint: &v1alpha1.Endpoint{URL: controlPlaneURL}, }, ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ - DNSDomain: in.ServiceDomain, + DNSDomain: in.Options.DNSDomain, PodSubnet: in.PodNet, ServiceSubnet: in.ServiceNet, - CNI: in.CNIConfig, + CNI: in.Options.CNIConfig, }, } - if in.DiscoveryEnabled { + if in.Options.DiscoveryEnabled != nil { cluster.ClusterDiscoveryConfig = &v1alpha1.ClusterDiscoveryConfig{ - DiscoveryEnabled: pointer.To(in.DiscoveryEnabled), + DiscoveryEnabled: pointer.To(*in.Options.DiscoveryEnabled), } - if in.VersionContract.KubernetesDiscoveryBackendDisabled() { + if in.Options.VersionContract.KubernetesDiscoveryBackendDisabled() { cluster.ClusterDiscoveryConfig.DiscoveryRegistries.RegistryKubernetes.RegistryDisabled = pointer.To(true) } } @@ -117,7 +118,7 @@ func workerUd(in *Input) (*v1alpha1.Config, error) { machine.MachineRegistries.RegistryMirrors = map[string]*v1alpha1.RegistryMirrorConfig{} } - if in.VersionContract.KubernetesAlternateImageRegistries() { + if in.Options.VersionContract.KubernetesAlternateImageRegistries() { if _, ok := machine.MachineRegistries.RegistryMirrors["k8s.gcr.io"]; !ok { machine.MachineRegistries.RegistryMirrors["k8s.gcr.io"] = &v1alpha1.RegistryMirrorConfig{ MirrorEndpoints: []string{ @@ -128,8 +129,8 @@ func workerUd(in *Input) (*v1alpha1.Config, error) { } } - config.MachineConfig = machine - config.ClusterConfig = cluster + v1alpha1Config.MachineConfig = machine + v1alpha1Config.ClusterConfig = cluster - return config, nil + return []config.Document{v1alpha1Config}, nil } diff --git a/pkg/machinery/config/internal/registry/registry.go b/pkg/machinery/config/internal/registry/registry.go index 8f36e40c9..7a3f11ed8 100644 --- a/pkg/machinery/config/internal/registry/registry.go +++ b/pkg/machinery/config/internal/registry/registry.go @@ -9,6 +9,8 @@ import ( "errors" "fmt" "sync" + + "github.com/siderolabs/talos/pkg/machinery/config/config" ) var ( @@ -19,7 +21,7 @@ var ( ) // NewDocumentFunc represents a function that creates a new document by version. -type NewDocumentFunc func(version string) any +type NewDocumentFunc func(version string) config.Document var registry = &Registry{ registered: map[string]NewDocumentFunc{}, @@ -37,7 +39,7 @@ func Register(kind string, f NewDocumentFunc) { } // New creates a new instance of the requested manifest. -func New(kind, version string) (any, error) { +func New(kind, version string) (config.Document, error) { return registry.new(kind, version) } @@ -52,7 +54,7 @@ func (r *Registry) register(kind string, f NewDocumentFunc) { r.registered[kind] = f } -func (r *Registry) new(kind, version string) (any, error) { +func (r *Registry) new(kind, version string) (config.Document, error) { r.m.Lock() defer r.m.Unlock() diff --git a/pkg/machinery/config/machine/machine.go b/pkg/machinery/config/machine/machine.go new file mode 100644 index 000000000..8bd63bfb5 --- /dev/null +++ b/pkg/machinery/config/machine/machine.go @@ -0,0 +1,68 @@ +// 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 machine defines common machine type. +package machine + +import ( + "fmt" +) + +//go:generate stringer -type=Type -linecomment + +// Type represents a machine type. +type Type int + +//structprotogen:gen_enum +const ( + // TypeUnknown represents undefined node type, when there is no machine configuration yet. + TypeUnknown Type = iota // unknown + + // TypeInit type designates the first control plane node to come up. You can think of it like a bootstrap node. + // This node will perform the initial steps to bootstrap the cluster -- generation of TLS assets, starting of the control plane, etc. + TypeInit // init + + // TypeControlPlane designates the node as a control plane member. + // This means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler. + TypeControlPlane // controlplane + + // TypeWorker designates the node as a worker node. + // This means it will be an available compute node for scheduling workloads. + TypeWorker // worker +) + +// ParseType parses string constant as Type. +func ParseType(s string) (Type, error) { + switch s { + case "init": + return TypeInit, nil + case "controlplane": + return TypeControlPlane, nil + case "worker", "join", "": + return TypeWorker, nil + case "unknown": + return TypeUnknown, nil + default: + return TypeUnknown, fmt.Errorf("invalid machine type: %q", s) + } +} + +// MarshalText implements encoding.TextMarshaler. +func (t Type) MarshalText() (text []byte, err error) { + return []byte(t.String()), nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (t *Type) UnmarshalText(text []byte) error { + var err error + + *t, err = ParseType(string(text)) + + return err +} + +// IsControlPlane returns true if the type is a control plane node. +func (t Type) IsControlPlane() bool { + return t == TypeControlPlane || t == TypeInit +} diff --git a/pkg/machinery/config/types/v1alpha1/machine/machine_test.go b/pkg/machinery/config/machine/machine_test.go similarity index 96% rename from pkg/machinery/config/types/v1alpha1/machine/machine_test.go rename to pkg/machinery/config/machine/machine_test.go index 936b85244..37d34d9cf 100644 --- a/pkg/machinery/config/types/v1alpha1/machine/machine_test.go +++ b/pkg/machinery/config/machine/machine_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/require" machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) func TestParseType(t *testing.T) { diff --git a/pkg/machinery/config/types/v1alpha1/machine/type_string.go b/pkg/machinery/config/machine/type_string.go similarity index 100% rename from pkg/machinery/config/types/v1alpha1/machine/type_string.go rename to pkg/machinery/config/machine/type_string.go diff --git a/pkg/machinery/config/provider.go b/pkg/machinery/config/provider.go index 3fbbcbea5..05f50de09 100644 --- a/pkg/machinery/config/provider.go +++ b/pkg/machinery/config/provider.go @@ -7,24 +7,23 @@ package config import ( "github.com/siderolabs/talos/pkg/machinery/config/config" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/validation" ) // Encoder provides the interface to encode configuration documents. type Encoder = config.Encoder +// Validator provides the interface to validate configuration. +type Validator = config.Validator + // Container provides the interface to access configuration documents. // // Container might contain multiple config documents, supporting encoding/decoding, // validation, and other operations. type Container interface { Encoder + Validator - // Validate checks configuration and returns warnings and fatal errors (as multierror). - Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) - - // RedactSecrets returns a copy of the Provider with all secrets replaced with the given string. - RedactSecrets(string) Encoder + Readonly() bool // RawV1Alpha1 returns internal config representation. RawV1Alpha1() *v1alpha1.Config @@ -34,4 +33,10 @@ type Container interface { type Provider interface { Config Container + + // Clone returns a copy of the Provider. + Clone() Provider + + // RedactSecrets returns a copy of the Provider with all secrets replaced with the given string. + RedactSecrets(string) Provider } diff --git a/pkg/machinery/config/types/meta/meta.go b/pkg/machinery/config/types/meta/meta.go new file mode 100644 index 000000000..b4343df2a --- /dev/null +++ b/pkg/machinery/config/types/meta/meta.go @@ -0,0 +1,12 @@ +// 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 meta provides common meta types for config documents. +package meta + +// Meta is a shared meta information for config documents. +type Meta struct { + Kind string `yaml:"kind"` + Version string `yaml:"version,omitempty"` +} diff --git a/pkg/machinery/config/types/meta/url.go b/pkg/machinery/config/types/meta/url.go new file mode 100644 index 000000000..67de93aed --- /dev/null +++ b/pkg/machinery/config/types/meta/url.go @@ -0,0 +1,43 @@ +// 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 meta + +import "net/url" + +// URL wraps the URL with proper YAML marshal/unmarshal. +type URL struct { + *url.URL +} + +// UnmarshalYAML is a custom unmarshaller for `URL`. +func (u *URL) UnmarshalYAML(unmarshal func(any) error) error { + var endpoint string + + if err := unmarshal(&endpoint); err != nil { + return err + } + + if endpoint == "" { + return nil + } + + url, err := url.Parse(endpoint) + if err != nil { + return err + } + + *u = URL{url} + + return nil +} + +// MarshalYAML is a custom marshaller for `URL`. +func (u URL) MarshalYAML() (any, error) { + if u.URL == nil { + return "", nil + } + + return u.URL.String(), nil +} diff --git a/pkg/machinery/config/types/siderolink/deep_copy.generated.go b/pkg/machinery/config/types/siderolink/deep_copy.generated.go new file mode 100644 index 000000000..e67db5ee7 --- /dev/null +++ b/pkg/machinery/config/types/siderolink/deep_copy.generated.go @@ -0,0 +1,25 @@ +// 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/. + +// Code generated by "deep-copy -type ConfigV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT. + +package siderolink + +import ( + "net/url" +) + +// DeepCopy generates a deep copy of *ConfigV1Alpha1. +func (o *ConfigV1Alpha1) DeepCopy() *ConfigV1Alpha1 { + var cp ConfigV1Alpha1 = *o + if o.APIUrlConfig.URL != nil { + cp.APIUrlConfig.URL = new(url.URL) + *cp.APIUrlConfig.URL = *o.APIUrlConfig.URL + if o.APIUrlConfig.URL.User != nil { + cp.APIUrlConfig.URL.User = new(url.Userinfo) + *cp.APIUrlConfig.URL.User = *o.APIUrlConfig.URL.User + } + } + return &cp +} diff --git a/pkg/machinery/config/types/siderolink/siderolink.go b/pkg/machinery/config/types/siderolink/siderolink.go new file mode 100644 index 000000000..55f0d5f2c --- /dev/null +++ b/pkg/machinery/config/types/siderolink/siderolink.go @@ -0,0 +1,80 @@ +// 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 siderolink provides siderolink config documents. +package siderolink + +import ( + "net/url" + + "github.com/siderolabs/talos/pkg/machinery/config/config" + "github.com/siderolabs/talos/pkg/machinery/config/internal/registry" + "github.com/siderolabs/talos/pkg/machinery/config/types/meta" +) + +//go:generate deep-copy -type ConfigV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go . + +// Kind is a siderolink config document kind. +const Kind = "SideroLinkConfig" + +func init() { + registry.Register(Kind, func(version string) config.Document { + switch version { + case "v1alpha1": + return &ConfigV1Alpha1{} + default: + return nil + } + }) +} + +// Check interfaces. +var _ config.SecretDocument = &ConfigV1Alpha1{} + +// ConfigV1Alpha1 is a siderolink config document. +type ConfigV1Alpha1 struct { + meta.Meta `yaml:",inline"` + APIUrlConfig meta.URL `yaml:"apiUrl"` +} + +// NewConfigV1Alpha1 creates a new siderolink config document. +func NewConfigV1Alpha1() *ConfigV1Alpha1 { + return &ConfigV1Alpha1{ + Meta: meta.Meta{ + Kind: Kind, + Version: "v1alpha1", + }, + } +} + +// Clone implements config.Document interface. +func (s *ConfigV1Alpha1) Clone() config.Document { + return s.DeepCopy() +} + +// Redact implements config.SecretDocument interface. +func (s *ConfigV1Alpha1) Redact(replacement string) { + if s.APIUrlConfig.URL != nil { + query := s.APIUrlConfig.Query() + if query.Has("jointoken") { + query.Set("jointoken", replacement) + } + + s.APIUrlConfig.RawQuery = query.Encode() + } +} + +// SideroLink implements config.SideroLink interface. +func (s *ConfigV1Alpha1) SideroLink() config.SideroLinkConfig { + return s +} + +// APIUrl implements config.SideroLink interface. +func (s *ConfigV1Alpha1) APIUrl() *url.URL { + if s == nil { + return nil + } + + return s.APIUrlConfig.URL +} diff --git a/pkg/machinery/config/types/siderolink/siderolink_test.go b/pkg/machinery/config/types/siderolink/siderolink_test.go new file mode 100644 index 000000000..777676921 --- /dev/null +++ b/pkg/machinery/config/types/siderolink/siderolink_test.go @@ -0,0 +1,33 @@ +// 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 siderolink_test + +import ( + "net/url" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/siderolabs/talos/pkg/machinery/config/types/siderolink" +) + +func TestRedact(t *testing.T) { + cfg := siderolink.NewConfigV1Alpha1() + cfg.APIUrlConfig.URL = must(url.Parse("https://siderolink.api/join?jointoken=secret&user=alice")) + + assert.Equal(t, "https://siderolink.api/join?jointoken=secret&user=alice", cfg.SideroLink().APIUrl().String()) + + cfg.Redact("REDACTED") + + assert.Equal(t, "https://siderolink.api/join?jointoken=REDACTED&user=alice", cfg.APIUrlConfig.String()) +} + +func must[T any](t T, err error) T { + if err != nil { + panic(err) + } + + return t +} diff --git a/pkg/machinery/config/types/types.go b/pkg/machinery/config/types/types.go new file mode 100644 index 000000000..a5fa0eb9c --- /dev/null +++ b/pkg/machinery/config/types/types.go @@ -0,0 +1,11 @@ +// 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 types imports all configuration document types to register them. +package types + +import ( + _ "github.com/siderolabs/talos/pkg/machinery/config/types/siderolink" //nolint:revive + _ "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" +) diff --git a/pkg/machinery/config/types/v1alpha1/bundle/bundle.go b/pkg/machinery/config/types/v1alpha1/bundle/bundle.go index 96450d045..8c16d8570 100644 --- a/pkg/machinery/config/types/v1alpha1/bundle/bundle.go +++ b/pkg/machinery/config/types/v1alpha1/bundle/bundle.go @@ -4,162 +4,16 @@ package bundle -import ( - "fmt" - "os" - "path/filepath" - "strings" +import "github.com/siderolabs/talos/pkg/machinery/config/bundle" - yaml "gopkg.in/yaml.v3" - - clientconfig "github.com/siderolabs/talos/pkg/machinery/client/config" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" -) +// ConfigBundle defines the group of v1alpha1 config files. +// docgen: nodoc +// +k8s:deepcopy-gen=false +type ConfigBundle = bundle.Bundle // NewConfigBundle returns a new bundle. // -//nolint:gocyclo,cyclop +// Deprecated: use bundle.NewBundle instead. func NewConfigBundle(opts ...Option) (*ConfigBundle, error) { - options := DefaultOptions() - - for _, opt := range opts { - if err := opt(&options); err != nil { - return nil, err - } - } - - bundle := &ConfigBundle{} - - // Configs already exist, we'll pull them in. - if options.ExistingConfigs != "" { - if options.InputOptions != nil { - return bundle, fmt.Errorf("both existing config path and input options specified") - } - - // Pull existing machine configs of each type - for _, configType := range []machine.Type{machine.TypeInit, machine.TypeControlPlane, machine.TypeWorker} { - data, err := os.ReadFile(filepath.Join(options.ExistingConfigs, strings.ToLower(configType.String())+".yaml")) - if err != nil { - if configType == machine.TypeInit && os.IsNotExist(err) { - continue - } - - return bundle, err - } - - unmarshalledConfig := &v1alpha1.Config{} - if err := yaml.Unmarshal(data, unmarshalledConfig); err != nil { - return bundle, err - } - - switch configType { - case machine.TypeInit: - bundle.InitCfg = unmarshalledConfig - case machine.TypeControlPlane: - bundle.ControlPlaneCfg = unmarshalledConfig - case machine.TypeWorker: - bundle.WorkerCfg = unmarshalledConfig - case machine.TypeUnknown: - fallthrough - default: - panic("unreachable") - } - } - - if err := applyJSONPatches(bundle, options); err != nil { - return nil, err - } - - // Pull existing talosconfig - talosConfig, err := os.Open(filepath.Join(options.ExistingConfigs, "talosconfig")) - if err != nil { - return bundle, err - } - - defer talosConfig.Close() //nolint:errcheck - - if bundle.TalosCfg, err = clientconfig.ReadFrom(talosConfig); err != nil { - return bundle, err - } - - return bundle, nil - } - - // Handle generating net-new configs - if options.Verbose { - fmt.Fprintln(os.Stderr, "generating PKI and tokens") - } - - if options.InputOptions == nil { - return nil, fmt.Errorf("no WithInputOptions is defined") - } - - secrets, err := generate.NewSecretsBundle(generate.NewClock(), options.InputOptions.GenOptions...) - if err != nil { - return bundle, err - } - - var input *generate.Input - - input, err = generate.NewInput( - options.InputOptions.ClusterName, - options.InputOptions.Endpoint, - options.InputOptions.KubeVersion, - secrets, - options.InputOptions.GenOptions..., - ) - if err != nil { - return bundle, err - } - - for _, configType := range []machine.Type{machine.TypeInit, machine.TypeControlPlane, machine.TypeWorker} { - var generatedConfig *v1alpha1.Config - - generatedConfig, err = generate.Config(configType, input) - if err != nil { - return bundle, err - } - - switch configType { - case machine.TypeInit: - bundle.InitCfg = generatedConfig - case machine.TypeControlPlane: - bundle.ControlPlaneCfg = generatedConfig - case machine.TypeWorker: - bundle.WorkerCfg = generatedConfig - case machine.TypeUnknown: - fallthrough - default: - panic("unreachable") - } - } - - if err = applyJSONPatches(bundle, options); err != nil { - return nil, err - } - - bundle.TalosCfg, err = generate.Talosconfig(input, options.InputOptions.GenOptions...) - if err != nil { - return bundle, err - } - - return bundle, nil -} - -func applyJSONPatches(bundle *ConfigBundle, options Options) error { - if err := bundle.ApplyPatches(options.Patches, true, true); err != nil { - return fmt.Errorf("error patching configs: %w", err) - } - - if err := bundle.ApplyPatches(options.PatchesControlPlane, true, false); err != nil { - return fmt.Errorf("error patching control plane configs: %w", err) - } - - if err := bundle.ApplyPatches(options.PatchesWorker, false, true); err != nil { - return fmt.Errorf("error patching worker config: %w", err) - } - - return nil + return bundle.NewBundle(opts...) } diff --git a/pkg/machinery/config/types/v1alpha1/bundle/options.go b/pkg/machinery/config/types/v1alpha1/bundle/options.go index b800f73ed..ba4a07113 100644 --- a/pkg/machinery/config/types/v1alpha1/bundle/options.go +++ b/pkg/machinery/config/types/v1alpha1/bundle/options.go @@ -7,122 +7,91 @@ package bundle import ( jsonpatch "github.com/evanphx/json-patch" + "github.com/siderolabs/talos/pkg/machinery/config/bundle" "github.com/siderolabs/talos/pkg/machinery/config/configpatcher" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" ) // Option controls config options specific to config bundle generation. -type Option func(o *Options) error +// +// Deprecated: user bundle.Option instead. +type Option = bundle.Option // InputOptions holds necessary params for generating an input. -type InputOptions struct { - ClusterName string - Endpoint string - KubeVersion string - GenOptions []generate.GenOption -} +// +// Deprecated: user bundle.InputOptions instead. +type InputOptions = bundle.InputOptions // Options describes generate parameters. -type Options struct { - ExistingConfigs string // path to existing config files - Verbose bool // wheither to write any logs during generate - InputOptions *InputOptions - - Patches []configpatcher.Patch - PatchesControlPlane []configpatcher.Patch - PatchesWorker []configpatcher.Patch -} +// +// Deprecated: user bundle.Options instead. +type Options = bundle.Options // DefaultOptions returns default options. +// +// Deprecated: user bundle.DefaultOptions instead. func DefaultOptions() Options { - return Options{ - Verbose: true, - } + return bundle.DefaultOptions() } // WithExistingConfigs sets the path to existing config files. +// +// Deprecated: use bundle.WithExistingConfigs instead. func WithExistingConfigs(configPath string) Option { - return func(o *Options) error { - o.ExistingConfigs = configPath - - return nil - } + return bundle.WithExistingConfigs(configPath) } // WithInputOptions allows passing in of various params for net-new input generation. +// +// Deprecated: use bundle.WithInputOptions instead. func WithInputOptions(inputOpts *InputOptions) Option { - return func(o *Options) error { - o.InputOptions = inputOpts - - return nil - } + return bundle.WithInputOptions(inputOpts) } // WithVerbose allows setting verbose logging. +// +// Deprecated: use bundle.WithVerbose instead. func WithVerbose(verbose bool) Option { - return func(o *Options) error { - o.Verbose = verbose - - return nil - } + return bundle.WithVerbose(verbose) } // WithJSONPatch allows patching every config in a bundle with a patch. // // Deprecated: use WithPatch instead. func WithJSONPatch(patch jsonpatch.Patch) Option { - return func(o *Options) error { - o.Patches = append(o.Patches, patch) - - return nil - } + return WithPatch([]configpatcher.Patch{patch}) } // WithPatch allows patching every config in a bundle with a patch. +// +// Deprecated: use bundle.WithPatch instead. func WithPatch(patch []configpatcher.Patch) Option { - return func(o *Options) error { - o.Patches = append(o.Patches, patch...) - - return nil - } + return bundle.WithPatch(patch) } // WithJSONPatchControlPlane allows patching init and controlplane config in a bundle with a patch. // // Deprecated: use WithPatchControlPlane instead. func WithJSONPatchControlPlane(patch jsonpatch.Patch) Option { - return func(o *Options) error { - o.PatchesControlPlane = append(o.PatchesControlPlane, patch) - - return nil - } + return WithPatchControlPlane([]configpatcher.Patch{patch}) } // WithPatchControlPlane allows patching init and controlplane config in a bundle with a patch. +// +// Deprecated: use bundle.WithPatchControlPlane instead. func WithPatchControlPlane(patch []configpatcher.Patch) Option { - return func(o *Options) error { - o.PatchesControlPlane = append(o.PatchesControlPlane, patch...) - - return nil - } + return bundle.WithPatchControlPlane(patch) } // WithJSONPatchWorker allows patching worker config in a bundle with a patch. // // Deprecated: use WithPatchWorker instead. func WithJSONPatchWorker(patch jsonpatch.Patch) Option { - return func(o *Options) error { - o.PatchesWorker = append(o.PatchesWorker, patch) - - return nil - } + return WithPatchWorker([]configpatcher.Patch{patch}) } // WithPatchWorker allows patching worker config in a bundle with a patch. +// +// Deprecated: use bundle.WithPatchWorker instead. func WithPatchWorker(patch []configpatcher.Patch) Option { - return func(o *Options) error { - o.PatchesWorker = append(o.PatchesWorker, patch...) - - return nil - } + return bundle.WithPatchWorker(patch) } diff --git a/pkg/machinery/config/types/v1alpha1/bundle/v1alpha1_configurator_bundle.go b/pkg/machinery/config/types/v1alpha1/bundle/v1alpha1_configurator_bundle.go deleted file mode 100644 index 8baa9c8d0..000000000 --- a/pkg/machinery/config/types/v1alpha1/bundle/v1alpha1_configurator_bundle.go +++ /dev/null @@ -1,135 +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 bundle - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - clientconfig "github.com/siderolabs/talos/pkg/machinery/client/config" - "github.com/siderolabs/talos/pkg/machinery/config" - "github.com/siderolabs/talos/pkg/machinery/config/configpatcher" - "github.com/siderolabs/talos/pkg/machinery/config/encoder" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" -) - -// ConfigBundle defines the group of v1alpha1 config files. -// docgen: nodoc -// +k8s:deepcopy-gen=false -type ConfigBundle struct { - InitCfg *v1alpha1.Config - ControlPlaneCfg *v1alpha1.Config - WorkerCfg *v1alpha1.Config - TalosCfg *clientconfig.Config -} - -// Init implements the ProviderBundle interface. -func (c *ConfigBundle) Init() config.Provider { - return c.InitCfg -} - -// ControlPlane implements the ProviderBundle interface. -func (c *ConfigBundle) ControlPlane() config.Provider { - return c.ControlPlaneCfg -} - -// Worker implements the ProviderBundle interface. -func (c *ConfigBundle) Worker() config.Provider { - return c.WorkerCfg -} - -// TalosConfig implements the ProviderBundle interface. -func (c *ConfigBundle) TalosConfig() *clientconfig.Config { - return c.TalosCfg -} - -// Write config files to output directory. -func (c *ConfigBundle) Write(outputDir string, commentsFlags encoder.CommentsFlags, types ...machine.Type) error { - for _, t := range types { - name := strings.ToLower(t.String()) + ".yaml" - fullFilePath := filepath.Join(outputDir, name) - - bytes, err := c.Serialize(commentsFlags, t) - if err != nil { - return err - } - - if err = os.WriteFile(fullFilePath, bytes, 0o644); err != nil { - return err - } - - fmt.Fprintf(os.Stderr, "created %s\n", fullFilePath) - } - - return nil -} - -// Serialize returns the config for the provided machine type as bytes. -func (c *ConfigBundle) Serialize(commentsFlags encoder.CommentsFlags, machineType machine.Type) ([]byte, error) { - switch machineType { - case machine.TypeInit: - return c.Init().EncodeBytes(encoder.WithComments(commentsFlags)) - case machine.TypeControlPlane: - return c.ControlPlane().EncodeBytes(encoder.WithComments(commentsFlags)) - case machine.TypeWorker: - return c.Worker().EncodeBytes(encoder.WithComments(commentsFlags)) - case machine.TypeUnknown: - fallthrough - default: - return nil, fmt.Errorf("unexpected machine type %v", machineType) - } -} - -// ApplyPatches patches every config type with a patch. -func (c *ConfigBundle) ApplyPatches(patches []configpatcher.Patch, patchControlPlane, patchWorker bool) error { - if len(patches) == 0 { - return nil - } - - apply := func(in *v1alpha1.Config) (*v1alpha1.Config, error) { - patched, err := configpatcher.Apply(configpatcher.WithConfig(in), patches) - if err != nil { - return nil, err - } - - cfg, err := patched.Config() - if err != nil { - return nil, err - } - - out := cfg.RawV1Alpha1() - if out == nil { - return nil, fmt.Errorf("unexpected config type %T", out) - } - - return out, nil - } - - var err error - - if patchControlPlane { - c.InitCfg, err = apply(c.InitCfg) - if err != nil { - return err - } - - c.ControlPlaneCfg, err = apply(c.ControlPlaneCfg) - if err != nil { - return err - } - } - - if patchWorker { - c.WorkerCfg, err = apply(c.WorkerCfg) - if err != nil { - return err - } - } - - return nil -} diff --git a/pkg/machinery/config/types/v1alpha1/generate/generate.go b/pkg/machinery/config/types/v1alpha1/generate/generate.go index 1c06c441c..483e79afa 100644 --- a/pkg/machinery/config/types/v1alpha1/generate/generate.go +++ b/pkg/machinery/config/types/v1alpha1/generate/generate.go @@ -4,777 +4,136 @@ // Package generate provides Talos machine configuration generation and client config generation. // -// Please see the example for more information on using this package. +// This package is deprecated, use github.com/siderolabs/talos/pkg/machinery/config/generate instead. package generate import ( - "bufio" - "crypto/rand" - stdx509 "crypto/x509" - "encoding/base64" - "errors" - "fmt" - "io" - "net" - "net/netip" - "net/url" - "os" - "path/filepath" "time" "github.com/siderolabs/crypto/x509" - "github.com/siderolabs/gen/slices" - tnet "github.com/siderolabs/net" "github.com/siderolabs/talos/pkg/machinery/config" - "github.com/siderolabs/talos/pkg/machinery/config/internal/cis" + "github.com/siderolabs/talos/pkg/machinery/config/generate" + "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets" + "github.com/siderolabs/talos/pkg/machinery/config/machine" v1alpha1 "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" - "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/role" ) // Config returns the talos config for a given node type. func Config(t machine.Type, in *Input) (*v1alpha1.Config, error) { - switch t { - case machine.TypeInit: - return initUd(in) - case machine.TypeControlPlane: - return controlPlaneUd(in) - case machine.TypeWorker: - return workerUd(in) - case machine.TypeUnknown: - fallthrough - default: - return nil, errors.New("failed to determine config type to generate") + cfg, err := in.Config(t) + if err != nil { + return nil, err } + + return cfg.RawV1Alpha1(), nil } // Input holds info about certs, ips, and node type. // //nolint:maligned -type Input struct { - Certs *Certs - VersionContract *config.VersionContract - - // ControlplaneEndpoint is the canonical address of the kubernetes control - // plane. It can be a DNS name, the IP address of a load balancer, or - // (default) the IP address of the first controlplane node. It is NOT - // multi-valued. It may optionally specify the port. - ControlPlaneEndpoint string - - LocalAPIServerPort int - - AdditionalSubjectAltNames []string - AdditionalMachineCertSANs []string - - ClusterID string - ClusterName string - ClusterSecret string - ServiceDomain string - PodNet []string - ServiceNet []string - KubernetesVersion string - Secrets *Secrets - TrustdInfo *TrustdInfo - - ExternalEtcd bool - - InstallDisk string - InstallImage string - InstallExtraKernelArgs []string - - NetworkConfigOptions []v1alpha1.NetworkConfigOption - CNIConfig *v1alpha1.CNIConfig - - RegistryMirrors map[string]*v1alpha1.RegistryMirrorConfig - RegistryConfig map[string]*v1alpha1.RegistryConfig - MachineDisks []*v1alpha1.MachineDisk - SystemDiskEncryptionConfig *v1alpha1.SystemDiskEncryptionConfig - Sysctls map[string]string - - Debug bool - Persist bool - AllowSchedulingOnControlPlanes bool - DiscoveryEnabled bool -} - -// GetAPIServerEndpoint returns the formatted host:port of the API server endpoint. -func (i *Input) GetAPIServerEndpoint(port string) string { - if port == "" { - return tnet.FormatAddress(i.ControlPlaneEndpoint) - } - - return net.JoinHostPort(i.ControlPlaneEndpoint, port) -} - -// GetControlPlaneEndpoint returns the formatted host:port of the canonical controlplane address, defaulting to the first controlplane IP. -func (i *Input) GetControlPlaneEndpoint() string { - if i == nil || i.ControlPlaneEndpoint == "" { - panic("cannot GetControlPlaneEndpoint without any controlplane IPs") - } - - return i.ControlPlaneEndpoint -} - -// GetAPIServerSANs returns the formatted list of Subject Alt Name addresses for the API Server. -func (i *Input) GetAPIServerSANs() []string { - list := []string{} - - endpointURL, err := url.Parse(i.ControlPlaneEndpoint) - if err == nil { - list = append(list, endpointURL.Hostname()) - } - - list = append(list, i.AdditionalSubjectAltNames...) - - return list -} +type Input = generate.Input // Certs holds the base64 encoded keys and certificates. -type Certs struct { - Admin *x509.PEMEncodedCertificateAndKey `json:"Admin,omitempty" yaml:",omitempty"` - Etcd *x509.PEMEncodedCertificateAndKey `json:"Etcd"` - K8s *x509.PEMEncodedCertificateAndKey `json:"K8s"` - K8sAggregator *x509.PEMEncodedCertificateAndKey `json:"K8sAggregator"` - K8sServiceAccount *x509.PEMEncodedKey `json:"K8sServiceAccount"` - OS *x509.PEMEncodedCertificateAndKey `json:"OS"` -} +type Certs = secrets.Certs // Cluster holds Talos cluster-wide secrets. -type Cluster struct { - ID string `json:"Id"` - Secret string `json:"Secret"` -} +type Cluster = secrets.Cluster // Secrets holds the sensitive kubeadm data. -type Secrets struct { - BootstrapToken string `json:"BootstrapToken"` - AESCBCEncryptionSecret string `json:"AESCBCEncryptionSecret,omitempty" yaml:",omitempty"` - SecretboxEncryptionSecret string `json:"SecretboxEncryptionSecret,omitempty" yaml:",omitempty"` -} +type Secrets = secrets.Secrets // TrustdInfo holds the trustd credentials. -type TrustdInfo struct { - Token string `json:"Token"` -} +type TrustdInfo = secrets.TrustdInfo // SecretsBundle holds trustd, kubeadm and certs information. -type SecretsBundle struct { - Clock Clock `yaml:"-" json:"-"` - Cluster *Cluster `json:"Cluster"` - Secrets *Secrets `json:"Secrets"` - TrustdInfo *TrustdInfo `json:"TrustdInfo"` - Certs *Certs `json:"Certs"` -} +type SecretsBundle = secrets.Bundle // Clock system clock. -type Clock interface { - Now() time.Time -} +type Clock = secrets.Clock // SystemClock is a real system clock, but the time returned can be made fixed. -type SystemClock struct { - Time time.Time -} +type SystemClock = secrets.SystemClock // NewClock creates new SystemClock. +// +// Deprecated: use secrets.NewClock instead. func NewClock() *SystemClock { - return &SystemClock{} -} - -// Now implements Clock. -func (c *SystemClock) Now() time.Time { - if c.Time.IsZero() { - return time.Now() - } - - return c.Time -} - -// SetFixedTimestamp freezes the clock by setting a timestamp. -func (c *SystemClock) SetFixedTimestamp(t time.Time) { - c.Time = t + return secrets.NewClock() } // NewSecretsBundle creates secrets bundle generating all secrets or reading from the input options if provided. +// +// Deprecated: use generate.NewSecretsBundle instead. func NewSecretsBundle(clock Clock, opts ...GenOption) (*SecretsBundle, error) { - options := DefaultGenOptions() + o := generate.DefaultOptions() for _, opt := range opts { - if err := opt(&options); err != nil { + if err := opt(&o); err != nil { return nil, err } } - // if secrets bundle is provided via gen options, just return it - if options.Secrets != nil { - return options.Secrets, nil - } - - bundle := SecretsBundle{ - Clock: clock, - } - - err := populateSecretsBundle(options.VersionContract, &bundle) - if err != nil { - return nil, err - } - - return &bundle, nil + return secrets.NewBundle(clock, o.VersionContract) } // NewSecretsBundleFromKubernetesPKI creates secrets bundle by reading the contents // of a Kubernetes PKI directory (typically `/etc/kubernetes/pki`) and using the provided bootstrapToken as input. // +// Deprecated: use generate.NewSecretsBundleFromKubernetesPKI instead. +// //nolint:gocyclo func NewSecretsBundleFromKubernetesPKI(pkiDir, bootstrapToken string, versionContract *config.VersionContract) (*SecretsBundle, error) { - dirStat, err := os.Stat(pkiDir) - if err != nil { - return nil, err - } - - if !dirStat.IsDir() { - return nil, fmt.Errorf("%q is not a directory", pkiDir) - } - - var ( - ca *x509.PEMEncodedCertificateAndKey - etcdCA *x509.PEMEncodedCertificateAndKey - aggregatorCA *x509.PEMEncodedCertificateAndKey - sa *x509.PEMEncodedKey - ) - - ca, err = x509.NewCertificateAndKeyFromFiles(filepath.Join(pkiDir, "ca.crt"), filepath.Join(pkiDir, "ca.key")) - if err != nil { - return nil, err - } - - err = validatePEMEncodedCertificateAndKey(ca) - if err != nil { - return nil, err - } - - etcdDir := filepath.Join(pkiDir, "etcd") - - etcdCA, err = x509.NewCertificateAndKeyFromFiles(filepath.Join(etcdDir, "ca.crt"), filepath.Join(etcdDir, "ca.key")) - if err != nil { - return nil, err - } - - err = validatePEMEncodedCertificateAndKey(etcdCA) - if err != nil { - return nil, err - } - - aggregatorCACrtPath := filepath.Join(pkiDir, "front-proxy-ca.crt") - _, err = os.Stat(aggregatorCACrtPath) - - aggregatorCAFound := err == nil - if aggregatorCAFound && !versionContract.SupportsAggregatorCA() { - return nil, fmt.Errorf("aggregator CA found in pki dir but is not supported by the requested version") - } - - if versionContract.SupportsAggregatorCA() { - aggregatorCA, err = x509.NewCertificateAndKeyFromFiles(aggregatorCACrtPath, filepath.Join(pkiDir, "front-proxy-ca.key")) - if err != nil { - return nil, err - } - - err = validatePEMEncodedCertificateAndKey(aggregatorCA) - if err != nil { - return nil, err - } - } - - saKeyPath := filepath.Join(pkiDir, "sa.key") - _, err = os.Stat(saKeyPath) - - saKeyFound := err == nil - if saKeyFound && !versionContract.SupportsServiceAccount() { - return nil, fmt.Errorf("service account key found in pki dir but is not supported by the requested version") - } - - if versionContract.SupportsServiceAccount() { - var saBytes []byte - - saBytes, err = os.ReadFile(filepath.Join(pkiDir, "sa.key")) - if err != nil { - return nil, err - } - - sa = &x509.PEMEncodedKey{ - Key: saBytes, - } - - _, err = sa.GetKey() - if err != nil { - return nil, err - } - } - - bundle := SecretsBundle{ - Secrets: &Secrets{ - BootstrapToken: bootstrapToken, - }, - Certs: &Certs{ - Etcd: etcdCA, - K8s: ca, - K8sAggregator: aggregatorCA, - K8sServiceAccount: sa, - }, - } - - err = populateSecretsBundle(versionContract, &bundle) - if err != nil { - return nil, err - } - - return &bundle, nil -} - -// populateSecretsBundle fills all the missing fields in the secrets bundle. -// -//nolint:gocyclo,cyclop -func populateSecretsBundle(versionContract *config.VersionContract, bundle *SecretsBundle) error { - if bundle.Clock == nil { - bundle.Clock = NewClock() - } - - if bundle.Certs == nil { - bundle.Certs = &Certs{} - } - - if bundle.Certs.Etcd == nil { - etcd, err := NewEtcdCA(bundle.Clock.Now(), versionContract) - if err != nil { - return err - } - - bundle.Certs.Etcd = &x509.PEMEncodedCertificateAndKey{ - Crt: etcd.CrtPEM, - Key: etcd.KeyPEM, - } - } - - if bundle.Certs.K8s == nil { - kubernetesCA, err := NewKubernetesCA(bundle.Clock.Now(), versionContract) - if err != nil { - return err - } - - bundle.Certs.K8s = &x509.PEMEncodedCertificateAndKey{ - Crt: kubernetesCA.CrtPEM, - Key: kubernetesCA.KeyPEM, - } - } - - if versionContract.SupportsAggregatorCA() && bundle.Certs.K8sAggregator == nil { - aggregatorCA, err := NewAggregatorCA(bundle.Clock.Now(), versionContract) - if err != nil { - return err - } - - bundle.Certs.K8sAggregator = &x509.PEMEncodedCertificateAndKey{ - Crt: aggregatorCA.CrtPEM, - Key: aggregatorCA.KeyPEM, - } - } - - if versionContract.SupportsServiceAccount() && bundle.Certs.K8sServiceAccount == nil { - serviceAccount, err := x509.NewECDSAKey() - if err != nil { - return err - } - - bundle.Certs.K8sServiceAccount = &x509.PEMEncodedKey{ - Key: serviceAccount.KeyPEM, - } - } - - if bundle.Certs.OS == nil { - talosCA, err := NewTalosCA(bundle.Clock.Now()) - if err != nil { - return err - } - - bundle.Certs.OS = &x509.PEMEncodedCertificateAndKey{ - Crt: talosCA.CrtPEM, - Key: talosCA.KeyPEM, - } - } - - if bundle.Secrets == nil { - bundle.Secrets = &Secrets{} - } - - if bundle.Secrets.BootstrapToken == "" { - token, err := genToken(6, 16) - if err != nil { - return err - } - - bundle.Secrets.BootstrapToken = token - } - - if versionContract.Greater(config.TalosVersion1_2) { - if bundle.Secrets.SecretboxEncryptionSecret == "" { - secretboxEncryptionSecret, err := cis.CreateEncryptionToken() - if err != nil { - return err - } - - bundle.Secrets.SecretboxEncryptionSecret = secretboxEncryptionSecret - } - } else { - if bundle.Secrets.AESCBCEncryptionSecret == "" { - aesCBCEncryptionSecret, err := cis.CreateEncryptionToken() - if err != nil { - return err - } - - bundle.Secrets.AESCBCEncryptionSecret = aesCBCEncryptionSecret - } - } - - if bundle.TrustdInfo == nil { - bundle.TrustdInfo = &TrustdInfo{} - } - - if bundle.TrustdInfo.Token == "" { - token, err := genToken(6, 16) - if err != nil { - return err - } - - bundle.TrustdInfo.Token = token - } - - if bundle.Cluster == nil { - bundle.Cluster = &Cluster{} - } - - if bundle.Cluster.ID == "" { - clusterID, err := randBytes(constants.DefaultClusterIDSize) - if err != nil { - return fmt.Errorf("failed to generate cluster ID: %w", err) - } - - bundle.Cluster.ID = base64.URLEncoding.EncodeToString(clusterID) - } - - if bundle.Cluster.Secret == "" { - clusterSecret, err := randBytes(constants.DefaultClusterSecretSize) - if err != nil { - return fmt.Errorf("failed to generate cluster secret: %w", err) - } - - bundle.Cluster.Secret = base64.StdEncoding.EncodeToString(clusterSecret) - } - - return nil + return secrets.NewBundleFromKubernetesPKI(pkiDir, bootstrapToken, versionContract) } // NewSecretsBundleFromConfig creates secrets bundle using existing config. +// +// Deprecated: use generate.NewSecretsBundleFromConfig instead. func NewSecretsBundleFromConfig(clock Clock, c config.Provider) *SecretsBundle { - certs := &Certs{ - K8s: c.Cluster().CA(), - K8sAggregator: c.Cluster().AggregatorCA(), - K8sServiceAccount: c.Cluster().ServiceAccount(), - Etcd: c.Cluster().Etcd().CA(), - OS: c.Machine().Security().CA(), - } - - cluster := &Cluster{ - ID: c.Cluster().ID(), - Secret: c.Cluster().Secret(), - } - - trustd := &TrustdInfo{ - Token: c.Machine().Security().Token(), - } - - bootstrapToken := fmt.Sprintf( - "%s.%s", - c.Cluster().Token().ID(), - c.Cluster().Token().Secret(), - ) - - secrets := &Secrets{ - AESCBCEncryptionSecret: c.Cluster().AESCBCEncryptionSecret(), - SecretboxEncryptionSecret: c.Cluster().SecretboxEncryptionSecret(), - BootstrapToken: bootstrapToken, - } - - return &SecretsBundle{ - Clock: clock, - Cluster: cluster, - Secrets: secrets, - TrustdInfo: trustd, - Certs: certs, - } + return secrets.NewBundleFromConfig(clock, c) } // NewEtcdCA generates a CA for the Etcd PKI. +// +// Deprecated: use secrets.NewEtcdCA instead. func NewEtcdCA(currentTime time.Time, contract *config.VersionContract) (ca *x509.CertificateAuthority, err error) { - opts := []x509.Option{ - x509.Organization("etcd"), - x509.NotAfter(currentTime.Add(87600 * time.Hour)), - x509.NotBefore(currentTime), - } - - if !contract.SupportsECDSAKeys() { - opts = append(opts, x509.RSA(true)) - } else { - if contract.SupportsECDSASHA256() { - opts = append(opts, x509.ECDSA(true)) - } else { - opts = append(opts, x509.ECDSASHA512(true)) - } - } - - return x509.NewSelfSignedCertificateAuthority(opts...) + return secrets.NewEtcdCA(currentTime, contract) } // NewKubernetesCA generates a CA for the Kubernetes PKI. +// +// Deprecated: use secrets.NewKubernetesCA instead. func NewKubernetesCA(currentTime time.Time, contract *config.VersionContract) (ca *x509.CertificateAuthority, err error) { - opts := []x509.Option{ - x509.Organization("kubernetes"), - x509.NotAfter(currentTime.Add(87600 * time.Hour)), - x509.NotBefore(currentTime), - } - - if !contract.SupportsECDSAKeys() { - opts = append(opts, x509.RSA(true)) - } else { - if contract.SupportsECDSASHA256() { - opts = append(opts, x509.ECDSA(true)) - } else { - opts = append(opts, x509.ECDSASHA512(true)) - } - } - - return x509.NewSelfSignedCertificateAuthority(opts...) + return secrets.NewKubernetesCA(currentTime, contract) } // NewAggregatorCA generates a CA for the Kubernetes aggregator/front-proxy. +// +// Deprecated: use secrets.NewAggregatorCA instead. func NewAggregatorCA(currentTime time.Time, contract *config.VersionContract) (ca *x509.CertificateAuthority, err error) { - opts := []x509.Option{ - x509.ECDSA(true), - x509.CommonName("front-proxy"), - x509.NotAfter(currentTime.Add(87600 * time.Hour)), - x509.NotBefore(currentTime), - } - - if contract.SupportsECDSASHA256() { - opts = append(opts, x509.ECDSA(true)) - } else { - opts = append(opts, x509.ECDSASHA512(true)) - } - - return x509.NewSelfSignedCertificateAuthority(opts...) + return secrets.NewAggregatorCA(currentTime, contract) } // NewTalosCA generates a CA for the Talos PKI. +// +// Deprecated: use secrets.NewTalosCA instead. func NewTalosCA(currentTime time.Time) (ca *x509.CertificateAuthority, err error) { - opts := []x509.Option{ - x509.Organization("talos"), - x509.NotAfter(currentTime.Add(87600 * time.Hour)), - x509.NotBefore(currentTime), - } - - return x509.NewSelfSignedCertificateAuthority(opts...) + return secrets.NewTalosCA(currentTime) } // NewAdminCertificateAndKey generates the admin Talos certificate and key. +// +// Deperecated: use secrets.NewAdminCertificateAndKey instead. func NewAdminCertificateAndKey(currentTime time.Time, ca *x509.PEMEncodedCertificateAndKey, roles role.Set, ttl time.Duration) (p *x509.PEMEncodedCertificateAndKey, err error) { - opts := []x509.Option{ - x509.Organization(roles.Strings()...), - x509.NotAfter(currentTime.Add(ttl)), - x509.NotBefore(currentTime), - x509.KeyUsage(stdx509.KeyUsageDigitalSignature), - x509.ExtKeyUsage([]stdx509.ExtKeyUsage{stdx509.ExtKeyUsageClientAuth}), - } - - talosCA, err := x509.NewCertificateAuthorityFromCertificateAndKey(ca) - if err != nil { - return nil, err - } - - keyPair, err := x509.NewKeyPair(talosCA, opts...) - if err != nil { - return nil, err - } - - return x509.NewCertificateAndKeyFromKeyPair(keyPair), nil + return secrets.NewAdminCertificateAndKey(currentTime, ca, roles, ttl) } // NewInput generates the sensitive data required to generate all config // types. +// +// Deprecated: use generate.NewInput instead. func NewInput(clustername, endpoint, kubernetesVersion string, secrets *SecretsBundle, opts ...GenOption) (input *Input, err error) { - options := DefaultGenOptions() - - for _, opt := range opts { - if err = opt(&options); err != nil { - return nil, err - } - } - - var podNet, serviceNet string - - if addr, addrErr := netip.ParseAddr(endpoint); addrErr == nil && addr.Is6() { - podNet = constants.DefaultIPv6PodNet - serviceNet = constants.DefaultIPv6ServiceNet - } else { - podNet = constants.DefaultIPv4PodNet - serviceNet = constants.DefaultIPv4ServiceNet - } - - secrets.Certs.Admin, err = NewAdminCertificateAndKey( - secrets.Clock.Now(), - secrets.Certs.OS, - options.Roles, - 87600*time.Hour, - ) - - if err != nil { - return nil, err - } - - additionalSubjectAltNames := slices.Clone(options.AdditionalSubjectAltNames) - - if !options.VersionContract.SupportsDynamicCertSANs() { - additionalSubjectAltNames = append(additionalSubjectAltNames, options.EndpointList...) - } - - discoveryEnabled := options.VersionContract.ClusterDiscoveryEnabled() - - if options.DiscoveryEnabled != nil { - discoveryEnabled = *options.DiscoveryEnabled - } - - input = &Input{ - Certs: secrets.Certs, - VersionContract: options.VersionContract, - ControlPlaneEndpoint: endpoint, - LocalAPIServerPort: options.LocalAPIServerPort, - PodNet: []string{podNet}, - ServiceNet: []string{serviceNet}, - ServiceDomain: options.DNSDomain, - ClusterID: secrets.Cluster.ID, - ClusterName: clustername, - ClusterSecret: secrets.Cluster.Secret, - KubernetesVersion: kubernetesVersion, - Secrets: secrets.Secrets, - TrustdInfo: secrets.TrustdInfo, - AdditionalSubjectAltNames: additionalSubjectAltNames, - AdditionalMachineCertSANs: additionalSubjectAltNames, - InstallDisk: options.InstallDisk, - InstallImage: options.InstallImage, - InstallExtraKernelArgs: options.InstallExtraKernelArgs, - NetworkConfigOptions: options.NetworkConfigOptions, - CNIConfig: options.CNIConfig, - RegistryMirrors: options.RegistryMirrors, - RegistryConfig: options.RegistryConfig, - Sysctls: options.Sysctls, - Debug: options.Debug, - Persist: options.Persist, - AllowSchedulingOnControlPlanes: options.AllowSchedulingOnControlPlanes, - MachineDisks: options.MachineDisks, - SystemDiskEncryptionConfig: options.SystemDiskEncryptionConfig, - DiscoveryEnabled: discoveryEnabled, - } - - return input, nil -} - -// randBootstrapTokenString returns a random string consisting of the characters in -// validBootstrapTokenChars, with the length customized by the parameter. -func randBootstrapTokenString(length int) (string, error) { - // validBootstrapTokenChars defines the characters a bootstrap token can consist of - const validBootstrapTokenChars = "0123456789abcdefghijklmnopqrstuvwxyz" - - // len("0123456789abcdefghijklmnopqrstuvwxyz") = 36 which doesn't evenly divide - // the possible values of a byte: 256 mod 36 = 4. Discard any random bytes we - // read that are >= 252 so the bytes we evenly divide the character set. - const maxByteValue = 252 - - var ( - b byte - err error - token = make([]byte, length) - ) - - reader := bufio.NewReaderSize(rand.Reader, length*2) - - for i := range token { - for { - if b, err = reader.ReadByte(); err != nil { - return "", err - } - - if b < maxByteValue { - break - } - } - - token[i] = validBootstrapTokenChars[int(b)%len(validBootstrapTokenChars)] - } - - return string(token), err -} - -// genToken will generate a token of the format abc.123 (like kubeadm/trustd), where the length of the first string (before the dot) -// and length of the second string (after dot) are specified as inputs. -func genToken(lenFirst, lenSecond int) (string, error) { - var err error - - tokenTemp := make([]string, 2) - - tokenTemp[0], err = randBootstrapTokenString(lenFirst) - if err != nil { - return "", err - } - - tokenTemp[1], err = randBootstrapTokenString(lenSecond) - if err != nil { - return "", err - } - - return tokenTemp[0] + "." + tokenTemp[1], nil -} - -// emptyIf returns empty string if the 2nd argument is empty string, otherwise returns the first argument. -func emptyIf(str, check string) string { - if check == "" { - return "" - } - - return str -} - -func randBytes(size int) ([]byte, error) { - buf := make([]byte, size) - - n, err := io.ReadFull(rand.Reader, buf) - if err != nil { - return nil, fmt.Errorf("failed to read from random generator: %w", err) - } - - if n != size { - return nil, fmt.Errorf("failed to generate sufficient number of random bytes (%d != %d)", n, size) - } - - return buf, nil -} - -func validatePEMEncodedCertificateAndKey(certs *x509.PEMEncodedCertificateAndKey) error { - _, err := certs.GetKey() - if err != nil { - return err - } - - _, err = certs.GetCert() - - return err + return generate.NewInput(clustername, endpoint, kubernetesVersion, append(opts, generate.WithSecretsBundle(secrets))...) } diff --git a/pkg/machinery/config/types/v1alpha1/generate/generate_test.go b/pkg/machinery/config/types/v1alpha1/generate/generate_test.go deleted file mode 100644 index 7fa7ff719..000000000 --- a/pkg/machinery/config/types/v1alpha1/generate/generate_test.go +++ /dev/null @@ -1,146 +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 generate_test - -import ( - "crypto/x509" - "fmt" - "testing" - - "github.com/stretchr/testify/suite" - - "github.com/siderolabs/talos/pkg/machinery/client" - "github.com/siderolabs/talos/pkg/machinery/config" - genv1alpha1 "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" - "github.com/siderolabs/talos/pkg/machinery/constants" - "github.com/siderolabs/talos/pkg/machinery/role" -) - -type GenerateSuite struct { - suite.Suite - - input *genv1alpha1.Input - genOptions []genv1alpha1.GenOption - - versionContract *config.VersionContract -} - -func TestGenerateSuite(t *testing.T) { - for _, tt := range []struct { - label string - genOptions []genv1alpha1.GenOption - }{ - { - label: "current", - }, - { - label: "0.11", - genOptions: []genv1alpha1.GenOption{genv1alpha1.WithVersionContract(config.TalosVersion0_11)}, - }, - { - label: "0.10", - genOptions: []genv1alpha1.GenOption{genv1alpha1.WithVersionContract(config.TalosVersion0_10)}, - }, - { - label: "0.9", - genOptions: []genv1alpha1.GenOption{genv1alpha1.WithVersionContract(config.TalosVersion0_9)}, - }, - { - label: "0.8", - genOptions: []genv1alpha1.GenOption{genv1alpha1.WithVersionContract(config.TalosVersion0_8)}, - }, - } { - tt := tt - - t.Run(tt.label, func(t *testing.T) { - suite.Run(t, &GenerateSuite{ - genOptions: tt.genOptions, - }) - }) - } -} - -func (suite *GenerateSuite) SetupSuite() { - var err error - secrets, err := genv1alpha1.NewSecretsBundle(genv1alpha1.NewClock(), suite.genOptions...) - suite.Require().NoError(err) - suite.input, err = genv1alpha1.NewInput("test", "https://10.0.1.5", constants.DefaultKubernetesVersion, secrets, suite.genOptions...) - suite.Require().NoError(err) - - var opts genv1alpha1.GenOptions - - for _, opt := range suite.genOptions { - suite.Require().NoError(opt(&opts)) - } - - suite.versionContract = opts.VersionContract -} - -func (suite *GenerateSuite) TestGenerateInitSuccess() { - cfg, err := genv1alpha1.Config(machine.TypeInit, suite.input) - suite.Require().NoError(err) - - if suite.versionContract.SupportsRBACFeature() { - suite.True(cfg.MachineConfig.Features().RBACEnabled()) - suite.True(*cfg.MachineConfig.MachineFeatures.RBAC) - } else { - suite.False(cfg.MachineConfig.Features().RBACEnabled()) - } -} - -func (suite *GenerateSuite) TestGenerateControlPlaneSuccess() { - cfg, err := genv1alpha1.Config(machine.TypeControlPlane, suite.input) - suite.Require().NoError(err) - - _, err = cfg.Validate(runtimeMode{false}) - suite.Require().NoError(err) - - if suite.versionContract.SupportsRBACFeature() { - suite.True(cfg.MachineConfig.Features().RBACEnabled()) - suite.True(*cfg.MachineConfig.MachineFeatures.RBAC) - } else { - suite.False(cfg.MachineConfig.Features().RBACEnabled()) - } -} - -func (suite *GenerateSuite) TestGenerateWorkerSuccess() { - cfg, err := genv1alpha1.Config(machine.TypeWorker, suite.input) - suite.Require().NoError(err) - - if suite.versionContract.SupportsRBACFeature() { - suite.True(cfg.MachineConfig.Features().RBACEnabled()) - suite.True(*cfg.MachineConfig.MachineFeatures.RBAC) - } else { - suite.False(cfg.MachineConfig.Features().RBACEnabled()) - } -} - -func (suite *GenerateSuite) TestGenerateTalosconfigSuccess() { - cfg, err := genv1alpha1.Talosconfig(suite.input) - suite.Require().NoError(err) - - creds, err := client.CertificateFromConfigContext(cfg.Contexts[cfg.Context]) - suite.Require().NoError(err) - suite.Require().Nil(creds.Leaf) - suite.Require().Len(creds.Certificate, 1) - - cert, err := x509.ParseCertificate(creds.Certificate[0]) - suite.Require().NoError(err) - - suite.Equal([]string{string(role.Admin)}, cert.Subject.Organization) -} - -type runtimeMode struct { - requiresInstall bool -} - -func (m runtimeMode) String() string { - return fmt.Sprintf("runtimeMode(%v)", m.requiresInstall) -} - -func (m runtimeMode) RequiresInstall() bool { - return m.requiresInstall -} diff --git a/pkg/machinery/config/types/v1alpha1/generate/options.go b/pkg/machinery/config/types/v1alpha1/generate/options.go index d90523687..34a127b46 100644 --- a/pkg/machinery/config/types/v1alpha1/generate/options.go +++ b/pkg/machinery/config/types/v1alpha1/generate/options.go @@ -5,295 +5,187 @@ package generate import ( - "os" - - "github.com/siderolabs/go-pointer" - "gopkg.in/yaml.v3" - "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/generate" + "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets" v1alpha1 "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/role" ) // GenOption controls generate options specific to input generation. -type GenOption func(o *GenOptions) error +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.GenOption instead. +type GenOption = generate.Option // WithEndpointList specifies endpoints to use when accessing Talos cluster. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithEndpointList instead. func WithEndpointList(endpoints []string) GenOption { - return func(o *GenOptions) error { - o.EndpointList = endpoints - - return nil - } + return generate.WithEndpointList(endpoints) } // WithLocalAPIServerPort specifies the local API server port for the cluster. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithLocalAPIServerPort instead. func WithLocalAPIServerPort(port int) GenOption { - return func(o *GenOptions) error { - o.LocalAPIServerPort = port - - return nil - } + return generate.WithLocalAPIServerPort(port) } // WithInstallDisk specifies install disk to use in Talos cluster. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithInstallDisk instead. func WithInstallDisk(disk string) GenOption { - return func(o *GenOptions) error { - o.InstallDisk = disk - - return nil - } + return generate.WithInstallDisk(disk) } // WithAdditionalSubjectAltNames specifies additional SANs. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithAdditionalSubjectAltNames instead. func WithAdditionalSubjectAltNames(sans []string) GenOption { - return func(o *GenOptions) error { - o.AdditionalSubjectAltNames = sans - - return nil - } + return generate.WithAdditionalSubjectAltNames(sans) } // WithInstallImage specifies install container image to use in Talos cluster. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithInstallImage instead. func WithInstallImage(imageRef string) GenOption { - return func(o *GenOptions) error { - o.InstallImage = imageRef - - return nil - } + return generate.WithInstallImage(imageRef) } // WithInstallExtraKernelArgs specifies extra kernel arguments to pass to the installer. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithInstallExtraKernelArgs instead. func WithInstallExtraKernelArgs(args []string) GenOption { - return func(o *GenOptions) error { - o.InstallExtraKernelArgs = append(o.InstallExtraKernelArgs, args...) - - return nil - } + return generate.WithInstallExtraKernelArgs(args) } // WithNetworkOptions adds network config generation option. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithNetworkOptions instead. func WithNetworkOptions(opts ...v1alpha1.NetworkConfigOption) GenOption { - return func(o *GenOptions) error { - o.NetworkConfigOptions = append(o.NetworkConfigOptions, opts...) - - return nil - } + return generate.WithNetworkOptions(opts...) } // WithRegistryMirror configures registry mirror endpoint(s). +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithRegistryMirror instead. func WithRegistryMirror(host string, endpoints ...string) GenOption { - return func(o *GenOptions) error { - if o.RegistryMirrors == nil { - o.RegistryMirrors = make(map[string]*v1alpha1.RegistryMirrorConfig) - } - - o.RegistryMirrors[host] = &v1alpha1.RegistryMirrorConfig{MirrorEndpoints: endpoints} - - return nil - } + return generate.WithRegistryMirror(host, endpoints...) } // WithRegistryCACert specifies the certificate of the certificate authority which signed certificate of the registry. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithRegistryCACert instead. func WithRegistryCACert(host, cacert string) GenOption { - return func(o *GenOptions) error { - if o.RegistryConfig == nil { - o.RegistryConfig = make(map[string]*v1alpha1.RegistryConfig) - } - - if _, ok := o.RegistryConfig[host]; !ok { - o.RegistryConfig[host] = &v1alpha1.RegistryConfig{} - } - - if o.RegistryConfig[host].RegistryTLS == nil { - o.RegistryConfig[host].RegistryTLS = &v1alpha1.RegistryTLSConfig{} - } - - o.RegistryConfig[host].RegistryTLS.TLSCA = v1alpha1.Base64Bytes(cacert) - - return nil - } + return generate.WithRegistryCACert(host, cacert) } // WithRegistryInsecureSkipVerify marks registry host to skip TLS verification. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithRegistryInsecureSkipVerify instead. func WithRegistryInsecureSkipVerify(host string) GenOption { - return func(o *GenOptions) error { - if o.RegistryConfig == nil { - o.RegistryConfig = make(map[string]*v1alpha1.RegistryConfig) - } - - if _, ok := o.RegistryConfig[host]; !ok { - o.RegistryConfig[host] = &v1alpha1.RegistryConfig{} - } - - if o.RegistryConfig[host].RegistryTLS == nil { - o.RegistryConfig[host].RegistryTLS = &v1alpha1.RegistryTLSConfig{} - } - - o.RegistryConfig[host].RegistryTLS.TLSInsecureSkipVerify = pointer.To(true) - - return nil - } + return generate.WithRegistryInsecureSkipVerify(host) } // WithDNSDomain specifies domain name to use in Talos cluster. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithDNSDomain instead. func WithDNSDomain(dnsDomain string) GenOption { - return func(o *GenOptions) error { - o.DNSDomain = dnsDomain - - return nil - } + return generate.WithDNSDomain(dnsDomain) } // WithDebug enables verbose logging to console for all services. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithDebug instead. func WithDebug(enable bool) GenOption { - return func(o *GenOptions) error { - o.Debug = enable - - return nil - } + return generate.WithDebug(enable) } // WithPersist enables persistence of machine config across reboots. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithPersist instead. func WithPersist(enable bool) GenOption { - return func(o *GenOptions) error { - o.Persist = enable - - return nil - } + return generate.WithPersist(enable) } // WithClusterCNIConfig specifies custom cluster CNI config. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithClusterCNIConfig instead. func WithClusterCNIConfig(config *v1alpha1.CNIConfig) GenOption { - return func(o *GenOptions) error { - o.CNIConfig = config - - return nil - } + return generate.WithClusterCNIConfig(config) } // WithUserDisks generates user partitions config. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithUserDisks instead. func WithUserDisks(disks []*v1alpha1.MachineDisk) GenOption { - return func(o *GenOptions) error { - o.MachineDisks = disks - - return nil - } + return generate.WithUserDisks(disks) } // WithAllowSchedulingOnControlPlanes specifies AllowSchedulingOnControlPlane flag. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithAllowSchedulingOnControlPlanes instead. func WithAllowSchedulingOnControlPlanes(enabled bool) GenOption { - return func(o *GenOptions) error { - o.AllowSchedulingOnControlPlanes = enabled - - return nil - } + return generate.WithAllowSchedulingOnControlPlanes(enabled) } // WithVersionContract specifies version contract to use when generating. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithVersionContract instead. func WithVersionContract(versionContract *config.VersionContract) GenOption { - return func(o *GenOptions) error { - o.VersionContract = versionContract - - return nil - } + return generate.WithVersionContract(versionContract) } // WithSystemDiskEncryption specifies encryption settings for the system disk partitions. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithSystemDiskEncryption instead. func WithSystemDiskEncryption(cfg *v1alpha1.SystemDiskEncryptionConfig) GenOption { - return func(o *GenOptions) error { - o.SystemDiskEncryptionConfig = cfg - - return nil - } + return generate.WithSystemDiskEncryption(cfg) } // WithRoles specifies user roles. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithRoles instead. func WithRoles(roles role.Set) GenOption { - return func(o *GenOptions) error { - o.Roles = roles - - return nil - } + return generate.WithRoles(roles) } // WithClusterDiscovery enables cluster discovery feature. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithClusterDiscovery instead. func WithClusterDiscovery(enabled bool) GenOption { - return func(o *GenOptions) error { - o.DiscoveryEnabled = pointer.To(enabled) - - return nil - } + return generate.WithClusterDiscovery(enabled) } // WithSysctls merges list of sysctls with new values. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithSysctls instead. func WithSysctls(params map[string]string) GenOption { - return func(o *GenOptions) error { - if o.Sysctls == nil { - o.Sysctls = make(map[string]string) - } - - for k, v := range params { - o.Sysctls[k] = v - } - - return nil - } + return generate.WithSysctls(params) } // WithSecrets reads secrets from a provided file. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.WithSecrets instead. func WithSecrets(file string) GenOption { - return func(o *GenOptions) error { - yamlBytes, err := os.ReadFile(file) + return func(o *generate.Options) error { + bundle, err := secrets.LoadBundle(file) if err != nil { return err } - var secrets SecretsBundle - - err = yaml.Unmarshal(yamlBytes, &secrets) - if err != nil { - return err - } - - secrets.Clock = NewClock() - - o.Secrets = &secrets - - return nil + return generate.WithSecretsBundle(bundle)(o) } } // GenOptions describes generate parameters. -type GenOptions struct { - EndpointList []string - InstallDisk string - InstallImage string - InstallExtraKernelArgs []string - AdditionalSubjectAltNames []string - NetworkConfigOptions []v1alpha1.NetworkConfigOption - CNIConfig *v1alpha1.CNIConfig - RegistryMirrors map[string]*v1alpha1.RegistryMirrorConfig - RegistryConfig map[string]*v1alpha1.RegistryConfig - Sysctls map[string]string - DNSDomain string - Debug bool - Persist bool - AllowSchedulingOnControlPlanes bool - MachineDisks []*v1alpha1.MachineDisk - VersionContract *config.VersionContract - SystemDiskEncryptionConfig *v1alpha1.SystemDiskEncryptionConfig - Roles role.Set - DiscoveryEnabled *bool - LocalAPIServerPort int - Secrets *SecretsBundle -} +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.GenOptions instead. +type GenOptions = generate.Options // DefaultGenOptions returns default options. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.DefaultGenOptions instead. func DefaultGenOptions() GenOptions { - return GenOptions{ - DNSDomain: "cluster.local", - Persist: true, - Roles: role.MakeSet(role.Admin), - } + return generate.DefaultOptions() } diff --git a/pkg/machinery/config/types/v1alpha1/generate/talosconfig.go b/pkg/machinery/config/types/v1alpha1/generate/talosconfig.go index 6b985402c..87b24d647 100644 --- a/pkg/machinery/config/types/v1alpha1/generate/talosconfig.go +++ b/pkg/machinery/config/types/v1alpha1/generate/talosconfig.go @@ -9,14 +9,8 @@ import ( ) // Talosconfig returns the talos admin Talos config. +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/generate.Talosconfig instead. func Talosconfig(in *Input, opts ...GenOption) (*clientconfig.Config, error) { - options := DefaultGenOptions() - - for _, opt := range opts { - if err := opt(&options); err != nil { - return nil, err - } - } - - return clientconfig.NewConfig(in.ClusterName, options.EndpointList, in.Certs.OS.Crt, in.Certs.Admin), nil + return in.Talosconfig() } diff --git a/pkg/machinery/config/types/v1alpha1/machine/machine.go b/pkg/machinery/config/types/v1alpha1/machine/machine.go index d65bc62c7..2bdc49594 100644 --- a/pkg/machinery/config/types/v1alpha1/machine/machine.go +++ b/pkg/machinery/config/types/v1alpha1/machine/machine.go @@ -2,66 +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/. +// Package machine defines common machine type. package machine -import ( - "fmt" -) - -//go:generate stringer -type=Type -linecomment +import "github.com/siderolabs/talos/pkg/machinery/config/machine" // Type represents a machine type. -type Type int - -//structprotogen:gen_enum -const ( - // TypeUnknown represents undefined node type, when there is no machine configuration yet. - TypeUnknown Type = iota // unknown - - // TypeInit type designates the first control plane node to come up. You can think of it like a bootstrap node. - // This node will perform the initial steps to bootstrap the cluster -- generation of TLS assets, starting of the control plane, etc. - TypeInit // init - - // TypeControlPlane designates the node as a control plane member. - // This means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler. - TypeControlPlane // controlplane - - // TypeWorker designates the node as a worker node. - // This means it will be an available compute node for scheduling workloads. - TypeWorker // worker -) - -// ParseType parses string constant as Type. -func ParseType(s string) (Type, error) { - switch s { - case "init": - return TypeInit, nil - case "controlplane": - return TypeControlPlane, nil - case "worker", "join", "": - return TypeWorker, nil - case "unknown": - return TypeUnknown, nil - default: - return TypeUnknown, fmt.Errorf("invalid machine type: %q", s) - } -} - -// MarshalText implements encoding.TextMarshaler. -func (t Type) MarshalText() (text []byte, err error) { - return []byte(t.String()), nil -} - -// UnmarshalText implements encoding.TextUnmarshaler. -func (t *Type) UnmarshalText(text []byte) error { - var err error - - *t, err = ParseType(string(text)) - - return err -} - -// IsControlPlane returns true if the type is a control plane node. -func (t Type) IsControlPlane() bool { - return t == TypeControlPlane || t == TypeInit -} +// +// Deprecated: use github.com/siderolabs/talos/pkg/machinery/config/machine.Type instead. +type Type = machine.Type diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_config_schema_test.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_config_schema_test.go index 5c58e07cd..a95b82a7f 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_config_schema_test.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_config_schema_test.go @@ -15,9 +15,9 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" + "github.com/siderolabs/talos/pkg/machinery/config/generate" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/constants" ) @@ -97,17 +97,14 @@ func TestSchemaValidation(t *testing.T) { } func newConfig(t *testing.T, modifications func(config *v1alpha1.Config), rawModifications func(rawConfig map[string]any)) map[string]any { - bundle, err := generate.NewSecretsBundle(generate.NewClock()) + input, err := generate.NewInput("test", "https://doesntmatter:6443", constants.DefaultKubernetesVersion) require.NoError(t, err) - input, err := generate.NewInput("test", "https://doesntmatter:6443", constants.DefaultKubernetesVersion, bundle) - require.NoError(t, err) - - config, err := generate.Config(machine.TypeControlPlane, input) + config, err := input.Config(machine.TypeControlPlane) require.NoError(t, err) if modifications != nil { - modifications(config) + modifications(config.RawV1Alpha1()) } configBytes, err := config.Bytes() diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_network_options.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_network_options.go index 3d5d4b70d..99a47c3d9 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_network_options.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_network_options.go @@ -7,7 +7,7 @@ package v1alpha1 import ( "github.com/siderolabs/go-pointer" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // NetworkConfigOption generates NetworkConfig. diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go index d0217622c..908445363 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go @@ -19,16 +19,27 @@ import ( "github.com/siderolabs/go-pointer" "github.com/siderolabs/talos/pkg/machinery/config/config" - "github.com/siderolabs/talos/pkg/machinery/config/encoder" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" ) +// Verify interfaces. +var ( + _ config.Document = (*Config)(nil) + _ config.SecretDocument = (*Config)(nil) + _ config.Validator = (*Config)(nil) +) + const ( // Version is the version string for v1alpha1. Version = "v1alpha1" ) +// Clone implements config.Document interface. +func (c *Config) Clone() config.Document { + return c.DeepCopy() +} + // Debug implements the config.Provider interface. func (c *Config) Debug() bool { return pointer.SafeDeref(c.ConfigDebug) @@ -77,32 +88,12 @@ func (c *Config) Cluster() config.ClusterConfig { return c.ClusterConfig } -// EncodeString implements the config.Provider interface. -func (c *Config) EncodeString(options ...encoder.Option) (string, error) { - b, err := c.EncodeBytes(options...) - if err != nil { - return "", err - } - - return string(b), nil -} - -// EncodeBytes implements the config.Provider interface. -func (c *Config) EncodeBytes(options ...encoder.Option) ([]byte, error) { - return encoder.NewEncoder(c, options...).Encode() -} - -// Bytes implements the config.Provider interface. -func (c *Config) Bytes() ([]byte, error) { - return c.EncodeBytes() -} - -// RedactSecrets implements the config.Provider interface. +// Redact implements the config.SecretDocument interface. // //nolint:gocyclo -func (c *Config) RedactSecrets(replacement string) config.Encoder { +func (c *Config) Redact(replacement string) { if c == nil { - return nil + return } redactBytes := func(b []byte) []byte { @@ -117,44 +108,35 @@ func (c *Config) RedactSecrets(replacement string) config.Encoder { return string(redactBytes([]byte(s))) } - clone := c.DeepCopy() - - if clone.MachineConfig != nil { - clone.MachineConfig.MachineToken = redactStr(clone.MachineConfig.MachineToken) - if clone.MachineConfig.MachineCA != nil { - clone.MachineConfig.MachineCA.Key = redactBytes(clone.MachineConfig.MachineCA.Key) + if c.MachineConfig != nil { + c.MachineConfig.MachineToken = redactStr(c.MachineConfig.MachineToken) + if c.MachineConfig.MachineCA != nil { + c.MachineConfig.MachineCA.Key = redactBytes(c.MachineConfig.MachineCA.Key) } } - if clone.ClusterConfig != nil { - clone.ClusterConfig.ClusterSecret = redactStr(clone.ClusterConfig.ClusterSecret) - clone.ClusterConfig.BootstrapToken = redactStr(clone.ClusterConfig.BootstrapToken) - clone.ClusterConfig.ClusterAESCBCEncryptionSecret = redactStr(clone.ClusterConfig.ClusterAESCBCEncryptionSecret) - clone.ClusterConfig.ClusterSecretboxEncryptionSecret = redactStr(clone.ClusterConfig.ClusterSecretboxEncryptionSecret) + if c.ClusterConfig != nil { + c.ClusterConfig.ClusterSecret = redactStr(c.ClusterConfig.ClusterSecret) + c.ClusterConfig.BootstrapToken = redactStr(c.ClusterConfig.BootstrapToken) + c.ClusterConfig.ClusterAESCBCEncryptionSecret = redactStr(c.ClusterConfig.ClusterAESCBCEncryptionSecret) + c.ClusterConfig.ClusterSecretboxEncryptionSecret = redactStr(c.ClusterConfig.ClusterSecretboxEncryptionSecret) - if clone.ClusterConfig.ClusterServiceAccount != nil { - clone.ClusterConfig.ClusterServiceAccount.Key = redactBytes(clone.ClusterConfig.ClusterServiceAccount.Key) + if c.ClusterConfig.ClusterServiceAccount != nil { + c.ClusterConfig.ClusterServiceAccount.Key = redactBytes(c.ClusterConfig.ClusterServiceAccount.Key) } - if clone.ClusterConfig.ClusterCA != nil { - clone.ClusterConfig.ClusterCA.Key = redactBytes(clone.ClusterConfig.ClusterCA.Key) + if c.ClusterConfig.ClusterCA != nil { + c.ClusterConfig.ClusterCA.Key = redactBytes(c.ClusterConfig.ClusterCA.Key) } - if clone.ClusterConfig.ClusterAggregatorCA != nil { - clone.ClusterConfig.ClusterAggregatorCA.Key = redactBytes(clone.ClusterConfig.ClusterAggregatorCA.Key) + if c.ClusterConfig.ClusterAggregatorCA != nil { + c.ClusterConfig.ClusterAggregatorCA.Key = redactBytes(c.ClusterConfig.ClusterAggregatorCA.Key) } - if clone.ClusterConfig.EtcdConfig != nil && clone.ClusterConfig.EtcdConfig.RootCA != nil { - clone.ClusterConfig.EtcdConfig.RootCA.Key = redactBytes(clone.ClusterConfig.EtcdConfig.RootCA.Key) + if c.ClusterConfig.EtcdConfig != nil && c.ClusterConfig.EtcdConfig.RootCA != nil { + c.ClusterConfig.EtcdConfig.RootCA.Key = redactBytes(c.ClusterConfig.EtcdConfig.RootCA.Key) } } - - return clone -} - -// RawV1Alpha1 implements the config.Provider interface. -func (c *Config) RawV1Alpha1() *Config { - return c } // Install implements the config.Provider interface. diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_readonly_provider.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_readonly_provider.go deleted file mode 100644 index 4dc90369c..000000000 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_readonly_provider.go +++ /dev/null @@ -1,83 +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 v1alpha1 - -import ( - "errors" - - "github.com/siderolabs/talos/pkg/machinery/config/config" - "github.com/siderolabs/talos/pkg/machinery/config/encoder" - "github.com/siderolabs/talos/pkg/machinery/config/validation" -) - -// ReadonlyProvider wraps the *v1alpha1.Config to make config read-only. -// -// +k8s:deepcopy-gen=false -type ReadonlyProvider struct { - cfg *Config - bytes []byte -} - -// WrapReadonly the v1alpha.Config providing read-only interface to it. -func WrapReadonly(cfg *Config, bytes []byte) *ReadonlyProvider { - return &ReadonlyProvider{ - cfg: cfg, - bytes: bytes, - } -} - -// Debug implements the config.Provider interface. -func (r *ReadonlyProvider) Debug() bool { - return r.cfg.Debug() -} - -// Persist implements the config.Provider interface. -func (r *ReadonlyProvider) Persist() bool { - return r.cfg.Persist() -} - -// Machine implements the config.Provider interface. -func (r *ReadonlyProvider) Machine() config.MachineConfig { - return r.cfg.Machine() -} - -// Cluster implements the config.Provider interface. -func (r *ReadonlyProvider) Cluster() config.ClusterConfig { - return r.cfg.Cluster() -} - -// Validate checks configuration and returns warnings and fatal errors (as multierror). -func (r *ReadonlyProvider) Validate(mode validation.RuntimeMode, opts ...validation.Option) ([]string, error) { - return r.cfg.Validate(mode, opts...) -} - -// Bytes returns source YAML representation (if available) or does default encoding. -func (r *ReadonlyProvider) Bytes() ([]byte, error) { - if r.bytes == nil { - return r.bytes, errors.New("incorrect provider state: bytes is nil") - } - - return r.bytes, nil -} - -// RedactSecrets implements the config.Provider interface. -func (r *ReadonlyProvider) RedactSecrets(replacement string) config.Encoder { - return r.cfg.RedactSecrets(replacement) -} - -// EncodeString implements the config.Provider interface. -func (r *ReadonlyProvider) EncodeString(encoderOptions ...encoder.Option) (string, error) { - return r.cfg.EncodeString(encoderOptions...) -} - -// EncodeBytes implements the config.Provider interface. -func (r *ReadonlyProvider) EncodeBytes(encoderOptions ...encoder.Option) ([]byte, error) { - return r.cfg.EncodeBytes(encoderOptions...) -} - -// RawV1Alpha1 implements the config.Provider interface. -func (r *ReadonlyProvider) RawV1Alpha1() *Config { - return r.cfg.DeepCopy() -} diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_redact_test.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_redact_test.go index 3fde23edf..6207277fe 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_redact_test.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_redact_test.go @@ -9,24 +9,22 @@ import ( "github.com/stretchr/testify/require" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/generate" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" ) func TestRedactSecrets(t *testing.T) { - bundle, err := generate.NewSecretsBundle(generate.NewClock()) + input, err := generate.NewInput("test", "https://doesntmatter:6443", constants.DefaultKubernetesVersion) require.NoError(t, err) - input, err := generate.NewInput("test", "https://doesntmatter:6443", constants.DefaultKubernetesVersion, bundle) - require.NoError(t, err) - - config, err := generate.Config(machine.TypeControlPlane, input) + container, err := input.Config(machine.TypeControlPlane) if err != nil { return } + config := container.RawV1Alpha1() + require.NotEmpty(t, config.MachineConfig.MachineToken) require.NotEmpty(t, config.MachineConfig.MachineCA.Key) require.NotEmpty(t, config.ClusterConfig.ClusterSecret) @@ -39,26 +37,15 @@ func TestRedactSecrets(t *testing.T) { replacement := "**.***" - configBytesBefore, err := config.Bytes() - require.NoError(t, err) + config.Redact(replacement) - redacted := config.RedactSecrets(replacement) - - configBytesAfter, err := config.Bytes() - require.NoError(t, err) - - require.Equal(t, string(configBytesBefore), string(configBytesAfter), "original config is modified") - - redactedCfg, ok := redacted.(*v1alpha1.Config) - require.True(t, ok) - - require.Equal(t, replacement, redactedCfg.Machine().Security().Token()) - require.Equal(t, replacement, string(redactedCfg.Machine().Security().CA().Key)) - require.Equal(t, replacement, redactedCfg.Cluster().Secret()) - require.Equal(t, "***", redactedCfg.Cluster().Token().Secret()) - require.Equal(t, "", redactedCfg.Cluster().AESCBCEncryptionSecret()) - require.Equal(t, replacement, redactedCfg.Cluster().SecretboxEncryptionSecret()) - require.Equal(t, replacement, string(redactedCfg.Cluster().CA().Key)) - require.Equal(t, replacement, string(redactedCfg.Cluster().Etcd().CA().Key)) - require.Equal(t, replacement, string(redactedCfg.Cluster().ServiceAccount().Key)) + require.Equal(t, replacement, config.Machine().Security().Token()) + require.Equal(t, replacement, string(config.Machine().Security().CA().Key)) + require.Equal(t, replacement, config.Cluster().Secret()) + require.Equal(t, "***", config.Cluster().Token().Secret()) + require.Equal(t, "", config.Cluster().AESCBCEncryptionSecret()) + require.Equal(t, replacement, config.Cluster().SecretboxEncryptionSecret()) + require.Equal(t, replacement, string(config.Cluster().CA().Key)) + require.Equal(t, replacement, string(config.Cluster().Etcd().CA().Key)) + require.Equal(t, replacement, string(config.Cluster().ServiceAccount().Key)) } diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_strategic_merge_test.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_strategic_merge_test.go index 9311e40e8..092c5111a 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_strategic_merge_test.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_strategic_merge_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/require" "github.com/siderolabs/talos/pkg/machinery/config/configloader" + "github.com/siderolabs/talos/pkg/machinery/config/container" "github.com/siderolabs/talos/pkg/machinery/config/encoder" "github.com/siderolabs/talos/pkg/machinery/config/merge" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" @@ -53,7 +54,10 @@ func testMerge(path string) func(t *testing.T) { err := merge.Merge(result, right) require.NoError(t, err) - marshaled, err := result.EncodeString(encoder.WithComments(encoder.CommentsDisabled)) + ctr, err := container.New(result) + require.NoError(t, err) + + marshaled, err := ctr.EncodeString(encoder.WithComments(encoder.CommentsDisabled)) require.NoError(t, err) assert.Equal(t, expected, result, "got:\n%v", marshaled) diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go index aa6a82a42..09f4424b3 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go @@ -35,13 +35,13 @@ import ( "github.com/siderolabs/talos/pkg/machinery/config/config" "github.com/siderolabs/talos/pkg/machinery/config/internal/registry" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/merge" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/siderolabs/talos/pkg/machinery/constants" ) func init() { - registry.Register("v1alpha1", func(version string) any { + registry.Register("v1alpha1", func(version string) config.Document { return &Config{} }) } diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_validation.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_validation.go index 7c69fbd0b..3fea73088 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_validation.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_validation.go @@ -21,7 +21,7 @@ import ( sideronet "github.com/siderolabs/net" "github.com/siderolabs/talos/pkg/machinery/config/config" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/validation" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/kubelet" diff --git a/pkg/machinery/proto/proto_test.go b/pkg/machinery/proto/proto_test.go index ed995f63d..7927d9956 100644 --- a/pkg/machinery/proto/proto_test.go +++ b/pkg/machinery/proto/proto_test.go @@ -17,7 +17,7 @@ import ( clusterpb "github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/cluster" "github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums" networkpb "github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/network" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/nethelpers" "github.com/siderolabs/talos/pkg/machinery/proto" "github.com/siderolabs/talos/pkg/machinery/resources/cluster" diff --git a/pkg/machinery/resources/cluster/affiliate.go b/pkg/machinery/resources/cluster/affiliate.go index ad117d9b0..5756ba731 100644 --- a/pkg/machinery/resources/cluster/affiliate.go +++ b/pkg/machinery/resources/cluster/affiliate.go @@ -13,7 +13,7 @@ import ( "github.com/cosi-project/runtime/pkg/resource/typed" "github.com/siderolabs/gen/value" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/proto" ) diff --git a/pkg/machinery/resources/cluster/affiliate_test.go b/pkg/machinery/resources/cluster/affiliate_test.go index b45c14b29..c05a6111d 100644 --- a/pkg/machinery/resources/cluster/affiliate_test.go +++ b/pkg/machinery/resources/cluster/affiliate_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/cluster" ) diff --git a/pkg/machinery/resources/cluster/member.go b/pkg/machinery/resources/cluster/member.go index a9a7017f3..2a5733a77 100644 --- a/pkg/machinery/resources/cluster/member.go +++ b/pkg/machinery/resources/cluster/member.go @@ -12,7 +12,7 @@ import ( "github.com/cosi-project/runtime/pkg/resource/protobuf" "github.com/cosi-project/runtime/pkg/resource/typed" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/proto" ) diff --git a/pkg/machinery/resources/config/machine_config.go b/pkg/machinery/resources/config/machine_config.go index 8c4795723..412d782ef 100644 --- a/pkg/machinery/resources/config/machine_config.go +++ b/pkg/machinery/resources/config/machine_config.go @@ -12,7 +12,6 @@ import ( configpb "github.com/siderolabs/talos/pkg/machinery/api/resource/config" "github.com/siderolabs/talos/pkg/machinery/config" "github.com/siderolabs/talos/pkg/machinery/config/configloader" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/proto" ) @@ -61,14 +60,10 @@ func (r *MachineConfig) Spec() interface{} { // DeepCopy implements resource.Resource. func (r *MachineConfig) DeepCopy() resource.Resource { - var cfgCopy config.Provider + cfgCopy := r.spec.cfg - switch r.spec.cfg.(type) { - case *v1alpha1.ReadonlyProvider: - // don't copy read only config - cfgCopy = r.spec.cfg - default: - cfgCopy = r.spec.cfg.RawV1Alpha1().DeepCopy() + if !cfgCopy.Readonly() { + cfgCopy = cfgCopy.Clone() } return &MachineConfig{ diff --git a/pkg/machinery/resources/config/machine_type.go b/pkg/machinery/resources/config/machine_type.go index d5b82a353..8916aed01 100644 --- a/pkg/machinery/resources/config/machine_type.go +++ b/pkg/machinery/resources/config/machine_type.go @@ -10,7 +10,7 @@ import ( "github.com/cosi-project/runtime/pkg/resource/protobuf" configpb "github.com/siderolabs/talos/pkg/machinery/api/resource/config" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/proto" ) diff --git a/pkg/machinery/resources/config/machine_type_test.go b/pkg/machinery/resources/config/machine_type_test.go index 36e9411d1..7c3e995b9 100644 --- a/pkg/machinery/resources/config/machine_type_test.go +++ b/pkg/machinery/resources/config/machine_type_test.go @@ -11,7 +11,7 @@ import ( "github.com/cosi-project/runtime/pkg/resource/protobuf" "github.com/stretchr/testify/require" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/resources/config" ) diff --git a/pkg/minimal/limits.go b/pkg/minimal/limits.go index 1e9ee25d1..95da4f27a 100644 --- a/pkg/minimal/limits.go +++ b/pkg/minimal/limits.go @@ -10,7 +10,7 @@ import ( "github.com/dustin/go-humanize" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // Memory returns the minimal/recommended amount of memory required to run the node. diff --git a/pkg/provision/access/adapter.go b/pkg/provision/access/adapter.go index e1e5ea565..399d4760c 100644 --- a/pkg/provision/access/adapter.go +++ b/pkg/provision/access/adapter.go @@ -6,7 +6,7 @@ package access import ( "github.com/siderolabs/talos/pkg/cluster" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/provision" ) diff --git a/pkg/provision/providers/docker/docker.go b/pkg/provision/providers/docker/docker.go index 31cbb82c0..2b1f46c40 100644 --- a/pkg/provision/providers/docker/docker.go +++ b/pkg/provision/providers/docker/docker.go @@ -13,8 +13,8 @@ import ( "github.com/docker/docker/client" + "github.com/siderolabs/talos/pkg/machinery/config/generate" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" "github.com/siderolabs/talos/pkg/provision" ) @@ -46,7 +46,7 @@ func (p *provisioner) Close() error { } // GenOptions provides a list of additional config generate options. -func (p *provisioner) GenOptions(networkReq provision.NetworkRequest) []generate.GenOption { +func (p *provisioner) GenOptions(networkReq provision.NetworkRequest) []generate.Option { nameservers := make([]string, 0, len(networkReq.Nameservers)) hasV4 := false @@ -69,7 +69,7 @@ func (p *provisioner) GenOptions(networkReq provision.NetworkRequest) []generate } } - return []generate.GenOption{ + return []generate.Option{ generate.WithNetworkOptions( v1alpha1.WithNetworkInterfaceIgnore("eth0"), v1alpha1.WithNetworkNameservers(nameservers...), diff --git a/pkg/provision/providers/docker/node.go b/pkg/provision/providers/docker/node.go index abc115253..dac0f6263 100644 --- a/pkg/provision/providers/docker/node.go +++ b/pkg/provision/providers/docker/node.go @@ -20,7 +20,7 @@ import ( "github.com/docker/go-connections/nat" "github.com/hashicorp/go-multierror" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/provision" ) diff --git a/pkg/provision/providers/docker/reflect.go b/pkg/provision/providers/docker/reflect.go index 4cabd5a8d..1e7d7562f 100644 --- a/pkg/provision/providers/docker/reflect.go +++ b/pkg/provision/providers/docker/reflect.go @@ -10,7 +10,7 @@ import ( "strconv" "strings" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/provision" ) diff --git a/pkg/provision/providers/qemu/qemu.go b/pkg/provision/providers/qemu/qemu.go index 1aaa8c9be..53675378b 100644 --- a/pkg/provision/providers/qemu/qemu.go +++ b/pkg/provision/providers/qemu/qemu.go @@ -7,8 +7,8 @@ package qemu import ( "context" + "github.com/siderolabs/talos/pkg/machinery/config/generate" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" "github.com/siderolabs/talos/pkg/provision" "github.com/siderolabs/talos/pkg/provision/providers/vm" ) @@ -34,7 +34,7 @@ func (p *provisioner) Close() error { } // GenOptions provides a list of additional config generate options. -func (p *provisioner) GenOptions(networkReq provision.NetworkRequest) []generate.GenOption { +func (p *provisioner) GenOptions(networkReq provision.NetworkRequest) []generate.Option { hasIPv4 := false hasIPv6 := false @@ -46,7 +46,7 @@ func (p *provisioner) GenOptions(networkReq provision.NetworkRequest) []generate } } - return []generate.GenOption{ + return []generate.Option{ generate.WithInstallDisk("/dev/vda"), generate.WithInstallExtraKernelArgs([]string{ "console=ttyS0", // TODO: should depend on arch diff --git a/pkg/provision/provision.go b/pkg/provision/provision.go index 6f4a08bdf..1c62b3a37 100644 --- a/pkg/provision/provision.go +++ b/pkg/provision/provision.go @@ -9,7 +9,7 @@ import ( "context" "io" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate" + "github.com/siderolabs/talos/pkg/machinery/config/generate" ) // Provisioner is an interface each provisioner should implement. @@ -21,7 +21,7 @@ type Provisioner interface { Reflect(ctx context.Context, clusterName, stateDirectory string) (Cluster, error) - GenOptions(NetworkRequest) []generate.GenOption + GenOptions(NetworkRequest) []generate.Option GetLoadBalancers(NetworkRequest) (internalEndpoint, externalEndpoint string) GetFirstInterface() string diff --git a/pkg/provision/request.go b/pkg/provision/request.go index 2ebc98758..259738093 100644 --- a/pkg/provision/request.go +++ b/pkg/provision/request.go @@ -11,8 +11,8 @@ import ( "github.com/siderolabs/go-procfs/procfs" "github.com/siderolabs/talos/pkg/machinery/config" + "github.com/siderolabs/talos/pkg/machinery/config/machine" "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" ) // ClusterRequest is the root object describing cluster to be provisioned. diff --git a/pkg/provision/result.go b/pkg/provision/result.go index d2f60c405..9298f35a1 100644 --- a/pkg/provision/result.go +++ b/pkg/provision/result.go @@ -9,7 +9,7 @@ import ( "github.com/google/uuid" - "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/siderolabs/talos/pkg/machinery/config/machine" ) // Cluster describes the provisioned Cluster.