Skip to content
Open
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cmd/controller/app/controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/kubesphere/ks-devops/controllers/jenkins/config"
jenkinspipeline "github.com/kubesphere/ks-devops/controllers/jenkins/pipeline"
"github.com/kubesphere/ks-devops/controllers/jenkins/pipelinerun"
tektoncontroller "github.com/kubesphere/ks-devops/controllers/tekton"
"github.com/kubesphere/ks-devops/pkg/client/devops"
"github.com/kubesphere/ks-devops/pkg/client/k8s"
"github.com/kubesphere/ks-devops/pkg/informers"
Expand All @@ -45,6 +46,9 @@ func addControllers(mgr manager.Manager, client k8s.Client, informerFactory info
}

reconcilers := getAllControllers(mgr, client, informerFactory, devopsClient, s, jenkinsCore)
reconcilers["tekton"] = func(mgr manager.Manager) error {
return (&tektoncontroller.Reconciler{Client: mgr.GetClient()}).SetupWithManager(mgr)
}
reconcilers["pipeline"] = func(mgr manager.Manager) (err error) {
// add PipelineRun controller
if err = (&pipelinerun.Reconciler{
Expand Down
1 change: 1 addition & 0 deletions cmd/controller/app/options/feature.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func (o *FeatureOptions) GetControllers() map[string]bool {
"jenkinsagent": true,
"gitrepository": true,
"pipeline": true,
"tekton": true,
}

// support to only enable the specific controllers
Expand Down
3 changes: 3 additions & 0 deletions cmd/controller/app/options/feature_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func TestFeatureOptions_GetControllers(t *testing.T) {
"jenkinsagent": true,
"gitrepository": true,
"pipeline": true,
"tekton": true,
},
}, {
name: "no input (be nil) from users",
Expand All @@ -55,6 +56,7 @@ func TestFeatureOptions_GetControllers(t *testing.T) {
"jenkinsagent": true,
"gitrepository": true,
"pipeline": true,
"tekton": true,
},
}, {
name: "merge with the input from users",
Expand All @@ -69,6 +71,7 @@ func TestFeatureOptions_GetControllers(t *testing.T) {
"jenkinsagent": true,
"gitrepository": true,
"pipeline": true,
"tekton": true,
"fake": true,
},
}, {
Expand Down
13 changes: 13 additions & 0 deletions config/crd/bases/devops.kubesphere.io_pipelineruns.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,19 @@ spec:
description: PipelineSpec is the specification of Pipeline when the
current PipelineRun is created.
properties:
engine:
description: Engine selects the backend that executes this Pipeline.
When omitted, the Pipeline uses Jenkins for backward compatibility.
properties:
type:
description: Type is the execution engine name.
enum:
- jenkins
- tekton
type: string
required:
- type
type: object
multi_branch_pipeline:
properties:
bitbucket_server_source:
Expand Down
13 changes: 13 additions & 0 deletions config/crd/bases/devops.kubesphere.io_pipelines.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ spec:
spec:
description: PipelineSpec defines the desired state of Pipeline
properties:
engine:
description: Engine selects the backend that executes this Pipeline.
When omitted, the Pipeline uses Jenkins for backward compatibility.
properties:
type:
description: Type is the execution engine name.
enum:
- jenkins
- tekton
type: string
required:
- type
type: object
multi_branch_pipeline:
properties:
bitbucket_server_source:
Expand Down
11 changes: 11 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -338,3 +338,14 @@ rules:
- get
- list
- watch
- apiGroups:
- tekton.dev
resources:
- pipelineruns
verbs:
- create
- get
- list
- patch
- update
- watch
15 changes: 15 additions & 0 deletions config/samples/tekton/kse-pipeline.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: devops.kubesphere.io/v1alpha3
kind: Pipeline
metadata:
name: smoke-demo
namespace: kse-tekton-demo
annotations:
devops.kubesphere.io/tekton-pipeline: smoke-demo
devops.kubesphere.io/tekton-timeout: 5m
spec:
engine:
type: tekton
type: pipeline
pipeline:
name: smoke-demo
description: KubeSphere facade for the native Tekton smoke-demo Pipeline.
18 changes: 18 additions & 0 deletions config/samples/tekton/kse-pipelinerun.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: devops.kubesphere.io/v1alpha3
kind: PipelineRun
metadata:
generateName: smoke-demo-manual-
namespace: kse-tekton-demo
spec:
pipelineRef:
apiVersion: devops.kubesphere.io/v1alpha3
kind: Pipeline
name: smoke-demo
namespace: kse-tekton-demo
pipelineSpec:
engine:
type: tekton
type: pipeline
parameters:
- name: message
value: hello-from-kse-tekton
8 changes: 8 additions & 0 deletions config/samples/tekton/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- native-pipeline.yaml
- secure-image-pipeline.yaml
- kse-pipeline.yaml
- secure-image-kse-pipeline.yaml
4 changes: 4 additions & 0 deletions config/samples/tekton/namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: kse-tekton-demo
28 changes: 28 additions & 0 deletions config/samples/tekton/native-pipeline.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: smoke-demo
namespace: kse-tekton-demo
spec:
description: A deterministic smoke test for the KubeSphere Tekton adapter.
params:
- name: message
type: string
default: hello-from-kse-tekton
tasks:
- name: smoke-test
params:
- name: message
value: $(params.message)
taskSpec:
params:
- name: message
type: string
steps:
- name: run
image: alpine:3.21
command:
- /bin/sh
- -c
args:
- echo "$(params.message)"
15 changes: 15 additions & 0 deletions config/samples/tekton/secure-image-kse-pipeline.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: devops.kubesphere.io/v1alpha3
kind: Pipeline
metadata:
name: secure-image-demo
namespace: kse-tekton-demo
annotations:
devops.kubesphere.io/tekton-pipeline: secure-image-demo
devops.kubesphere.io/tekton-timeout: 20m
spec:
engine:
type: tekton
type: pipeline
pipeline:
name: secure-image-demo
description: KubeSphere facade for a blocking Trivy image scan.
18 changes: 18 additions & 0 deletions config/samples/tekton/secure-image-kse-pipelinerun.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: devops.kubesphere.io/v1alpha3
kind: PipelineRun
metadata:
generateName: secure-image-demo-manual-
namespace: kse-tekton-demo
spec:
pipelineRef:
apiVersion: devops.kubesphere.io/v1alpha3
kind: Pipeline
name: secure-image-demo
namespace: kse-tekton-demo
pipelineSpec:
engine:
type: tekton
type: pipeline
parameters:
- name: image
value: alpine:3.21
43 changes: 43 additions & 0 deletions config/samples/tekton/secure-image-pipeline.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: secure-image-demo
namespace: kse-tekton-demo
spec:
description: A blocking Trivy policy gate for an image that was built earlier in CI.
params:
- name: image
type: string
description: Immutable image reference to scan; use a digest in production.
tasks:
- name: scan-image
params:
- name: image
value: $(params.image)
taskSpec:
params:
- name: image
type: string
steps:
- name: trivy
# Pin this image to a verified multi-architecture digest in production.
image: aquasec/trivy:0.70.0
command:
- trivy
args:
- image
- --exit-code
- "1"
- --severity
- CRITICAL
- --ignore-unfixed
- --scanners
- vuln,secret
- $(params.image)
computeResources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: "1"
memory: 1Gi
4 changes: 4 additions & 0 deletions controllers/jenkins/pipeline/json_converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"k8s.io/client-go/util/retry"

v1alpha3 "github.com/kubesphere/ks-devops/pkg/api/devops/v1alpha3"
"github.com/kubesphere/ks-devops/pkg/pipelineengine"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
Expand Down Expand Up @@ -59,6 +60,9 @@ func (r *JenkinsfileReconciler) Reconcile(ctx context.Context, req ctrl.Request)
err = client.IgnoreNotFound(err)
return
}
if pipelineengine.IsTekton(pip) {
return
}

if pip.Spec.Type != v1alpha3.NoScmPipelineType || pip.Spec.Pipeline == nil {
return
Expand Down
4 changes: 4 additions & 0 deletions controllers/jenkins/pipeline/pipeline_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import (
devopsinformers "github.com/kubesphere/ks-devops/pkg/client/informers/externalversions/devops/v1alpha3"
devopslisters "github.com/kubesphere/ks-devops/pkg/client/listers/devops/v1alpha3"
"github.com/kubesphere/ks-devops/pkg/constants"
"github.com/kubesphere/ks-devops/pkg/pipelineengine"
)

// Controller is the controller of the Pipeline
Expand Down Expand Up @@ -232,6 +233,9 @@ func (c *Controller) syncHandler(key string) error {
klog.Error(err, fmt.Sprintf("could not get copyPipeline %s ", key))
return err
}
if pipelineengine.IsTekton(pipeline) {
return nil
}

copyPipeline := pipeline.DeepCopy()
// DeletionTimestamp.IsZero() means copyPipeline has not been deleted.
Expand Down
4 changes: 4 additions & 0 deletions controllers/jenkins/pipeline/pipeline_metadata_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/jenkins-zh/jenkins-client/pkg/core"
"github.com/jenkins-zh/jenkins-client/pkg/job"
"github.com/kubesphere/ks-devops/pkg/api/devops/v1alpha3"
"github.com/kubesphere/ks-devops/pkg/pipelineengine"
v1 "k8s.io/api/core/v1"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/retry"
Expand Down Expand Up @@ -63,6 +64,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
// ignore resource not found due to deletion
return ctrl.Result{}, client.IgnoreNotFound(err)
}
if pipelineengine.IsTekton(pipeline) {
return ctrl.Result{}, nil
}

if err := r.obtainAndUpdatePipelineMetadata(pipeline); err != nil {
log.Error(err, "unable to obtain and update Pipeline metadata from Jenkins")
Expand Down
22 changes: 22 additions & 0 deletions controllers/jenkins/pipelinerun/pipelinerun_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (
"github.com/kubesphere/ks-devops/pkg/api/devops/v1alpha3"
devopsClient "github.com/kubesphere/ks-devops/pkg/client/devops"
"github.com/kubesphere/ks-devops/pkg/client/devops/jenkins"
"github.com/kubesphere/ks-devops/pkg/pipelineengine"
cmstore "github.com/kubesphere/ks-devops/pkg/store/configmap"
storeInter "github.com/kubesphere/ks-devops/pkg/store/store"
"github.com/kubesphere/ks-devops/pkg/utils/k8sutil"
Expand Down Expand Up @@ -80,6 +81,11 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
if err = r.Client.Get(ctx, req.NamespacedName, pipelineRun); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
if skip, skipErr := r.shouldSkipForTekton(ctx, pipelineRun); skipErr != nil {
return ctrl.Result{}, skipErr
} else if skip {
return ctrl.Result{}, nil
}

jHandler := &jenkinsHandler{&r.JenkinsCore}

Expand Down Expand Up @@ -276,6 +282,22 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
return ctrl.Result{}, nil
}

// shouldSkipForTekton prevents Jenkins from reconciling runs owned by the Tekton engine.
func (r *Reconciler) shouldSkipForTekton(ctx context.Context, run *v1alpha3.PipelineRun) (bool, error) {
if pipelineengine.IsTekton(run) {
return true, nil
}
if run.Spec.PipelineRef == nil || run.Spec.PipelineRef.Name == "" {
return false, nil
}
pipeline := &v1alpha3.Pipeline{}
key := client.ObjectKey{Namespace: run.Namespace, Name: run.Spec.PipelineRef.Name}
if err := r.Get(ctx, key, pipeline); err != nil {
return false, client.IgnoreNotFound(err)
}
return pipelineengine.IsTekton(pipeline), nil
}

// match /blue/rest/organizations/jenkins/pipelines/{devops}/{pipeline}/runs/{run}/log/?start=0
// match /blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/log/?
func (r *Reconciler) getAgentInfo(ctx context.Context, pr *v1alpha3.PipelineRun) error {
Expand Down
23 changes: 23 additions & 0 deletions controllers/jenkins/pipelinerun/pipelinerun_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,29 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client/fake"
)

// TestShouldSkipForTektonSpec verifies that Jenkins ignores a run whose PipelineSpec snapshot selects Tekton.
func TestShouldSkipForTektonSpec(t *testing.T) {
pipeline := &v1alpha3.Pipeline{
ObjectMeta: metav1.ObjectMeta{Name: "tekton-pipeline", Namespace: "demo"},
Spec: v1alpha3.PipelineSpec{
Engine: &v1alpha3.PipelineEngineSpec{Type: v1alpha3.PipelineEngineTekton},
Type: v1alpha3.NoScmPipelineType,
},
}
run := &v1alpha3.PipelineRun{
ObjectMeta: metav1.ObjectMeta{Name: "tekton-run", Namespace: "demo"},
Spec: v1alpha3.PipelineRunSpec{
PipelineRef: &v1.ObjectReference{Name: pipeline.Name},
PipelineSpec: pipeline.Spec.DeepCopy(),
},
}
reconciler := &Reconciler{Client: fake.NewClientBuilder().WithScheme(scheme.Scheme).WithObjects(pipeline).Build()}

skip, err := reconciler.shouldSkipForTekton(context.Background(), run)
assert.NoError(t, err)
assert.True(t, skip)
}

func Test_getBranch(t *testing.T) {
type args struct {
prSpec *v1alpha3.PipelineRunSpec
Expand Down
Loading