From 65f1c35d22ef08b41dcb461c821a37b08f65a58c Mon Sep 17 00:00:00 2001 From: Ricardo Zanini <1538000+ricardozanini@users.noreply.github.com> Date: Fri, 26 Jan 2024 16:05:52 -0300 Subject: [PATCH] Fix #359 - Change pullpolicy conditionally based on image tag (#362) * Fix #359 - Change pullpolicy conditionally based on image tag Signed-off-by: Ricardo Zanini * Fix leftovers on rebase Signed-off-by: Ricardo Zanini --------- Signed-off-by: Ricardo Zanini --- controllers/platform/k8s.go | 13 +++--- .../profiles/common/mutate_visitors.go | 1 + .../profiles/common/object_creators.go | 1 - utils/kubernetes/image.go | 39 ++++++++++++++++ utils/kubernetes/image_test.go | 46 +++++++++++++++++++ 5 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 utils/kubernetes/image.go create mode 100644 utils/kubernetes/image_test.go diff --git a/controllers/platform/k8s.go b/controllers/platform/k8s.go index 94e253555..8360f1bc9 100644 --- a/controllers/platform/k8s.go +++ b/controllers/platform/k8s.go @@ -104,12 +104,14 @@ func createDeployment(ctx context.Context, client client.Client, platform *opera } liveProbe := readyProbe.DeepCopy() liveProbe.ProbeHandler.HTTPGet.Path = common.QuarkusHealthPathLive + imageTag := psh.GetServiceImageName(constants.PersistenceTypeEphemeral) dataDeployContainer := &corev1.Container{ - Image: psh.GetServiceImageName(constants.PersistenceTypeEphemeral), - Env: psh.GetEnvironmentVariables(), - Resources: psh.GetPodResourceRequirements(), - ReadinessProbe: readyProbe, - LivenessProbe: liveProbe, + Image: imageTag, + ImagePullPolicy: kubeutil.GetImagePullPolicy(imageTag), + Env: psh.GetEnvironmentVariables(), + Resources: psh.GetPodResourceRequirements(), + ReadinessProbe: readyProbe, + LivenessProbe: liveProbe, Ports: []corev1.ContainerPort{ { Name: utils.HttpScheme, @@ -117,7 +119,6 @@ func createDeployment(ctx context.Context, client client.Client, platform *opera Protocol: corev1.ProtocolTCP, }, }, - ImagePullPolicy: corev1.PullAlways, VolumeMounts: []corev1.VolumeMount{ { Name: "application-config", diff --git a/controllers/profiles/common/mutate_visitors.go b/controllers/profiles/common/mutate_visitors.go index cffda66af..ffe9784a3 100644 --- a/controllers/profiles/common/mutate_visitors.go +++ b/controllers/profiles/common/mutate_visitors.go @@ -50,6 +50,7 @@ func ImageDeploymentMutateVisitor(workflow *operatorapi.SonataFlow, image string deployment := object.(*appsv1.Deployment) _, idx := kubeutil.GetContainerByName(operatorapi.DefaultContainerName, &deployment.Spec.Template.Spec) deployment.Spec.Template.Spec.Containers[idx].Image = image + deployment.Spec.Template.Spec.Containers[idx].ImagePullPolicy = kubeutil.GetImagePullPolicy(image) return nil } } diff --git a/controllers/profiles/common/object_creators.go b/controllers/profiles/common/object_creators.go index 79f2b660e..5739b6ad5 100644 --- a/controllers/profiles/common/object_creators.go +++ b/controllers/profiles/common/object_creators.go @@ -151,7 +151,6 @@ func defaultContainer(workflow *operatorapi.SonataFlow) (*corev1.Container, erro FailureThreshold: healthStartedFailureThreshold, PeriodSeconds: healthStartedPeriodSeconds, }, - ImagePullPolicy: corev1.PullAlways, SecurityContext: kubeutil.SecurityDefaults(), } // Merge with flowContainer diff --git a/utils/kubernetes/image.go b/utils/kubernetes/image.go new file mode 100644 index 000000000..d7e0b4959 --- /dev/null +++ b/utils/kubernetes/image.go @@ -0,0 +1,39 @@ +// Copyright 2024 Apache Software Foundation (ASF) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package kubernetes + +import ( + "strings" + + corev1 "k8s.io/api/core/v1" +) + +// GetImagePullPolicy gets the default corev1.PullPolicy depending on the image tag specified. +// It follows the conventions of docker client and OpenShift. If no tag specified, it assumes latest. +// Returns PullAlways if latest tag, empty otherwise to let the cluster figure it out. +func GetImagePullPolicy(imageTag string) corev1.PullPolicy { + if len(imageTag) == 0 { + return "" + } + idx := strings.LastIndex(imageTag, ":") + if idx < 0 { + return corev1.PullAlways + } + tag := imageTag[idx+1:] + if tag == "latest" { + return corev1.PullAlways + } + return "" +} diff --git a/utils/kubernetes/image_test.go b/utils/kubernetes/image_test.go new file mode 100644 index 000000000..1ba1d1670 --- /dev/null +++ b/utils/kubernetes/image_test.go @@ -0,0 +1,46 @@ +// Copyright 2024 Apache Software Foundation (ASF) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package kubernetes + +import ( + "testing" + + "github.com/stretchr/testify/assert" + v1 "k8s.io/api/core/v1" +) + +func TestGetImagePullPolicy(t *testing.T) { + type args struct { + imageTag string + } + tests := []struct { + name string + args args + want v1.PullPolicy + }{ + {"Short name with latest", args{"ubi9-micro:latest"}, v1.PullAlways}, + {"Long name with latest", args{"gcr.io/knative-releases/knative.dev/eventing/cmd/event_display:latest"}, v1.PullAlways}, + {"No tag specified", args{"ubi9-micro"}, v1.PullAlways}, + {"Short name with tag", args{"ubi9-micro:9.3.1-2"}, ""}, + {"Long name with tag", args{"gcr.io/knative-releases/knative.dev/eventing/cmd/event_display:1.2"}, ""}, + {"Empty tag", args{""}, ""}, + {"Messy tag", args{":"}, ""}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equalf(t, tt.want, GetImagePullPolicy(tt.args.imageTag), "GetImagePullPolicy(%v)", tt.args.imageTag) + }) + } +}