diff --git a/cmd/kubeadm/app/cmd/init.go b/cmd/kubeadm/app/cmd/init.go index 17ff9f1b90b..8cca593e91b 100644 --- a/cmd/kubeadm/app/cmd/init.go +++ b/cmd/kubeadm/app/cmd/init.go @@ -19,6 +19,7 @@ package cmd import ( "fmt" "io" + "io/ioutil" "github.com/renstrom/dedent" "github.com/spf13/cobra" @@ -26,8 +27,10 @@ import ( kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubemaster "k8s.io/kubernetes/cmd/kubeadm/app/master" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/cloudprovider" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" + "k8s.io/kubernetes/pkg/runtime" netutil "k8s.io/kubernetes/pkg/util/net" ) @@ -44,12 +47,19 @@ var ( // NewCmdInit returns "kubeadm init" command. func NewCmdInit(out io.Writer) *cobra.Command { cfg := &kubeadmapi.MasterConfiguration{} + var cfgPath string 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, cfg) - cmdutil.CheckErr(err) + check := func(err error) { + if err != nil { + cmdutil.CheckErr(fmt.Errorf(" %v", err)) + } + } + i, err := NewInit(cfgPath, cfg) + check(err) + check(i.Run(out)) }, } @@ -87,6 +97,8 @@ func NewCmdInit(out io.Writer) *cobra.Command { `Choose a specific Kubernetes version for the control plane`, ) + cmd.PersistentFlags().StringVar(&cfgPath, "config", "", "Path to kubeadm config file") + // TODO (phase1+) @errordeveloper make the flags below not show up in --help but rather on --advanced-help cmd.PersistentFlags().StringSliceVar( &cfg.Etcd.Endpoints, "external-etcd-endpoints", []string{}, @@ -115,14 +127,26 @@ func NewCmdInit(out io.Writer) *cobra.Command { return cmd } -// RunInit executes master node provisioning, including certificates, needed static pod manifests, etc. -func RunInit(out io.Writer, cmd *cobra.Command, args []string, cfg *kubeadmapi.MasterConfiguration) error { +type Init struct { + cfg *kubeadmapi.MasterConfiguration +} + +func NewInit(cfgPath string, cfg *kubeadmapi.MasterConfiguration) (*Init, error) { + if cfgPath != "" { + b, err := ioutil.ReadFile(cfgPath) + if err != nil { + return nil, fmt.Errorf("unable to read config from %q [%v]", cfgPath, err) + } + if err := runtime.DecodeInto(api.Codecs.UniversalDecoder(), b, cfg); err != nil { + return nil, fmt.Errorf("unable to decode config from %q [%v]", cfgPath, err) + } + } // Auto-detect the IP 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 + return nil, err } cfg.API.AdvertiseAddresses = []string{ip.String()} } @@ -130,26 +154,31 @@ func RunInit(out io.Writer, cmd *cobra.Command, args []string, cfg *kubeadmapi.M // TODO(phase1+) create a custom flag 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) + 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", cfg.CloudProvider, cloudprovider.CloudProviders()) + return nil, fmt.Errorf("cloud provider %q is not supported, you can use any of %v, or leave it unset.\n", cfg.CloudProvider, cloudprovider.CloudProviders()) } } + return &Init{cfg: cfg}, nil +} - if err := kubemaster.CreateTokenAuthFile(&cfg.Secrets); err != nil { +// RunInit executes master node provisioning, including certificates, needed static pod manifests, etc. +func (i *Init) Run(out io.Writer) error { + + if err := kubemaster.CreateTokenAuthFile(&i.cfg.Secrets); err != nil { return err } - if err := kubemaster.WriteStaticPodManifests(cfg); err != nil { + if err := kubemaster.WriteStaticPodManifests(i.cfg); err != nil { return err } - caKey, caCert, err := kubemaster.CreatePKIAssets(cfg) + caKey, caCert, err := kubemaster.CreatePKIAssets(i.cfg) if err != nil { return err } - kubeconfigs, err := kubemaster.CreateCertsAndConfigForClients(cfg.API.AdvertiseAddresses, []string{"kubelet", "admin"}, caKey, caCert) + kubeconfigs, err := kubemaster.CreateCertsAndConfigForClients(i.cfg.API.AdvertiseAddresses, []string{"kubelet", "admin"}, caKey, caCert) if err != nil { return err } @@ -179,18 +208,18 @@ func RunInit(out io.Writer, cmd *cobra.Command, args []string, cfg *kubeadmapi.M return err } - if err := kubemaster.CreateDiscoveryDeploymentAndSecret(cfg, client, caCert); err != nil { + if err := kubemaster.CreateDiscoveryDeploymentAndSecret(i.cfg, client, caCert); err != nil { return err } - if err := kubemaster.CreateEssentialAddons(cfg, client); err != nil { + if err := kubemaster.CreateEssentialAddons(i.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, - cfg.Secrets.GivenToken, - cfg.API.AdvertiseAddresses[0], + i.cfg.Secrets.GivenToken, + i.cfg.API.AdvertiseAddresses[0], ) return nil