Commit 080d1081 authored by Maru Newby's avatar Maru Newby

fed: Add support for etcd image override to kubefed init

parent 4d6ef25f
...@@ -28,13 +28,16 @@ import ( ...@@ -28,13 +28,16 @@ import (
_ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration _ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration
) )
const hyperkubeImageName = "gcr.io/google_containers/hyperkube-amd64" const (
hyperkubeImageName = "gcr.io/google_containers/hyperkube-amd64"
defaultEtcdImage = "gcr.io/google_containers/etcd:3.0.17"
)
func Run() error { func Run() error {
logs.InitLogs() logs.InitLogs()
defer logs.FlushLogs() defer logs.FlushLogs()
defaultImage := fmt.Sprintf("%s:%s", hyperkubeImageName, version.Get()) defaultServerImage := fmt.Sprintf("%s:%s", hyperkubeImageName, version.Get())
cmd := kubefed.NewKubeFedCommand(cmdutil.NewFactory(nil), os.Stdin, os.Stdout, os.Stderr, defaultImage) cmd := kubefed.NewKubeFedCommand(cmdutil.NewFactory(nil), os.Stdin, os.Stdout, os.Stderr, defaultServerImage, defaultEtcdImage)
return cmd.Execute() return cmd.Execute()
} }
...@@ -134,9 +134,10 @@ type initFederation struct { ...@@ -134,9 +134,10 @@ type initFederation struct {
type initFederationOptions struct { type initFederationOptions struct {
dnsZoneName string dnsZoneName string
image string serverImage string
dnsProvider string dnsProvider string
dnsProviderConfig string dnsProviderConfig string
etcdImage string
etcdPVCapacity string etcdPVCapacity string
etcdPersistentStorage bool etcdPersistentStorage bool
dryRun bool dryRun bool
...@@ -151,11 +152,12 @@ type initFederationOptions struct { ...@@ -151,11 +152,12 @@ type initFederationOptions struct {
apiServerEnableTokenAuth bool apiServerEnableTokenAuth bool
} }
func (o *initFederationOptions) Bind(flags *pflag.FlagSet, defaultImage string) { func (o *initFederationOptions) Bind(flags *pflag.FlagSet, defaultServerImage, defaultEtcdImage string) {
flags.StringVar(&o.dnsZoneName, "dns-zone-name", "", "DNS suffix for this federation. Federated Service DNS names are published with this suffix.") flags.StringVar(&o.dnsZoneName, "dns-zone-name", "", "DNS suffix for this federation. Federated Service DNS names are published with this suffix.")
flags.StringVar(&o.image, "image", defaultImage, "Image to use for federation API server and controller manager binaries.") flags.StringVar(&o.serverImage, "image", defaultServerImage, "Image to use for federation API server and controller manager binaries.")
flags.StringVar(&o.dnsProvider, "dns-provider", "", "Dns provider to be used for this deployment.") flags.StringVar(&o.dnsProvider, "dns-provider", "", "Dns provider to be used for this deployment.")
flags.StringVar(&o.dnsProviderConfig, "dns-provider-config", "", "Config file path on local file system for configuring DNS provider.") flags.StringVar(&o.dnsProviderConfig, "dns-provider-config", "", "Config file path on local file system for configuring DNS provider.")
flags.StringVar(&o.etcdImage, "etcd-image", defaultEtcdImage, "Image to use for etcd server.")
flags.StringVar(&o.etcdPVCapacity, "etcd-pv-capacity", "10Gi", "Size of persistent volume claim to be used for etcd.") flags.StringVar(&o.etcdPVCapacity, "etcd-pv-capacity", "10Gi", "Size of persistent volume claim to be used for etcd.")
flags.BoolVar(&o.etcdPersistentStorage, "etcd-persistent-storage", true, "Use persistent volume for etcd. Defaults to 'true'.") flags.BoolVar(&o.etcdPersistentStorage, "etcd-persistent-storage", true, "Use persistent volume for etcd. Defaults to 'true'.")
flags.BoolVar(&o.dryRun, "dry-run", false, "dry run without sending commands to server.") flags.BoolVar(&o.dryRun, "dry-run", false, "dry run without sending commands to server.")
...@@ -169,7 +171,7 @@ func (o *initFederationOptions) Bind(flags *pflag.FlagSet, defaultImage string) ...@@ -169,7 +171,7 @@ func (o *initFederationOptions) Bind(flags *pflag.FlagSet, defaultImage string)
// NewCmdInit defines the `init` command that bootstraps a federation // NewCmdInit defines the `init` command that bootstraps a federation
// control plane inside a set of host clusters. // control plane inside a set of host clusters.
func NewCmdInit(cmdOut io.Writer, config util.AdminConfig, defaultImage string) *cobra.Command { func NewCmdInit(cmdOut io.Writer, config util.AdminConfig, defaultServerImage, defaultEtcdImage string) *cobra.Command {
opts := &initFederation{} opts := &initFederation{}
cmd := &cobra.Command{ cmd := &cobra.Command{
...@@ -185,7 +187,7 @@ func NewCmdInit(cmdOut io.Writer, config util.AdminConfig, defaultImage string) ...@@ -185,7 +187,7 @@ func NewCmdInit(cmdOut io.Writer, config util.AdminConfig, defaultImage string)
flags := cmd.Flags() flags := cmd.Flags()
opts.commonOptions.Bind(flags) opts.commonOptions.Bind(flags)
opts.options.Bind(flags, defaultImage) opts.options.Bind(flags, defaultServerImage, defaultEtcdImage)
return cmd return cmd
} }
...@@ -341,7 +343,7 @@ func (i *initFederation) Run(cmdOut io.Writer, config util.AdminConfig) error { ...@@ -341,7 +343,7 @@ func (i *initFederation) Run(cmdOut io.Writer, config util.AdminConfig) error {
fmt.Fprint(cmdOut, "Creating federation component deployments...") fmt.Fprint(cmdOut, "Creating federation component deployments...")
glog.V(4).Info("Creating federation control plane components") glog.V(4).Info("Creating federation control plane components")
_, err = createAPIServer(hostClientset, i.commonOptions.FederationSystemNamespace, serverName, i.commonOptions.Name, i.options.image, advertiseAddress, serverCredName, i.options.apiServerEnableHTTPBasicAuth, i.options.apiServerEnableTokenAuth, i.options.apiServerOverrides, pvc, i.options.dryRun) _, err = createAPIServer(hostClientset, i.commonOptions.FederationSystemNamespace, serverName, i.commonOptions.Name, i.options.serverImage, i.options.etcdImage, advertiseAddress, serverCredName, i.options.apiServerEnableHTTPBasicAuth, i.options.apiServerEnableTokenAuth, i.options.apiServerOverrides, pvc, i.options.dryRun)
if err != nil { if err != nil {
return err return err
} }
...@@ -376,7 +378,7 @@ func (i *initFederation) Run(cmdOut io.Writer, config util.AdminConfig) error { ...@@ -376,7 +378,7 @@ func (i *initFederation) Run(cmdOut io.Writer, config util.AdminConfig) error {
glog.V(4).Info("Creating federation controller manager deployment") glog.V(4).Info("Creating federation controller manager deployment")
_, err = createControllerManager(hostClientset, i.commonOptions.FederationSystemNamespace, i.commonOptions.Name, svc.Name, cmName, i.options.image, cmKubeconfigName, i.options.dnsZoneName, i.options.dnsProvider, i.options.dnsProviderConfig, sa.Name, dnsProviderSecret, i.options.controllerManagerOverrides, i.options.dryRun) _, err = createControllerManager(hostClientset, i.commonOptions.FederationSystemNamespace, i.commonOptions.Name, svc.Name, cmName, i.options.serverImage, cmKubeconfigName, i.options.dnsZoneName, i.options.dnsProvider, i.options.dnsProviderConfig, sa.Name, dnsProviderSecret, i.options.controllerManagerOverrides, i.options.dryRun)
if err != nil { if err != nil {
return err return err
} }
...@@ -670,7 +672,7 @@ func createPVC(clientset client.Interface, namespace, svcName, federationName, e ...@@ -670,7 +672,7 @@ func createPVC(clientset client.Interface, namespace, svcName, federationName, e
return clientset.Core().PersistentVolumeClaims(namespace).Create(pvc) return clientset.Core().PersistentVolumeClaims(namespace).Create(pvc)
} }
func createAPIServer(clientset client.Interface, namespace, name, federationName, image, advertiseAddress, credentialsName string, hasHTTPBasicAuthFile, hasTokenAuthFile bool, argOverrides map[string]string, pvc *api.PersistentVolumeClaim, dryRun bool) (*extensions.Deployment, error) { func createAPIServer(clientset client.Interface, namespace, name, federationName, serverImage, etcdImage, advertiseAddress, credentialsName string, hasHTTPBasicAuthFile, hasTokenAuthFile bool, argOverrides map[string]string, pvc *api.PersistentVolumeClaim, dryRun bool) (*extensions.Deployment, error) {
command := []string{ command := []string{
"/hyperkube", "/hyperkube",
"federation-apiserver", "federation-apiserver",
...@@ -717,7 +719,7 @@ func createAPIServer(clientset client.Interface, namespace, name, federationName ...@@ -717,7 +719,7 @@ func createAPIServer(clientset client.Interface, namespace, name, federationName
Containers: []api.Container{ Containers: []api.Container{
{ {
Name: "apiserver", Name: "apiserver",
Image: image, Image: serverImage,
Command: command, Command: command,
Ports: []api.ContainerPort{ Ports: []api.ContainerPort{
{ {
...@@ -739,7 +741,7 @@ func createAPIServer(clientset client.Interface, namespace, name, federationName ...@@ -739,7 +741,7 @@ func createAPIServer(clientset client.Interface, namespace, name, federationName
}, },
{ {
Name: "etcd", Name: "etcd",
Image: "gcr.io/google_containers/etcd:3.0.17", Image: etcdImage,
Command: []string{ Command: []string{
"/usr/local/bin/etcd", "/usr/local/bin/etcd",
"--data-dir", "--data-dir",
......
...@@ -95,7 +95,8 @@ func TestInitFederation(t *testing.T) { ...@@ -95,7 +95,8 @@ func TestInitFederation(t *testing.T) {
lbIP string lbIP string
apiserverServiceType v1.ServiceType apiserverServiceType v1.ServiceType
advertiseAddress string advertiseAddress string
image string serverImage string
etcdImage string
etcdPVCapacity string etcdPVCapacity string
etcdPersistence string etcdPersistence string
expectedErr string expectedErr string
...@@ -115,7 +116,7 @@ func TestInitFederation(t *testing.T) { ...@@ -115,7 +116,7 @@ func TestInitFederation(t *testing.T) {
dnsZoneName: "example.test.", dnsZoneName: "example.test.",
lbIP: lbIP, lbIP: lbIP,
apiserverServiceType: v1.ServiceTypeLoadBalancer, apiserverServiceType: v1.ServiceTypeLoadBalancer,
image: "example.test/foo:bar", serverImage: "example.test/foo:bar",
etcdPVCapacity: "5Gi", etcdPVCapacity: "5Gi",
etcdPersistence: "true", etcdPersistence: "true",
expectedErr: "", expectedErr: "",
...@@ -132,7 +133,7 @@ func TestInitFederation(t *testing.T) { ...@@ -132,7 +133,7 @@ func TestInitFederation(t *testing.T) {
dnsZoneName: "example.test.", dnsZoneName: "example.test.",
lbIP: lbIP, lbIP: lbIP,
apiserverServiceType: v1.ServiceTypeLoadBalancer, apiserverServiceType: v1.ServiceTypeLoadBalancer,
image: "example.test/foo:bar", serverImage: "example.test/foo:bar",
etcdPVCapacity: "", //test for default value of pvc-size etcdPVCapacity: "", //test for default value of pvc-size
etcdPersistence: "true", etcdPersistence: "true",
expectedErr: "", expectedErr: "",
...@@ -145,7 +146,7 @@ func TestInitFederation(t *testing.T) { ...@@ -145,7 +146,7 @@ func TestInitFederation(t *testing.T) {
dnsZoneName: "example.test.", dnsZoneName: "example.test.",
lbIP: lbIP, lbIP: lbIP,
apiserverServiceType: v1.ServiceTypeLoadBalancer, apiserverServiceType: v1.ServiceTypeLoadBalancer,
image: "example.test/foo:bar", serverImage: "example.test/foo:bar",
etcdPVCapacity: "", etcdPVCapacity: "",
etcdPersistence: "true", etcdPersistence: "true",
expectedErr: "", expectedErr: "",
...@@ -158,7 +159,7 @@ func TestInitFederation(t *testing.T) { ...@@ -158,7 +159,7 @@ func TestInitFederation(t *testing.T) {
dnsZoneName: "example.test.", dnsZoneName: "example.test.",
lbIP: lbIP, lbIP: lbIP,
apiserverServiceType: v1.ServiceTypeLoadBalancer, apiserverServiceType: v1.ServiceTypeLoadBalancer,
image: "example.test/foo:bar", serverImage: "example.test/foo:bar",
etcdPVCapacity: "5Gi", etcdPVCapacity: "5Gi",
etcdPersistence: "false", etcdPersistence: "false",
expectedErr: "", expectedErr: "",
...@@ -170,7 +171,7 @@ func TestInitFederation(t *testing.T) { ...@@ -170,7 +171,7 @@ func TestInitFederation(t *testing.T) {
kubeconfigExplicit: "", kubeconfigExplicit: "",
dnsZoneName: "example.test.", dnsZoneName: "example.test.",
apiserverServiceType: v1.ServiceTypeNodePort, apiserverServiceType: v1.ServiceTypeNodePort,
image: "example.test/foo:bar", serverImage: "example.test/foo:bar",
etcdPVCapacity: "5Gi", etcdPVCapacity: "5Gi",
etcdPersistence: "true", etcdPersistence: "true",
expectedErr: "", expectedErr: "",
...@@ -183,7 +184,7 @@ func TestInitFederation(t *testing.T) { ...@@ -183,7 +184,7 @@ func TestInitFederation(t *testing.T) {
dnsZoneName: "example.test.", dnsZoneName: "example.test.",
apiserverServiceType: v1.ServiceTypeNodePort, apiserverServiceType: v1.ServiceTypeNodePort,
advertiseAddress: nodeIP, advertiseAddress: nodeIP,
image: "example.test/foo:bar", serverImage: "example.test/foo:bar",
etcdPVCapacity: "5Gi", etcdPVCapacity: "5Gi",
etcdPersistence: "true", etcdPersistence: "true",
expectedErr: "", expectedErr: "",
...@@ -196,7 +197,8 @@ func TestInitFederation(t *testing.T) { ...@@ -196,7 +197,8 @@ func TestInitFederation(t *testing.T) {
dnsZoneName: "example.test.", dnsZoneName: "example.test.",
apiserverServiceType: v1.ServiceTypeNodePort, apiserverServiceType: v1.ServiceTypeNodePort,
advertiseAddress: nodeIP, advertiseAddress: nodeIP,
image: "example.test/foo:bar", serverImage: "example.test/foo:bar",
etcdImage: "gcr.io/google_containers/etcd:latest",
etcdPVCapacity: "5Gi", etcdPVCapacity: "5Gi",
etcdPersistence: "true", etcdPersistence: "true",
expectedErr: "", expectedErr: "",
...@@ -207,6 +209,8 @@ func TestInitFederation(t *testing.T) { ...@@ -207,6 +209,8 @@ func TestInitFederation(t *testing.T) {
}, },
} }
defaultEtcdImage := "gcr.io/google_containers/etcd:3.0.17"
//TODO: implement a negative case for dry run //TODO: implement a negative case for dry run
for i, tc := range testCases { for i, tc := range testCases {
...@@ -234,7 +238,13 @@ func TestInitFederation(t *testing.T) { ...@@ -234,7 +238,13 @@ func TestInitFederation(t *testing.T) {
} }
defer os.Remove(tmpDirPath) defer os.Remove(tmpDirPath)
hostFactory, err := fakeInitHostFactory(tc.apiserverServiceType, tc.federation, util.DefaultFederationSystemNamespace, tc.advertiseAddress, tc.lbIP, tc.dnsZoneName, tc.image, tc.dnsProvider, tc.dnsProviderConfig, tc.etcdPersistence, tc.etcdPVCapacity, tc.apiserverArgOverrides, tc.cmArgOverrides, tmpDirPath, tc.apiserverEnableHTTPBasicAuth, tc.apiserverEnableTokenAuth, tc.isRBACAPIAvailable) // If tc.etcdImage is set, setting the etcd image via the flag will be
// validated. If not set, the default value will be validated.
if tc.etcdImage == "" {
tc.etcdImage = defaultEtcdImage
}
hostFactory, err := fakeInitHostFactory(tc.apiserverServiceType, tc.federation, util.DefaultFederationSystemNamespace, tc.advertiseAddress, tc.lbIP, tc.dnsZoneName, tc.serverImage, tc.etcdImage, tc.dnsProvider, tc.dnsProviderConfig, tc.etcdPersistence, tc.etcdPVCapacity, tc.apiserverArgOverrides, tc.cmArgOverrides, tmpDirPath, tc.apiserverEnableHTTPBasicAuth, tc.apiserverEnableTokenAuth, tc.isRBACAPIAvailable)
if err != nil { if err != nil {
t.Fatalf("[%d] unexpected error: %v", i, err) t.Fatalf("[%d] unexpected error: %v", i, err)
} }
...@@ -244,12 +254,13 @@ func TestInitFederation(t *testing.T) { ...@@ -244,12 +254,13 @@ func TestInitFederation(t *testing.T) {
t.Fatalf("[%d] unexpected error: %v", i, err) t.Fatalf("[%d] unexpected error: %v", i, err)
} }
cmd := NewCmdInit(buf, adminConfig, "image") cmd := NewCmdInit(buf, adminConfig, "serverImage", defaultEtcdImage)
cmd.Flags().Set("kubeconfig", tc.kubeconfigExplicit) cmd.Flags().Set("kubeconfig", tc.kubeconfigExplicit)
cmd.Flags().Set("host-cluster-context", "substrate") cmd.Flags().Set("host-cluster-context", "substrate")
cmd.Flags().Set("dns-zone-name", tc.dnsZoneName) cmd.Flags().Set("dns-zone-name", tc.dnsZoneName)
cmd.Flags().Set("image", tc.image) cmd.Flags().Set("image", tc.serverImage)
cmd.Flags().Set("etcd-image", tc.etcdImage)
cmd.Flags().Set("dns-provider", tc.dnsProvider) cmd.Flags().Set("dns-provider", tc.dnsProvider)
cmd.Flags().Set("apiserver-arg-overrides", tc.apiserverArgOverrides) cmd.Flags().Set("apiserver-arg-overrides", tc.apiserverArgOverrides)
cmd.Flags().Set("controllermanager-arg-overrides", tc.cmArgOverrides) cmd.Flags().Set("controllermanager-arg-overrides", tc.cmArgOverrides)
...@@ -605,7 +616,7 @@ func TestCertsHTTPS(t *testing.T) { ...@@ -605,7 +616,7 @@ func TestCertsHTTPS(t *testing.T) {
} }
} }
func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, namespaceName, advertiseAddress, lbIp, dnsZoneName, image, dnsProvider, dnsProviderConfig, etcdPersistence, etcdPVCapacity, apiserverOverrideArg, cmOverrideArg, tmpDirPath string, apiserverEnableHTTPBasicAuth, apiserverEnableTokenAuth, isRBACAPIAvailable bool) (cmdutil.Factory, error) { func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, namespaceName, advertiseAddress, lbIp, dnsZoneName, serverImage, etcdImage, dnsProvider, dnsProviderConfig, etcdPersistence, etcdPVCapacity, apiserverOverrideArg, cmOverrideArg, tmpDirPath string, apiserverEnableHTTPBasicAuth, apiserverEnableTokenAuth, isRBACAPIAvailable bool) (cmdutil.Factory, error) {
svcName := federationName + "-apiserver" svcName := federationName + "-apiserver"
svcUrlPrefix := "/api/v1/namespaces/federation-system/services" svcUrlPrefix := "/api/v1/namespaces/federation-system/services"
credSecretName := svcName + "-credentials" credSecretName := svcName + "-credentials"
...@@ -892,7 +903,7 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na ...@@ -892,7 +903,7 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Containers: []v1.Container{ Containers: []v1.Container{
{ {
Name: "apiserver", Name: "apiserver",
Image: image, Image: serverImage,
Command: apiserverCommand, Command: apiserverCommand,
Ports: []v1.ContainerPort{ Ports: []v1.ContainerPort{
{ {
...@@ -914,7 +925,7 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na ...@@ -914,7 +925,7 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
}, },
{ {
Name: "etcd", Name: "etcd",
Image: "gcr.io/google_containers/etcd:3.0.17", Image: etcdImage,
Command: []string{ Command: []string{
"/usr/local/bin/etcd", "/usr/local/bin/etcd",
"--data-dir", "--data-dir",
...@@ -1009,7 +1020,7 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na ...@@ -1009,7 +1020,7 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Containers: []v1.Container{ Containers: []v1.Container{
{ {
Name: "controller-manager", Name: "controller-manager",
Image: image, Image: serverImage,
Command: cmCommand, Command: cmCommand,
VolumeMounts: []v1.VolumeMount{ VolumeMounts: []v1.VolumeMount{
{ {
......
...@@ -31,7 +31,7 @@ import ( ...@@ -31,7 +31,7 @@ import (
) )
// NewKubeFedCommand creates the `kubefed` command and its nested children. // NewKubeFedCommand creates the `kubefed` command and its nested children.
func NewKubeFedCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer, defaultImage string) *cobra.Command { func NewKubeFedCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer, defaultServerImage, defaultEtcdImage string) *cobra.Command {
// Parent command to which all subcommands are added. // Parent command to which all subcommands are added.
cmds := &cobra.Command{ cmds := &cobra.Command{
Use: "kubefed", Use: "kubefed",
...@@ -53,7 +53,7 @@ func NewKubeFedCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer, defa ...@@ -53,7 +53,7 @@ func NewKubeFedCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer, defa
{ {
Message: "Basic Commands:", Message: "Basic Commands:",
Commands: []*cobra.Command{ Commands: []*cobra.Command{
kubefedinit.NewCmdInit(out, util.NewAdminConfig(clientcmd.NewDefaultPathOptions()), defaultImage), kubefedinit.NewCmdInit(out, util.NewAdminConfig(clientcmd.NewDefaultPathOptions()), defaultServerImage, defaultEtcdImage),
NewCmdJoin(f, out, util.NewAdminConfig(clientcmd.NewDefaultPathOptions())), NewCmdJoin(f, out, util.NewAdminConfig(clientcmd.NewDefaultPathOptions())),
NewCmdUnjoin(f, out, err, util.NewAdminConfig(clientcmd.NewDefaultPathOptions())), NewCmdUnjoin(f, out, err, util.NewAdminConfig(clientcmd.NewDefaultPathOptions())),
}, },
......
...@@ -207,6 +207,7 @@ etcd-cafile ...@@ -207,6 +207,7 @@ etcd-cafile
etcd-certfile etcd-certfile
etcd-config etcd-config
etcd-keyfile etcd-keyfile
etcd-image
etcd-metrics-scrape-uri etcd-metrics-scrape-uri
etcd-metrics-scrape-uri etcd-metrics-scrape-uri
etcd-mutation-timeout etcd-mutation-timeout
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment