diff --git a/internal/kubernetes/client.go b/internal/kubernetes/client.go index d974b863..86669488 100644 --- a/internal/kubernetes/client.go +++ b/internal/kubernetes/client.go @@ -4,6 +4,7 @@ import ( "path/filepath" "github.com/spf13/cobra" + "k8s.io/client-go/discovery" "k8s.io/client-go/kubernetes" v1 "k8s.io/client-go/kubernetes/typed/core/v1" "k8s.io/client-go/rest" @@ -13,6 +14,7 @@ import ( type KubeClient struct { ClientSet kubernetes.Interface ClientConfig *rest.Config + Discovery *discovery.DiscoveryClient Namespace string } @@ -64,6 +66,11 @@ func NewClient(kubeconfig, context, namespace string) (config KubeClient, err er return config, err } + config.Discovery, err = discovery.NewDiscoveryClientForConfig(config.ClientConfig) + if err != nil { + return config, err + } + return config, err } diff --git a/internal/kubernetes/version.go b/internal/kubernetes/version.go new file mode 100644 index 00000000..2fd7c173 --- /dev/null +++ b/internal/kubernetes/version.go @@ -0,0 +1,33 @@ +package kubernetes + +import ( + "fmt" + "strconv" + "strings" +) + +func (c *KubeClient) MinServerVersion(wantMajor, wantMinor int) (bool, error) { + serverVersion, err := c.Discovery.ServerVersion() + if err != nil { + return false, err + } + + vers := strings.TrimPrefix(serverVersion.GitVersion, "v") + majorStr, minorStr, found := strings.Cut(vers, ".") + if !found { + return false, fmt.Errorf("invalid version: %s", serverVersion.GitVersion) + } + minorStr, _, _ = strings.Cut(minorStr, ".") + + major, err := strconv.Atoi(majorStr) + if err != nil { + return false, err + } + + minor, err := strconv.Atoi(minorStr) + if err != nil { + return false, err + } + + return wantMajor <= major && wantMinor <= minor, nil +} diff --git a/internal/util/cmd_setup.go b/internal/util/cmd_setup.go index 63880830..2c4d120b 100644 --- a/internal/util/cmd_setup.go +++ b/internal/util/cmd_setup.go @@ -288,7 +288,7 @@ func watchJobPod(cmd *cobra.Command, conf *config.Global) error { defer cancel() watch, err := conf.Client.ClientSet.CoreV1().Pods(conf.Namespace).Watch(ctx, metav1.ListOptions{ - LabelSelector: "batch.kubernetes.io/controller-uid=" + string(conf.Job.ObjectMeta.UID), + LabelSelector: jobPodLabelSelector(conf, conf.Job), }) if err != nil { return pollJobPod(ctx, conf) @@ -324,7 +324,7 @@ func pollJobPod(ctx context.Context, conf *config.Global) error { return wait.PollUntilContextCancel( ctx, time.Second, true, func(ctx context.Context) (done bool, err error) { list, err := conf.Client.ClientSet.CoreV1().Pods(conf.Namespace).List(ctx, metav1.ListOptions{ - LabelSelector: "batch.kubernetes.io/controller-uid=" + string(conf.Job.ObjectMeta.UID), + LabelSelector: jobPodLabelSelector(conf, conf.Job), }) if err != nil { return false, err @@ -349,3 +349,16 @@ func pollJobPod(ctx context.Context, conf *config.Global) error { }, ) } + +func jobPodLabelSelector(conf *config.Global, job *batchv1.Job) string { + useNewLabel, err := conf.Client.MinServerVersion(1, 27) + if err != nil { + log.WithError(err).Warn("failed to query server version; assuming v1.27+") + useNewLabel = true + } + + if useNewLabel { + return "batch.kubernetes.io/controller-uid=" + string(job.ObjectMeta.UID) + } + return "controller-uid=" + string(job.ObjectMeta.UID) +}