diff --git a/cmd/kubeadm/app/api/defaults.go b/cmd/kubeadm/app/api/defaults.go new file mode 100644 index 00000000000..c79bb32ce4f --- /dev/null +++ b/cmd/kubeadm/app/api/defaults.go @@ -0,0 +1,23 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package api + +const ( + DefaultServiceDNSDomain = "cluster.local" + DefaultServicesSubnet = "10.12.0.0/12" + DefaultKubernetesVersion = "v1.4.0" +) diff --git a/cmd/kubeadm/app/api/env.go b/cmd/kubeadm/app/api/env.go new file mode 100644 index 00000000000..a9cc09656d7 --- /dev/null +++ b/cmd/kubeadm/app/api/env.go @@ -0,0 +1,49 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package api + +import ( + "fmt" + "os" + "runtime" + "strings" +) + +// TODO(phase2) use componentconfig +// we need some params for testing etc, let's keep these hidden for now +func GetEnvParams() map[string]string { + + envParams := map[string]string{ + // TODO(phase1+): Mode prefix and host_pki_path to another place as constants, and use them everywhere + // Right now they're used here and there, but not consequently + "kubernetes_dir": "/etc/kubernetes", + "host_pki_path": "/etc/kubernetes/pki", + "host_etcd_path": "/var/lib/etcd", + "hyperkube_image": "", + "discovery_image": fmt.Sprintf("gcr.io/google_containers/kube-discovery-%s:%s", runtime.GOARCH, "1.0"), + "etcd_image": "", + "component_loglevel": "--v=4", + } + + for k := range envParams { + if v := os.Getenv(fmt.Sprintf("KUBE_%s", strings.ToUpper(k))); v != "" { + envParams[k] = v + } + } + + return envParams +} diff --git a/cmd/kubeadm/app/api/types.go b/cmd/kubeadm/app/api/types.go index 1c1717f9d94..233bb65aa9d 100644 --- a/cmd/kubeadm/app/api/types.go +++ b/cmd/kubeadm/app/api/types.go @@ -16,89 +16,54 @@ limitations under the License. package api -import ( - "net" -) +import "k8s.io/kubernetes/pkg/api/unversioned" -// KubeadmConfig TODO add description -// TODO(phase1+) @krousey: Please don't embed structs. It obfuscates the source of the fields and doesn't really buy you anything. -type KubeadmConfig struct { - InitFlags - JoinFlags - Secrets struct { - GivenToken string // dot-separated `.` set by the user - TokenID string // optional on master side, will be generated if not specified - Token []byte // optional on master side, will be generated if not specified - BearerToken string // set based on Token - } - EnvParams map[string]string // TODO(phase2) this is likely to be come componentconfig +type MasterConfiguration struct { + unversioned.TypeMeta + + Secrets Secrets + API API + Etcd Etcd + Networking Networking + KubernetesVersion string + CloudProvider string } -// TODO(phase2) should we add validation functions for these structs? - -// TODO(phase1+) refactor token handling -// - https://github.com/kubernetes/kubernetes/pull/33262/files#r80333662 -// - https://github.com/kubernetes/kubernetes/pull/33262/files#r80336374 -// - https://github.com/kubernetes/kubernetes/pull/33262/files#r80333982 - -// InitFlags holds values for "kubeadm init" command flags. -type InitFlags struct { - API struct { - AdvertiseAddrs []net.IP - ExternalDNSNames []string - Etcd struct { - ExternalEndpoints []string - ExternalCAFile string - ExternalCertFile string - ExternalKeyFile string - } - } - Services struct { - CIDR net.IPNet - DNSDomain string - } - PodNetwork struct { - CIDR net.IPNet - } - Versions struct { - Kubernetes string - } - CloudProvider string +type API struct { + AdvertiseAddresses []string + ExternalDNSNames []string } -const ( - DefaultServiceDNSDomain = "cluster.local" - DefaultServicesCIDRString = "10.12.0.0/12" - DefaultKubernetesVersion = "v1.4.0" -) - -var ( - DefaultServicesCIDR *net.IPNet - ListOfCloudProviders = []string{ - "aws", - "azure", - "cloudstack", - "gce", - "mesos", - "openstack", - "ovirt", - "rackspace", - "vsphere", - } -) - -func init() { - _, DefaultServicesCIDR, _ = net.ParseCIDR(DefaultServicesCIDRString) +type Networking struct { + ServiceSubnet string + PodSubnet string + DNSDomain string } -// JoinFlags holds values for "kubeadm join" command flags. -type JoinFlags struct { - MasterAddrs []net.IP - // TODO(phase1+) add manual mode flags here, e.g. RootCACertPath +type Etcd struct { + Endpoints []string + CAFile string + CertFile string + KeyFile string +} + +type Secrets struct { + GivenToken string // dot-separated `.` set by the user + TokenID string // optional on master side, will be generated if not specified + Token []byte // optional on master side, will be generated if not specified + BearerToken string // set based on Token +} + +type NodeConfiguration struct { + unversioned.TypeMeta + + MasterAddresses []string + Secrets Secrets } // ClusterInfo TODO add description type ClusterInfo struct { + unversioned.TypeMeta // TODO(phase1+) this may become simply `api.Config` CertificateAuthorities []string `json:"certificateAuthorities"` Endpoints []string `json:"endpoints"` diff --git a/cmd/kubeadm/app/api/validation.go b/cmd/kubeadm/app/api/validation.go new file mode 100644 index 00000000000..98cb5b4b46e --- /dev/null +++ b/cmd/kubeadm/app/api/validation.go @@ -0,0 +1,25 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package api + +func ValidateMasterConfiguration(o *MasterConfiguration) error { + return nil +} + +func ValidateNodeConfiguration(o *MasterConfiguration) error { + return nil +} diff --git a/cmd/kubeadm/app/cmd/cmd.go b/cmd/kubeadm/app/cmd/cmd.go index 7dd94c0a63b..f459469584f 100644 --- a/cmd/kubeadm/app/cmd/cmd.go +++ b/cmd/kubeadm/app/cmd/cmd.go @@ -22,12 +22,11 @@ import ( "github.com/renstrom/dedent" "github.com/spf13/cobra" - kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/api" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/util/flag" ) -func NewKubeadmCommand(f *cmdutil.Factory, in io.Reader, out, err io.Writer, envParams map[string]string) *cobra.Command { +func NewKubeadmCommand(f *cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Command { cmds := &cobra.Command{ Use: "kubeadm", Short: "kubeadm: easily bootstrap a secure Kubernetes cluster.", @@ -76,14 +75,11 @@ func NewKubeadmCommand(f *cmdutil.Factory, in io.Reader, out, err io.Writer, env // would then be able to look at files users has given an diff or validate if those are sane, we could also warn // if any of the files had been deprecated - s := new(kubeadmapi.KubeadmConfig) - s.EnvParams = envParams - cmds.ResetFlags() cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc) - cmds.AddCommand(NewCmdInit(out, s)) - cmds.AddCommand(NewCmdJoin(out, s)) + cmds.AddCommand(NewCmdInit(out)) + cmds.AddCommand(NewCmdJoin(out)) cmds.AddCommand(NewCmdVersion(out)) return cmds diff --git a/cmd/kubeadm/app/cmd/init.go b/cmd/kubeadm/app/cmd/init.go index b651e0473f2..3ce90e36da4 100644 --- a/cmd/kubeadm/app/cmd/init.go +++ b/cmd/kubeadm/app/cmd/init.go @@ -19,8 +19,6 @@ package cmd import ( "fmt" "io" - "net" - "strings" "github.com/renstrom/dedent" "github.com/spf13/cobra" @@ -28,6 +26,7 @@ import ( kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/api" kubemaster "k8s.io/kubernetes/cmd/kubeadm/app/master" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" + "k8s.io/kubernetes/pkg/cloudprovider" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" netutil "k8s.io/kubernetes/pkg/util/net" ) @@ -43,66 +42,66 @@ var ( ) // NewCmdInit returns "kubeadm init" command. -func NewCmdInit(out io.Writer, s *kubeadmapi.KubeadmConfig) *cobra.Command { - advertiseAddrs := &[]string{} // TODO(pahse1+) make it work somehow else, custom flag or whatever +func NewCmdInit(out io.Writer) *cobra.Command { + cfg := &kubeadmapi.MasterConfiguration{} cmd := &cobra.Command{ Use: "init", Short: "Run this in order to set up the Kubernetes master.", Run: func(cmd *cobra.Command, args []string) { - err := RunInit(out, cmd, args, s, advertiseAddrs) + err := RunInit(out, cmd, args, cfg) cmdutil.CheckErr(err) }, } cmd.PersistentFlags().StringVar( - &s.Secrets.GivenToken, "token", "", + &cfg.Secrets.GivenToken, "token", "", "Shared secret used to secure cluster bootstrap; if none is provided, one will be generated for you", ) cmd.PersistentFlags().StringSliceVar( - advertiseAddrs, "api-advertise-addresses", []string{}, + &cfg.API.AdvertiseAddresses, "api-advertise-addresses", []string{}, "The IP addresses to advertise, in case autodetection fails", ) cmd.PersistentFlags().StringSliceVar( - &s.InitFlags.API.ExternalDNSNames, "api-external-dns-names", []string{}, + &cfg.API.ExternalDNSNames, "api-external-dns-names", []string{}, "The DNS names to advertise, in case you have configured them yourself", ) - cmd.PersistentFlags().IPNetVar( - &s.InitFlags.Services.CIDR, "service-cidr", *kubeadmapi.DefaultServicesCIDR, - `Use alterantive range of IP address for service VIPs, defaults to `+ - kubeadmapi.DefaultServicesCIDRString, + cmd.PersistentFlags().StringVar( + &cfg.Networking.ServiceSubnet, "service-cidr", kubeadmapi.DefaultServicesSubnet, + "Use alterantive range of IP address for service VIPs", ) - cmd.PersistentFlags().IPNetVar( - &s.InitFlags.PodNetwork.CIDR, "pod-network-cidr", net.IPNet{}, + cmd.PersistentFlags().StringVar( + &cfg.Networking.PodSubnet, "pod-network-cidr", "", "Specify range of IP addresses for the pod network; if set, the control plane will automatically allocate CIDRs for every node", ) cmd.PersistentFlags().StringVar( - &s.InitFlags.Services.DNSDomain, "service-dns-domain", kubeadmapi.DefaultServiceDNSDomain, + &cfg.Networking.DNSDomain, "service-dns-domain", kubeadmapi.DefaultServiceDNSDomain, `Use alternative domain for services, e.g. "myorg.internal"`, ) cmd.PersistentFlags().StringVar( - &s.InitFlags.CloudProvider, "cloud-provider", "", + &cfg.CloudProvider, "cloud-provider", "", `Enable cloud provider features (external load-balancers, storage, etc), e.g. "gce"`, ) + cmd.PersistentFlags().StringVar( - &s.InitFlags.Versions.Kubernetes, "use-kubernetes-version", kubeadmapi.DefaultKubernetesVersion, + &cfg.KubernetesVersion, "use-kubernetes-version", kubeadmapi.DefaultKubernetesVersion, `Choose a specific Kubernetes version for the control plane`, ) // TODO (phase1+) @errordeveloper make the flags below not show up in --help but rather on --advanced-help cmd.PersistentFlags().StringSliceVar( - &s.InitFlags.API.Etcd.ExternalEndpoints, "external-etcd-endpoints", []string{}, + &cfg.Etcd.Endpoints, "external-etcd-endpoints", []string{}, "etcd endpoints to use, in case you have an external cluster", ) cmd.PersistentFlags().StringVar( - &s.InitFlags.API.Etcd.ExternalCAFile, "external-etcd-cafile", "", + &cfg.Etcd.CAFile, "external-etcd-cafile", "", "etcd certificate authority certificate file. Note: The path must be in /etc/ssl/certs", ) cmd.PersistentFlags().StringVar( - &s.InitFlags.API.Etcd.ExternalCertFile, "external-etcd-certfile", "", + &cfg.Etcd.CertFile, "external-etcd-certfile", "", "etcd client certificate file. Note: The path must be in /etc/ssl/certs", ) cmd.PersistentFlags().StringVar( - &s.InitFlags.API.Etcd.ExternalKeyFile, "external-etcd-keyfile", "", + &cfg.Etcd.KeyFile, "external-etcd-keyfile", "", "etcd client key file. Note: The path must be in /etc/ssl/certs", ) @@ -110,57 +109,40 @@ func NewCmdInit(out io.Writer, s *kubeadmapi.KubeadmConfig) *cobra.Command { } // RunInit executes master node provisioning, including certificates, needed static pod manifests, etc. -func RunInit(out io.Writer, cmd *cobra.Command, args []string, s *kubeadmapi.KubeadmConfig, advertiseAddrs *[]string) error { +func RunInit(out io.Writer, cmd *cobra.Command, args []string, cfg *kubeadmapi.MasterConfiguration) error { // Auto-detect the IP - if len(*advertiseAddrs) == 0 { + if len(cfg.API.AdvertiseAddresses) == 0 { // TODO(phase1+) perhaps we could actually grab eth0 and eth1 ip, err := netutil.ChooseHostInterface() if err != nil { return err } - s.InitFlags.API.AdvertiseAddrs = []net.IP{ip} - } else { - for _, i := range *advertiseAddrs { - addr := net.ParseIP(i) - if addr == nil { - // TODO(phase1+) custom flag will help to get this error message into a better place - return fmt.Errorf(" failed to parse %q (in %q) as an IP address", i, "--api-advertise-addresses="+strings.Join(*advertiseAddrs, ",")) - } - s.InitFlags.API.AdvertiseAddrs = append(s.InitFlags.API.AdvertiseAddrs, addr) - } + cfg.API.AdvertiseAddresses = []string{ip.String()} } // TODO(phase1+) create a custom flag - if s.InitFlags.CloudProvider != "" { - found := false - for _, provider := range kubeadmapi.ListOfCloudProviders { - if provider == s.InitFlags.CloudProvider { - found = true - break - } - } - - if found { - fmt.Printf(" cloud provider %q initialized for the control plane. Remember to set the same cloud provider flag on the kubelet.\n", s.InitFlags.CloudProvider) + if cfg.CloudProvider != "" { + if cloudprovider.IsCloudProvider(cfg.CloudProvider) { + fmt.Printf(" cloud provider %q initialized for the control plane. Remember to set the same cloud provider flag on the kubelet.\n", cfg.CloudProvider) } else { - return fmt.Errorf(" cloud provider %q is not supported, you can use any of %v, or leave it unset.\n", s.InitFlags.CloudProvider, kubeadmapi.ListOfCloudProviders) + return fmt.Errorf(" cloud provider %q is not supported, you can use any of %v, or leave it unset.\n", cfg.CloudProvider, cloudprovider.CloudProviders()) } } - if err := kubemaster.CreateTokenAuthFile(s); err != nil { + if err := kubemaster.CreateTokenAuthFile(&cfg.Secrets); err != nil { return err } - if err := kubemaster.WriteStaticPodManifests(s); err != nil { + if err := kubemaster.WriteStaticPodManifests(cfg); err != nil { return err } - caKey, caCert, err := kubemaster.CreatePKIAssets(s) + caKey, caCert, err := kubemaster.CreatePKIAssets(cfg) if err != nil { return err } - kubeconfigs, err := kubemaster.CreateCertsAndConfigForClients(s, []string{"kubelet", "admin"}, caKey, caCert) + kubeconfigs, err := kubemaster.CreateCertsAndConfigForClients(cfg.API.AdvertiseAddresses, []string{"kubelet", "admin"}, caKey, caCert) if err != nil { return err } @@ -175,7 +157,7 @@ func RunInit(out io.Writer, cmd *cobra.Command, args []string, s *kubeadmapi.Kub // importing existing files, may be we could even make our command idempotant, // or at least allow for external PKI and stuff) for name, kubeconfig := range kubeconfigs { - if err := kubeadmutil.WriteKubeconfigIfNotExists(s, name, kubeconfig); err != nil { + if err := kubeadmutil.WriteKubeconfigIfNotExists(name, kubeconfig); err != nil { return err } } @@ -190,18 +172,18 @@ func RunInit(out io.Writer, cmd *cobra.Command, args []string, s *kubeadmapi.Kub return err } - if err := kubemaster.CreateDiscoveryDeploymentAndSecret(s, client, caCert); err != nil { + if err := kubemaster.CreateDiscoveryDeploymentAndSecret(cfg, client, caCert); err != nil { return err } - if err := kubemaster.CreateEssentialAddons(s, client); err != nil { + if err := kubemaster.CreateEssentialAddons(cfg, client); err != nil { return err } // TODO(phase1+) use templates to reference struct fields directly as order of args is fragile fmt.Fprintf(out, initDoneMsgf, - s.Secrets.GivenToken, - s.InitFlags.API.AdvertiseAddrs[0].String(), + cfg.Secrets.GivenToken, + cfg.API.AdvertiseAddresses[0], ) return nil diff --git a/cmd/kubeadm/app/cmd/join.go b/cmd/kubeadm/app/cmd/join.go index 78c3b76a029..517e14c8e32 100644 --- a/cmd/kubeadm/app/cmd/join.go +++ b/cmd/kubeadm/app/cmd/join.go @@ -19,7 +19,6 @@ package cmd import ( "fmt" "io" - "net" "github.com/renstrom/dedent" "github.com/spf13/cobra" @@ -42,18 +41,19 @@ var ( ) // NewCmdJoin returns "kubeadm join" command. -func NewCmdJoin(out io.Writer, s *kubeadmapi.KubeadmConfig) *cobra.Command { +func NewCmdJoin(out io.Writer) *cobra.Command { + cfg := &kubeadmapi.NodeConfiguration{} cmd := &cobra.Command{ Use: "join", Short: "Run this on any machine you wish to join an existing cluster.", Run: func(cmd *cobra.Command, args []string) { - err := RunJoin(out, cmd, args, s) + err := RunJoin(out, cmd, args, cfg) cmdutil.CheckErr(err) }, } cmd.PersistentFlags().StringVar( - &s.Secrets.GivenToken, "token", "", + &cfg.Secrets.GivenToken, "token", "", "(required) Shared secret used to secure bootstrap. Must match the output of 'kubeadm init'", ) @@ -61,20 +61,14 @@ func NewCmdJoin(out io.Writer, s *kubeadmapi.KubeadmConfig) *cobra.Command { } // RunJoin executes worked node provisioning and tries to join an existing cluster. -func RunJoin(out io.Writer, cmd *cobra.Command, args []string, s *kubeadmapi.KubeadmConfig) error { +func RunJoin(out io.Writer, cmd *cobra.Command, args []string, s *kubeadmapi.NodeConfiguration) error { // TODO(phase1+) this we are missing args from the help text, there should be a way to tell cobra about it if len(args) == 0 { return fmt.Errorf(" must specify master IP address (see --help)") } - for _, i := range args { - addr := net.ParseIP(i) // TODO(phase1+) should allow resolvable names too - if addr == nil { - return fmt.Errorf(" failed to parse argument (%q) as an IP address", i) - } - s.JoinFlags.MasterAddrs = append(s.JoinFlags.MasterAddrs, addr) - } + s.MasterAddresses = append(s.MasterAddresses, args...) - ok, err := kubeadmutil.UseGivenTokenIfValid(s) + ok, err := kubeadmutil.UseGivenTokenIfValid(&s.Secrets) if !ok { if err != nil { return fmt.Errorf(" %v (see --help)\n", err) @@ -87,7 +81,7 @@ func RunJoin(out io.Writer, cmd *cobra.Command, args []string, s *kubeadmapi.Kub return err } - err = kubeadmutil.WriteKubeconfigIfNotExists(s, "kubelet", kubeconfig) + err = kubeadmutil.WriteKubeconfigIfNotExists("kubelet", kubeconfig) if err != nil { return err } diff --git a/cmd/kubeadm/app/images/images.go b/cmd/kubeadm/app/images/images.go index bda982c0797..1cc81c2ced4 100644 --- a/cmd/kubeadm/app/images/images.go +++ b/cmd/kubeadm/app/images/images.go @@ -43,17 +43,17 @@ const ( exechealthzVersion = "1.1" ) -func GetCoreImage(image string, cfg *kubeadmapi.KubeadmConfig, overrideImage string) string { +func GetCoreImage(image string, cfg *kubeadmapi.MasterConfiguration, overrideImage string) string { if overrideImage != "" { return overrideImage } return map[string]string{ KubeEtcdImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "etcd", runtime.GOARCH, etcdVersion), - KubeAPIServerImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-apiserver", runtime.GOARCH, cfg.Versions.Kubernetes), - KubeControllerManagerImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-controller-manager", runtime.GOARCH, cfg.Versions.Kubernetes), - KubeSchedulerImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-scheduler", runtime.GOARCH, cfg.Versions.Kubernetes), - KubeProxyImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-proxy", runtime.GOARCH, cfg.Versions.Kubernetes), + KubeAPIServerImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-apiserver", runtime.GOARCH, cfg.KubernetesVersion), + KubeControllerManagerImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-controller-manager", runtime.GOARCH, cfg.KubernetesVersion), + KubeSchedulerImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-scheduler", runtime.GOARCH, cfg.KubernetesVersion), + KubeProxyImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-proxy", runtime.GOARCH, cfg.KubernetesVersion), }[image] } diff --git a/cmd/kubeadm/app/kubeadm.go b/cmd/kubeadm/app/kubeadm.go index c1543bc186c..b0693bcd06d 100644 --- a/cmd/kubeadm/app/kubeadm.go +++ b/cmd/kubeadm/app/kubeadm.go @@ -17,10 +17,7 @@ limitations under the License. package app import ( - "fmt" "os" - "runtime" - "strings" "github.com/renstrom/dedent" "github.com/spf13/pflag" @@ -36,31 +33,6 @@ var AlphaWarningOnExit = dedent.Dedent(` kubeadm: and make sure to mention @kubernetes/sig-cluster-lifecycle. Thank you! `) -// TODO(phase2) use componentconfig -// we need some params for testing etc, let's keep these hidden for now -func getEnvParams() map[string]string { - - envParams := map[string]string{ - // TODO(phase1+): Mode prefix and host_pki_path to another place as constants, and use them everywhere - // Right now they're used here and there, but not consequently - "kubernetes_dir": "/etc/kubernetes", - "host_pki_path": "/etc/kubernetes/pki", - "host_etcd_path": "/var/lib/etcd", - "hyperkube_image": "", - "discovery_image": fmt.Sprintf("gcr.io/google_containers/kube-discovery-%s:%s", runtime.GOARCH, "1.0"), - "etcd_image": "", - "component_loglevel": "--v=4", - } - - for k := range envParams { - if v := os.Getenv(fmt.Sprintf("KUBE_%s", strings.ToUpper(k))); v != "" { - envParams[k] = v - } - } - - return envParams -} - func Run() error { logs.InitLogs() defer logs.FlushLogs() @@ -69,6 +41,6 @@ func Run() error { pflag.CommandLine.MarkHidden("google-json-key") pflag.CommandLine.MarkHidden("log-flush-frequency") - cmd := cmd.NewKubeadmCommand(cmdutil.NewFactory(nil), os.Stdin, os.Stdout, os.Stderr, getEnvParams()) + cmd := cmd.NewKubeadmCommand(cmdutil.NewFactory(nil), os.Stdin, os.Stdout, os.Stderr) return cmd.Execute() } diff --git a/cmd/kubeadm/app/master/addons.go b/cmd/kubeadm/app/master/addons.go index 9e2759115c7..2e2da2c179c 100644 --- a/cmd/kubeadm/app/master/addons.go +++ b/cmd/kubeadm/app/master/addons.go @@ -18,6 +18,7 @@ package master import ( "fmt" + "net" "path" "runtime" @@ -31,7 +32,8 @@ import ( ) // TODO(phase1+): kube-proxy should be a daemonset, three different daemonsets should not be here -func createKubeProxyPodSpec(s *kubeadmapi.KubeadmConfig, architecture string) api.PodSpec { +func createKubeProxyPodSpec(s *kubeadmapi.MasterConfiguration, architecture string) api.PodSpec { + envParams := kubeadmapi.GetEnvParams() privilegedTrue := true return api.PodSpec{ SecurityContext: &api.PodSecurityContext{HostNetwork: true}, @@ -40,7 +42,7 @@ func createKubeProxyPodSpec(s *kubeadmapi.KubeadmConfig, architecture string) ap }, Containers: []api.Container{{ Name: kubeProxy, - Image: images.GetCoreImage(images.KubeProxyImage, s, s.EnvParams["hyperkube_image"]), + Image: images.GetCoreImage(images.KubeProxyImage, s, envParams["hyperkube_image"]), Command: append(getComponentCommand("proxy", s), "--kubeconfig=/run/kubeconfig"), SecurityContext: &api.SecurityContext{Privileged: &privilegedTrue}, VolumeMounts: []api.VolumeMount{ @@ -70,7 +72,7 @@ func createKubeProxyPodSpec(s *kubeadmapi.KubeadmConfig, architecture string) ap { Name: "kubeconfig", VolumeSource: api.VolumeSource{ - HostPath: &api.HostPathVolumeSource{Path: path.Join(s.EnvParams["kubernetes_dir"], "kubelet.conf")}, + HostPath: &api.HostPathVolumeSource{Path: path.Join(envParams["kubernetes_dir"], "kubelet.conf")}, }, }, { @@ -83,7 +85,7 @@ func createKubeProxyPodSpec(s *kubeadmapi.KubeadmConfig, architecture string) ap } } -func createKubeDNSPodSpec(s *kubeadmapi.KubeadmConfig) api.PodSpec { +func createKubeDNSPodSpec(s *kubeadmapi.MasterConfiguration) api.PodSpec { dnsPodResources := api.ResourceList{ api.ResourceName(api.ResourceCPU): resource.MustParse("100m"), @@ -98,7 +100,7 @@ func createKubeDNSPodSpec(s *kubeadmapi.KubeadmConfig) api.PodSpec { kubeDNSPort := int32(10053) dnsmasqPort := int32(53) - nslookup := fmt.Sprintf("nslookup kubernetes.default.svc.%s 127.0.0.1", s.InitFlags.Services.DNSDomain) + nslookup := fmt.Sprintf("nslookup kubernetes.default.svc.%s 127.0.0.1", s.Networking.DNSDomain) nslookup = fmt.Sprintf("-cmd=%s:%d >/dev/null && %s:%d >/dev/null", nslookup, dnsmasqPort, @@ -119,7 +121,7 @@ func createKubeDNSPodSpec(s *kubeadmapi.KubeadmConfig) api.PodSpec { Requests: dnsPodResources, }, Args: []string{ - fmt.Sprintf("--domain=%s", s.InitFlags.Services.DNSDomain), + fmt.Sprintf("--domain=%s", s.Networking.DNSDomain), fmt.Sprintf("--dns-port=%d", kubeDNSPort), // TODO __PILLAR__FEDERATIONS__DOMAIN__MAP__ }, @@ -212,10 +214,14 @@ func createKubeDNSPodSpec(s *kubeadmapi.KubeadmConfig) api.PodSpec { } -func createKubeDNSServiceSpec(s *kubeadmapi.KubeadmConfig) (*api.ServiceSpec, error) { - ip, err := ipallocator.GetIndexedIP(&s.InitFlags.Services.CIDR, 10) +func createKubeDNSServiceSpec(s *kubeadmapi.MasterConfiguration) (*api.ServiceSpec, error) { + _, n, err := net.ParseCIDR(s.Networking.ServiceSubnet) if err != nil { - return nil, fmt.Errorf("unable to allocate IP address for kube-dns addon from the given CIDR (%q) [%v]", s.InitFlags.Services.CIDR, err) + return nil, fmt.Errorf("could not parse %q: %v", s.Networking.ServiceSubnet, err) + } + ip, err := ipallocator.GetIndexedIP(n, 10) + if err != nil { + return nil, fmt.Errorf("unable to allocate IP address for kube-dns addon from the given CIDR (%q) [%v]", s.Networking.ServiceSubnet, err) } svc := &api.ServiceSpec{ @@ -230,7 +236,7 @@ func createKubeDNSServiceSpec(s *kubeadmapi.KubeadmConfig) (*api.ServiceSpec, er return svc, nil } -func CreateEssentialAddons(s *kubeadmapi.KubeadmConfig, client *clientset.Clientset) error { +func CreateEssentialAddons(s *kubeadmapi.MasterConfiguration, client *clientset.Clientset) error { arches := [3]string{"amd64", "arm", "arm64"} for _, arch := range arches { diff --git a/cmd/kubeadm/app/master/discovery.go b/cmd/kubeadm/app/master/discovery.go index d65c4a51a6f..b17040df72a 100644 --- a/cmd/kubeadm/app/master/discovery.go +++ b/cmd/kubeadm/app/master/discovery.go @@ -40,15 +40,15 @@ const ( kubeDiscoverySecretName = "clusterinfo" ) -func encodeKubeDiscoverySecretData(s *kubeadmapi.KubeadmConfig, caCert *x509.Certificate) map[string][]byte { +func encodeKubeDiscoverySecretData(s *kubeadmapi.MasterConfiguration, caCert *x509.Certificate) map[string][]byte { var ( data = map[string][]byte{} endpointList = []string{} tokenMap = map[string]string{} ) - for _, addr := range s.InitFlags.API.AdvertiseAddrs { - endpointList = append(endpointList, fmt.Sprintf("https://%s:443", addr.String())) + for _, addr := range s.API.AdvertiseAddresses { + endpointList = append(endpointList, fmt.Sprintf("https://%s:443", addr)) } tokenMap[s.Secrets.TokenID] = s.Secrets.BearerToken @@ -60,7 +60,8 @@ func encodeKubeDiscoverySecretData(s *kubeadmapi.KubeadmConfig, caCert *x509.Cer return data } -func newKubeDiscoveryPodSpec(s *kubeadmapi.KubeadmConfig) api.PodSpec { +func newKubeDiscoveryPodSpec() api.PodSpec { + envParams := kubeadmapi.GetEnvParams() return api.PodSpec{ // We have to use host network namespace, as `HostPort`/`HostIP` are Docker's // buisness and CNI support isn't quite there yet (except for kubenet) @@ -69,7 +70,7 @@ func newKubeDiscoveryPodSpec(s *kubeadmapi.KubeadmConfig) api.PodSpec { SecurityContext: &api.PodSecurityContext{HostNetwork: true}, Containers: []api.Container{{ Name: kubeDiscoveryName, - Image: s.EnvParams["discovery_image"], + Image: envParams["discovery_image"], Command: []string{"/usr/local/bin/kube-discovery"}, VolumeMounts: []api.VolumeMount{{ Name: kubeDiscoverySecretName, @@ -100,9 +101,9 @@ func newKubeDiscoveryPodSpec(s *kubeadmapi.KubeadmConfig) api.PodSpec { } } -func newKubeDiscovery(s *kubeadmapi.KubeadmConfig, caCert *x509.Certificate) kubeDiscovery { +func newKubeDiscovery(s *kubeadmapi.MasterConfiguration, caCert *x509.Certificate) kubeDiscovery { kd := kubeDiscovery{ - Deployment: NewDeployment(kubeDiscoveryName, 1, newKubeDiscoveryPodSpec(s)), + Deployment: NewDeployment(kubeDiscoveryName, 1, newKubeDiscoveryPodSpec()), Secret: &api.Secret{ ObjectMeta: api.ObjectMeta{Name: kubeDiscoverySecretName}, Type: api.SecretTypeOpaque, @@ -116,7 +117,7 @@ func newKubeDiscovery(s *kubeadmapi.KubeadmConfig, caCert *x509.Certificate) kub return kd } -func CreateDiscoveryDeploymentAndSecret(s *kubeadmapi.KubeadmConfig, client *clientset.Clientset, caCert *x509.Certificate) error { +func CreateDiscoveryDeploymentAndSecret(s *kubeadmapi.MasterConfiguration, client *clientset.Clientset, caCert *x509.Certificate) error { kd := newKubeDiscovery(s, caCert) if _, err := client.Extensions().Deployments(api.NamespaceSystem).Create(kd.Deployment); err != nil { diff --git a/cmd/kubeadm/app/master/kubeconfig.go b/cmd/kubeadm/app/master/kubeconfig.go index d94c20dcb84..e6bf07feaf0 100644 --- a/cmd/kubeadm/app/master/kubeconfig.go +++ b/cmd/kubeadm/app/master/kubeconfig.go @@ -22,20 +22,19 @@ import ( "fmt" // TODO: "k8s.io/client-go/client/tools/clientcmd/api" - kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/api" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" certutil "k8s.io/kubernetes/pkg/util/cert" ) -func CreateCertsAndConfigForClients(s *kubeadmapi.KubeadmConfig, clientNames []string, caKey *rsa.PrivateKey, caCert *x509.Certificate) (map[string]*clientcmdapi.Config, error) { +func CreateCertsAndConfigForClients(advertiseAddresses, clientNames []string, caKey *rsa.PrivateKey, caCert *x509.Certificate) (map[string]*clientcmdapi.Config, error) { basicClientConfig := kubeadmutil.CreateBasicClientConfig( "kubernetes", // TODO this is not great, but there is only one address we can use here // so we'll pick the first one, there is much of chance to have an empty // slice by the time this gets called - fmt.Sprintf("https://%s:443", s.InitFlags.API.AdvertiseAddrs[0]), + fmt.Sprintf("https://%s:443", advertiseAddresses[0]), certutil.EncodeCertPEM(caCert), ) diff --git a/cmd/kubeadm/app/master/manifests.go b/cmd/kubeadm/app/master/manifests.go index eefed4b7bf4..c053b25477c 100644 --- a/cmd/kubeadm/app/master/manifests.go +++ b/cmd/kubeadm/app/master/manifests.go @@ -53,12 +53,13 @@ const ( // WriteStaticPodManifests builds manifest objects based on user provided configuration and then dumps it to disk // where kubelet will pick and schedule them. -func WriteStaticPodManifests(s *kubeadmapi.KubeadmConfig) error { +func WriteStaticPodManifests(s *kubeadmapi.MasterConfiguration) error { + envParams := kubeadmapi.GetEnvParams() // Prepare static pod specs staticPodSpecs := map[string]api.Pod{ kubeAPIServer: componentPod(api.Container{ Name: kubeAPIServer, - Image: images.GetCoreImage(images.KubeAPIServerImage, s, s.EnvParams["hyperkube_image"]), + Image: images.GetCoreImage(images.KubeAPIServerImage, s, envParams["hyperkube_image"]), Command: getComponentCommand(apiServer, s), VolumeMounts: []api.VolumeMount{certsVolumeMount(), k8sVolumeMount()}, LivenessProbe: componentProbe(8080, "/healthz"), @@ -66,7 +67,7 @@ func WriteStaticPodManifests(s *kubeadmapi.KubeadmConfig) error { }, certsVolume(s), k8sVolume(s)), kubeControllerManager: componentPod(api.Container{ Name: kubeControllerManager, - Image: images.GetCoreImage(images.KubeControllerManagerImage, s, s.EnvParams["hyperkube_image"]), + Image: images.GetCoreImage(images.KubeControllerManagerImage, s, envParams["hyperkube_image"]), Command: getComponentCommand(controllerManager, s), VolumeMounts: []api.VolumeMount{certsVolumeMount(), k8sVolumeMount()}, LivenessProbe: componentProbe(10252, "/healthz"), @@ -74,7 +75,7 @@ func WriteStaticPodManifests(s *kubeadmapi.KubeadmConfig) error { }, certsVolume(s), k8sVolume(s)), kubeScheduler: componentPod(api.Container{ Name: kubeScheduler, - Image: images.GetCoreImage(images.KubeSchedulerImage, s, s.EnvParams["hyperkube_image"]), + Image: images.GetCoreImage(images.KubeSchedulerImage, s, envParams["hyperkube_image"]), Command: getComponentCommand(scheduler, s), LivenessProbe: componentProbe(10251, "/healthz"), Resources: componentResources("100m"), @@ -82,7 +83,7 @@ func WriteStaticPodManifests(s *kubeadmapi.KubeadmConfig) error { } // Add etcd static pod spec only if external etcd is not configured - if len(s.InitFlags.API.Etcd.ExternalEndpoints) == 0 { + if len(s.Etcd.Endpoints) == 0 { staticPodSpecs[etcd] = componentPod(api.Container{ Name: etcd, Command: []string{ @@ -92,7 +93,7 @@ func WriteStaticPodManifests(s *kubeadmapi.KubeadmConfig) error { "--data-dir=/var/etcd/data", }, VolumeMounts: []api.VolumeMount{certsVolumeMount(), etcdVolumeMount(), k8sVolumeMount()}, - Image: images.GetCoreImage(images.KubeEtcdImage, s, s.EnvParams["etcd_image"]), + Image: images.GetCoreImage(images.KubeEtcdImage, s, envParams["etcd_image"]), LivenessProbe: componentProbe(2379, "/health"), Resources: componentResources("200m"), SecurityContext: &api.SecurityContext{ @@ -107,7 +108,7 @@ func WriteStaticPodManifests(s *kubeadmapi.KubeadmConfig) error { }, certsVolume(s), etcdVolume(s), k8sVolume(s)) } - manifestsPath := path.Join(s.EnvParams["kubernetes_dir"], "manifests") + manifestsPath := path.Join(envParams["kubernetes_dir"], "manifests") if err := os.MkdirAll(manifestsPath, 0700); err != nil { return fmt.Errorf(" failed to create directory %q [%v]", manifestsPath, err) } @@ -125,11 +126,12 @@ func WriteStaticPodManifests(s *kubeadmapi.KubeadmConfig) error { } // etcdVolume exposes a path on the host in order to guarantee data survival during reboot. -func etcdVolume(s *kubeadmapi.KubeadmConfig) api.Volume { +func etcdVolume(s *kubeadmapi.MasterConfiguration) api.Volume { + envParams := kubeadmapi.GetEnvParams() return api.Volume{ Name: "etcd", VolumeSource: api.VolumeSource{ - HostPath: &api.HostPathVolumeSource{Path: s.EnvParams["host_etcd_path"]}, + HostPath: &api.HostPathVolumeSource{Path: envParams["host_etcd_path"]}, }, } } @@ -142,7 +144,7 @@ func etcdVolumeMount() api.VolumeMount { } // certsVolume exposes host SSL certificates to pod containers. -func certsVolume(s *kubeadmapi.KubeadmConfig) api.Volume { +func certsVolume(s *kubeadmapi.MasterConfiguration) api.Volume { return api.Volume{ Name: "certs", VolumeSource: api.VolumeSource{ @@ -159,11 +161,12 @@ func certsVolumeMount() api.VolumeMount { } } -func k8sVolume(s *kubeadmapi.KubeadmConfig) api.Volume { +func k8sVolume(s *kubeadmapi.MasterConfiguration) api.Volume { + envParams := kubeadmapi.GetEnvParams() return api.Volume{ Name: "pki", VolumeSource: api.VolumeSource{ - HostPath: &api.HostPathVolumeSource{Path: s.EnvParams["kubernetes_dir"]}, + HostPath: &api.HostPathVolumeSource{Path: envParams["kubernetes_dir"]}, }, } } @@ -218,13 +221,13 @@ func componentPod(container api.Container, volumes ...api.Volume) api.Pod { } } -func getComponentCommand(component string, s *kubeadmapi.KubeadmConfig) (command []string) { +func getComponentCommand(component string, s *kubeadmapi.MasterConfiguration) (command []string) { baseFlags := map[string][]string{ apiServer: { "--insecure-bind-address=127.0.0.1", "--etcd-servers=http://127.0.0.1:2379", "--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota", - "--service-cluster-ip-range=" + s.InitFlags.Services.CIDR.String(), + "--service-cluster-ip-range=" + s.Networking.ServiceSubnet, "--service-account-key-file=" + pkiDir + "/apiserver-key.pem", "--client-ca-file=" + pkiDir + "/ca.pem", "--tls-cert-file=" + pkiDir + "/apiserver.pem", @@ -252,37 +255,38 @@ func getComponentCommand(component string, s *kubeadmapi.KubeadmConfig) (command proxy: {}, } - if s.EnvParams["hyperkube_image"] != "" { + envParams := kubeadmapi.GetEnvParams() + if envParams["hyperkube_image"] != "" { command = []string{"/hyperkube", component} } else { command = []string{"/usr/local/bin/kube-" + component} } - command = append(command, s.EnvParams["component_loglevel"]) + command = append(command, envParams["component_loglevel"]) command = append(command, baseFlags[component]...) if component == apiServer { // Check if the user decided to use an external etcd cluster - if len(s.InitFlags.API.Etcd.ExternalEndpoints) > 0 { - command = append(command, fmt.Sprintf("--etcd-servers=%s", strings.Join(s.InitFlags.API.Etcd.ExternalEndpoints, ","))) + if len(s.Etcd.Endpoints) > 0 { + command = append(command, fmt.Sprintf("--etcd-servers=%s", strings.Join(s.Etcd.Endpoints, ","))) } else { command = append(command, "--etcd-servers=http://127.0.0.1:2379") } // Is etcd secured? - if s.InitFlags.API.Etcd.ExternalCAFile != "" { - command = append(command, fmt.Sprintf("--etcd-cafile=%s", s.InitFlags.API.Etcd.ExternalCAFile)) + if s.Etcd.CAFile != "" { + command = append(command, fmt.Sprintf("--etcd-cafile=%s", s.Etcd.CAFile)) } - if s.InitFlags.API.Etcd.ExternalCertFile != "" && s.InitFlags.API.Etcd.ExternalKeyFile != "" { - etcdClientFileArg := fmt.Sprintf("--etcd-certfile=%s", s.InitFlags.API.Etcd.ExternalCertFile) - etcdKeyFileArg := fmt.Sprintf("--etcd-keyfile=%s", s.InitFlags.API.Etcd.ExternalKeyFile) + if s.Etcd.CertFile != "" && s.Etcd.KeyFile != "" { + etcdClientFileArg := fmt.Sprintf("--etcd-certfile=%s", s.Etcd.CertFile) + etcdKeyFileArg := fmt.Sprintf("--etcd-keyfile=%s", s.Etcd.KeyFile) command = append(command, etcdClientFileArg, etcdKeyFileArg) } } if component == controllerManager { - if s.InitFlags.CloudProvider != "" { - command = append(command, "--cloud-provider="+s.InitFlags.CloudProvider) + if s.CloudProvider != "" { + command = append(command, "--cloud-provider="+s.CloudProvider) // Only append the --cloud-config option if there's a such file // TODO(phase1+) this won't work unless it's in one of the few directories we bind-mount @@ -290,12 +294,9 @@ func getComponentCommand(component string, s *kubeadmapi.KubeadmConfig) (command command = append(command, "--cloud-config="+DefaultCloudConfigPath) } } - - if s.InitFlags.PodNetwork.CIDR.IP != nil { - // Let the controller-manager allocate Node CIDRs for the Pod network. - // Each node will get a subspace of the address CIDR provided with --pod-network-cidr. - command = append(command, "--allocate-node-cidrs=true", "--cluster-cidr="+s.InitFlags.PodNetwork.CIDR.String()) - } + // Let the controller-manager allocate Node CIDRs for the Pod network. + // Each node will get a subspace of the address CIDR provided with --pod-network-cidr. + command = append(command, "--allocate-node-cidrs=true", "--cluster-cidr="+s.Networking.PodSubnet) } return diff --git a/cmd/kubeadm/app/master/pki.go b/cmd/kubeadm/app/master/pki.go index d4c7f617350..155cf2ef00a 100644 --- a/cmd/kubeadm/app/master/pki.go +++ b/cmd/kubeadm/app/master/pki.go @@ -20,6 +20,7 @@ import ( "crypto/rsa" "crypto/x509" "fmt" + "net" "path" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/api" @@ -45,7 +46,7 @@ func newCertificateAuthority() (*rsa.PrivateKey, *x509.Certificate, error) { return key, cert, nil } -func newServerKeyAndCert(s *kubeadmapi.KubeadmConfig, caCert *x509.Certificate, caKey *rsa.PrivateKey, altNames certutil.AltNames) (*rsa.PrivateKey, *x509.Certificate, error) { +func newServerKeyAndCert(s *kubeadmapi.MasterConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey, altNames certutil.AltNames) (*rsa.PrivateKey, *x509.Certificate, error) { key, err := certutil.NewPrivateKey() if err != nil { return nil, nil, fmt.Errorf("unabel to create private key [%v]", err) @@ -55,12 +56,16 @@ func newServerKeyAndCert(s *kubeadmapi.KubeadmConfig, caCert *x509.Certificate, "kubernetes", "kubernetes.default", "kubernetes.default.svc", - fmt.Sprintf("kubernetes.default.svc.%s", s.InitFlags.Services.DNSDomain), + fmt.Sprintf("kubernetes.default.svc.%s", s.Networking.DNSDomain), } - internalAPIServerVirtualIP, err := ipallocator.GetIndexedIP(&s.InitFlags.Services.CIDR, 1) + _, n, err := net.ParseCIDR(s.Networking.ServiceSubnet) if err != nil { - return nil, nil, fmt.Errorf("unable to allocate IP address for the API server from the given CIDR (%q) [%v]", &s.InitFlags.Services.CIDR, err) + return nil, nil, fmt.Errorf("error parsing CIDR %q: %v", s.Networking.ServiceSubnet, err) + } + internalAPIServerVirtualIP, err := ipallocator.GetIndexedIP(n, 1) + if err != nil { + return nil, nil, fmt.Errorf("unable to allocate IP address for the API server from the given CIDR (%q) [%v]", &s.Networking.ServiceSubnet, err) } altNames.IPs = append(altNames.IPs, internalAPIServerVirtualIP) @@ -138,16 +143,22 @@ func newServiceAccountKey() (*rsa.PrivateKey, error) { // It first generates a self-signed CA certificate, a server certificate (signed by the CA) and a key for // signing service account tokens. It returns CA key and certificate, which is convenient for use with // client config funcs. -func CreatePKIAssets(s *kubeadmapi.KubeadmConfig) (*rsa.PrivateKey, *x509.Certificate, error) { +func CreatePKIAssets(s *kubeadmapi.MasterConfiguration) (*rsa.PrivateKey, *x509.Certificate, error) { var ( err error altNames certutil.AltNames ) - altNames.IPs = append(altNames.IPs, s.InitFlags.API.AdvertiseAddrs...) - altNames.DNSNames = append(altNames.DNSNames, s.InitFlags.API.ExternalDNSNames...) + for _, a := range s.API.AdvertiseAddresses { + if ip := net.ParseIP(a); ip != nil { + altNames.IPs = append(altNames.IPs, ip) + } else { + return nil, nil, fmt.Errorf("could not parse ip %q", a) + } + } + altNames.DNSNames = append(altNames.DNSNames, s.API.ExternalDNSNames...) - pkiPath := path.Join(s.EnvParams["host_pki_path"]) + pkiPath := path.Join(kubeadmapi.GetEnvParams()["host_pki_path"]) caKey, caCert, err := newCertificateAuthority() if err != nil { diff --git a/cmd/kubeadm/app/master/tokens.go b/cmd/kubeadm/app/master/tokens.go index dd1b6f541da..8b001c08891 100644 --- a/cmd/kubeadm/app/master/tokens.go +++ b/cmd/kubeadm/app/master/tokens.go @@ -28,7 +28,7 @@ import ( "k8s.io/kubernetes/pkg/util/uuid" ) -func generateTokenIfNeeded(s *kubeadmapi.KubeadmConfig) error { +func generateTokenIfNeeded(s *kubeadmapi.Secrets) error { ok, err := kubeadmutil.UseGivenTokenIfValid(s) // TODO(phase1+) @krousey: I know it won't happen with the way it is currently implemented, but this doesn't handle case where ok is true and err is non-nil. if !ok { @@ -39,7 +39,7 @@ func generateTokenIfNeeded(s *kubeadmapi.KubeadmConfig) error { if err != nil { return err } - fmt.Printf(" generated token: %q\n", s.Secrets.GivenToken) + fmt.Printf(" generated token: %q\n", s.GivenToken) } else { fmt.Println(" accepted provided token") } @@ -47,15 +47,15 @@ func generateTokenIfNeeded(s *kubeadmapi.KubeadmConfig) error { return nil } -func CreateTokenAuthFile(s *kubeadmapi.KubeadmConfig) error { - tokenAuthFilePath := path.Join(s.EnvParams["host_pki_path"], "tokens.csv") +func CreateTokenAuthFile(s *kubeadmapi.Secrets) error { + tokenAuthFilePath := path.Join(kubeadmapi.GetEnvParams()["host_pki_path"], "tokens.csv") if err := generateTokenIfNeeded(s); err != nil { return fmt.Errorf(" failed to generate token(s) [%v]", err) } - if err := os.MkdirAll(s.EnvParams["host_pki_path"], 0700); err != nil { - return fmt.Errorf(" failed to create directory %q [%v]", s.EnvParams["host_pki_path"], err) + if err := os.MkdirAll(kubeadmapi.GetEnvParams()["host_pki_path"], 0700); err != nil { + return fmt.Errorf(" failed to create directory %q [%v]", kubeadmapi.GetEnvParams()["host_pki_path"], err) } - serialized := []byte(fmt.Sprintf("%s,kubeadm-node-csr,%s,system:kubelet-bootstrap\n", s.Secrets.BearerToken, uuid.NewUUID())) + serialized := []byte(fmt.Sprintf("%s,kubeadm-node-csr,%s,system:kubelet-bootstrap\n", s.BearerToken, uuid.NewUUID())) // DumpReaderToFile create a file with mode 0600 if err := cmdutil.DumpReaderToFile(bytes.NewReader(serialized), tokenAuthFilePath); err != nil { return fmt.Errorf(" failed to save token auth file (%q) [%v]", tokenAuthFilePath, err) diff --git a/cmd/kubeadm/app/node/csr.go b/cmd/kubeadm/app/node/csr.go index 1da8aad0fb4..0d8027c48ab 100644 --- a/cmd/kubeadm/app/node/csr.go +++ b/cmd/kubeadm/app/node/csr.go @@ -34,8 +34,8 @@ import ( ) // PerformTLSBootstrap creates a RESTful client in order to execute certificate signing request. -func PerformTLSBootstrap(s *kubeadmapi.KubeadmConfig, apiEndpoint string, caCert []byte) (*clientcmdapi.Config, error) { - // TODO(phase2) try all the api servers until we find one that works +func PerformTLSBootstrap(s *kubeadmapi.NodeConfiguration, apiEndpoint string, caCert []byte) (*clientcmdapi.Config, error) { + // TODO(phase1+) try all the api servers until we find one that works bareClientConfig := kubeadmutil.CreateBasicClientConfig("kubernetes", apiEndpoint, caCert) hostName, err := os.Hostname() diff --git a/cmd/kubeadm/app/node/discovery.go b/cmd/kubeadm/app/node/discovery.go index f5c82a63556..ea51a1a4abc 100644 --- a/cmd/kubeadm/app/node/discovery.go +++ b/cmd/kubeadm/app/node/discovery.go @@ -28,8 +28,8 @@ import ( clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" ) -func RetrieveTrustedClusterInfo(s *kubeadmapi.KubeadmConfig) (*clientcmdapi.Config, error) { - host, port := s.JoinFlags.MasterAddrs[0].String(), 9898 +func RetrieveTrustedClusterInfo(s *kubeadmapi.NodeConfiguration) (*clientcmdapi.Config, error) { + host, port := s.MasterAddresses[0], 9898 requestURL := fmt.Sprintf("http://%s:%d/cluster-info/v1/?token-id=%s", host, port, s.Secrets.TokenID) req, err := http.NewRequest("GET", requestURL, nil) if err != nil { diff --git a/cmd/kubeadm/app/util/kubeconfig.go b/cmd/kubeadm/app/util/kubeconfig.go index 40553b1c80c..bf40c686967 100644 --- a/cmd/kubeadm/app/util/kubeconfig.go +++ b/cmd/kubeadm/app/util/kubeconfig.go @@ -75,12 +75,13 @@ func MakeClientConfigWithToken(config *clientcmdapi.Config, clusterName string, return newConfig } -func WriteKubeconfigIfNotExists(s *kubeadmapi.KubeadmConfig, name string, kubeconfig *clientcmdapi.Config) error { - if err := os.MkdirAll(s.EnvParams["kubernetes_dir"], 0700); err != nil { - return fmt.Errorf(" failed to create directory %q [%v]", s.EnvParams["kubernetes_dir"], err) +func WriteKubeconfigIfNotExists(name string, kubeconfig *clientcmdapi.Config) error { + envParams := kubeadmapi.GetEnvParams() + if err := os.MkdirAll(envParams["kubernetes_dir"], 0700); err != nil { + return fmt.Errorf(" failed to create directory %q [%v]", envParams["kubernetes_dir"], err) } - filename := path.Join(s.EnvParams["kubernetes_dir"], fmt.Sprintf("%s.conf", name)) + filename := path.Join(envParams["kubernetes_dir"], fmt.Sprintf("%s.conf", name)) // Create and open the file, only if it does not already exist. f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0600) if err != nil { diff --git a/cmd/kubeadm/app/util/tokens.go b/cmd/kubeadm/app/util/tokens.go index 99da5e6557c..5f8f9fa4c30 100644 --- a/cmd/kubeadm/app/util/tokens.go +++ b/cmd/kubeadm/app/util/tokens.go @@ -42,7 +42,7 @@ func RandBytes(length int) ([]byte, string, error) { return b, hex.EncodeToString(b), nil } -func GenerateToken(s *kubeadmapi.KubeadmConfig) error { +func GenerateToken(s *kubeadmapi.Secrets) error { _, tokenID, err := RandBytes(TokenIDLen / 2) if err != nil { return err @@ -53,19 +53,19 @@ func GenerateToken(s *kubeadmapi.KubeadmConfig) error { return err } - s.Secrets.TokenID = tokenID - s.Secrets.BearerToken = token - s.Secrets.Token = tokenBytes - s.Secrets.GivenToken = fmt.Sprintf("%s.%s", tokenID, token) + s.TokenID = tokenID + s.BearerToken = token + s.Token = tokenBytes + s.GivenToken = fmt.Sprintf("%s.%s", tokenID, token) return nil } -func UseGivenTokenIfValid(s *kubeadmapi.KubeadmConfig) (bool, error) { - if s.Secrets.GivenToken == "" { +func UseGivenTokenIfValid(s *kubeadmapi.Secrets) (bool, error) { + if s.GivenToken == "" { return false, nil // not given } fmt.Println(" validating provided token") - givenToken := strings.Split(strings.ToLower(s.Secrets.GivenToken), ".") + givenToken := strings.Split(strings.ToLower(s.GivenToken), ".") // TODO(phase1+) print desired format // TODO(phase1+) could also print more specific messages in each case invalidErr := " provided token is invalid - %s" @@ -78,8 +78,8 @@ func UseGivenTokenIfValid(s *kubeadmapi.KubeadmConfig) (bool, error) { len(givenToken[0]), TokenIDLen)) } tokenBytes := []byte(givenToken[1]) - s.Secrets.TokenID = givenToken[0] - s.Secrets.BearerToken = givenToken[1] - s.Secrets.Token = tokenBytes + s.TokenID = givenToken[0] + s.BearerToken = givenToken[1] + s.Token = tokenBytes return true, nil // given and valid } diff --git a/pkg/cloudprovider/plugins.go b/pkg/cloudprovider/plugins.go index 670400f628f..19e90b4d50d 100644 --- a/pkg/cloudprovider/plugins.go +++ b/pkg/cloudprovider/plugins.go @@ -32,8 +32,10 @@ import ( type Factory func(config io.Reader) (Interface, error) // All registered cloud providers. -var providersMutex sync.Mutex -var providers = make(map[string]Factory) +var ( + providersMutex sync.Mutex + providers = make(map[string]Factory) +) // RegisterCloudProvider registers a cloudprovider.Factory by name. This // is expected to happen during app startup. @@ -47,6 +49,27 @@ func RegisterCloudProvider(name string, cloud Factory) { providers[name] = cloud } +// IsCloudProvider returns true if name corresponds to an already registered +// cloud provider. +func IsCloudProvider(name string) bool { + providersMutex.Lock() + defer providersMutex.Unlock() + _, found := providers[name] + return found +} + +// CloudProviders returns the name of all registered cloud providers in a +// string slice +func CloudProviders() []string { + names := []string{} + providersMutex.Lock() + defer providersMutex.Unlock() + for name := range providers { + names = append(names, name) + } + return names +} + // GetCloudProvider creates an instance of the named cloud provider, or nil if // the name is not known. The error return is only used if the named provider // was known but failed to initialize. The config parameter specifies the