diff --git a/pkg/image/minio.go b/pkg/image/minio.go index 313eb0020f..92ebe329b0 100644 --- a/pkg/image/minio.go +++ b/pkg/image/minio.go @@ -2,7 +2,7 @@ package image import ( "context" - "strings" + "regexp" "github.com/pkg/errors" "github.com/replicatedhq/kots/pkg/kurl" @@ -11,6 +11,11 @@ import ( "k8s.io/client-go/kubernetes" ) +// minioReleaseImageRegexp matches any repository whose image name is "minio" with an +// upstream RELEASE tag, e.g. "minio/minio:RELEASE.2025-10-15T17-29-55Z" and +// "kurlsh/minio:RELEASE.2025-10-15T17-29-55Z". +var minioReleaseImageRegexp = regexp.MustCompile(`(^|/)minio:RELEASE\.`) + // MinioImage looks through the nodes in the cluster and finds nodes that have already pulled Minio, and then finds the latest image tag listed func GetMinioImage(clientset kubernetes.Interface, kotsadmNamespace string) (string, error) { /* @@ -30,7 +35,7 @@ func GetMinioImage(clientset kubernetes.Interface, kotsadmNamespace string) (str } if err == nil { for _, container := range deployment.Spec.Template.Spec.Containers { - if strings.Contains(container.Image, "minio/minio:RELEASE.") { + if isMinioReleaseImage(container.Image) { return container.Image, nil } } @@ -44,7 +49,7 @@ func GetMinioImage(clientset kubernetes.Interface, kotsadmNamespace string) (str } if err == nil { for _, container := range statefulset.Spec.Template.Spec.Containers { - if strings.Contains(container.Image, "minio/minio:RELEASE.") { + if isMinioReleaseImage(container.Image) { return container.Image, nil } } @@ -52,3 +57,11 @@ func GetMinioImage(clientset kubernetes.Interface, kotsadmNamespace string) (str return "", nil } + +// isMinioReleaseImage returns true if the image is a minio image with an upstream +// RELEASE tag, regardless of which repository it was published to. The add-on has +// shipped from more than one repository (minio/minio, kurlsh/minio), so only the +// image name and tag are matched, not the registry or organization. +func isMinioReleaseImage(image string) bool { + return minioReleaseImageRegexp.MatchString(image) +} diff --git a/pkg/image/minio_test.go b/pkg/image/minio_test.go index 64208040c6..ea40072f52 100644 --- a/pkg/image/minio_test.go +++ b/pkg/image/minio_test.go @@ -71,6 +71,102 @@ func Test_GetMinioImage(t *testing.T) { wantImage: "minio/minio:RELEASE.2020-10-27T00-54-19Z", wantErr: false, }, + { + name: "should return minio image from deployment when the add-on ships from the kurlsh repository", + 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: "kurlsh/minio:RELEASE.2025-10-15T17-29-55Z", + }, + }, + }, + }, + }, + }, + ), + kotsadmNamespace: metav1.NamespaceDefault, + wantImage: "kurlsh/minio:RELEASE.2025-10-15T17-29-55Z", + wantErr: false, + }, + { + name: "should return minio image from deployment when the add-on is pulled from a private registry", + 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: "registry.example.com:5000/kurlsh/minio:RELEASE.2025-10-15T17-29-55Z", + }, + }, + }, + }, + }, + }, + ), + kotsadmNamespace: metav1.NamespaceDefault, + wantImage: "registry.example.com:5000/kurlsh/minio:RELEASE.2025-10-15T17-29-55Z", + wantErr: false, + }, + { + name: "should return empty image when the minio container is not a RELEASE build", + 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: "kurlsh/minio:0.20250101.0", + }, + }, + }, + }, + }, + }, + ), + kotsadmNamespace: metav1.NamespaceDefault, + wantImage: "", + wantErr: false, + }, { name: "should return minio image from statefulset for kurl instance with default namespace", clientset: fake.NewSimpleClientset(