kubeadm: refactor config

1) break object into substructures
2) seperate a config object for master and node
This commit is contained in:
Mike Danese 2016-09-28 23:36:18 -07:00
parent 3933ddbc9a
commit 56ea178e7c
20 changed files with 317 additions and 269 deletions

View File

@ -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"
)

View File

@ -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
}

View File

@ -16,89 +16,54 @@ limitations under the License.
package api package api
import ( import "k8s.io/kubernetes/pkg/api/unversioned"
"net"
)
// KubeadmConfig TODO add description type MasterConfiguration struct {
// TODO(phase1+) @krousey: Please don't embed structs. It obfuscates the source of the fields and doesn't really buy you anything. unversioned.TypeMeta
type KubeadmConfig struct {
InitFlags Secrets Secrets
JoinFlags API API
Secrets struct { Etcd Etcd
Networking Networking
KubernetesVersion string
CloudProvider string
}
type API struct {
AdvertiseAddresses []string
ExternalDNSNames []string
}
type Networking struct {
ServiceSubnet string
PodSubnet string
DNSDomain string
}
type Etcd struct {
Endpoints []string
CAFile string
CertFile string
KeyFile string
}
type Secrets struct {
GivenToken string // dot-separated `<TokenID>.<Token>` set by the user GivenToken string // dot-separated `<TokenID>.<Token>` set by the user
TokenID string // optional on master side, will be generated if not specified TokenID string // optional on master side, will be generated if not specified
Token []byte // 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 BearerToken string // set based on Token
}
EnvParams map[string]string // TODO(phase2) this is likely to be come componentconfig
} }
// TODO(phase2) should we add validation functions for these structs? type NodeConfiguration struct {
unversioned.TypeMeta
// TODO(phase1+) refactor token handling MasterAddresses []string
// - https://github.com/kubernetes/kubernetes/pull/33262/files#r80333662 Secrets Secrets
// - 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
}
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)
}
// JoinFlags holds values for "kubeadm join" command flags.
type JoinFlags struct {
MasterAddrs []net.IP
// TODO(phase1+) add manual mode flags here, e.g. RootCACertPath
} }
// ClusterInfo TODO add description // ClusterInfo TODO add description
type ClusterInfo struct { type ClusterInfo struct {
unversioned.TypeMeta
// TODO(phase1+) this may become simply `api.Config` // TODO(phase1+) this may become simply `api.Config`
CertificateAuthorities []string `json:"certificateAuthorities"` CertificateAuthorities []string `json:"certificateAuthorities"`
Endpoints []string `json:"endpoints"` Endpoints []string `json:"endpoints"`

View File

@ -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
}

View File

@ -22,12 +22,11 @@ import (
"github.com/renstrom/dedent" "github.com/renstrom/dedent"
"github.com/spf13/cobra" "github.com/spf13/cobra"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/api"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/util/flag" "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{ cmds := &cobra.Command{
Use: "kubeadm", Use: "kubeadm",
Short: "kubeadm: easily bootstrap a secure Kubernetes cluster.", 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 // 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 // if any of the files had been deprecated
s := new(kubeadmapi.KubeadmConfig)
s.EnvParams = envParams
cmds.ResetFlags() cmds.ResetFlags()
cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc) cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc)
cmds.AddCommand(NewCmdInit(out, s)) cmds.AddCommand(NewCmdInit(out))
cmds.AddCommand(NewCmdJoin(out, s)) cmds.AddCommand(NewCmdJoin(out))
cmds.AddCommand(NewCmdVersion(out)) cmds.AddCommand(NewCmdVersion(out))
return cmds return cmds

View File

@ -19,8 +19,6 @@ package cmd
import ( import (
"fmt" "fmt"
"io" "io"
"net"
"strings"
"github.com/renstrom/dedent" "github.com/renstrom/dedent"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -28,6 +26,7 @@ import (
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/api" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/api"
kubemaster "k8s.io/kubernetes/cmd/kubeadm/app/master" kubemaster "k8s.io/kubernetes/cmd/kubeadm/app/master"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
"k8s.io/kubernetes/pkg/cloudprovider"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
netutil "k8s.io/kubernetes/pkg/util/net" netutil "k8s.io/kubernetes/pkg/util/net"
) )
@ -43,66 +42,66 @@ var (
) )
// NewCmdInit returns "kubeadm init" command. // NewCmdInit returns "kubeadm init" command.
func NewCmdInit(out io.Writer, s *kubeadmapi.KubeadmConfig) *cobra.Command { func NewCmdInit(out io.Writer) *cobra.Command {
advertiseAddrs := &[]string{} // TODO(pahse1+) make it work somehow else, custom flag or whatever cfg := &kubeadmapi.MasterConfiguration{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "init", Use: "init",
Short: "Run this in order to set up the Kubernetes master.", Short: "Run this in order to set up the Kubernetes master.",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
err := RunInit(out, cmd, args, s, advertiseAddrs) err := RunInit(out, cmd, args, cfg)
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
}, },
} }
cmd.PersistentFlags().StringVar( 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", "Shared secret used to secure cluster bootstrap; if none is provided, one will be generated for you",
) )
cmd.PersistentFlags().StringSliceVar( cmd.PersistentFlags().StringSliceVar(
advertiseAddrs, "api-advertise-addresses", []string{}, &cfg.API.AdvertiseAddresses, "api-advertise-addresses", []string{},
"The IP addresses to advertise, in case autodetection fails", "The IP addresses to advertise, in case autodetection fails",
) )
cmd.PersistentFlags().StringSliceVar( 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", "The DNS names to advertise, in case you have configured them yourself",
) )
cmd.PersistentFlags().IPNetVar( cmd.PersistentFlags().StringVar(
&s.InitFlags.Services.CIDR, "service-cidr", *kubeadmapi.DefaultServicesCIDR, &cfg.Networking.ServiceSubnet, "service-cidr", kubeadmapi.DefaultServicesSubnet,
`Use alterantive range of IP address for service VIPs, defaults to `+ "Use alterantive range of IP address for service VIPs",
kubeadmapi.DefaultServicesCIDRString,
) )
cmd.PersistentFlags().IPNetVar( cmd.PersistentFlags().StringVar(
&s.InitFlags.PodNetwork.CIDR, "pod-network-cidr", net.IPNet{}, &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", "Specify range of IP addresses for the pod network; if set, the control plane will automatically allocate CIDRs for every node",
) )
cmd.PersistentFlags().StringVar( 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"`, `Use alternative domain for services, e.g. "myorg.internal"`,
) )
cmd.PersistentFlags().StringVar( cmd.PersistentFlags().StringVar(
&s.InitFlags.CloudProvider, "cloud-provider", "", &cfg.CloudProvider, "cloud-provider", "",
`Enable cloud provider features (external load-balancers, storage, etc), e.g. "gce"`, `Enable cloud provider features (external load-balancers, storage, etc), e.g. "gce"`,
) )
cmd.PersistentFlags().StringVar( 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`, `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 // TODO (phase1+) @errordeveloper make the flags below not show up in --help but rather on --advanced-help
cmd.PersistentFlags().StringSliceVar( 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", "etcd endpoints to use, in case you have an external cluster",
) )
cmd.PersistentFlags().StringVar( 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", "etcd certificate authority certificate file. Note: The path must be in /etc/ssl/certs",
) )
cmd.PersistentFlags().StringVar( 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", "etcd client certificate file. Note: The path must be in /etc/ssl/certs",
) )
cmd.PersistentFlags().StringVar( 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", "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. // 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 // Auto-detect the IP
if len(*advertiseAddrs) == 0 { if len(cfg.API.AdvertiseAddresses) == 0 {
// TODO(phase1+) perhaps we could actually grab eth0 and eth1 // TODO(phase1+) perhaps we could actually grab eth0 and eth1
ip, err := netutil.ChooseHostInterface() ip, err := netutil.ChooseHostInterface()
if err != nil { if err != nil {
return err return err
} }
s.InitFlags.API.AdvertiseAddrs = []net.IP{ip} cfg.API.AdvertiseAddresses = []string{ip.String()}
} 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("<cmd/init> 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)
}
} }
// TODO(phase1+) create a custom flag // TODO(phase1+) create a custom flag
if s.InitFlags.CloudProvider != "" { if cfg.CloudProvider != "" {
found := false if cloudprovider.IsCloudProvider(cfg.CloudProvider) {
for _, provider := range kubeadmapi.ListOfCloudProviders { fmt.Printf("<cmd/init> cloud provider %q initialized for the control plane. Remember to set the same cloud provider flag on the kubelet.\n", cfg.CloudProvider)
if provider == s.InitFlags.CloudProvider {
found = true
break
}
}
if found {
fmt.Printf("<cmd/init> cloud provider %q initialized for the control plane. Remember to set the same cloud provider flag on the kubelet.\n", s.InitFlags.CloudProvider)
} else { } else {
return fmt.Errorf("<cmd/init> 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("<cmd/init> 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 return err
} }
if err := kubemaster.WriteStaticPodManifests(s); err != nil { if err := kubemaster.WriteStaticPodManifests(cfg); err != nil {
return err return err
} }
caKey, caCert, err := kubemaster.CreatePKIAssets(s) caKey, caCert, err := kubemaster.CreatePKIAssets(cfg)
if err != nil { if err != nil {
return err 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 { if err != nil {
return err 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, // importing existing files, may be we could even make our command idempotant,
// or at least allow for external PKI and stuff) // or at least allow for external PKI and stuff)
for name, kubeconfig := range kubeconfigs { for name, kubeconfig := range kubeconfigs {
if err := kubeadmutil.WriteKubeconfigIfNotExists(s, name, kubeconfig); err != nil { if err := kubeadmutil.WriteKubeconfigIfNotExists(name, kubeconfig); err != nil {
return err return err
} }
} }
@ -190,18 +172,18 @@ func RunInit(out io.Writer, cmd *cobra.Command, args []string, s *kubeadmapi.Kub
return err return err
} }
if err := kubemaster.CreateDiscoveryDeploymentAndSecret(s, client, caCert); err != nil { if err := kubemaster.CreateDiscoveryDeploymentAndSecret(cfg, client, caCert); err != nil {
return err return err
} }
if err := kubemaster.CreateEssentialAddons(s, client); err != nil { if err := kubemaster.CreateEssentialAddons(cfg, client); err != nil {
return err return err
} }
// TODO(phase1+) use templates to reference struct fields directly as order of args is fragile // TODO(phase1+) use templates to reference struct fields directly as order of args is fragile
fmt.Fprintf(out, initDoneMsgf, fmt.Fprintf(out, initDoneMsgf,
s.Secrets.GivenToken, cfg.Secrets.GivenToken,
s.InitFlags.API.AdvertiseAddrs[0].String(), cfg.API.AdvertiseAddresses[0],
) )
return nil return nil

View File

@ -19,7 +19,6 @@ package cmd
import ( import (
"fmt" "fmt"
"io" "io"
"net"
"github.com/renstrom/dedent" "github.com/renstrom/dedent"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -42,18 +41,19 @@ var (
) )
// NewCmdJoin returns "kubeadm join" command. // 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{ cmd := &cobra.Command{
Use: "join", Use: "join",
Short: "Run this on any machine you wish to join an existing cluster.", Short: "Run this on any machine you wish to join an existing cluster.",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
err := RunJoin(out, cmd, args, s) err := RunJoin(out, cmd, args, cfg)
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
}, },
} }
cmd.PersistentFlags().StringVar( 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'", "(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. // 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 // 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 { if len(args) == 0 {
return fmt.Errorf("<cmd/join> must specify master IP address (see --help)") return fmt.Errorf("<cmd/join> must specify master IP address (see --help)")
} }
for _, i := range args { s.MasterAddresses = append(s.MasterAddresses, args...)
addr := net.ParseIP(i) // TODO(phase1+) should allow resolvable names too
if addr == nil {
return fmt.Errorf("<cmd/join> failed to parse argument (%q) as an IP address", i)
}
s.JoinFlags.MasterAddrs = append(s.JoinFlags.MasterAddrs, addr)
}
ok, err := kubeadmutil.UseGivenTokenIfValid(s) ok, err := kubeadmutil.UseGivenTokenIfValid(&s.Secrets)
if !ok { if !ok {
if err != nil { if err != nil {
return fmt.Errorf("<cmd/join> %v (see --help)\n", err) return fmt.Errorf("<cmd/join> %v (see --help)\n", err)
@ -87,7 +81,7 @@ func RunJoin(out io.Writer, cmd *cobra.Command, args []string, s *kubeadmapi.Kub
return err return err
} }
err = kubeadmutil.WriteKubeconfigIfNotExists(s, "kubelet", kubeconfig) err = kubeadmutil.WriteKubeconfigIfNotExists("kubelet", kubeconfig)
if err != nil { if err != nil {
return err return err
} }

View File

@ -43,17 +43,17 @@ const (
exechealthzVersion = "1.1" 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 != "" { if overrideImage != "" {
return overrideImage return overrideImage
} }
return map[string]string{ return map[string]string{
KubeEtcdImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "etcd", runtime.GOARCH, etcdVersion), 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), 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.Versions.Kubernetes), 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.Versions.Kubernetes), 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.Versions.Kubernetes), KubeProxyImage: fmt.Sprintf("%s/%s-%s:%s", gcrPrefix, "kube-proxy", runtime.GOARCH, cfg.KubernetesVersion),
}[image] }[image]
} }

View File

@ -17,10 +17,7 @@ limitations under the License.
package app package app
import ( import (
"fmt"
"os" "os"
"runtime"
"strings"
"github.com/renstrom/dedent" "github.com/renstrom/dedent"
"github.com/spf13/pflag" "github.com/spf13/pflag"
@ -36,31 +33,6 @@ var AlphaWarningOnExit = dedent.Dedent(`
kubeadm: and make sure to mention @kubernetes/sig-cluster-lifecycle. Thank you! 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 { func Run() error {
logs.InitLogs() logs.InitLogs()
defer logs.FlushLogs() defer logs.FlushLogs()
@ -69,6 +41,6 @@ func Run() error {
pflag.CommandLine.MarkHidden("google-json-key") pflag.CommandLine.MarkHidden("google-json-key")
pflag.CommandLine.MarkHidden("log-flush-frequency") 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() return cmd.Execute()
} }

View File

@ -18,6 +18,7 @@ package master
import ( import (
"fmt" "fmt"
"net"
"path" "path"
"runtime" "runtime"
@ -31,7 +32,8 @@ import (
) )
// TODO(phase1+): kube-proxy should be a daemonset, three different daemonsets should not be here // 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 privilegedTrue := true
return api.PodSpec{ return api.PodSpec{
SecurityContext: &api.PodSecurityContext{HostNetwork: true}, SecurityContext: &api.PodSecurityContext{HostNetwork: true},
@ -40,7 +42,7 @@ func createKubeProxyPodSpec(s *kubeadmapi.KubeadmConfig, architecture string) ap
}, },
Containers: []api.Container{{ Containers: []api.Container{{
Name: kubeProxy, 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"), Command: append(getComponentCommand("proxy", s), "--kubeconfig=/run/kubeconfig"),
SecurityContext: &api.SecurityContext{Privileged: &privilegedTrue}, SecurityContext: &api.SecurityContext{Privileged: &privilegedTrue},
VolumeMounts: []api.VolumeMount{ VolumeMounts: []api.VolumeMount{
@ -70,7 +72,7 @@ func createKubeProxyPodSpec(s *kubeadmapi.KubeadmConfig, architecture string) ap
{ {
Name: "kubeconfig", Name: "kubeconfig",
VolumeSource: api.VolumeSource{ 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{ dnsPodResources := api.ResourceList{
api.ResourceName(api.ResourceCPU): resource.MustParse("100m"), api.ResourceName(api.ResourceCPU): resource.MustParse("100m"),
@ -98,7 +100,7 @@ func createKubeDNSPodSpec(s *kubeadmapi.KubeadmConfig) api.PodSpec {
kubeDNSPort := int32(10053) kubeDNSPort := int32(10053)
dnsmasqPort := int32(53) 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 = fmt.Sprintf("-cmd=%s:%d >/dev/null && %s:%d >/dev/null",
nslookup, dnsmasqPort, nslookup, dnsmasqPort,
@ -119,7 +121,7 @@ func createKubeDNSPodSpec(s *kubeadmapi.KubeadmConfig) api.PodSpec {
Requests: dnsPodResources, Requests: dnsPodResources,
}, },
Args: []string{ Args: []string{
fmt.Sprintf("--domain=%s", s.InitFlags.Services.DNSDomain), fmt.Sprintf("--domain=%s", s.Networking.DNSDomain),
fmt.Sprintf("--dns-port=%d", kubeDNSPort), fmt.Sprintf("--dns-port=%d", kubeDNSPort),
// TODO __PILLAR__FEDERATIONS__DOMAIN__MAP__ // TODO __PILLAR__FEDERATIONS__DOMAIN__MAP__
}, },
@ -212,10 +214,14 @@ func createKubeDNSPodSpec(s *kubeadmapi.KubeadmConfig) api.PodSpec {
} }
func createKubeDNSServiceSpec(s *kubeadmapi.KubeadmConfig) (*api.ServiceSpec, error) { func createKubeDNSServiceSpec(s *kubeadmapi.MasterConfiguration) (*api.ServiceSpec, error) {
ip, err := ipallocator.GetIndexedIP(&s.InitFlags.Services.CIDR, 10) _, n, err := net.ParseCIDR(s.Networking.ServiceSubnet)
if err != nil { 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{ svc := &api.ServiceSpec{
@ -230,7 +236,7 @@ func createKubeDNSServiceSpec(s *kubeadmapi.KubeadmConfig) (*api.ServiceSpec, er
return svc, nil 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"} arches := [3]string{"amd64", "arm", "arm64"}
for _, arch := range arches { for _, arch := range arches {

View File

@ -40,15 +40,15 @@ const (
kubeDiscoverySecretName = "clusterinfo" 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 ( var (
data = map[string][]byte{} data = map[string][]byte{}
endpointList = []string{} endpointList = []string{}
tokenMap = map[string]string{} tokenMap = map[string]string{}
) )
for _, addr := range s.InitFlags.API.AdvertiseAddrs { for _, addr := range s.API.AdvertiseAddresses {
endpointList = append(endpointList, fmt.Sprintf("https://%s:443", addr.String())) endpointList = append(endpointList, fmt.Sprintf("https://%s:443", addr))
} }
tokenMap[s.Secrets.TokenID] = s.Secrets.BearerToken tokenMap[s.Secrets.TokenID] = s.Secrets.BearerToken
@ -60,7 +60,8 @@ func encodeKubeDiscoverySecretData(s *kubeadmapi.KubeadmConfig, caCert *x509.Cer
return data return data
} }
func newKubeDiscoveryPodSpec(s *kubeadmapi.KubeadmConfig) api.PodSpec { func newKubeDiscoveryPodSpec() api.PodSpec {
envParams := kubeadmapi.GetEnvParams()
return api.PodSpec{ return api.PodSpec{
// We have to use host network namespace, as `HostPort`/`HostIP` are Docker's // 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) // 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}, SecurityContext: &api.PodSecurityContext{HostNetwork: true},
Containers: []api.Container{{ Containers: []api.Container{{
Name: kubeDiscoveryName, Name: kubeDiscoveryName,
Image: s.EnvParams["discovery_image"], Image: envParams["discovery_image"],
Command: []string{"/usr/local/bin/kube-discovery"}, Command: []string{"/usr/local/bin/kube-discovery"},
VolumeMounts: []api.VolumeMount{{ VolumeMounts: []api.VolumeMount{{
Name: kubeDiscoverySecretName, 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{ kd := kubeDiscovery{
Deployment: NewDeployment(kubeDiscoveryName, 1, newKubeDiscoveryPodSpec(s)), Deployment: NewDeployment(kubeDiscoveryName, 1, newKubeDiscoveryPodSpec()),
Secret: &api.Secret{ Secret: &api.Secret{
ObjectMeta: api.ObjectMeta{Name: kubeDiscoverySecretName}, ObjectMeta: api.ObjectMeta{Name: kubeDiscoverySecretName},
Type: api.SecretTypeOpaque, Type: api.SecretTypeOpaque,
@ -116,7 +117,7 @@ func newKubeDiscovery(s *kubeadmapi.KubeadmConfig, caCert *x509.Certificate) kub
return kd 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) kd := newKubeDiscovery(s, caCert)
if _, err := client.Extensions().Deployments(api.NamespaceSystem).Create(kd.Deployment); err != nil { if _, err := client.Extensions().Deployments(api.NamespaceSystem).Create(kd.Deployment); err != nil {

View File

@ -22,20 +22,19 @@ import (
"fmt" "fmt"
// TODO: "k8s.io/client-go/client/tools/clientcmd/api" // 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" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
certutil "k8s.io/kubernetes/pkg/util/cert" 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( basicClientConfig := kubeadmutil.CreateBasicClientConfig(
"kubernetes", "kubernetes",
// TODO this is not great, but there is only one address we can use here // 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 // so we'll pick the first one, there is much of chance to have an empty
// slice by the time this gets called // 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), certutil.EncodeCertPEM(caCert),
) )

View File

@ -53,12 +53,13 @@ const (
// WriteStaticPodManifests builds manifest objects based on user provided configuration and then dumps it to disk // WriteStaticPodManifests builds manifest objects based on user provided configuration and then dumps it to disk
// where kubelet will pick and schedule them. // 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 // Prepare static pod specs
staticPodSpecs := map[string]api.Pod{ staticPodSpecs := map[string]api.Pod{
kubeAPIServer: componentPod(api.Container{ kubeAPIServer: componentPod(api.Container{
Name: kubeAPIServer, 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), Command: getComponentCommand(apiServer, s),
VolumeMounts: []api.VolumeMount{certsVolumeMount(), k8sVolumeMount()}, VolumeMounts: []api.VolumeMount{certsVolumeMount(), k8sVolumeMount()},
LivenessProbe: componentProbe(8080, "/healthz"), LivenessProbe: componentProbe(8080, "/healthz"),
@ -66,7 +67,7 @@ func WriteStaticPodManifests(s *kubeadmapi.KubeadmConfig) error {
}, certsVolume(s), k8sVolume(s)), }, certsVolume(s), k8sVolume(s)),
kubeControllerManager: componentPod(api.Container{ kubeControllerManager: componentPod(api.Container{
Name: kubeControllerManager, 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), Command: getComponentCommand(controllerManager, s),
VolumeMounts: []api.VolumeMount{certsVolumeMount(), k8sVolumeMount()}, VolumeMounts: []api.VolumeMount{certsVolumeMount(), k8sVolumeMount()},
LivenessProbe: componentProbe(10252, "/healthz"), LivenessProbe: componentProbe(10252, "/healthz"),
@ -74,7 +75,7 @@ func WriteStaticPodManifests(s *kubeadmapi.KubeadmConfig) error {
}, certsVolume(s), k8sVolume(s)), }, certsVolume(s), k8sVolume(s)),
kubeScheduler: componentPod(api.Container{ kubeScheduler: componentPod(api.Container{
Name: kubeScheduler, 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), Command: getComponentCommand(scheduler, s),
LivenessProbe: componentProbe(10251, "/healthz"), LivenessProbe: componentProbe(10251, "/healthz"),
Resources: componentResources("100m"), 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 // 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{ staticPodSpecs[etcd] = componentPod(api.Container{
Name: etcd, Name: etcd,
Command: []string{ Command: []string{
@ -92,7 +93,7 @@ func WriteStaticPodManifests(s *kubeadmapi.KubeadmConfig) error {
"--data-dir=/var/etcd/data", "--data-dir=/var/etcd/data",
}, },
VolumeMounts: []api.VolumeMount{certsVolumeMount(), etcdVolumeMount(), k8sVolumeMount()}, 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"), LivenessProbe: componentProbe(2379, "/health"),
Resources: componentResources("200m"), Resources: componentResources("200m"),
SecurityContext: &api.SecurityContext{ SecurityContext: &api.SecurityContext{
@ -107,7 +108,7 @@ func WriteStaticPodManifests(s *kubeadmapi.KubeadmConfig) error {
}, certsVolume(s), etcdVolume(s), k8sVolume(s)) }, 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 { if err := os.MkdirAll(manifestsPath, 0700); err != nil {
return fmt.Errorf("<master/manifests> failed to create directory %q [%v]", manifestsPath, err) return fmt.Errorf("<master/manifests> 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. // 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{ return api.Volume{
Name: "etcd", Name: "etcd",
VolumeSource: api.VolumeSource{ 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. // 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{ return api.Volume{
Name: "certs", Name: "certs",
VolumeSource: api.VolumeSource{ 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{ return api.Volume{
Name: "pki", Name: "pki",
VolumeSource: api.VolumeSource{ 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{ baseFlags := map[string][]string{
apiServer: { apiServer: {
"--insecure-bind-address=127.0.0.1", "--insecure-bind-address=127.0.0.1",
"--etcd-servers=http://127.0.0.1:2379", "--etcd-servers=http://127.0.0.1:2379",
"--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota", "--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", "--service-account-key-file=" + pkiDir + "/apiserver-key.pem",
"--client-ca-file=" + pkiDir + "/ca.pem", "--client-ca-file=" + pkiDir + "/ca.pem",
"--tls-cert-file=" + pkiDir + "/apiserver.pem", "--tls-cert-file=" + pkiDir + "/apiserver.pem",
@ -252,37 +255,38 @@ func getComponentCommand(component string, s *kubeadmapi.KubeadmConfig) (command
proxy: {}, proxy: {},
} }
if s.EnvParams["hyperkube_image"] != "" { envParams := kubeadmapi.GetEnvParams()
if envParams["hyperkube_image"] != "" {
command = []string{"/hyperkube", component} command = []string{"/hyperkube", component}
} else { } else {
command = []string{"/usr/local/bin/kube-" + component} 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]...) command = append(command, baseFlags[component]...)
if component == apiServer { if component == apiServer {
// Check if the user decided to use an external etcd cluster // Check if the user decided to use an external etcd cluster
if len(s.InitFlags.API.Etcd.ExternalEndpoints) > 0 { if len(s.Etcd.Endpoints) > 0 {
command = append(command, fmt.Sprintf("--etcd-servers=%s", strings.Join(s.InitFlags.API.Etcd.ExternalEndpoints, ","))) command = append(command, fmt.Sprintf("--etcd-servers=%s", strings.Join(s.Etcd.Endpoints, ",")))
} else { } else {
command = append(command, "--etcd-servers=http://127.0.0.1:2379") command = append(command, "--etcd-servers=http://127.0.0.1:2379")
} }
// Is etcd secured? // Is etcd secured?
if s.InitFlags.API.Etcd.ExternalCAFile != "" { if s.Etcd.CAFile != "" {
command = append(command, fmt.Sprintf("--etcd-cafile=%s", s.InitFlags.API.Etcd.ExternalCAFile)) command = append(command, fmt.Sprintf("--etcd-cafile=%s", s.Etcd.CAFile))
} }
if s.InitFlags.API.Etcd.ExternalCertFile != "" && s.InitFlags.API.Etcd.ExternalKeyFile != "" { if s.Etcd.CertFile != "" && s.Etcd.KeyFile != "" {
etcdClientFileArg := fmt.Sprintf("--etcd-certfile=%s", s.InitFlags.API.Etcd.ExternalCertFile) etcdClientFileArg := fmt.Sprintf("--etcd-certfile=%s", s.Etcd.CertFile)
etcdKeyFileArg := fmt.Sprintf("--etcd-keyfile=%s", s.InitFlags.API.Etcd.ExternalKeyFile) etcdKeyFileArg := fmt.Sprintf("--etcd-keyfile=%s", s.Etcd.KeyFile)
command = append(command, etcdClientFileArg, etcdKeyFileArg) command = append(command, etcdClientFileArg, etcdKeyFileArg)
} }
} }
if component == controllerManager { if component == controllerManager {
if s.InitFlags.CloudProvider != "" { if s.CloudProvider != "" {
command = append(command, "--cloud-provider="+s.InitFlags.CloudProvider) command = append(command, "--cloud-provider="+s.CloudProvider)
// Only append the --cloud-config option if there's a such file // 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 // 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) command = append(command, "--cloud-config="+DefaultCloudConfigPath)
} }
} }
if s.InitFlags.PodNetwork.CIDR.IP != nil {
// Let the controller-manager allocate Node CIDRs for the Pod network. // 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. // 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()) command = append(command, "--allocate-node-cidrs=true", "--cluster-cidr="+s.Networking.PodSubnet)
}
} }
return return

View File

@ -20,6 +20,7 @@ import (
"crypto/rsa" "crypto/rsa"
"crypto/x509" "crypto/x509"
"fmt" "fmt"
"net"
"path" "path"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/api" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/api"
@ -45,7 +46,7 @@ func newCertificateAuthority() (*rsa.PrivateKey, *x509.Certificate, error) {
return key, cert, nil 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() key, err := certutil.NewPrivateKey()
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("unabel to create private key [%v]", err) 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",
"kubernetes.default", "kubernetes.default",
"kubernetes.default.svc", "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 { 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) 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 // 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 // signing service account tokens. It returns CA key and certificate, which is convenient for use with
// client config funcs. // client config funcs.
func CreatePKIAssets(s *kubeadmapi.KubeadmConfig) (*rsa.PrivateKey, *x509.Certificate, error) { func CreatePKIAssets(s *kubeadmapi.MasterConfiguration) (*rsa.PrivateKey, *x509.Certificate, error) {
var ( var (
err error err error
altNames certutil.AltNames altNames certutil.AltNames
) )
altNames.IPs = append(altNames.IPs, s.InitFlags.API.AdvertiseAddrs...) for _, a := range s.API.AdvertiseAddresses {
altNames.DNSNames = append(altNames.DNSNames, s.InitFlags.API.ExternalDNSNames...) 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() caKey, caCert, err := newCertificateAuthority()
if err != nil { if err != nil {

View File

@ -28,7 +28,7 @@ import (
"k8s.io/kubernetes/pkg/util/uuid" "k8s.io/kubernetes/pkg/util/uuid"
) )
func generateTokenIfNeeded(s *kubeadmapi.KubeadmConfig) error { func generateTokenIfNeeded(s *kubeadmapi.Secrets) error {
ok, err := kubeadmutil.UseGivenTokenIfValid(s) 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. // 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 { if !ok {
@ -39,7 +39,7 @@ func generateTokenIfNeeded(s *kubeadmapi.KubeadmConfig) error {
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("<master/tokens> generated token: %q\n", s.Secrets.GivenToken) fmt.Printf("<master/tokens> generated token: %q\n", s.GivenToken)
} else { } else {
fmt.Println("<master/tokens> accepted provided token") fmt.Println("<master/tokens> accepted provided token")
} }
@ -47,15 +47,15 @@ func generateTokenIfNeeded(s *kubeadmapi.KubeadmConfig) error {
return nil return nil
} }
func CreateTokenAuthFile(s *kubeadmapi.KubeadmConfig) error { func CreateTokenAuthFile(s *kubeadmapi.Secrets) error {
tokenAuthFilePath := path.Join(s.EnvParams["host_pki_path"], "tokens.csv") tokenAuthFilePath := path.Join(kubeadmapi.GetEnvParams()["host_pki_path"], "tokens.csv")
if err := generateTokenIfNeeded(s); err != nil { if err := generateTokenIfNeeded(s); err != nil {
return fmt.Errorf("<master/tokens> failed to generate token(s) [%v]", err) return fmt.Errorf("<master/tokens> failed to generate token(s) [%v]", err)
} }
if err := os.MkdirAll(s.EnvParams["host_pki_path"], 0700); err != nil { if err := os.MkdirAll(kubeadmapi.GetEnvParams()["host_pki_path"], 0700); err != nil {
return fmt.Errorf("<master/tokens> failed to create directory %q [%v]", s.EnvParams["host_pki_path"], err) return fmt.Errorf("<master/tokens> 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 // DumpReaderToFile create a file with mode 0600
if err := cmdutil.DumpReaderToFile(bytes.NewReader(serialized), tokenAuthFilePath); err != nil { if err := cmdutil.DumpReaderToFile(bytes.NewReader(serialized), tokenAuthFilePath); err != nil {
return fmt.Errorf("<master/tokens> failed to save token auth file (%q) [%v]", tokenAuthFilePath, err) return fmt.Errorf("<master/tokens> failed to save token auth file (%q) [%v]", tokenAuthFilePath, err)

View File

@ -34,8 +34,8 @@ import (
) )
// PerformTLSBootstrap creates a RESTful client in order to execute certificate signing request. // PerformTLSBootstrap creates a RESTful client in order to execute certificate signing request.
func PerformTLSBootstrap(s *kubeadmapi.KubeadmConfig, apiEndpoint string, caCert []byte) (*clientcmdapi.Config, error) { func PerformTLSBootstrap(s *kubeadmapi.NodeConfiguration, apiEndpoint string, caCert []byte) (*clientcmdapi.Config, error) {
// TODO(phase2) try all the api servers until we find one that works // TODO(phase1+) try all the api servers until we find one that works
bareClientConfig := kubeadmutil.CreateBasicClientConfig("kubernetes", apiEndpoint, caCert) bareClientConfig := kubeadmutil.CreateBasicClientConfig("kubernetes", apiEndpoint, caCert)
hostName, err := os.Hostname() hostName, err := os.Hostname()

View File

@ -28,8 +28,8 @@ import (
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
) )
func RetrieveTrustedClusterInfo(s *kubeadmapi.KubeadmConfig) (*clientcmdapi.Config, error) { func RetrieveTrustedClusterInfo(s *kubeadmapi.NodeConfiguration) (*clientcmdapi.Config, error) {
host, port := s.JoinFlags.MasterAddrs[0].String(), 9898 host, port := s.MasterAddresses[0], 9898
requestURL := fmt.Sprintf("http://%s:%d/cluster-info/v1/?token-id=%s", host, port, s.Secrets.TokenID) requestURL := fmt.Sprintf("http://%s:%d/cluster-info/v1/?token-id=%s", host, port, s.Secrets.TokenID)
req, err := http.NewRequest("GET", requestURL, nil) req, err := http.NewRequest("GET", requestURL, nil)
if err != nil { if err != nil {

View File

@ -75,12 +75,13 @@ func MakeClientConfigWithToken(config *clientcmdapi.Config, clusterName string,
return newConfig return newConfig
} }
func WriteKubeconfigIfNotExists(s *kubeadmapi.KubeadmConfig, name string, kubeconfig *clientcmdapi.Config) error { func WriteKubeconfigIfNotExists(name string, kubeconfig *clientcmdapi.Config) error {
if err := os.MkdirAll(s.EnvParams["kubernetes_dir"], 0700); err != nil { envParams := kubeadmapi.GetEnvParams()
return fmt.Errorf("<util/kubeconfig> failed to create directory %q [%v]", s.EnvParams["kubernetes_dir"], err) if err := os.MkdirAll(envParams["kubernetes_dir"], 0700); err != nil {
return fmt.Errorf("<util/kubeconfig> 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. // 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) f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0600)
if err != nil { if err != nil {

View File

@ -42,7 +42,7 @@ func RandBytes(length int) ([]byte, string, error) {
return b, hex.EncodeToString(b), nil return b, hex.EncodeToString(b), nil
} }
func GenerateToken(s *kubeadmapi.KubeadmConfig) error { func GenerateToken(s *kubeadmapi.Secrets) error {
_, tokenID, err := RandBytes(TokenIDLen / 2) _, tokenID, err := RandBytes(TokenIDLen / 2)
if err != nil { if err != nil {
return err return err
@ -53,19 +53,19 @@ func GenerateToken(s *kubeadmapi.KubeadmConfig) error {
return err return err
} }
s.Secrets.TokenID = tokenID s.TokenID = tokenID
s.Secrets.BearerToken = token s.BearerToken = token
s.Secrets.Token = tokenBytes s.Token = tokenBytes
s.Secrets.GivenToken = fmt.Sprintf("%s.%s", tokenID, token) s.GivenToken = fmt.Sprintf("%s.%s", tokenID, token)
return nil return nil
} }
func UseGivenTokenIfValid(s *kubeadmapi.KubeadmConfig) (bool, error) { func UseGivenTokenIfValid(s *kubeadmapi.Secrets) (bool, error) {
if s.Secrets.GivenToken == "" { if s.GivenToken == "" {
return false, nil // not given return false, nil // not given
} }
fmt.Println("<util/tokens> validating provided token") fmt.Println("<util/tokens> 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+) print desired format
// TODO(phase1+) could also print more specific messages in each case // TODO(phase1+) could also print more specific messages in each case
invalidErr := "<util/tokens> provided token is invalid - %s" invalidErr := "<util/tokens> provided token is invalid - %s"
@ -78,8 +78,8 @@ func UseGivenTokenIfValid(s *kubeadmapi.KubeadmConfig) (bool, error) {
len(givenToken[0]), TokenIDLen)) len(givenToken[0]), TokenIDLen))
} }
tokenBytes := []byte(givenToken[1]) tokenBytes := []byte(givenToken[1])
s.Secrets.TokenID = givenToken[0] s.TokenID = givenToken[0]
s.Secrets.BearerToken = givenToken[1] s.BearerToken = givenToken[1]
s.Secrets.Token = tokenBytes s.Token = tokenBytes
return true, nil // given and valid return true, nil // given and valid
} }

View File

@ -32,8 +32,10 @@ import (
type Factory func(config io.Reader) (Interface, error) type Factory func(config io.Reader) (Interface, error)
// All registered cloud providers. // All registered cloud providers.
var providersMutex sync.Mutex var (
var providers = make(map[string]Factory) providersMutex sync.Mutex
providers = make(map[string]Factory)
)
// RegisterCloudProvider registers a cloudprovider.Factory by name. This // RegisterCloudProvider registers a cloudprovider.Factory by name. This
// is expected to happen during app startup. // is expected to happen during app startup.
@ -47,6 +49,27 @@ func RegisterCloudProvider(name string, cloud Factory) {
providers[name] = cloud 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 // 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 // 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 // was known but failed to initialize. The config parameter specifies the