This is an automated email from the ASF dual-hosted git repository.
squakez pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-k.git
The following commit(s) were added to refs/heads/main by this push:
new 1c980893d fix(cmd): read operator image from Pod
1c980893d is described below
commit 1c980893d9e38b6cb558fb63f7d2d671d1ed8e49
Author: Pasquale Congiusti <[email protected]>
AuthorDate: Wed Aug 12 08:45:51 2026 +0200
fix(cmd): read operator image from Pod
Instead of having a dedicated env var which may be difficult to fill in all
installation methods.
Closes #6730
---
pkg/cmd/operator/operator.go | 40 +++++++++-
pkg/cmd/operator/operator_test.go | 87 ++++++++++++++++++++--
pkg/resources/config/manager/kustomization.yaml | 10 ---
.../config/manager/operator-deployment.yaml | 3 -
4 files changed, 117 insertions(+), 23 deletions(-)
diff --git a/pkg/cmd/operator/operator.go b/pkg/cmd/operator/operator.go
index 58d11ebbc..1ed9c5760 100644
--- a/pkg/cmd/operator/operator.go
+++ b/pkg/cmd/operator/operator.go
@@ -19,6 +19,7 @@ package operator
import (
"context"
+ "errors"
"flag"
"fmt"
"os"
@@ -39,6 +40,7 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
+ "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/leaderelection/resourcelock"
"sigs.k8s.io/controller-runtime/pkg/cache"
ctrl "sigs.k8s.io/controller-runtime/pkg/client"
@@ -156,7 +158,10 @@ func Run(healthPort, monitoringPort int32, leaderElection
bool, leaderElectionID
}
// Set the operator container image if it runs in-container
- platform.OperatorImage = getOperatorImage()
+ platform.OperatorImage, err = getOperatorImage(ctx, bootstrapClient)
+ if err != nil {
+ log.Info("WARN: Camel K operator is running outside a
container. Some features (eg, running build in pod mode) may be disabled!")
+ }
if !leaderElection {
log.Info("Leader election is disabled!")
@@ -270,8 +275,37 @@ func getWatchNamespace() (string, error) {
}
// getOperatorImage returns the image currently used by the running operator
if present (when running out of cluster, it may be absent).
-func getOperatorImage() string {
- return os.Getenv("CONTAINER_IMAGE")
+func getOperatorImage(ctx context.Context, kubeClient client.Client) (string,
error) {
+ podName := os.Getenv("POD_NAME")
+ podNamespace := os.Getenv("NAMESPACE")
+
+ if podName == "" {
+ return "", errors.New("POD_NAME environment variable is not
set")
+ }
+ if podNamespace == "" {
+ return "", errors.New("NAMESPACE environment variable is not
set")
+ }
+
+ pod := &corev1.Pod{}
+ if err := kubeClient.Get(ctx, types.NamespacedName{
+ Name: podName,
+ Namespace: podNamespace,
+ }, pod); err != nil {
+ return "", fmt.Errorf("failed to get operator pod %s/%s: %w",
+ podNamespace, podName, err)
+ }
+
+ for _, container := range pod.Spec.Containers {
+ if container.Name == "camel-k-operator" {
+ return container.Image, nil
+ }
+ }
+
+ return "", fmt.Errorf(
+ "camel-k-operator container not found in pod %s/%s",
+ podNamespace,
+ podName,
+ )
}
func exitOnError(err error, msg string) {
diff --git a/pkg/cmd/operator/operator_test.go
b/pkg/cmd/operator/operator_test.go
index 00eac0784..364271ce6 100644
--- a/pkg/cmd/operator/operator_test.go
+++ b/pkg/cmd/operator/operator_test.go
@@ -18,11 +18,16 @@ limitations under the License.
package operator
import (
+ "context"
"testing"
+ "github.com/apache/camel-k/v2/pkg/internal"
"github.com/apache/camel-k/v2/pkg/platform"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/cache"
)
@@ -132,19 +137,87 @@ func TestGetWatchNamespace(t *testing.T) {
}
func TestGetOperatorImage(t *testing.T) {
- t.Run("env variable set", func(t *testing.T) {
- t.Setenv("CONTAINER_IMAGE", "quay.io/example/operator:latest")
+ scheme := runtime.NewScheme()
+ require.NoError(t, corev1.AddToScheme(scheme))
+
+ t.Run("returns operator image", func(t *testing.T) {
+ t.Setenv("POD_NAME", "operator-123")
+ t.Setenv("NAMESPACE", "default")
+
+ pod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "operator-123",
+ Namespace: "default",
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "camel-k-operator",
+ Image: "my-operator:v1.2.3",
+ },
+ },
+ },
+ }
+
+ kubeClient, err := internal.NewFakeClient(pod)
+ require.NoError(t, err)
- image := getOperatorImage()
+ image, err := getOperatorImage(context.Background(), kubeClient)
- assert.Equal(t, "quay.io/example/operator:latest", image)
+ require.NoError(t, err)
+ assert.Equal(t, "my-operator:v1.2.3", image)
})
- t.Run("env variable not set", func(t *testing.T) {
- t.Setenv("CONTAINER_IMAGE", "")
+ t.Run("returns error when pod does not exist", func(t *testing.T) {
+ t.Setenv("POD_NAME", "operator-123")
+ t.Setenv("NAMESPACE", "default")
+
+ kubeClient, err := internal.NewFakeClient()
+ require.NoError(t, err)
+
+ image, err := getOperatorImage(context.Background(), kubeClient)
+
+ require.Error(t, err)
+ assert.Empty(t, image)
+ })
+
+ t.Run("returns error when environment is missing", func(t *testing.T) {
+ t.Setenv("POD_NAME", "")
+ t.Setenv("NAMESPACE", "default")
+
+ kubeClient, err := internal.NewFakeClient()
+ require.NoError(t, err)
- image := getOperatorImage()
+ image, err := getOperatorImage(context.Background(), kubeClient)
+
+ require.Error(t, err)
+ assert.Empty(t, image)
+ })
+ t.Run("returns error when operator container is missing", func(t
*testing.T) {
+ t.Setenv("POD_NAME", "operator-123")
+ t.Setenv("NAMESPACE", "default")
+
+ pod := &corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "operator-123",
+ Namespace: "default",
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "some-other-container",
+ Image: "other:v1",
+ },
+ },
+ },
+ }
+ kubeClient, err := internal.NewFakeClient(pod)
+ require.NoError(t, err)
+
+ image, err := getOperatorImage(context.Background(), kubeClient)
+
+ require.Error(t, err)
assert.Empty(t, image)
})
}
diff --git a/pkg/resources/config/manager/kustomization.yaml
b/pkg/resources/config/manager/kustomization.yaml
index b067e2c33..a4543333a 100644
--- a/pkg/resources/config/manager/kustomization.yaml
+++ b/pkg/resources/config/manager/kustomization.yaml
@@ -28,13 +28,3 @@ patches:
target:
kind: Deployment
name: camel-k-operator
-
-replacements:
- - source:
- kind: Deployment
- fieldPath: spec.template.spec.containers.[name=camel-k-operator].image
- targets:
- - select:
- kind: Deployment
- fieldPaths:
- -
spec.template.spec.containers.[name=camel-k-operator].env.[name=CONTAINER_IMAGE].value
diff --git a/pkg/resources/config/manager/operator-deployment.yaml
b/pkg/resources/config/manager/operator-deployment.yaml
index 1331ea35d..70e329e9c 100644
--- a/pkg/resources/config/manager/operator-deployment.yaml
+++ b/pkg/resources/config/manager/operator-deployment.yaml
@@ -77,9 +77,6 @@ spec:
# Note: remove the variable to disable the feature.
- name: CAMEL_MONITOR_OPERATOR_LABEL
value: "camel.apache.org/monitor"
- # Used to query which is the image this operator is running
- - name: CONTAINER_IMAGE
- value: ""
# You can provide a different SA for builder Pods
- name: BUILDER_SA
value: "camel-k-builder"