Skip to content

Commit c094153

Browse files
authored
[Fix][kubectl-plugin]: make version handle digests (#2876)
Right now `kubectl ray version` returns only the image digest if the KubeRay operator uses an image reference that contains both tag and digest. This change returns both and also handles the case where only the digest is present. We depend on the https://github.com/novln/docker-parser library to simplify image reference parsing logic except in the case where both tag and digest are used which the library doesn't seem to handle. See [this issue][1]. [1]: novln/docker-parser#3
1 parent accc0cf commit c094153

File tree

4 files changed

+79
-11
lines changed

4 files changed

+79
-11
lines changed

kubectl-plugin/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ toolchain go1.22.5
66

77
require (
88
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
9+
github.com/novln/docker-parser v1.0.0
910
github.com/onsi/ginkgo/v2 v2.20.2
1011
github.com/onsi/gomega v1.34.2
1112
github.com/ray-project/kuberay/ray-operator v0.0.0

kubectl-plugin/go.sum

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

kubectl-plugin/pkg/util/client/client.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"strings"
77

8+
dockerparser "github.com/novln/docker-parser"
89
"github.com/ray-project/kuberay/kubectl-plugin/pkg/util"
910
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1011
"k8s.io/client-go/kubernetes"
@@ -80,12 +81,18 @@ func (c *k8sClient) GetKubeRayOperatorVersion(ctx context.Context) (string, erro
8081
}
8182

8283
image := containers[0].Image
83-
parts := strings.Split(image, ":")
84-
if len(parts) < 2 {
85-
return "", fmt.Errorf("unable to parse KubeRay operator version from image: %s", image)
84+
ref, err := dockerparser.Parse(image)
85+
if err != nil {
86+
return "", fmt.Errorf("unable to parse KubeRay operator version from image: %w", err)
87+
}
88+
89+
// If image reference contains both digest and tag, return both
90+
if strings.Contains(image, "@sha256:") && strings.Count(image, ":") == 2 {
91+
parts := strings.SplitN(image, ":", 2)
92+
return parts[len(parts)-1], nil
8693
}
8794

88-
return parts[len(parts)-1], nil
95+
return ref.Tag(), nil
8996
}
9097

9198
func (c *k8sClient) GetRayHeadSvcName(ctx context.Context, namespace string, resourceType util.ResourceType, name string) (string, error) {

kubectl-plugin/pkg/util/client/client_test.go

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func TestGetKubeRayOperatorVersion(t *testing.T) {
3131
Spec: corev1.PodSpec{
3232
Containers: []corev1.Container{
3333
{
34-
Image: "kuberay/operator:v0.5.0",
34+
Image: "kuberay/operator:v0.5.0@sha256:cc8ce713f3b4be3c72cca1f63ee78e3733bc7283472ecae367b47a128f7e4478",
3535
},
3636
},
3737
},
@@ -40,6 +40,28 @@ func TestGetKubeRayOperatorVersion(t *testing.T) {
4040
},
4141
}
4242
kustomizeObjects := []runtime.Object{
43+
&appsv1.Deployment{
44+
ObjectMeta: metav1.ObjectMeta{
45+
Name: "kuberay-operator-kustomize",
46+
Namespace: "test",
47+
Labels: map[string]string{
48+
"app.kubernetes.io/name": "kuberay",
49+
},
50+
},
51+
Spec: appsv1.DeploymentSpec{
52+
Template: corev1.PodTemplateSpec{
53+
Spec: corev1.PodSpec{
54+
Containers: []corev1.Container{
55+
{
56+
Image: "kuberay/operator:v0.6.0@sha256:cc8ce713f3b4be3c72cca1f63ee78e3733bc7283472ecae367b47a128f7e4478",
57+
},
58+
},
59+
},
60+
},
61+
},
62+
},
63+
}
64+
kustomizeObjectsImageWithOnlyTag := []runtime.Object{
4365
&appsv1.Deployment{
4466
ObjectMeta: metav1.ObjectMeta{
4567
Name: "kuberay-operator-kustomize",
@@ -61,6 +83,28 @@ func TestGetKubeRayOperatorVersion(t *testing.T) {
6183
},
6284
},
6385
}
86+
kustomizeObjectsImageWithOnlyDigest := []runtime.Object{
87+
&appsv1.Deployment{
88+
ObjectMeta: metav1.ObjectMeta{
89+
Name: "kuberay-operator-kustomize",
90+
Namespace: "test",
91+
Labels: map[string]string{
92+
"app.kubernetes.io/name": "kuberay",
93+
},
94+
},
95+
Spec: appsv1.DeploymentSpec{
96+
Template: corev1.PodTemplateSpec{
97+
Spec: corev1.PodSpec{
98+
Containers: []corev1.Container{
99+
{
100+
Image: "kuberay/operator@sha256:cc8ce713f3b4be3c72cca1f63ee78e3733bc7283472ecae367b47a128f7e4478",
101+
},
102+
},
103+
},
104+
},
105+
},
106+
},
107+
}
64108

65109
tests := []struct {
66110
name string
@@ -69,23 +113,35 @@ func TestGetKubeRayOperatorVersion(t *testing.T) {
69113
kubeObjects []runtime.Object
70114
}{
71115
{
72-
name: "kubeRay operator not found",
116+
name: "KubeRay operator not found",
73117
expectedVersion: "",
74118
expectedError: "no KubeRay operator deployments found in any namespace",
75119
kubeObjects: nil,
76120
},
77121
{
78-
name: "find kubeRay operator version for helm chart",
79-
expectedVersion: "v0.5.0",
122+
name: "find KubeRay operator version for helm chart",
123+
expectedVersion: "v0.5.0@sha256:cc8ce713f3b4be3c72cca1f63ee78e3733bc7283472ecae367b47a128f7e4478",
80124
expectedError: "",
81125
kubeObjects: helmKubeObjects,
82126
},
83127
{
84-
name: "find kubeRay operator version for Kustomize",
85-
expectedVersion: "v0.6.0",
128+
name: "find KubeRay operator version for Kustomize",
129+
expectedVersion: "v0.6.0@sha256:cc8ce713f3b4be3c72cca1f63ee78e3733bc7283472ecae367b47a128f7e4478",
86130
expectedError: "",
87131
kubeObjects: kustomizeObjects,
88132
},
133+
{
134+
name: "find KubeRay operator version for Kustomize",
135+
expectedVersion: "v0.6.0",
136+
expectedError: "",
137+
kubeObjects: kustomizeObjectsImageWithOnlyTag,
138+
},
139+
{
140+
name: "find KubeRay operator version for Kustomize",
141+
expectedVersion: "sha256:cc8ce713f3b4be3c72cca1f63ee78e3733bc7283472ecae367b47a128f7e4478",
142+
expectedError: "",
143+
kubeObjects: kustomizeObjectsImageWithOnlyDigest,
144+
},
89145
}
90146

91147
for _, tc := range tests {
@@ -96,7 +152,7 @@ func TestGetKubeRayOperatorVersion(t *testing.T) {
96152
version, err := client.GetKubeRayOperatorVersion(context.Background())
97153

98154
if tc.expectedVersion != "" {
99-
assert.Equal(t, version, tc.expectedVersion)
155+
assert.Equal(t, tc.expectedVersion, version)
100156
assert.NoError(t, err)
101157
} else {
102158
assert.EqualError(t, err, tc.expectedError)

0 commit comments

Comments
 (0)