diff --git a/cmd/osctl/cmd/cluster.go b/cmd/osctl/cmd/cluster.go index f4d8f4cc3..37a9107d5 100644 --- a/cmd/osctl/cmd/cluster.go +++ b/cmd/osctl/cmd/cluster.go @@ -25,6 +25,7 @@ import ( "github.com/talos-systems/talos/cmd/osctl/cmd/cluster/pkg/node" "github.com/talos-systems/talos/cmd/osctl/pkg/client/config" "github.com/talos-systems/talos/cmd/osctl/pkg/helpers" + "github.com/talos-systems/talos/pkg/constants" "github.com/talos-systems/talos/pkg/userdata/v1alpha1/generate" "github.com/talos-systems/talos/pkg/version" ) @@ -105,7 +106,7 @@ func create() (err error) { ips[i] = fmt.Sprintf(baseNetwork, i+2) } - input, err := generate.NewInput(clusterName, ips) + input, err := generate.NewInput(clusterName, ips, kubernetesVersion) if err != nil { return err } @@ -363,6 +364,7 @@ func init() { clusterUpCmd.Flags().IntVar(&masters, "masters", 3, "the number of masters to create") clusterUpCmd.Flags().StringVar(&clusterCpus, "cpus", "1.5", "the share of CPUs as fraction (each container)") clusterUpCmd.Flags().IntVar(&clusterMemory, "memory", 1024, "the limit on memory usage in MB (each container)") + clusterUpCmd.Flags().StringVar(&kubernetesVersion, "kubernetes-version", constants.DefaultKubernetesVersion, "desired kubernetes version to run") clusterCmd.PersistentFlags().StringVar(&clusterName, "name", "talos_default", "the name of the cluster") clusterCmd.AddCommand(clusterUpCmd) clusterCmd.AddCommand(clusterDownCmd) diff --git a/cmd/osctl/cmd/config.go b/cmd/osctl/cmd/config.go index 4edf59664..24983807b 100644 --- a/cmd/osctl/cmd/config.go +++ b/cmd/osctl/cmd/config.go @@ -18,6 +18,7 @@ import ( "github.com/talos-systems/talos/cmd/osctl/pkg/client/config" "github.com/talos-systems/talos/cmd/osctl/pkg/helpers" + "github.com/talos-systems/talos/pkg/constants" udv0 "github.com/talos-systems/talos/pkg/userdata" udgenv0 "github.com/talos-systems/talos/pkg/userdata/generate" "github.com/talos-systems/talos/pkg/userdata/translate" @@ -26,7 +27,10 @@ import ( "gopkg.in/yaml.v2" ) -var genVersion string +var ( + configVersion string + kubernetesVersion string +) // configCmd represents the config command. var configCmd = &cobra.Command{ @@ -133,7 +137,7 @@ var configGenerateCmd = &cobra.Command{ if len(args) != 2 { log.Fatal("expected a cluster name and comma delimited list of IP addresses") } - switch genVersion { + switch configVersion { case "v0": genV0Userdata(args) case "v1alpha1": @@ -143,7 +147,7 @@ var configGenerateCmd = &cobra.Command{ } func genV0Userdata(args []string) { - input, err := udgenv0.NewInput(args[0], strings.Split(args[1], ",")) + input, err := udgenv0.NewInput(args[0], strings.Split(args[1], ","), kubernetesVersion) if err != nil { helpers.Fatalf("failed to generate PKI and tokens: %v", err) } @@ -206,7 +210,7 @@ func writeV0Userdata(input *udgenv0.Input, t udgenv0.Type, name string) (err err } func genV1Alpha1Userdata(args []string) { - input, err := udgenv1alpha1.NewInput(args[0], strings.Split(args[1], ",")) + input, err := udgenv1alpha1.NewInput(args[0], strings.Split(args[1], ","), kubernetesVersion) if err != nil { helpers.Fatalf("failed to generate PKI and tokens: %v", err) } @@ -270,9 +274,11 @@ func writeV1Alpha1Userdata(input *udgenv1alpha1.Input, t udgenv1alpha1.Type, nam if err = ud.Validate(); err != nil { return err } + if err = ioutil.WriteFile(strings.ToLower(name)+".yaml", []byte(data), 0644); err != nil { return err } + return nil } @@ -283,7 +289,8 @@ func init() { configAddCmd.Flags().StringVar(&key, "key", "", "the path to the key") configGenerateCmd.Flags().StringSliceVar(&additionalSANs, "additional-sans", []string{}, "additional Subject-Alt-Names for the APIServer certificate") configGenerateCmd.Flags().StringVar(&canonicalControlplaneEndpoint, "controlplane-endpoint", "", "the canonical controlplane endpoint (IP or DNS name) and optional port (defaults to 6443)") - configGenerateCmd.Flags().StringVar(&genVersion, "version", "v0", "desired machine config version to generate") + configGenerateCmd.Flags().StringVar(&configVersion, "version", "v0", "desired machine config version to generate") + configGenerateCmd.Flags().StringVar(&kubernetesVersion, "kubernetes-version", constants.DefaultKubernetesVersion, "desired kubernetes version to run") helpers.Should(configGenerateCmd.Flags().MarkDeprecated("version", "the v0 version of machine config will be removed in the next version of Talos")) helpers.Should(configAddCmd.MarkFlagRequired("ca")) helpers.Should(configAddCmd.MarkFlagRequired("crt")) diff --git a/cmd/osctl/cmd/install_linux.go b/cmd/osctl/cmd/install_linux.go index b1449bc85..abb34ae66 100644 --- a/cmd/osctl/cmd/install_linux.go +++ b/cmd/osctl/cmd/install_linux.go @@ -40,15 +40,22 @@ var installCmd = &cobra.Command{ platform, err := platform.NewPlatform() if err == nil { - data, err = platform.UserData() - if err != nil { - log.Fatal(err) + if platform.Name() != platformArg { + log.Println("platform mismatch") + } else { + data, err = platform.UserData() + if err != nil { + log.Fatal(err) + } } - } else { + } + + if data == nil { // Ignore userdata load errors, since it need not necessarily exist yet. log.Printf("failed to source userdata from platform; falling back to defaults: %v", err) data = &userdata.UserData{ - Install: &userdata.Install{}, + KubernetesVersion: constants.DefaultKubernetesVersion, + Install: &userdata.Install{}, } } diff --git a/go.mod b/go.mod index d05abcdb5..16cf7fa29 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( code.cloudfoundry.org/bytefmt v0.0.0-20180906201452-2aa6f33b730c github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e github.com/beevik/ntp v0.2.0 + github.com/blang/semver v3.5.0+incompatible github.com/containerd/cgroups v0.0.0-20190328223300-4994991857f9 github.com/containerd/containerd v1.2.7 github.com/containerd/continuity v0.0.0-20181003075958-be9bd761db19 // indirect diff --git a/go.sum b/go.sum index e45523b92..e14773eee 100644 --- a/go.sum +++ b/go.sum @@ -50,6 +50,7 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU= +github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/bradbeam/rtnetlink v0.0.0-20190820045831-7b9ca088b93d h1:w82c4zYkkMi98stDhWV5EB/+Pt6q8eyMzmtnzwy1HSs= diff --git a/internal/app/machined/pkg/system/services/kubeadm.go b/internal/app/machined/pkg/system/services/kubeadm.go index 278d3d765..c8cbfc382 100644 --- a/internal/app/machined/pkg/system/services/kubeadm.go +++ b/internal/app/machined/pkg/system/services/kubeadm.go @@ -56,8 +56,9 @@ func (k *Kubeadm) PreFunc(ctx context.Context, data *userdata.UserData) (err err // Pull the image and unpack it. containerdctx := namespaces.WithNamespace(ctx, "k8s.io") - if _, err = client.Pull(containerdctx, constants.KubernetesImage, containerdapi.WithPullUnpack); err != nil { - return fmt.Errorf("failed to pull image %q: %v", constants.KubernetesImage, err) + image := fmt.Sprintf("%s:v%s", constants.KubernetesImage, data.KubernetesVersion) + if _, err = client.Pull(containerdctx, image, containerdapi.WithPullUnpack); err != nil { + return fmt.Errorf("failed to pull image %q: %v", image, err) } return nil @@ -82,7 +83,7 @@ func (k *Kubeadm) Condition(data *userdata.UserData) conditions.Condition { // Runner implements the Service interface. func (k *Kubeadm) Runner(data *userdata.UserData) (runner.Runner, error) { - image := constants.KubernetesImage + image := fmt.Sprintf("%s:v%s", constants.KubernetesImage, data.KubernetesVersion) // We only wan't to run kubeadm if it hasn't been ran already. if _, err := os.Stat("/etc/kubernetes/kubelet.conf"); !os.IsNotExist(err) { diff --git a/internal/app/machined/pkg/system/services/kubeadm/kubeadm.go b/internal/app/machined/pkg/system/services/kubeadm/kubeadm.go index b47f5f197..ad5dc5839 100644 --- a/internal/app/machined/pkg/system/services/kubeadm/kubeadm.go +++ b/internal/app/machined/pkg/system/services/kubeadm/kubeadm.go @@ -95,7 +95,7 @@ func editClusterConfig(data *userdata.UserData) (err error) { } // Hardcodes specific kubeadm config parameters - clusterConfiguration.KubernetesVersion = constants.KubernetesVersion + clusterConfiguration.KubernetesVersion = data.KubernetesVersion clusterConfiguration.UseHyperKubeImage = true // Apply CIS hardening recommendations; only generate encryption token only if we're the bootstrap node diff --git a/internal/app/machined/pkg/system/services/kubelet.go b/internal/app/machined/pkg/system/services/kubelet.go index 9100a30b0..e08409e67 100644 --- a/internal/app/machined/pkg/system/services/kubelet.go +++ b/internal/app/machined/pkg/system/services/kubelet.go @@ -58,7 +58,7 @@ func (k *Kubelet) DependsOn(data *userdata.UserData) []string { // Runner implements the Service interface. func (k *Kubelet) Runner(data *userdata.UserData) (runner.Runner, error) { - image := constants.KubernetesImage + image := fmt.Sprintf("%s:v%s", constants.KubernetesImage, data.KubernetesVersion) // Set the process arguments. args := runner.Args{ diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index fc715dd10..7be713357 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -105,11 +105,11 @@ const ( // KubeadmEtcdPeerKey is the path to the etcd CA private key. KubeadmEtcdPeerKey = v1beta1.DefaultCertificatesDir + "/" + constants.EtcdPeerKeyName - // KubernetesVersion is the enforced target version of the control plane. - KubernetesVersion = "v1.16.0" + // DefaultKubernetesVersion is the default target version of the control plane. + DefaultKubernetesVersion = "1.16.0" // KubernetesImage is the enforced hyperkube image to use for the control plane. - KubernetesImage = "k8s.gcr.io/hyperkube:" + KubernetesVersion + KubernetesImage = "k8s.gcr.io/hyperkube" // UserDataPath is the path to the downloaded user data. UserDataPath = "/run/userdata.yaml" diff --git a/pkg/userdata/download/download_test.go b/pkg/userdata/download/download_test.go index 980dbb5a9..1bdb70893 100644 --- a/pkg/userdata/download/download_test.go +++ b/pkg/userdata/download/download_test.go @@ -110,6 +110,7 @@ machine: install: {} cluster: controlPlane: + version: 1.16.0 ips: - 10.254.0.10 clusterName: spencer-test @@ -131,6 +132,7 @@ cluster: // nolint: lll const testV0Config = `version: "" +kubernetesVersion: 1.16.0 security: os: ca: diff --git a/pkg/userdata/generate/controlplane.go b/pkg/userdata/generate/controlplane.go index 57f17a8a3..4bb455196 100644 --- a/pkg/userdata/generate/controlplane.go +++ b/pkg/userdata/generate/controlplane.go @@ -6,6 +6,7 @@ package generate const controlPlaneTempl = `#!talos version: "" +kubernetesVersion: {{ .KubernetesVersion }} security: os: ca: diff --git a/pkg/userdata/generate/generate.go b/pkg/userdata/generate/generate.go index 16d98a00d..04702dcbe 100644 --- a/pkg/userdata/generate/generate.go +++ b/pkg/userdata/generate/generate.go @@ -19,10 +19,12 @@ import ( "text/template" "time" + "gopkg.in/yaml.v2" + "github.com/talos-systems/talos/internal/pkg/cis" - "github.com/talos-systems/talos/pkg/constants" "github.com/talos-systems/talos/pkg/crypto/x509" tnet "github.com/talos-systems/talos/pkg/net" + "github.com/talos-systems/talos/pkg/userdata" ) // DefaultIPv4PodNet is the network to be used for kubernetes Pods when using IPv4-based master nodes @@ -214,7 +216,7 @@ func isIPv6(addrs ...string) bool { // NewInput generates the sensitive data required to generate all userdata // types. // nolint: dupl,gocyclo -func NewInput(clustername string, masterIPs []string) (input *Input, err error) { +func NewInput(clustername string, masterIPs []string, kubernetesVersion string) (input *Input, err error) { var loopbackIP, podNet, serviceNet string if isIPv6(masterIPs...) { @@ -348,7 +350,7 @@ func NewInput(clustername string, masterIPs []string) (input *Input, err error) ServiceNet: []string{serviceNet}, ServiceDomain: "cluster.local", ClusterName: clustername, - KubernetesVersion: constants.KubernetesVersion, + KubernetesVersion: kubernetesVersion, KubeadmTokens: kubeadmTokens, TrustdInfo: trustdInfo, } @@ -399,24 +401,14 @@ func Userdata(t Type, in *Input) (string, error) { return "", err } - // TODO: We cant implement this currently because of - // issues with kubeadm dependency mismatch between - // talos and clusterapi//kubebuilder. - // We should figure out way we can work around/through - // this - /* - // Create an actual userdata struct from the - // generated data so we can call validate - // and ensure we are providing proper data - data := &userdata.UserData{} - if err = yaml.Unmarshal([]byte(ud), data); err != nil { - return "", err - } + data := &userdata.UserData{} + if err = yaml.Unmarshal([]byte(ud), data); err != nil { + return "", err + } - if err = data.Validate(); err != nil { - return "", err - } - */ + if err = data.Validate(); err != nil { + return "", err + } return ud, nil } diff --git a/pkg/userdata/generate/generate_test.go b/pkg/userdata/generate/generate_test.go index aa8aee438..e34f80ea9 100644 --- a/pkg/userdata/generate/generate_test.go +++ b/pkg/userdata/generate/generate_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/suite" "gopkg.in/yaml.v2" + "github.com/talos-systems/talos/pkg/constants" "github.com/talos-systems/talos/pkg/userdata" "github.com/talos-systems/talos/pkg/userdata/generate" ) @@ -31,10 +32,10 @@ func TestGenerateSuite(t *testing.T) { func (suite *GenerateSuite) SetupSuite() { var err error - input, err = generate.NewInput("test", []string{"10.0.1.5", "10.0.1.6", "10.0.1.7"}) + input, err = generate.NewInput("test", []string{"10.0.1.5", "10.0.1.6", "10.0.1.7"}, constants.DefaultKubernetesVersion) suite.Require().NoError(err) - inputv6, err = generate.NewInput("test", []string{"2001:db8::1", "2001:db8::2", "2001:db8::3"}) + inputv6, err = generate.NewInput("test", []string{"2001:db8::1", "2001:db8::2", "2001:db8::3"}, constants.DefaultKubernetesVersion) suite.Require().NoError(err) } diff --git a/pkg/userdata/generate/init.go b/pkg/userdata/generate/init.go index 4480f0298..968c1a64e 100644 --- a/pkg/userdata/generate/init.go +++ b/pkg/userdata/generate/init.go @@ -6,6 +6,7 @@ package generate const initTempl = `#!talos version: "" +kubernetesVersion: {{ .KubernetesVersion }} security: os: ca: diff --git a/pkg/userdata/generate/join.go b/pkg/userdata/generate/join.go index 9f9d869d4..52e59e2e4 100644 --- a/pkg/userdata/generate/join.go +++ b/pkg/userdata/generate/join.go @@ -6,6 +6,7 @@ package generate const workerTempl = `#!talos version: "" +kubernetesVersion: {{ .KubernetesVersion }} security: null services: init: diff --git a/pkg/userdata/services.go b/pkg/userdata/services.go index dc5c13e5c..805ee3ff4 100644 --- a/pkg/userdata/services.go +++ b/pkg/userdata/services.go @@ -57,6 +57,10 @@ func CheckServices() ServiceCheck { return func(s *Services) error { var result *multierror.Error + if s == nil { + return nil + } + if s.Kubeadm == nil { result = multierror.Append(result, xerrors.Errorf("[%s] %q: %w", "services.kubeadm", "", ErrRequiredSection)) } diff --git a/pkg/userdata/translate/translate_test.go b/pkg/userdata/translate/translate_test.go index 4e99a87d3..ea2232e79 100644 --- a/pkg/userdata/translate/translate_test.go +++ b/pkg/userdata/translate/translate_test.go @@ -43,6 +43,7 @@ machine: install: {} cluster: controlPlane: + version: 1.16.0 ips: - 10.254.0.10 clusterName: spencer-test diff --git a/pkg/userdata/translate/translate_v1alpha1.go b/pkg/userdata/translate/translate_v1alpha1.go index e91e416a0..f1c8fa224 100644 --- a/pkg/userdata/translate/translate_v1alpha1.go +++ b/pkg/userdata/translate/translate_v1alpha1.go @@ -15,7 +15,6 @@ import ( kubeletconfig "k8s.io/kubelet/config/v1beta1" kubeadm "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2" - "github.com/talos-systems/talos/pkg/constants" "github.com/talos-systems/talos/pkg/crypto/x509" "github.com/talos-systems/talos/pkg/userdata" v1alpha1 "github.com/talos-systems/talos/pkg/userdata/v1alpha1" @@ -37,8 +36,9 @@ func (tv1a1 *V1Alpha1Translator) Translate() (*userdata.UserData, error) { // Lay down the absolute minimum for all node types ud := &userdata.UserData{ - Version: "v1alpha1", - Security: &userdata.Security{}, + Version: "v1alpha1", + KubernetesVersion: nc.Cluster.ControlPlane.Version, + Security: &userdata.Security{}, Services: &userdata.Services{ Init: &userdata.Init{ CNI: "flannel", @@ -74,6 +74,11 @@ func (tv1a1 *V1Alpha1Translator) Translate() (*userdata.UserData, error) { case "worker": translateV1Alpha1Worker(nc, ud) } + + if err = ud.Validate(); err != nil { + return nil, err + } + return ud, nil } @@ -218,7 +223,7 @@ func translateV1Alpha1Init(nc *v1alpha1.NodeConfig, ud *userdata.UserData) error APIVersion: "kubeadm.k8s.io/v1beta2", }, ClusterName: nc.Cluster.ClusterName, - KubernetesVersion: constants.KubernetesVersion, + KubernetesVersion: ud.KubernetesVersion, ControlPlaneEndpoint: nc.Cluster.ControlPlane.IPs[0] + ":443", Networking: kubeadm.Networking{ DNSDomain: nc.Cluster.Network.DNSDomain, diff --git a/pkg/userdata/userdata.go b/pkg/userdata/userdata.go index d3acaac28..ea57c1988 100644 --- a/pkg/userdata/userdata.go +++ b/pkg/userdata/userdata.go @@ -11,24 +11,26 @@ import ( "os" "strings" + "github.com/blang/semver" "github.com/hashicorp/go-multierror" + "github.com/pkg/errors" "golang.org/x/xerrors" + yaml "gopkg.in/yaml.v2" "github.com/talos-systems/talos/pkg/crypto/x509" - - yaml "gopkg.in/yaml.v2" ) // UserData represents the user data. type UserData struct { - Version Version `yaml:"version"` - Security *Security `yaml:"security"` - Networking *Networking `yaml:"networking"` - Services *Services `yaml:"services"` - Files []*File `yaml:"files"` - Debug bool `yaml:"debug"` - Env Env `yaml:"env,omitempty"` - Install *Install `yaml:"install,omitempty"` + Version Version `yaml:"version"` + Security *Security `yaml:"security"` + Networking *Networking `yaml:"networking"` + Services *Services `yaml:"services"` + Files []*File `yaml:"files"` + Debug bool `yaml:"debug"` + Env Env `yaml:"env,omitempty"` + Install *Install `yaml:"install,omitempty"` + KubernetesVersion string `yaml:"kubernetesVersion,omitempty"` } // Validate ensures the required fields are present in the userdata @@ -36,10 +38,31 @@ type UserData struct { func (data *UserData) Validate() error { var result *multierror.Error + if _, err := semver.Parse(data.KubernetesVersion); err != nil { + result = multierror.Append(result, errors.Wrap(err, "version must be semantic")) + } + // All nodeType checks - result = multierror.Append(result, data.Services.Validate(CheckServices())) - result = multierror.Append(result, data.Services.Trustd.Validate(CheckTrustdAuth(), CheckTrustdEndpointsAreValidIPsOrHostnames())) - result = multierror.Append(result, data.Services.Init.Validate(CheckInitCNI())) + if data.Services != nil { + result = multierror.Append(result, data.Services.Validate(CheckServices())) + if data.Services.Trustd != nil { + result = multierror.Append(result, data.Services.Trustd.Validate(CheckTrustdAuth(), CheckTrustdEndpointsAreValidIPsOrHostnames())) + } + if data.Services.Init != nil { + result = multierror.Append(result, data.Services.Init.Validate(CheckInitCNI())) + } + if data.Services.Kubeadm != nil { + switch { + case data.Services.Kubeadm.IsBootstrap(): + result = multierror.Append(result, data.Security.OS.Validate(CheckOSCA())) + result = multierror.Append(result, data.Security.Kubernetes.Validate(CheckKubernetesCA())) + case data.Services.Kubeadm.IsControlPlane(): + result = multierror.Append(result, data.Services.Trustd.Validate(CheckTrustdEndpointsArePresent())) + case data.Services.Kubeadm.IsWorker(): + result = multierror.Append(result, data.Services.Trustd.Validate(CheckTrustdEndpointsArePresent())) + } + } + } // Surely there's a better way to do this if data.Networking != nil && data.Networking.OS != nil { @@ -48,16 +71,6 @@ func (data *UserData) Validate() error { } } - switch { - case data.Services.Kubeadm.IsBootstrap(): - result = multierror.Append(result, data.Security.OS.Validate(CheckOSCA())) - result = multierror.Append(result, data.Security.Kubernetes.Validate(CheckKubernetesCA())) - case data.Services.Kubeadm.IsControlPlane(): - result = multierror.Append(result, data.Services.Trustd.Validate(CheckTrustdEndpointsArePresent())) - case data.Services.Kubeadm.IsWorker(): - result = multierror.Append(result, data.Services.Trustd.Validate(CheckTrustdEndpointsArePresent())) - } - return result.ErrorOrNil() } diff --git a/pkg/userdata/v1alpha1/cluster_config.go b/pkg/userdata/v1alpha1/cluster_config.go index 44032abe7..f9c9f9588 100644 --- a/pkg/userdata/v1alpha1/cluster_config.go +++ b/pkg/userdata/v1alpha1/cluster_config.go @@ -21,6 +21,7 @@ type ClusterConfig struct { // ControlPlaneConfig represents control plane config vals type ControlPlaneConfig struct { + Version string `yaml:"version"` // Endpoint is the canonical controlplane endpoint, which can be an IP // address or a DNS hostname, is single-valued, and may optionally include a diff --git a/pkg/userdata/v1alpha1/generate/controlplane.go b/pkg/userdata/v1alpha1/generate/controlplane.go index b9484ec47..69b4dc2ad 100644 --- a/pkg/userdata/v1alpha1/generate/controlplane.go +++ b/pkg/userdata/v1alpha1/generate/controlplane.go @@ -25,8 +25,9 @@ func controlPlaneUd(in *Input) (string, error) { cluster := &v1alpha1.ClusterConfig{ Token: in.KubeadmTokens.BootstrapToken, ControlPlane: &v1alpha1.ControlPlaneConfig{ - IPs: in.MasterIPs, - Index: in.Index, + Version: in.KubernetesVersion, + IPs: in.MasterIPs, + Index: in.Index, }, CertificateKey: in.KubeadmTokens.CertificateKey, AESCBCEncryptionSecret: in.KubeadmTokens.AESCBCEncryptionSecret, diff --git a/pkg/userdata/v1alpha1/generate/generate.go b/pkg/userdata/v1alpha1/generate/generate.go index 606b4add8..bb0b13e56 100644 --- a/pkg/userdata/v1alpha1/generate/generate.go +++ b/pkg/userdata/v1alpha1/generate/generate.go @@ -18,9 +18,9 @@ import ( "time" "github.com/talos-systems/talos/internal/pkg/cis" - "github.com/talos-systems/talos/pkg/constants" "github.com/talos-systems/talos/pkg/crypto/x509" tnet "github.com/talos-systems/talos/pkg/net" + "github.com/talos-systems/talos/pkg/userdata/translate" ) // DefaultIPv4PodNet is the network to be used for kubernetes Pods when using IPv4-based master nodes @@ -227,7 +227,7 @@ func isIPv6(addrs ...string) bool { // NewInput generates the sensitive data required to generate all userdata // types. // nolint: dupl,gocyclo -func NewInput(clustername string, masterIPs []string) (input *Input, err error) { +func NewInput(clustername string, masterIPs []string, kubernetesVersion string) (input *Input, err error) { var loopbackIP, podNet, serviceNet string if isIPv6(masterIPs...) { @@ -358,7 +358,7 @@ func NewInput(clustername string, masterIPs []string) (input *Input, err error) ServiceNet: []string{serviceNet}, ServiceDomain: "cluster.local", ClusterName: clustername, - KubernetesVersion: constants.KubernetesVersion, + KubernetesVersion: kubernetesVersion, KubeadmTokens: kubeadmTokens, TrustdInfo: trustdInfo, } @@ -388,15 +388,38 @@ func (t Type) String() string { } // Userdata returns the talos userdata for a given node type. -func Userdata(t Type, in *Input) (string, error) { +// nolint: gocyclo +func Userdata(t Type, in *Input) (s string, err error) { switch t { case TypeInit: - return initUd(in) + if s, err = initUd(in); err != nil { + return "", err + } case TypeControlPlane: - return controlPlaneUd(in) + if s, err = controlPlaneUd(in); err != nil { + return "", err + } case TypeJoin: - return workerUd(in) + if s, err = workerUd(in); err != nil { + return "", err + } default: + return "", errors.New("failed to determine userdata type to generate") } - return "", errors.New("failed to determine userdata type to generate") + + trans, err := translate.NewTranslator("v1alpha1", s) + if err != nil { + return "", err + } + + ud, err := trans.Translate() + if err != nil { + return "", err + } + + if err = ud.Validate(); err != nil { + return "", err + } + + return s, nil } diff --git a/pkg/userdata/v1alpha1/generate/generate_test.go b/pkg/userdata/v1alpha1/generate/generate_test.go index 553fa25b0..04ba318bf 100644 --- a/pkg/userdata/v1alpha1/generate/generate_test.go +++ b/pkg/userdata/v1alpha1/generate/generate_test.go @@ -11,14 +11,15 @@ import ( "github.com/stretchr/testify/suite" "gopkg.in/yaml.v2" + "github.com/talos-systems/talos/pkg/constants" v1alpha1 "github.com/talos-systems/talos/pkg/userdata/v1alpha1" udgenv1alpha1 "github.com/talos-systems/talos/pkg/userdata/v1alpha1/generate" ) -var input *udgenv1alpha1.Input - type GenerateSuite struct { suite.Suite + + input *udgenv1alpha1.Input } func TestGenerateSuite(t *testing.T) { @@ -27,13 +28,13 @@ func TestGenerateSuite(t *testing.T) { func (suite *GenerateSuite) SetupSuite() { var err error - input, err = udgenv1alpha1.NewInput("test", []string{"10.0.1.5", "10.0.1.6", "10.0.1.7"}) + suite.input, err = udgenv1alpha1.NewInput("test", []string{"10.0.1.5", "10.0.1.6", "10.0.1.7"}, constants.DefaultKubernetesVersion) suite.Require().NoError(err) } func (suite *GenerateSuite) TestGenerateInitSuccess() { - input.IP = net.ParseIP("10.0.1.5") - dataString, err := udgenv1alpha1.Userdata(udgenv1alpha1.TypeInit, input) + suite.input.IP = net.ParseIP("10.0.1.5") + dataString, err := udgenv1alpha1.Userdata(udgenv1alpha1.TypeInit, suite.input) suite.Require().NoError(err) data := &v1alpha1.NodeConfig{} err = yaml.Unmarshal([]byte(dataString), data) @@ -41,8 +42,9 @@ func (suite *GenerateSuite) TestGenerateInitSuccess() { } func (suite *GenerateSuite) TestGenerateControlPlaneSuccess() { - input.IP = net.ParseIP("10.0.1.6") - dataString, err := udgenv1alpha1.Userdata(udgenv1alpha1.TypeControlPlane, input) + suite.input.IP = net.ParseIP("10.0.1.6") + suite.input.Index = 1 + dataString, err := udgenv1alpha1.Userdata(udgenv1alpha1.TypeControlPlane, suite.input) suite.Require().NoError(err) data := &v1alpha1.NodeConfig{} err = yaml.Unmarshal([]byte(dataString), data) @@ -50,7 +52,7 @@ func (suite *GenerateSuite) TestGenerateControlPlaneSuccess() { } func (suite *GenerateSuite) TestGenerateWorkerSuccess() { - dataString, err := udgenv1alpha1.Userdata(udgenv1alpha1.TypeJoin, input) + dataString, err := udgenv1alpha1.Userdata(udgenv1alpha1.TypeJoin, suite.input) suite.Require().NoError(err) data := &v1alpha1.NodeConfig{} err = yaml.Unmarshal([]byte(dataString), data) @@ -58,6 +60,6 @@ func (suite *GenerateSuite) TestGenerateWorkerSuccess() { } func (suite *GenerateSuite) TestGenerateTalosconfigSuccess() { - _, err := udgenv1alpha1.Talosconfig(input) + _, err := udgenv1alpha1.Talosconfig(suite.input) suite.Require().NoError(err) } diff --git a/pkg/userdata/v1alpha1/generate/init.go b/pkg/userdata/v1alpha1/generate/init.go index 9503cd8e2..12a7d8ecf 100644 --- a/pkg/userdata/v1alpha1/generate/init.go +++ b/pkg/userdata/v1alpha1/generate/init.go @@ -27,6 +27,7 @@ func initUd(in *Input) (string, error) { cluster := &v1alpha1.ClusterConfig{ ClusterName: in.ClusterName, ControlPlane: &v1alpha1.ControlPlaneConfig{ + Version: in.KubernetesVersion, Endpoint: in.ControlPlaneEndpoint, IPs: in.MasterIPs, Index: in.Index, diff --git a/pkg/userdata/v1alpha1/generate/join.go b/pkg/userdata/v1alpha1/generate/join.go index ea45eb5e2..20f22d5cc 100644 --- a/pkg/userdata/v1alpha1/generate/join.go +++ b/pkg/userdata/v1alpha1/generate/join.go @@ -21,7 +21,8 @@ func workerUd(in *Input) (string, error) { cluster := &v1alpha1.ClusterConfig{ Token: in.KubeadmTokens.BootstrapToken, ControlPlane: &v1alpha1.ControlPlaneConfig{ - IPs: in.MasterIPs, + Version: in.KubernetesVersion, + IPs: in.MasterIPs, }, }