diff --git a/pkg/apis/etcd/v1beta2/cluster.go b/pkg/apis/etcd/v1beta2/cluster.go index 889534b6b..45d232b02 100644 --- a/pkg/apis/etcd/v1beta2/cluster.go +++ b/pkg/apis/etcd/v1beta2/cluster.go @@ -18,7 +18,7 @@ import ( "errors" "strings" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -162,6 +162,11 @@ type PodPolicy struct { // '.cluster.local'. // The default is to not set a cluster domain explicitly. ClusterDomain string `json:"ClusterDomain"` + + // curl init container image. default is tutum/curl. + // pulling tutum/curl:latest requires external access. + // More info: https://github.com/coreos/etcd-operator/issues/1933 + CurlImage string `json:"curlImage,omitempty"` } // TODO: move this to initializer diff --git a/pkg/util/k8sutil/k8sutil.go b/pkg/util/k8sutil/k8sutil.go index 8db36f18a..ee9a83318 100644 --- a/pkg/util/k8sutil/k8sutil.go +++ b/pkg/util/k8sutil/k8sutil.go @@ -63,6 +63,7 @@ const ( MaxNameLength = 63 - randomSuffixLength - 1 defaultBusyboxImage = "busybox:1.28.0-glibc" + defaultCurlImage = "tutum/curl:latest" // AnnotationScope annotation name for defining instance scope. Used for specifying cluster wide clusters. AnnotationScope = "etcd.database.coreos.com/scope" @@ -100,11 +101,12 @@ func PVCNameFromMember(memberName string) string { return memberName } -func makeRestoreInitContainers(backupURL *url.URL, token, repo, version string, m *etcdutil.Member) []v1.Container { +func makeRestoreInitContainers(backupURL *url.URL, token, repo, version string, m *etcdutil.Member, podPolicy *api.PodPolicy) []v1.Container { return []v1.Container{ { - Name: "fetch-backup", - Image: "tutum/curl", + Name: "fetch-backup", + //Image default: "tutum/curl:latest", + Image: imageNameCurl(podPolicy), Command: []string{ "/bin/bash", "-ec", fmt.Sprintf(` @@ -147,6 +149,14 @@ func imageNameBusybox(policy *api.PodPolicy) string { return defaultBusyboxImage } +// imageNameCurl returns the default image for curl init container, or the image specified in the PodPolicy +func imageNameCurl(policy *api.PodPolicy) string { + if policy != nil && len(policy.CurlImage) > 0 { + return policy.CurlImage + } + return defaultCurlImage +} + func PodWithNodeSelector(p *v1.Pod, ns map[string]string) *v1.Pod { p.Spec.NodeSelector = ns return p @@ -261,7 +271,7 @@ func AddEtcdVolumeToPod(pod *v1.Pod, pvc *v1.PersistentVolumeClaim) { func addRecoveryToPod(pod *v1.Pod, token string, m *etcdutil.Member, cs api.ClusterSpec, backupURL *url.URL) { pod.Spec.InitContainers = append(pod.Spec.InitContainers, - makeRestoreInitContainers(backupURL, token, cs.Repository, cs.Version, m)...) + makeRestoreInitContainers(backupURL, token, cs.Repository, cs.Version, m, cs.Pod)...) } func addOwnerRefToObject(o metav1.Object, r metav1.OwnerReference) { diff --git a/pkg/util/k8sutil/k8sutils_test.go b/pkg/util/k8sutil/k8sutils_test.go index cce491401..54edd765c 100644 --- a/pkg/util/k8sutil/k8sutils_test.go +++ b/pkg/util/k8sutil/k8sutils_test.go @@ -47,3 +47,31 @@ func TestSetBusyboxImageName(t *testing.T) { t.Errorf("expect image=%s, get=%s", expected, image) } } + +func TestDefaultCurlImageName(t *testing.T) { + policy := &api.PodPolicy{} + image := imageNameCurl(policy) + expected := defaultCurlImage + if image != expected { + t.Errorf("expect image=%s, get=%s", expected, image) + } +} + +func TestDefaultNilCurlImageName(t *testing.T) { + image := imageNameCurl(nil) + expected := defaultCurlImage + if image != expected { + t.Errorf("expect image=%s, get=%s", expected, image) + } +} + +func TestSetCurlImageName(t *testing.T) { + policy := &api.PodPolicy{ + CurlImage: "myRepo/curl:1.3.2", + } + image := imageNameCurl(policy) + expected := "myRepo/curl:1.3.2" + if image != expected { + t.Errorf("expect image=%s, get=%s", expected, image) + } +}