Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect MinIO image from the 'ha-minio' StatefulSet if exists #4349

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions pkg/image/minio.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,28 @@ func GetMinioImage(clientset kubernetes.Interface, kotsadmNamespace string) (str
}

deployment, err := clientset.AppsV1().Deployments("minio").Get(context.TODO(), "minio", metav1.GetOptions{})
if err != nil {
if kuberneteserrors.IsNotFound(err) {
return "", nil
}
if err != nil && !kuberneteserrors.IsNotFound(err) {
return "", errors.Wrap(err, "failed to get minio deployment")
}
if err == nil {
for _, container := range deployment.Spec.Template.Spec.Containers {
if strings.Contains(container.Image, "minio/minio:RELEASE.") {
return container.Image, nil
}
}
}

for _, container := range deployment.Spec.Template.Spec.Containers {
if strings.Contains(container.Image, "minio/minio:RELEASE.") {
return container.Image, nil
// minio deployment doesn't exist, check if ha-minio statefulset exists

statefulset, err := clientset.AppsV1().StatefulSets("minio").Get(context.TODO(), "ha-minio", metav1.GetOptions{})
if err != nil && !kuberneteserrors.IsNotFound(err) {
return "", errors.Wrap(err, "failed to get ha-minio statefulset")
}
if err == nil {
for _, container := range statefulset.Spec.Template.Spec.Containers {
if strings.Contains(container.Image, "minio/minio:RELEASE.") {
return container.Image, nil
}
}
}

Expand Down
131 changes: 131 additions & 0 deletions pkg/image/minio_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package image

import (
"testing"

"github.com/replicatedhq/kots/pkg/kurl"
"github.com/stretchr/testify/require"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/fake"
)

func Test_GetMinioImage(t *testing.T) {
tests := []struct {
name string
clientset kubernetes.Interface
kotsadmNamespace string
wantImage string
wantErr bool
}{
{
name: "should return static image for non-kurl instance",
clientset: fake.NewSimpleClientset(),
kotsadmNamespace: metav1.NamespaceDefault,
wantImage: Minio,
wantErr: false,
},
{
name: "should return static image for kurl instance with non-default namespace",
clientset: fake.NewSimpleClientset(&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: kurl.ConfigMapName,
Namespace: kurl.ConfigMapNamespace,
},
}),
kotsadmNamespace: "custom-namespace",
wantImage: Minio,
wantErr: false,
},
{
name: "should return minio image from deployment for kurl instance with default namespace",
clientset: fake.NewSimpleClientset(
&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: kurl.ConfigMapName,
Namespace: kurl.ConfigMapNamespace,
},
},
&appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "minio",
Namespace: "minio",
},
Spec: appsv1.DeploymentSpec{
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "minio",
Image: "minio/minio:RELEASE.2020-10-27T00-54-19Z",
},
},
},
},
},
},
),
kotsadmNamespace: metav1.NamespaceDefault,
wantImage: "minio/minio:RELEASE.2020-10-27T00-54-19Z",
wantErr: false,
},
{
name: "should return minio image from statefulset for kurl instance with default namespace",
clientset: fake.NewSimpleClientset(
&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: kurl.ConfigMapName,
Namespace: kurl.ConfigMapNamespace,
},
},
&appsv1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{
Name: "ha-minio",
Namespace: "minio",
},
Spec: appsv1.StatefulSetSpec{
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "minio",
Image: "minio/minio:RELEASE.2020-10-27T00-54-19Z",
},
},
},
},
},
}),
kotsadmNamespace: metav1.NamespaceDefault,
wantImage: "minio/minio:RELEASE.2020-10-27T00-54-19Z",
wantErr: false,
},
{
name: "should return empty image if deployment and statefulset don't exist for kurl instance with default namespace",
clientset: fake.NewSimpleClientset(&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: kurl.ConfigMapName,
Namespace: kurl.ConfigMapNamespace,
},
}),
kotsadmNamespace: metav1.NamespaceDefault,
wantImage: "",
wantErr: false,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
req := require.New(t)
gotImage, err := GetMinioImage(test.clientset, test.kotsadmNamespace)
if test.wantErr {
req.Error(err)
} else {
req.NoError(err)
}
req.Equal(test.wantImage, gotImage)
})
}
}
10 changes: 5 additions & 5 deletions pkg/kurl/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import (
"k8s.io/client-go/kubernetes"
)

const configMapName = "kurl-config"
const configMapNamespace = "kube-system"
const ConfigMapName = "kurl-config"
const ConfigMapNamespace = "kube-system"

const bootstrapTokenKey = "bootstrap_token"
const bootstrapTokenExpirationKey = "bootstrap_token_expiration"
Expand Down Expand Up @@ -46,12 +46,12 @@ func IsKurl(clientset kubernetes.Interface) (bool, error) {

// ReadConfigMap will read the Kurl config from a configmap
func ReadConfigMap(client kubernetes.Interface) (*corev1.ConfigMap, error) {
return client.CoreV1().ConfigMaps(configMapNamespace).Get(context.TODO(), configMapName, metav1.GetOptions{})
return client.CoreV1().ConfigMaps(ConfigMapNamespace).Get(context.TODO(), ConfigMapName, metav1.GetOptions{})
}

// UpdateConfigMap will save the Kurl config in a configmap
func UpdateConfigMap(client kubernetes.Interface, generateBootstrapToken, uploadCerts bool) (*corev1.ConfigMap, error) {
cm, err := client.CoreV1().ConfigMaps(configMapNamespace).Get(context.TODO(), configMapName, metav1.GetOptions{})
cm, err := client.CoreV1().ConfigMaps(ConfigMapNamespace).Get(context.TODO(), ConfigMapName, metav1.GetOptions{})
if err != nil {
return nil, errors.Wrap(err, "get configmap")
}
Expand Down Expand Up @@ -94,7 +94,7 @@ func UpdateConfigMap(client kubernetes.Interface, generateBootstrapToken, upload
cm.Data[certsExpirationKey] = certsExpiration.Format(time.RFC3339)
}

cm, err = client.CoreV1().ConfigMaps(configMapNamespace).Update(context.TODO(), cm, metav1.UpdateOptions{})
cm, err = client.CoreV1().ConfigMaps(ConfigMapNamespace).Update(context.TODO(), cm, metav1.UpdateOptions{})
if err != nil {
return nil, errors.Wrap(err, "update configmap")
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/kurl/configmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func Test_IsKurl(t *testing.T) {
},
{
name: "expect false when configmap is not found",
args: mockClientWithError(kuberneteserrors.NewNotFound(corev1.Resource("configmaps"), configMapName)),
args: mockClientWithError(kuberneteserrors.NewNotFound(corev1.Resource("configmaps"), ConfigMapName)),
want: false,
},
{
Expand All @@ -46,7 +46,7 @@ func Test_IsKurl(t *testing.T) {
},
{
name: "expect false when client is forbidden",
args: mockClientWithError(kuberneteserrors.NewForbidden(corev1.Resource("configmaps"), configMapName, errors.New("Forbidden"))),
args: mockClientWithError(kuberneteserrors.NewForbidden(corev1.Resource("configmaps"), ConfigMapName, errors.New("Forbidden"))),
want: false,
},
{
Expand All @@ -59,7 +59,7 @@ func Test_IsKurl(t *testing.T) {
name: "expect true when configmap is found",
args: fake.NewSimpleClientset(&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: configMapName,
Name: ConfigMapName,
Namespace: metav1.NamespaceSystem,
},
}),
Expand Down
Loading