Skip to content

Commit

Permalink
manage pipeline console plugin deployment on openshift
Browse files Browse the repository at this point in the history
Signed-off-by: Jeeva Kandasamy <[email protected]>
  • Loading branch information
jkandasa committed Dec 13, 2023
1 parent f1cf325 commit 6620a45
Show file tree
Hide file tree
Showing 12 changed files with 786 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Copyright 2023 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.

# to know about dynamic plugin visit,
# https://github.com/openshift/enhancements/blob/master/enhancements/console/dynamic-plugins.md

# service to access static contents: js, CSS, HTML. etc.,
# this service creates and manages secret called "pipeline-console-plugin-cert"
# generated secret will be used in the console plugin container (nginx + static content)
---
apiVersion: v1
kind: Service
metadata:
name: pipeline-console-plugin
namespace: openshift-pipelines
annotations:
# https://docs.openshift.com/container-platform/4.13/security/certificates/service-serving-certificate.html
service.beta.openshift.io/serving-cert-secret-name: pipeline-console-plugin-cert
labels:
app.kubernetes.io/part-of: tektoncd-results
spec:
ports:
- name: 8443-tcp
protocol: TCP
port: 8443
targetPort: 8443
selector:
name: pipeline-console-plugin
app: pipeline-console-plugin

# nginx configuration
---
apiVersion: v1
kind: ConfigMap
metadata:
name: pipeline-console-plugin
namespace: openshift-pipelines
labels:
app.kubernetes.io/part-of: tektoncd-results
data:
nginx.conf: |
error_log /dev/stdout warn;
events {}
http {
access_log /dev/stdout;
include /etc/nginx/mime.types;
default_type application/octet-stream;
keepalive_timeout 65;
server {
listen 8443 ssl;
listen [::]:8443 ssl;
ssl_certificate /var/cert/tls.crt;
ssl_certificate_key /var/cert/tls.key;
root /usr/share/nginx/html;
}
}
# nginx + pipeline dynamic console custom static contents
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: pipeline-console-plugin
namespace: openshift-pipelines
labels:
app.kubernetes.io/part-of: tektoncd-results
spec:
replicas: 1
selector:
matchLabels:
name: pipeline-console-plugin
app: pipeline-console-plugin
template:
metadata:
labels:
name: pipeline-console-plugin
app: pipeline-console-plugin
app.kubernetes.io/part-of: tektoncd-results
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
volumes:
- name: pipeline-console-plugin-cert
secret:
secretName: pipeline-console-plugin-cert
defaultMode: 420
- name: nginx-conf
configMap:
name: pipeline-console-plugin
defaultMode: 420
containers:
- name: pipeline-console-plugin
image: ghcr.io/openshift-pipelines/console-plugin:main
imagePullPolicy: Always
ports:
- protocol: TCP
containerPort: 8443
volumeMounts:
- name: pipeline-console-plugin-cert
readOnly: true
mountPath: /var/cert
- name: nginx-conf
readOnly: true
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf

# Console plugin is a cluster wide resource
# updates pipeline dynamic content provider service details
---
apiVersion: console.openshift.io/v1
kind: ConsolePlugin
metadata:
name: pipeline-console-plugin
labels:
app.kubernetes.io/part-of: tektoncd-results
spec:
displayName: Pipeline Console Plugin
backend:
type: Service
service:
name: pipeline-console-plugin
namespace: openshift-pipelines
port: 8443
basePath: "/"
proxy:
i18n:
loadType: Preload # options: Preload, Lazy
2 changes: 2 additions & 0 deletions config/openshift/base/operator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ spec:
value: registry.redhat.io/source-to-image/source-to-image-rhel8@sha256:6a6025914296a62fdf2092c3a40011bd9b966a6806b094d51eec5e1bd5026ef4
- name: IMAGE_ADDONS_PARAM_MAVEN_IMAGE
value: registry.redhat.io/ubi8/openjdk-17@sha256:0d12c4097e098b62f78a7a31c0d711d78e1e5a53f4c007b9a5fc6cc6ab4dc018
- name: IMAGE_PIPELINE_CONSOLE_PLUGIN
value: ghcr.io/openshift-pipelines/console-plugin:main
- name: openshift-pipelines-operator-cluster-operations # tektoninstallerset reconciler
image: ko://github.com/tektoncd/operator/cmd/openshift/operator
args:
Expand Down
13 changes: 13 additions & 0 deletions config/openshift/base/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -376,3 +376,16 @@ rules:
- delete
- update
- patch
# to manage ConsolePlugin custom resource
- apiGroups:
- console.openshift.io
resources:
- consoleplugins
verbs:
- get
- list
- watch
- create
- delete
- update
- patch
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ metadata:
capabilities: Full Lifecycle
categories: Developer Tools, Integration & Delivery
certified: "false"
console.openshift.io/plugins: '["pipeline-console-plugin"]'
description: Red Hat OpenShift Pipelines is a cloud-native CI/CD solution for building pipelines using Tekton concepts which run natively on OpenShift and Kubernetes.
operators.operatorframework.io/builder: operator-sdk-v1.7.2
operators.openshift.io/infrastructure-features: '["disconnected","proxy-aware"]'
Expand Down
27 changes: 27 additions & 0 deletions pkg/apis/operator/v1alpha1/tektonresult_lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ var (
DependenciesInstalled,
InstallerSetAvailable,
InstallerSetReady,
PreReconciler,
PostReconciler,
)
)

Expand Down Expand Up @@ -125,3 +127,28 @@ func (trs *TektonResultStatus) GetVersion() string {
func (trs *TektonResultStatus) SetVersion(version string) {
trs.Version = version
}

func (trs *TektonResultStatus) MarkPreReconcilerComplete() {
resultsCondSet.Manage(trs).MarkTrue(PreReconciler)
}

func (trs *TektonResultStatus) MarkPostReconcilerComplete() {
resultsCondSet.Manage(trs).MarkTrue(PostReconciler)
}

func (trs *TektonResultStatus) MarkPreReconcilerFailed(msg string) {
trs.MarkNotReady("PreReconciliation failed")
resultsCondSet.Manage(trs).MarkFalse(
PreReconciler,
"Error",
"PreReconciliation failed with message: %s", msg)
resultsCondSet.Manage(trs).MarkTrue(PreReconciler)
}

func (trs *TektonResultStatus) MarkPostReconcilerFailed(msg string) {
trs.MarkNotReady("PostReconciliation failed")
resultsCondSet.Manage(trs).MarkFalse(
PostReconciler,
"Error",
"PostReconciliation failed with message: %s", msg)
}
16 changes: 16 additions & 0 deletions pkg/apis/operator/v1alpha1/tektonresult_lifecycle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ func TestTektonResultHappyPath(t *testing.T) {
apistest.CheckConditionOngoing(tt, DependenciesInstalled, t)
apistest.CheckConditionOngoing(tt, InstallerSetAvailable, t)
apistest.CheckConditionOngoing(tt, InstallerSetReady, t)
apistest.CheckConditionOngoing(tt, PreReconciler, t)
apistest.CheckConditionOngoing(tt, PostReconciler, t)

tt.MarkPreReconcilerComplete()
apistest.CheckConditionSucceeded(tt, PreReconciler, t)

// Dependencies installed
tt.MarkDependenciesInstalled()
Expand All @@ -53,6 +58,9 @@ func TestTektonResultHappyPath(t *testing.T) {
tt.MarkInstallerSetReady()
apistest.CheckConditionSucceeded(tt, InstallerSetReady, t)

tt.MarkPostReconcilerComplete()
apistest.CheckConditionSucceeded(tt, PostReconciler, t)

if ready := tt.IsReady(); !ready {
t.Errorf("tt.IsReady() = %v, want true", ready)
}
Expand All @@ -65,6 +73,11 @@ func TestTektonResultErrorPath(t *testing.T) {
apistest.CheckConditionOngoing(tt, DependenciesInstalled, t)
apistest.CheckConditionOngoing(tt, InstallerSetAvailable, t)
apistest.CheckConditionOngoing(tt, InstallerSetReady, t)
apistest.CheckConditionOngoing(tt, PreReconciler, t)
apistest.CheckConditionOngoing(tt, PostReconciler, t)

tt.MarkPreReconcilerComplete()
apistest.CheckConditionSucceeded(tt, PreReconciler, t)

// Dependencies installed
tt.MarkDependenciesInstalled()
Expand All @@ -81,6 +94,9 @@ func TestTektonResultErrorPath(t *testing.T) {
tt.MarkInstallerSetReady()
apistest.CheckConditionSucceeded(tt, InstallerSetReady, t)

tt.MarkPostReconcilerComplete()
apistest.CheckConditionSucceeded(tt, PostReconciler, t)

if ready := tt.IsReady(); !ready {
t.Errorf("tt.IsReady() = %v, want true", ready)
}
Expand Down
10 changes: 0 additions & 10 deletions pkg/apis/operator/v1alpha1/tektonresult_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,6 @@ type TektonResultStatus struct {
TektonInstallerSet string `json:"tektonInstallerSet,omitempty"`
}

func (in *TektonResultStatus) MarkPreReconcilerFailed(s string) {
//TODO implement me
panic("implement me")
}

func (in *TektonResultStatus) MarkPostReconcilerFailed(s string) {
//TODO implement me
panic("implement me")
}

// TektonResultsList contains a list of TektonResult
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type TektonResultList struct {
Expand Down
24 changes: 24 additions & 0 deletions pkg/reconciler/kubernetes/tektonresult/tektonresult.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,18 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tr *v1alpha1.TektonResul
return nil
}

// execute PreReconcile
if err := r.extension.PreReconcile(ctx, tr); err != nil {
logger.Error("pre reconcile failed", err)
if err == v1alpha1.REQUEUE_EVENT_AFTER {
return err
}
tr.Status.MarkPostReconcilerFailed(err.Error())
return nil
}
// mark PreReconcile Complete
tr.Status.MarkPreReconcilerComplete()

// find the valid tekton-pipeline installation
tp, err := common.PipelineReady(r.pipelineInformer)
if err != nil {
Expand Down Expand Up @@ -267,6 +279,18 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tr *v1alpha1.TektonResul
return v1alpha1.REQUEUE_EVENT_AFTER
}

// execute PostReconcile
if err := r.extension.PostReconcile(ctx, tr); err != nil {
logger.Error("post reconcile failed", err)
if err == v1alpha1.REQUEUE_EVENT_AFTER {
return err
}
tr.Status.MarkPostReconcilerFailed(err.Error())
return nil
}
// mark PostReconcile Complete
tr.Status.MarkPostReconcilerComplete()

// Mark InstallerSet Ready
tr.Status.MarkInstallerSetReady()

Expand Down
41 changes: 36 additions & 5 deletions pkg/reconciler/openshift/tektonresult/extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,46 @@ package tektonresult

import (
"context"
"fmt"
"path/filepath"

mf "github.com/manifestival/manifestival"
"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
"github.com/tektoncd/operator/pkg/client/clientset/versioned"
operatorclient "github.com/tektoncd/operator/pkg/client/injection/client"
"github.com/tektoncd/operator/pkg/reconciler/common"
occommon "github.com/tektoncd/operator/pkg/reconciler/openshift/common"
"go.uber.org/zap"
"knative.dev/pkg/logging"
)

func OpenShiftExtension(ctx context.Context) common.Extension {
logger := logging.FromContext(ctx)

operatorVer, err := common.OperatorVersion(ctx)
if err != nil {
logger.Fatal(err)
}

ext := openshiftExtension{
logger: logger,
operatorClientSet: operatorclient.Get(ctx),
}

ext.postManifestReconcile = &postReconcileManifest{
resourcesYamlDirectory: filepath.Join(common.ComponentBaseDir(), postReconcileManifestYamlDirectory),
logger: logger,
operatorClientSet: ext.operatorClientSet,
operatorVersion: operatorVer,
}

return ext
}

type openshiftExtension struct {
operatorClientSet versioned.Interface
logger *zap.SugaredLogger
operatorClientSet versioned.Interface
postManifestReconcile *postReconcileManifest
}

func (oe openshiftExtension) Transformers(comp v1alpha1.TektonComponent) []mf.Transformer {
Expand All @@ -45,12 +67,21 @@ func (oe openshiftExtension) Transformers(comp v1alpha1.TektonComponent) []mf.Tr
occommon.ApplyCABundles,
}
}
func (oe openshiftExtension) PreReconcile(ctx context.Context, tc v1alpha1.TektonComponent) error {

func (oe openshiftExtension) PreReconcile(ctx context.Context, comp v1alpha1.TektonComponent) error {
return nil
}
func (oe openshiftExtension) PostReconcile(context.Context, v1alpha1.TektonComponent) error {
return nil

func (oe openshiftExtension) PostReconcile(ctx context.Context, comp v1alpha1.TektonComponent) error {
resultCR, ok := comp.(*v1alpha1.TektonResult)
if !ok {
return fmt.Errorf("expecting tektonResult component, but received:%t", comp)
}

// reconcile post manifests
return oe.postManifestReconcile.reconcile(ctx, resultCR)
}
func (oe openshiftExtension) Finalize(context.Context, v1alpha1.TektonComponent) error {

func (oe openshiftExtension) Finalize(ctx context.Context, comp v1alpha1.TektonComponent) error {
return nil
}
Loading

0 comments on commit 6620a45

Please sign in to comment.