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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
10 changes: 10 additions & 0 deletions config/openshift/base/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -396,3 +396,13 @@ rules:
- delete
- update
- patch
# to read cluster TLS security profile for centralized TLS configuration
- apiGroups:
- config.openshift.io
resources:
- apiservers
- clusterversions
verbs:
- get
- list
- watch
74 changes: 43 additions & 31 deletions docs/AirGapImageConfiguration.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,34 +106,46 @@ kubectl delete tektoninstallerset <installer-set-name>
#### Images supported in OpenShift
Supports all the images listed above in kubernetes and following are specific to OpenShift

| Component | Container/Args name | Environment Variable |
|-----------------------|-----------------------------------|-----------------------------------------------------|
| Pipeline-as-code | pac-controller | `IMAGE_PAC_PAC_CONTROLLER` |
| Pipeline-as-code | pac-webhook | `IMAGE_PAC_PAC_WEBHOOK` |
| Pipeline-as-code | pac-watcher | `IMAGE_PAC_PAC_WATCHER` |
| Console Plugin | console-plugin | `IMAGE_PIPELINES_CONSOLE_PLUGIN` |
| Results | retention-policy-agent | `IMAGE_RESULTS_RETENTION_POLICY_AGENT` |
| Addons | | `IMAGE_ADDONS_BUILD` |
| Addons | | `IMAGE_ADDONS_GENERATE` |
| Addons | | `IMAGE_ADDONS_GEN_ENV_FILE` |
| Addons | | `IMAGE_ADDONS_GIT_RUN` |
| Addons | | `IMAGE_ADDONS_KN` |
| Addons | | `IMAGE_ADDONS_LOAD_SCRIPTS` |
| Addons | | `IMAGE_ADDONS_MAVEN_GENERATE` |
| Addons | | `IMAGE_ADDONS_MAVEN_GOALS` |
| Addons | | `IMAGE_ADDONS_MVN_SETTINGS` |
| Addons | | `IMAGE_ADDONS_OC` |
| Addons | | `IMAGE_ADDONS_PARAM_BUILDER_IMAGE` |
| Addons | | `IMAGE_ADDONS_PARAM_GITINITIMAGE` |
| Addons | | `IMAGE_ADDONS_PARAM_KN_IMAGE` |
| Addons | | `IMAGE_ADDONS_PARAM_MAVEN_IMAGE` |
| Addons | | `IMAGE_ADDONS_PARAM_TKN_IMAGE` |
| Addons | | `IMAGE_ADDONS_PREPARE` |
| Addons | | `IMAGE_ADDONS_REPORT` |
| Addons | | `IMAGE_ADDONS_S2I_BUILD` |
| Addons | | `IMAGE_ADDONS_S2I_GENERATE` |
| Addons | | `IMAGE_ADDONS_SKOPEO_COPY` |
| Addons | | `IMAGE_ADDONS_SKOPEO_RESULTS` |
| Addons | | `IMAGE_ADDONS_TKN` |
| Addons | | `IMAGE_ADDONS_TKN_CLI_SERVE` |
| Addons | | `IMAGE_ADDONS_TKN_CLI_SERVE_INIT_CONFIG` |
| Component | Container/Args name | Environment Variable |
|----------------------|-----------------------------------|-------------------------------------------|
| Pipeline-as-code | pac-controller | `IMAGE_PAC_PAC_CONTROLLER` |
| Pipeline-as-code | pac-webhook | `IMAGE_PAC_PAC_WEBHOOK` |
| Pipeline-as-code | pac-watcher | `IMAGE_PAC_PAC_WATCHER` |
| Console Plugin (PF5) | console-plugin | `IMAGE_PIPELINES_CONSOLE_PLUGIN_LEGACY` |
| Console Plugin (PF6) | console-plugin | `IMAGE_PIPELINES_CONSOLE_PLUGIN` |
| Results | retention-policy-agent | `IMAGE_RESULTS_RETENTION_POLICY_AGENT` |
| Addons | | `IMAGE_ADDONS_BUILD` |
| Addons | | `IMAGE_ADDONS_GENERATE` |
| Addons | | `IMAGE_ADDONS_GEN_ENV_FILE` |
| Addons | | `IMAGE_ADDONS_GIT_RUN` |
| Addons | | `IMAGE_ADDONS_KN` |
| Addons | | `IMAGE_ADDONS_LOAD_SCRIPTS` |
| Addons | | `IMAGE_ADDONS_MAVEN_GENERATE` |
| Addons | | `IMAGE_ADDONS_MAVEN_GOALS` |
| Addons | | `IMAGE_ADDONS_MVN_SETTINGS` |
| Addons | | `IMAGE_ADDONS_OC` |
| Addons | | `IMAGE_ADDONS_PARAM_BUILDER_IMAGE` |
| Addons | | `IMAGE_ADDONS_PARAM_GITINITIMAGE` |
| Addons | | `IMAGE_ADDONS_PARAM_KN_IMAGE` |
| Addons | | `IMAGE_ADDONS_PARAM_MAVEN_IMAGE` |
| Addons | | `IMAGE_ADDONS_PARAM_TKN_IMAGE` |
| Addons | | `IMAGE_ADDONS_PREPARE` |
| Addons | | `IMAGE_ADDONS_REPORT` |
| Addons | | `IMAGE_ADDONS_S2I_BUILD` |
| Addons | | `IMAGE_ADDONS_S2I_GENERATE` |
| Addons | | `IMAGE_ADDONS_SKOPEO_COPY` |
| Addons | | `IMAGE_ADDONS_SKOPEO_RESULTS` |
| Addons | | `IMAGE_ADDONS_TKN` |
| Addons | | `IMAGE_ADDONS_TKN_CLI_SERVE` |
| Addons | | `IMAGE_ADDONS_TKN_CLI_SERVE_INIT_CONFIG` |

#### OpenShift Console Plugin Compatibility
When deploying the Tekton Operator on OpenShift Container Platform (OCP) with the console plugin enabled, you must account for your OCP version.

Starting with **OpenShift 4.22**, the console plugin was upgraded to use PatternFly 6 (PF6), while earlier versions use PatternFly 5 (PF5). To ensure compatibility, you need to provide both of the following environment variables:

`IMAGE_PIPELINES_CONSOLE_PLUGIN`: Point this to the **PF6** image.

`IMAGE_PIPELINES_CONSOLE_PLUGIN_LEGACY`: Point this to the **PF5** image.

**Note:** You do not need to manually configure which image to use at runtime. The operator will automatically detect your OCP version and deploy the correct console plugin image.
8 changes: 8 additions & 0 deletions operatorhub/openshift/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,14 @@ image-substitutions:
envKeys:
- IMAGE_PIPELINES_CONSOLE_PLUGIN

- image: registry.redhat.io/openshift-pipelines/pipelines-console-plugin-pf5-rhel9@
replaceLocations:
envTargets:
- deploymentName: openshift-pipelines-operator
containerName: openshift-pipelines-operator-lifecycle
envKeys:
- IMAGE_PIPELINES_CONSOLE_PLUGIN_LEGACY

# add third party images which are not replaced by operator
# but pulled directly by tasks here
defaultRelatedImages: []
Expand Down
58 changes: 58 additions & 0 deletions pkg/reconciler/openshift/common/common_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
Copyright 2026 The Tekton Authors

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 common

import (
"context"
"fmt"

"github.com/Masterminds/semver"
openshiftconfigclient "github.com/openshift/client-go/config/clientset/versioned"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var (
openshiftClient openshiftconfigclient.Interface
)

func GetOCPVersion(ctx context.Context) (*semver.Version, error) {

if openshiftClient == nil {
return nil, fmt.Errorf("OpenShift client not initialized")
}

// Fetch the ClusterVersion object (always named "version")
cv, err := openshiftClient.ConfigV1().ClusterVersions().Get(ctx, "version", metav1.GetOptions{})
if err != nil {
// If running on standard Kubernetes, this will return an IsNotFound error.
// Handle gracefully if your operator supports both vanilla K8s and OCP.
return nil, err
}
versionStr := cv.Status.Desired.Version
if versionStr == "" {
return nil, fmt.Errorf("empty OpenShift version in ClusterVersion status")
}

v, err := semver.NewVersion(versionStr)
if err != nil {
return nil, fmt.Errorf("failed to parse OpenShift version %q: %w", versionStr, err)
}
return v, nil
}

func SetOpenshiftClient(client openshiftconfigclient.Interface) {
openshiftClient = client
}
44 changes: 44 additions & 0 deletions pkg/reconciler/openshift/common/common_utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
Copyright 2026 The Tekton Authors

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 common

import (
"testing"

configv1 "github.com/openshift/api/config/v1"
"github.com/openshift/client-go/config/clientset/versioned/fake"
"gotest.tools/v3/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func Test_GetOCPVersion(t *testing.T) {
cv := &configv1.ClusterVersion{
ObjectMeta: metav1.ObjectMeta{
Name: "version",
},
Status: configv1.ClusterVersionStatus{
Desired: configv1.Release{
Version: "v4.21.1",
},
},
}
openshiftClient = fake.NewSimpleClientset(cv)
ocpVersion, err := GetOCPVersion(t.Context())
if err != nil {
t.Error(err)
}
assert.Equal(t, ocpVersion.String(), "4.21.1")
}
27 changes: 21 additions & 6 deletions pkg/reconciler/openshift/tektonconfig/console_plugin_reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ import (

"github.com/go-logr/zapr"
mf "github.com/manifestival/manifestival"

"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
"github.com/tektoncd/operator/pkg/client/clientset/versioned"
"github.com/tektoncd/operator/pkg/reconciler/common"
occommon "github.com/tektoncd/operator/pkg/reconciler/openshift/common"
"github.com/tektoncd/operator/pkg/reconciler/shared/hash"
"go.uber.org/zap"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -41,7 +41,8 @@ const (
// installerSet label value
consolePluginReconcileLabelCreatedByValue = "tekton-config-console-plugin-manifests"
// pipelines console plugin environment variable key
PipelinesConsolePluginImageEnvironmentKey = "IMAGE_PIPELINES_CONSOLE_PLUGIN"
PipelinesConsolePluginImageEnvironmentKey = "IMAGE_PIPELINES_CONSOLE_PLUGIN"
PipelinesConsolePluginImageEnvironmentKeyLegacy = "IMAGE_PIPELINES_CONSOLE_PLUGIN_LEGACY"
// pipelines console plugin container name, used to replace the image from the environment
PipelinesConsolePluginContainerName = "pipelines-console-plugin"
)
Expand Down Expand Up @@ -157,16 +158,30 @@ func (cpr *consolePluginReconciler) updateOnce(ctx context.Context) {
cpr.manifest = manifest

// update pipelines console image details
consoleImage, found := os.LookupEnv(PipelinesConsolePluginImageEnvironmentKey)

// Below logic is to pick Console Plugin Image based on the OCP Version.
// OCP versions older than 4.22 uses the legacy Console Plugin.
var envKey string
ocpVersion, err := occommon.GetOCPVersion(ctx)
if err != nil {
cpr.logger.Errorf("error getting OCP version: %q", err)
} else if ocpVersion.Major() == 4 && ocpVersion.Minor() < 22 {
cpr.logger.Infof("Using Legacy Console Plugin on OCP : %v", ocpVersion)
envKey = PipelinesConsolePluginImageEnvironmentKeyLegacy
} else {
envKey = PipelinesConsolePluginImageEnvironmentKey
}

consoleImage, found := os.LookupEnv(envKey)
if found {
cpr.pipelinesConsolePluginImage = consoleImage
cpr.logger.Debugw("pipelines console plugin image found from environment",
cpr.logger.Infow("pipelines console plugin image found from environment",
"image", consoleImage,
"environmentVariable", PipelinesConsolePluginImageEnvironmentKey,
"environmentVariable", envKey,
)
} else {
cpr.logger.Warnw("pipelines console plugin image not found from environment, continuing with the default image from the manifest",
"environmentVariable", PipelinesConsolePluginImageEnvironmentKey,
"environmentVariable", envKey,
)
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ import (
"sync"
"testing"

configv1 "github.com/openshift/api/config/v1"
ocpfake "github.com/openshift/client-go/config/clientset/versioned/fake"
"github.com/stretchr/testify/require"
"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
"github.com/tektoncd/operator/pkg/client/clientset/versioned/fake"
"github.com/tektoncd/operator/pkg/reconciler/common"
occommon "github.com/tektoncd/operator/pkg/reconciler/openshift/common"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -51,30 +54,56 @@ func generateNameReactor(action k8sTesting.Action) (bool, apimachineryRuntime.Ob

func TestPostReconcileManifest(t *testing.T) {
defaultConsolePluginImage := "ghcr.io/openshift-pipelines/console-plugin:main"
defaultConsolePluginLegacyImage := "ghcr.io/openshift-pipelines/console-plugin-pf5:main"
defaultOCPVersion := "4.22.0"
t.Setenv("IMAGE_PIPELINES_CONSOLE_PLUGIN_LEGACY", defaultConsolePluginLegacyImage)

tests := []struct {
name string
consolePluginImage string
operatorVersion string
targetNamespace string
tcConfig *v1alpha1.Config
name string
consolePluginImage string
consolePluginLegacyImage string
operatorVersion string
targetNamespace string
tcConfig *v1alpha1.Config
ocpVersion string
expectedConsolePluginImage string
}{
{
name: "test-without-console-plugin-image",
operatorVersion: "1.14.0",
targetNamespace: "foo",
},
{
name: "test-with-console-plugin-image",
consolePluginImage: "custom-image:tag1",
operatorVersion: "0.70.0",
targetNamespace: "bar",
name: "test-with-legacy-console-plugin-image",
operatorVersion: "1.14.0",
targetNamespace: "foo",
consolePluginImage: defaultConsolePluginImage,
consolePluginLegacyImage: defaultConsolePluginLegacyImage,
ocpVersion: "4.21.0",
expectedConsolePluginImage: defaultConsolePluginLegacyImage,
},
{
name: "test-with-tc-config",
consolePluginImage: "custom-image:tag1",
operatorVersion: "0.70.0",
targetNamespace: "bar",
name: "test-with-new-console-plugin-image",
operatorVersion: "1.14.0",
targetNamespace: "foo",
consolePluginImage: defaultConsolePluginImage,
consolePluginLegacyImage: defaultConsolePluginLegacyImage,
ocpVersion: "4.22.0",
expectedConsolePluginImage: defaultConsolePluginImage,
},
{
name: "test-with-console-plugin-image",
consolePluginImage: "custom-image:tag1",
operatorVersion: "0.70.0",
targetNamespace: "bar",
expectedConsolePluginImage: "custom-image:tag1",
},
{
name: "test-with-tc-config",
consolePluginImage: "custom-image:tag1",
operatorVersion: "0.70.0",
targetNamespace: "bar",
expectedConsolePluginImage: "custom-image:tag1",
tcConfig: &v1alpha1.Config{
NodeSelector: map[string]string{
"node-role.kubernetes.io/infra": "",
Expand Down Expand Up @@ -145,6 +174,22 @@ func TestPostReconcileManifest(t *testing.T) {
}
}
}
// Mock CV
if test.ocpVersion == "" {
test.ocpVersion = defaultOCPVersion
}
mockCV := &configv1.ClusterVersion{
ObjectMeta: metav1.ObjectMeta{Name: "version"},
Status: configv1.ClusterVersionStatus{
Desired: configv1.Release{
Version: test.ocpVersion,
},
},
}

// Openshift Client
openshiftFakeClientSet := ocpfake.NewSimpleClientset(mockCV)
occommon.SetOpenshiftClient(openshiftFakeClientSet)

// reconciler reference
postReconcile := &consolePluginReconciler{
Expand Down Expand Up @@ -175,9 +220,10 @@ func TestPostReconcileManifest(t *testing.T) {
// console plugin image
consolePluginImage := defaultConsolePluginImage
// update image env variable
if test.consolePluginImage != "" {
t.Setenv("IMAGE_PIPELINES_CONSOLE_PLUGIN", test.consolePluginImage)
consolePluginImage = test.consolePluginImage
if test.consolePluginImage != "" || test.consolePluginLegacyImage != "" {
t.Setenv(PipelinesConsolePluginImageEnvironmentKey, test.consolePluginImage)
t.Setenv(PipelinesConsolePluginImageEnvironmentKeyLegacy, test.consolePluginLegacyImage)
consolePluginImage = test.expectedConsolePluginImage
}
// TEST: image name
err := postReconcile.reconcile(ctx, tektonConfigCR) // perform reconcile
Expand Down
Loading
Loading