Skip to content

Commit

Permalink
Detect MinIO image from the 'ha-minio' StatefulSet if exists (#4349)
Browse files Browse the repository at this point in the history
  • Loading branch information
sgalsaleh authored Jan 12, 2024
1 parent c185dc5 commit 017f85f
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 15 deletions.
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

0 comments on commit 017f85f

Please sign in to comment.