Skip to content
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
19 changes: 16 additions & 3 deletions pkg/image/minio.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package image

import (
"context"
"strings"
"regexp"

"github.com/pkg/errors"
"github.com/replicatedhq/kots/pkg/kurl"
Expand All @@ -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) {
/*
Expand All @@ -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
}
}
Expand All @@ -44,11 +49,19 @@ 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
}
}
}

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)
}
96 changes: 96 additions & 0 deletions pkg/image/minio_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading