一键导入
kubesphere-devops-pipeline
// Use when creating, running, or managing CI/CD pipelines in KubeSphere DevOps, including pipeline API operations and run monitoring
// Use when creating, running, or managing CI/CD pipelines in KubeSphere DevOps, including pipeline API operations and run monitoring
Operate the KubeSphere network extension. Use when Codex needs to install, upgrade, configure, enable, disable, or inspect the `network` extension; manage Calico `IPPool` resources, namespace bindings, migrations, or network isolation flows; or consult the bundled network extension references in this skill.
Use when working with KubeSphere DevOps extension, CI/CD pipelines, Jenkins integration, or pipeline troubleshooting
Use when working with WizTelemetry Logging extension for KubeSphere, including installation, configuration, and log query API
KubeSphere Fluid management Skill. Use when user asks to install or enable Fluid, check Fluid status, view Fluid pods/logs/CRDs, create or update Dataset, AlluxioRuntime, JuiceFSRuntime, or ThinRuntime, perform DataLoad or cache warming, scale runtime, or troubleshoot Fluid issues in KubeSphere.
Use when managing credentials in KubeSphere DevOps, including repository credentials, kubeconfig, and API tokens
NodeGroup operation Skill for the edgewize nodegroup project. Use this whenever the user wants to query, create, update, delete, bind, unbind, or troubleshoot NodeGroup resources, including node binding, namespace binding, workspace binding, and deployment/config inspection for nodegroup.
| name | kubesphere-devops-pipeline |
| description | Use when creating, running, or managing CI/CD pipelines in KubeSphere DevOps, including pipeline API operations and run monitoring |
Pipelines in KubeSphere DevOps are Kubernetes custom resources that integrate with Jenkins. KubeSphere uses a cloud-native, object-reconcile approach where Kubernetes resources are the source of truth.
KubeSphere DevOps maps Kubernetes resources to Jenkins objects:
| KubeSphere Resource | K8s Resource | Jenkins Resource |
|---|---|---|
| DevOpsProject | DevOpsProject CR + Namespace | Folder |
| Pipeline | Pipeline CR | WorkflowJob |
| PipelineRun | PipelineRun CR | Build Run |
| Workspace | Workspace CR | (authorization context) |
KubeSphere Kubernetes Jenkins
─────────────────────────────────────────────────────────────
Workspace demo
└── DevOpsProject → demo-project NS → Folder demo-project
└── Pipeline → Pipeline CR → WorkflowJob
└── Run → PipelineRun CR → Build #1
CRITICAL: ALWAYS Check for Parameters First!
Before triggering ANY pipeline (regular or multi-branch), you MUST check if the pipeline has parameters defined. Triggering a pipeline without required parameters will cause the build to fail or use incorrect defaults.
For Multi-Branch Pipelines: Query
/branches/{branch}endpoint to get.parametersarray For Regular Pipelines: Query the Pipeline CR and check.spec.pipeline.jenkinsfileforparameters {}directive
Preferred Approach: Create a PipelineRun custom resource. KubeSphere watches for these resources and triggers the corresponding Jenkins build.
apiVersion: devops.kubesphere.io/v1alpha3
kind: PipelineRun
metadata:
name: my-pipeline-run-001
namespace: demo-project
spec:
pipelineRef:
name: my-pipeline
parameters:
- name: BRANCH
value: "main"
Apply with kubectl:
kubectl apply -f pipelinerun.yaml
# List all runs
kubectl get pipelineruns -n demo-project
# Get specific run status
kubectl get pipelinerun my-pipeline-run-001 -n demo-project -o yaml
# Watch run progress
kubectl get pipelineruns -n demo-project -w
| Field | Description |
|---|---|
status.phase | Current state (Pending, Running, Succeeded, Failed, Unknown) |
status.conditions | Detailed conditions (Succeeded, Ready) |
status.completionTime | When run finished |
status.startTime | When run started |
kubectl delete pipelinerun my-pipeline-run-001 -n demo-project
Here's a complete, working pipeline that builds a Go application:
apiVersion: devops.kubesphere.io/v1alpha3
kind: Pipeline
metadata:
name: go-demo-pipeline
namespace: demo-project
spec:
type: pipeline
pipeline:
name: go-demo-pipeline
description: "Build and test Go application"
jenkinsfile: |
pipeline {
agent any
stages {
stage('Build, Test and Archive') {
agent {
kubernetes {
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: golang
image: golang:1.21
command: ["sleep"]
args: ["99d"]
'''
}
}
steps {
container('golang') {
sh '''
export GO111MODULE=on
git clone https://github.com/kubesphere-sigs/demo-go-http.git .
go mod download
go test ./... -v
go build -o service main.go
'''
}
archiveArtifacts artifacts: 'service', followSymlinks: false
}
}
}
}
Key Points:
agent { kubernetes { yaml ... } } to define a custom pod with Go containerarchiveArtifacts step must be in the same stage as the build (same workspace)container('golang') must match the container name in the YAMLapiVersion: devops.kubesphere.io/v1alpha3
kind: Pipeline
metadata:
name: my-pipeline
namespace: demo-project
spec:
type: pipeline
pipeline:
name: my-pipeline
description: "Build and deploy app"
jenkinsfile: |-
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'make build'
}
}
}
}
When creating pipelines as a tenant (not cluster-admin), you MUST include the kubesphere.io/creator annotation to properly track ownership:
apiVersion: devops.kubesphere.io/v1alpha3
kind: Pipeline
metadata:
name: my-pipeline
namespace: demo-project
annotations:
kubesphere.io/creator: "stone-ns-admin" # Required for tenant-created resources
spec:
type: pipeline
pipeline:
name: my-pipeline
description: "Pipeline created by tenant"
jenkinsfile: |-
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'echo Building...'
}
}
}
}
Why this matters:
Example API call with creator annotation for regular pipeline:
curl -s -X POST "${KUBESPHERE_API}/kapis/devops.kubesphere.io/v1alpha3/namespaces/demo-project/pipelines" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"apiVersion": "devops.kubesphere.io/v1alpha3",
"kind": "Pipeline",
"metadata": {
"name": "my-pipeline",
"namespace": "demo-project",
"annotations": {
"kubesphere.io/creator": "'${USERNAME}'"
}
},
"spec": {
"type": "pipeline",
"pipeline": {
"name": "my-pipeline",
"description": "Tenant-created pipeline",
"jenkinsfile": "pipeline { agent any; stages { stage(\"Build\") { steps { sh \"echo hello\" } } } }"
}
}
}'
Multi-branch pipelines automatically discover branches from SCM and create jobs for each branch. The Jenkinsfile is loaded from the repository.
⚠️ CRITICAL: Always Check Repository Type First
Before creating a multi-branch pipeline, you MUST ask the user:
"Is this a private repository?"
If YES (Private Repo):
- Ask if they want to use an existing credential or create a new one
- Create a DevOps credential (
basic-authtype with GitHub PAT) if needed- Reference the credential in
git_source.credential_id- (Optional) Create a GitRepository CR for additional metadata
If NO (Public Repo):
- Set
credential_id: ""(empty string)Never assume repository type - always confirm with the user first.
Step 1: Check Repository Type
Step 2: Create Credential (For Private Repos Only)
# Create GitHub credential
export GITHUB_PAT="ghp_xxxxxxxxxxxxxxxxxxxx"
curl -s -X POST "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/credentials" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"apiVersion": "v1",
"kind": "Secret",
"metadata": {
"name": "github-token",
"namespace": "'${DEVOPS_PROJECT}'",
"annotations": {
"kubesphere.io/creator": "'${USERNAME}'",
"credential.devops.kubesphere.io/type": "basic-auth"
}
},
"stringData": {
"username": "git",
"password": "'${GITHUB_PAT}'"
},
"type": "credential.devops.kubesphere.io/basic-auth"
}'
Step 3a: For Public Repository:
apiVersion: devops.kubesphere.io/v1alpha3
kind: Pipeline
metadata:
name: demo-jenkinsfiles-go
namespace: demo-project
annotations:
kubesphere.io/creator: "stone-ns-admin" # Required for tenant-created resources
spec:
type: multi-branch-pipeline
multi_branch_pipeline:
name: demo-jenkinsfiles-go
description: "Multi-branch Go pipeline"
source_type: git
git_source:
url: https://github.com/kubesphere/demo-jenkinsfiles
credential_id: "" # Empty for public repos
discover_branches: true
discover_tags: false
script_path: go/Jenkinsfile # Path to Jenkinsfile in repo
Step 3b: For Private Repository (with credential):
apiVersion: devops.kubesphere.io/v1alpha3
kind: Pipeline
metadata:
name: private-repo-pipeline
namespace: demo-project
annotations:
kubesphere.io/creator: "stone-ns-admin"
spec:
type: multi-branch-pipeline
multi_branch_pipeline:
name: private-repo-pipeline
description: "Pipeline for private repository"
source_type: git
git_source:
url: https://github.com/org/private-repo.git
credential_id: "github-token" # Reference to DevOps credential
discover_branches: true
discover_tags: false
script_path: Jenkinsfile
Complete Flow for Private Repo:
basic-auth type with GitHub PAT)provider and secret fields)git_source.credential_idImportant: Never use GITHUB_ env vars directly in the pipeline spec. Always create proper DevOps credentials.
SCM Source Types:
| Type | Field | Use Case |
|---|---|---|
| Git | git_source | Generic Git repositories |
| GitHub | github_source | GitHub.com or GitHub Enterprise |
| GitLab | gitlab_source | GitLab.com or self-hosted GitLab |
| SVN | svn_source | Subversion repositories |
apiVersion: devops.kubesphere.io/v1alpha3
kind: PipelineRun
metadata:
name: demo-jenkinsfiles-go-main-run
namespace: demo-project
spec:
pipelineRef:
name: demo-jenkinsfiles-go
scm:
refName: main # Branch name
refType: branch # or 'tag'
Via v1alpha3 API (preferred):
curl -s "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/branches?filter=origin&page=1&limit=10" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" | jq -r '.items[] | "- Branch: \(.name) | Latest Run: \(.latestRun.id // "N/A") | Status: \(.latestRun.result // "N/A")"'
Via Jenkins (admin only):
kubectl run curl-jenkins --rm -i --restart=Never --image=curlimages/curl \
-- "http://admin:${TOKEN}@devops-jenkins.kubesphere-devops-system:80/job/demo-project/job/demo-jenkinsfiles-go/api/json"
Note: Repository scanning uses v1alpha2 API (not v1alpha3). This is an exception to the general rule of preferring v1alpha3.
Step 1: Trigger Scan
curl -X POST "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha2/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/scan" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{}'
Step 2: Fetch Scanning Log
curl -s "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha2/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/consolelog" \
-H "Authorization: Bearer ${API_TOKEN}"
When to use:
Example scanning log output:
Started by user admin
Starting branch indexing...
> git ls-remote --symref -- https://github.com/org/repo.git
Checking branches:
Checking branch main ✓
'Jenkinsfile' found
Met criteria
Checking branch feature-x ✓
'Jenkinsfile' found
Met criteria
Checking branch old-branch
'Jenkinsfile' not found
Does not meet criteria
Processed 3 branches
Finished branch indexing. Indexing took 3 sec
Finished: SUCCESS
Scenario: Create a multi-branch pipeline for a private GitHub repository with proper authentication.
Step 1: Ask User About Repository Type
Question: "Is https://github.com/stoneshi-yunify/jenkinsfiles a private repository?"
User Answer: "Yes"
Step 2: Create GitHub Credential
export KUBESPHERE_API="http://kubesphere-apiserver:80"
export API_TOKEN="<tenant-oauth-token>"
export DEVOPS_PROJECT="devopstestc2nj7"
export USERNAME="stone-ns-admin"
export GITHUB_PAT="ghp_xxxxxxxxxxxxxxxxxxxx"
curl -s -X POST "${KUBESPHERE_API}/clusters/member-1/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/credentials" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"apiVersion": "v1",
"kind": "Secret",
"metadata": {
"name": "github-token",
"namespace": "'${DEVOPS_PROJECT}'",
"annotations": {
"kubesphere.io/creator": "'${USERNAME}'",
"credential.devops.kubesphere.io/type": "basic-auth"
}
},
"stringData": {
"username": "git",
"password": "'${GITHUB_PAT}'"
},
"type": "credential.devops.kubesphere.io/basic-auth"
}'
Step 3: Create Multi-Branch Pipeline with Credential
curl -s -X POST "${KUBESPHERE_API}/clusters/member-1/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelines" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"apiVersion": "devops.kubesphere.io/v1alpha3",
"kind": "Pipeline",
"metadata": {
"name": "echo-jenkinsfile-pipeline",
"namespace": "'${DEVOPS_PROJECT}'",
"annotations": {
"kubesphere.io/creator": "'${USERNAME}'"
}
},
"spec": {
"type": "multi-branch-pipeline",
"multi_branch_pipeline": {
"name": "echo-jenkinsfile-pipeline",
"description": "Multi-branch pipeline with GitHub auth",
"source_type": "git",
"git_source": {
"url": "https://github.com/stoneshi-yunify/jenkinsfiles.git",
"credential_id": "github-token",
"discover_branches": true,
"discover_tags": false
},
"script_path": "echo/Jenkinsfile"
}
}
}'
Note: The kubesphere.io/creator annotation is required for all pipelines (both regular and multi-branch). Without it, the pipeline may not appear correctly in the KubeSphere UI.
Step 4: Verify Creation
curl -s "${KUBESPHERE_API}/clusters/member-1/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelines/echo-jenkinsfile-pipeline" \
-H "Authorization: Bearer ${API_TOKEN}" | jq -r '{
name: .metadata.name,
syncStatus: .metadata.annotations."pipeline.devops.kubesphere.io/syncstatus",
credential: .spec.multi_branch_pipeline.git_source.credential_id
}'
Expected output:
{
"name": "echo-jenkinsfile-pipeline",
"syncStatus": "successful",
"credential": "github-token"
}
Scenario: Trigger build, monitor, retrieve logs, and download artifacts.
Step 1: Check Pipeline Exists
kubectl get pipelines -n demo-project
# NAME TYPE AGE
# demo-jenkinsfiles-go multi-branch-pipeline 12d
Step 2: Trigger Build via Jenkins API
# Get token
TOKEN=$(kubectl -n kubesphere-devops-system get secret devops-jenkins -o jsonpath='{.data.jenkins-admin-token}' | base64 -d)
# Trigger main branch build
kubectl run curl-trigger --rm -i --restart=Never --image=curlimages/curl \
-- "http://admin:${TOKEN}@devops-jenkins.kubesphere-devops-system:80/job/demo-project/job/demo-jenkinsfiles-go/job/main/build" \
-X POST -w "\nHTTP Status: %{http_code}\n"
# Expected: HTTP Status: 201
Step 3: Monitor Build Status
# Check PipelineRun created
kubectl get pipelineruns -n demo-project --sort-by=.metadata.creationTimestamp | tail -3
# Example output:
# demo-jenkinsfiles-go-vf8p5 3 Succeeded 2m
# Get detailed status
# Or check via Jenkins API
kubectl run curl-status --rm -i --restart=Never --image=curlimages/curl \
-- "http://admin:${TOKEN}@devops-jenkins.kubesphere-devops-system:80/job/demo-project/job/demo-jenkinsfiles-go/job/main/3/api/json" \
| grep -E '"result"|"building"|"duration"'
Step 4: Retrieve Console Log
# Get full console log from build #3
kubectl run curl-log --rm -i --restart=Never --image=curlimages/curl \
-- "http://admin:${TOKEN}@devops-jenkins.kubesphere-devops-system:80/job/demo-project/job/demo-jenkinsfiles-go/job/main/3/consoleText"
# Look for:
# [Pipeline] Start of Pipeline
# [Pipeline] { (Clone Repository)
# [Pipeline] { (Run Tests)
# === RUN TestHello
# --- PASS: TestHello (0.00s)
# [Pipeline] End of Pipeline
# Finished: SUCCESS
Step 5: Download Build Artifacts
For binary artifacts, use pod-based download:
# Create download pod
kubectl run artifact-downloader --image=curlimages/curl -- sleep 300
kubectl wait --for=condition=Ready pod/artifact-downloader --timeout=60s
# Download artifact inside pod
TOKEN=$(kubectl -n kubesphere-devops-system get secret devops-jenkins -o jsonpath='{.data.jenkins-admin-token}' | base64 -d)
kubectl exec artifact-downloader -- sh -c \
"curl -s -o /tmp/service 'http://admin:${TOKEN}@devops-jenkins.kubesphere-devops-system:80/job/demo-project/job/demo-jenkinsfiles-go/job/main/3/artifact/service'"
# Copy to local
kubectl cp artifact-downloader:/tmp/service /tmp/service
# Clean up
kubectl delete pod artifact-downloader --force
Step 6: Verify Downloaded Artifact
# Check file details
ls -lh /tmp/service
file /tmp/service
# Expected output:
# /tmp/service: ELF 64-bit LSB executable, x86-64...
# Make executable and test
chmod +x /tmp/service
/tmp/service --help
Build Summary Example:
Build #3 Summary:
- Status: SUCCESS
- Duration: ~54 seconds
- Test Results: 1/1 passed
- Artifact: service (8.0 MB Go binary)
- Stages: Checkout → Clone → Dependencies → Test → Build → Archive
| Feature | Regular Pipeline | Multi-Branch Pipeline |
|---|---|---|
| Type | pipeline | multi-branch-pipeline |
| Jenkinsfile | Inline in CRD | From SCM (script_path) |
| Branches | Single | Auto-discovered |
| SCM Config | Manual checkout | Automatic |
| Trigger | PipelineRun/API | Branch indexing + webhooks |
| Get Parameters | From .spec.pipeline.jenkinsfile | From /branches/{branch} endpoint |
For regular pipelines, use this two-step procedure to handle parameters:
Unlike multi-branch pipelines, regular pipelines don't have a dedicated /parameters endpoint. Instead, retrieve the Pipeline CR and extract parameters from the Jenkinsfile:
# Get the pipeline definition
curl -s "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" | jq -r '.spec.pipeline.jenkinsfile'
Look for the parameters {} directive in the Jenkinsfile:
pipeline {
agent any
stages {
stage('Example') {
steps {
echo "Hello ${params.PERSON}"
}
}
}
parameters {
string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?')
booleanParam(name: 'TOGGLE', defaultValue: true, description: 'Toggle this value')
choice(name: 'CHOICE', choices: ['One', 'Two', 'Three'], description: 'Pick something')
}
}
Parameter Types in Jenkinsfile:
| Directive | Type | Example |
|---|---|---|
string() | Single-line text | string(name: 'VAR', defaultValue: 'default', description: '...') |
text() | Multi-line text | text(name: 'VAR', defaultValue: '', description: '...') |
booleanParam() | True/false | booleanParam(name: 'FLAG', defaultValue: true, description: '...') |
choice() | Dropdown | choice(name: 'ENV', choices: ['dev', 'prod'], description: '...') |
password() | Hidden value | password(name: 'SECRET', defaultValue: '', description: '...') |
Use the /pipelineruns endpoint to create a new run with parameters:
# Trigger with parameters
curl -s -X POST "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/pipelineruns" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"parameters": [
{"name": "PERSON", "value": "John Doe"},
{"name": "TOGGLE", "value": "true"},
{"name": "CHOICE", "value": "Two"}
]
}' | jq -r '.metadata.name'
Key Points:
"true" or "false"#!/bin/bash
export KUBESPHERE_API="http://kubesphere-apiserver:80"
export API_TOKEN="<tenant-oauth-token>"
export DEVOPS_PROJECT="devopstestc2nj7"
export PIPELINE_NAME="my-regular-pipeline"
# Step 1: Get pipeline definition and check for parameters
echo "Checking for parameters in pipeline..."
JENKINSFILE=$(curl -s "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}" \
-H "Authorization: Bearer ${API_TOKEN}" | jq -r '.spec.pipeline.jenkinsfile')
# Check if parameters exist
if echo "$JENKINSFILE" | grep -q "parameters {"; then
echo "Pipeline has parameters defined. Extracting..."
# In practice, parse the Jenkinsfile to extract parameter names and defaults
echo "$JENKINSFILE" | grep -E "(string|booleanParam|choice|password|text)\(name:"
else
echo "No parameters found. Triggering without parameters."
fi
# Step 2: Trigger with parameters
echo "Triggering pipeline with parameters..."
curl -s -X POST "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/pipelineruns" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"parameters": [
{"name": "PERSON", "value": "Test User"},
{"name": "TOGGLE", "value": "true"},
{"name": "CHOICE", "value": "Two"},
{"name": "BIOGRAPHY", "value": "Testing API"},
{"name": "PASSWORD", "value": "secret123"}
]
}' | jq -r '.metadata.name'
⚠️ API Version Notice: The
/kapis/devops.kubesphere.io/v1alpha2/APIs are deprecated. Always preferv1alpha3APIs when available.
For multi-branch pipelines, use this three-step procedure with v1alpha3 APIs:
curl -s "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/branches?filter=origin&page=1&limit=10" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" | jq -r '.items[] | "- Branch: \(.name) | Latest Run: \(.latestRun.id // "N/A") | Status: \(.latestRun.result // "N/A")"'
Example output:
- Branch: main | Latest Run: 2 | Status: SUCCESS
- Branch: stone | Latest Run: 1 | Status: SUCCESS
Present the available branches to the user and ask:
"Which branch would you like to build?"
export BRANCH="main" # User's selection
curl -s -X POST "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/pipelineruns?branch=${BRANCH}" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"parameters":[]}' | jq -r '.metadata.name'
Key Points:
v1alpha3 endpoint (not v1alpha2)?branch=${BRANCH}When a pipeline has parameters defined in the Jenkinsfile, you can provide values when triggering a build. Follow this workflow:
Query the branch to retrieve parameter definitions:
curl -s "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/branches/${BRANCH}" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" | jq '.parameters'
Example Response:
[
{
"description": "Who should I say hello to?",
"name": "PERSON",
"type": "StringParameterDefinition",
"value": "",
"defaultParameterValue": {
"name": "PERSON",
"value": "Mr Jenkins"
}
},
{
"description": "Toggle this value",
"name": "TOGGLE",
"type": "BooleanParameterDefinition",
"value": "",
"defaultParameterValue": {
"name": "TOGGLE",
"value": true
}
},
{
"description": "Pick something",
"name": "CHOICE",
"type": "ChoiceParameterDefinition",
"value": "",
"defaultParameterValue": {
"name": "CHOICE",
"value": "One"
},
"choices": ["One", "Two", "Three"]
}
]
Parameter Types:
| Type | Description | Value Format |
|---|---|---|
StringParameterDefinition | Single-line text | "value": "text" |
TextParameterDefinition | Multi-line text | "value": "multi\\nline" |
BooleanParameterDefinition | True/false toggle | "value": "true" or "value": "false" |
ChoiceParameterDefinition | Predefined options | "value": "Option" (must match one of choices) |
PasswordParameterDefinition | Hidden value | "value": "secret" |
Create the parameters JSON array with user-provided values:
# Example parameters
cat > params.json << 'EOF'
{
"parameters": [
{"name": "PERSON", "value": "stone"},
{"name": "BIOGRAPHY", "value": "i'm a software engineer"},
{"name": "TOGGLE", "value": "true"},
{"name": "CHOICE", "value": "Two"},
{"name": "PASSWORD", "value": "secret123"}
]
}
EOF
Important:
"true" or "false"name field, not the descriptionexport BRANCH="main"
# Trigger with parameters
curl -s -X POST "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/pipelineruns?branch=${BRANCH}" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
-d @params.json | jq -r '.metadata.name'
#!/bin/bash
export KUBESPHERE_API="http://kubesphere-apiserver:80"
export API_TOKEN="<tenant-oauth-token>"
export DEVOPS_PROJECT="devopstestc2nj7"
export PIPELINE_NAME="echo-jenkinsfile-pipeline"
export BRANCH="main"
# Step 1: Get parameters
echo "Fetching parameter definitions..."
PARAMS=$(curl -s "${KUBESPHERE_API}/clusters/member-1/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/branches/${BRANCH}" \
-H "Authorization: Bearer ${API_TOKEN}")
echo "Available parameters:"
echo "$PARAMS" | jq -r '.parameters[] | "- \(.name) (\(.type)): \(.description // "No description") [Default: \(.defaultParameterValue.value // "(none)")]"'
# Step 2: Ask user for values (or use defaults)
# In practice, prompt user or read from input
# Step 3: Build and trigger with parameters
echo "Triggering build with parameters..."
curl -s -X POST "${KUBESPHERE_API}/clusters/member-1/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/pipelineruns?branch=${BRANCH}" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"parameters": [
{"name": "PERSON", "value": "stone"},
{"name": "BIOGRAPHY", "value": "software engineer"},
{"name": "TOGGLE", "value": "true"},
{"name": "CHOICE", "value": "Two"},
{"name": "PASSWORD", "value": "secret123"}
]
}' | jq -r '.metadata.name'
#!/bin/bash
export KUBESPHERE_API="http://kubesphere-apiserver:80"
export API_TOKEN="<oauth-token>"
export DEVOPS_PROJECT="devopstestc2nj7"
export PIPELINE_NAME="echo-jenkinsfile-pipeline"
# Step 1: List branches
echo "Available branches:"
curl -s "${KUBESPHERE_API}/clusters/member-1/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/branches?filter=origin&page=1&limit=10" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" | jq -r '.items[] | " - \(.name)"'
# Step 2: User selects branch (example: main)
BRANCH="main"
# Step 3: Trigger build
echo "Triggering build on branch: ${BRANCH}"
PIPELINE_RUN=$(curl -s -X POST "${KUBESPHERE_API}/clusters/member-1/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/pipelineruns?branch=${BRANCH}" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"parameters":[]}')
RUN_NAME=$(echo "$PIPELINE_RUN" | jq -r '.metadata.name')
echo "PipelineRun created: ${RUN_NAME}"
⚠️ Deprecated: The
/kapis/devops.kubesphere.io/v1alpha2/APIs are deprecated. Usev1alpha3APIs shown above.
Use APIs when you need programmatic access from external systems:
| Operation | Method | Endpoint | Status |
|---|---|---|---|
| List Pipelines | GET | /kapis/devops.kubesphere.io/v1alpha2/search?q=type:pipeline | Deprecated |
| Get Pipeline | GET | /kapis/devops.kubesphere.io/v1alpha2/namespaces/{devops}/pipelines/{pipeline} | |
| List Runs | GET | /kapis/devops.kubesphere.io/v1alpha2/namespaces/{devops}/pipelines/{pipeline}/runs | |
| Run Pipeline (API) | POST | /kapis/devops.kubesphere.io/v1alpha2/namespaces/{devops}/pipelines/{pipeline}/runs | |
| Get Run | GET | /kapis/devops.kubesphere.io/v1alpha2/namespaces/{devops}/pipelines/{pipeline}/runs/{run} | |
| Stop Run | POST | /kapis/devops.kubesphere.io/v1alpha2/namespaces/{devops}/pipelines/{pipeline}/runs/{run}/stop | |
| Get Log | GET | /kapis/devops.kubesphere.io/v1alpha2/namespaces/{devops}/pipelines/{pipeline}/runs/{run}/log?start=0 | Use ?start=0 for tenant access |
| Get Artifacts | GET | /kapis/devops.kubesphere.io/v1alpha2/namespaces/{devops}/pipelines/{pipeline}/runs/{run}/artifacts |
curl -X POST "https://kubesphere-api/kapis/devops.kubesphere.io/v1alpha2/namespaces/{devops}/pipelines/{pipeline}/runs" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"parameters": [
{"name": "BRANCH", "value": "main"}
]
}'
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Queue │───▶│ Running │───▶│ Complete │───▶│ Success │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ Paused │ │ Failed │
│ (Input) │ │ │
└──────────┘ └──────────┘
| Status | Meaning |
|---|---|
| QUEUED | Waiting for available agent |
| RUNNING | Currently executing |
| PAUSED | Waiting for user input |
| SUCCESS | Completed successfully |
| FAILED | Failed during execution |
| ABORTED | Manually stopped |
When a pipeline reaches an input step (e.g., approval gates), it enters the PAUSED state and waits for user interaction. Tenants can approve or reject these steps via the KubeSphere API.
Use the nodedetails endpoint to identify the paused step with input:
# Get node details for the pipeline run
curl -s "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelineruns/${PIPELINE_RUN_NAME}/nodedetails" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" | jq '.[-1]'
Look for steps with approvable: true:
{
"displayName": "Build Binary",
"id": "38",
"state": "PAUSED",
"steps": [
{
"id": "41",
"displayName": "Wait for interactive input",
"state": "PAUSED",
"input": {
"id": "Build-binary-confirm",
"message": "Build binary now?",
"ok": "Proceed"
},
"approvable": true
}
]
}
Key Fields:
| Field | Description |
|---|---|
steps[].id | Step ID (e.g., "41") |
steps[].input.id | Input action ID (e.g., "Build-binary-confirm") |
steps[].approvable | true if this step can be approved/rejected |
Use the v1alpha2 API to submit your decision:
Approve (Proceed):
curl -s -X POST "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha2/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/branches/${BRANCH}/runs/${JENKINS_RUN_ID}/nodes/${NODE_ID}/steps/${STEP_ID}/" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"id":"${INPUT_ID}","abort":false}'
Reject (Abort):
curl -s -X POST "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha2/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/branches/${BRANCH}/runs/${JENKINS_RUN_ID}/nodes/${NODE_ID}/steps/${STEP_ID}/" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"id":"${INPUT_ID}","abort":true}'
Parameters:
| Parameter | Description | Example |
|---|---|---|
JENKINS_RUN_ID | Jenkins build number | 9 |
NODE_ID | Stage/node ID from nodedetails | 38 |
STEP_ID | Step ID from nodedetails | 41 |
INPUT_ID | Input ID from the input object | Build-binary-confirm |
abort | false to proceed, true to abort | false |
export KUBESPHERE_API="http://kubesphere-apiserver:80"
export API_TOKEN="<tenant-oauth-token>"
export DEVOPS_PROJECT="devopstestc2nj7"
export PIPELINE_NAME="echo-jenkinsfile-pipeline"
export BRANCH="main"
export PIPELINE_RUN_NAME="echo-jenkinsfile-pipeline-ndrkn"
# Step 1: Get nodedetails and extract input information
NODES=$(curl -s "${KUBESPHERE_API}/clusters/member-1/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelineruns/${PIPELINE_RUN_NAME}/nodedetails" \
-H "Authorization: Bearer ${API_TOKEN}")
# Extract the last node (current stage) and find approvable step
NODE_ID=$(echo "$NODES" | jq -r '.[-1].id')
STEP_ID=$(echo "$NODES" | jq -r '.[-1].steps[] | select(.approvable == true) | .id')
INPUT_ID=$(echo "$NODES" | jq -r '.[-1].steps[] | select(.approvable == true) | .input.id')
JENKINS_RUN_ID=$(echo "$NODES" | jq -r '.[-1].steps[] | select(.approvable == true) | .jenkinsRunId // "9"')
echo "Approving step ${STEP_ID} in node ${NODE_ID}"
echo "Input ID: ${INPUT_ID}"
# Step 2: Approve the step
curl -s -X POST "${KUBESPHERE_API}/clusters/member-1/kapis/devops.kubesphere.io/v1alpha2/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/branches/${BRANCH}/runs/${JENKINS_RUN_ID}/nodes/${NODE_ID}/steps/${STEP_ID}/" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"id\":\"${INPUT_ID}\",\"abort\":false}"
# Step 3: Verify the pipeline continues
echo "Pipeline resumed. Check status..."
Important Notes:
/ in the URL is requiredTo retrieve build logs through the KubeSphere API (recommended for tenants):
First, get the Jenkins PipelineRun ID from the PipelineRun CR annotation:
# Get fresh token
TOKEN_RESPONSE=$(curl -s -X POST "${KUBESPHERE_API}/oauth/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode 'grant_type=password' \
--data-urlencode "username=${USERNAME}" \
--data-urlencode "password=${PASSWORD}" \
--data-urlencode 'client_id=kubesphere' \
--data-urlencode 'client_secret=kubesphere')
export API_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.access_token')
# Get Jenkins PipelineRun ID from annotation
JENKINS_ID=$(curl -s "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelineruns/${PIPELINE_RUN_NAME}" \
-H "Authorization: Bearer ${API_TOKEN}" \
| jq -r '.metadata.annotations."devops.kubesphere.io/jenkins-pipelinerun-id"')
echo "Jenkins Run ID: $JENKINS_ID"
Use the v1alpha2 API to fetch logs. Note: The ?start=0 parameter is required for tenant access:
# For multi-branch pipelines
curl -s "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha2/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/branches/${BRANCH}/runs/${JENKINS_ID}/log/?start=0" \
-H "Authorization: Bearer ${API_TOKEN}"
# Example:
curl -s "${KUBESPHERE_API}/clusters/member-1/kapis/devops.kubesphere.io/v1alpha2/namespaces/devopstestc2nj7/pipelines/echo-jenkinsfile-pipeline/branches/main/runs/5/log/?start=0" \
-H "Authorization: Bearer ${API_TOKEN}"
Key Points:
jenkins-pipelinerun-id annotation (not the Kubernetes PipelineRun name)/branches/{branch}/ in the path?start=0 query parameter - required for tenant access/ at the end of the URL path is requiredTo query and download build artifacts through the KubeSphere API:
Query artifacts for a specific run:
curl -s "${KUBESPHERE_API}/clusters/${CLUSTER}/kapis/devops.kubesphere.io/v1alpha2/namespaces/${DEVOPS_PROJECT}/pipelines/${PIPELINE_NAME}/branches/${BRANCH}/runs/${JENKINS_ID}/artifacts/?start=0&limit=10" \
-H "Authorization: Bearer ${API_TOKEN}"
Example Response:
[
{
"name": "service",
"path": "service",
"size": 8344228,
"downloadable": true,
"url": "/job/devopstestc2nj7/job/go-pipeline/job/main/2/artifact/service"
}
]
Download a specific artifact by filename:
curl -s -o service "${KUBESPHERE_API}/kapis/clusters/${CLUSTER}/devops.kubesphere.io/v1alpha3/namespaces/${DEVOPS_PROJECT}/pipelineruns/${PIPELINE_RUN_NAME}/artifacts/download?filename=service" \
-H "Authorization: Bearer ${API_TOKEN}"
Key Points:
start and limit parameters for listingFor debugging, you can query Jenkins directly using the admin token:
# Get Jenkins admin token
TOKEN=$(kubectl -n kubesphere-devops-system get secret devops-jenkins -o jsonpath='{.data.jenkins-admin-token}' | base64 -d)
# List all folders (maps to DevOpsProjects)
kubectl run curl-jenkins --rm -i --restart=Never --image=curlimages/curl \
-- "http://admin:${TOKEN}@devops-jenkins.kubesphere-devops-system:80/api/json" \
-H "Content-Type: application/json"
# List jobs in a specific folder
kubectl run curl-jenkins --rm -i --restart=Never --image=curlimages/curl \
-- "http://admin:${TOKEN}@devops-jenkins.kubesphere-devops-system:80/job/demo-project/api/json" \
-H "Content-Type: application/json"
| Mistake | Fix |
|---|---|
| PipelineRun not triggering | Check Pipeline exists and is synced to Jenkins |
| Controller panic (getAgentInfo nil pointer) | Known issue with PipelineRef; use Jenkins API directly as workaround |
| Agent label not found | Check available labels: kubectl run curl-jenkins --rm -i --restart=Never --image=curlimages/curl -- "http://admin:${TOKEN}@devops-jenkins.kubesphere-devops-system:80/labelsdashboard/labelsData" |
| Go/Tool not found in agent | Use kubernetes { yaml ... } agent with appropriate container image |
| Artifact not found | Run archiveArtifacts in the same stage where the file was created (same workspace) |
| Permission denied | Check DevOps project membership and RBAC |
| Pipeline shows in KubeSphere but not Jenkins | Check sync status annotation: pipeline.devops.kubesphere.io/syncstatus |
| Run fails immediately | Check controller logs: kubectl logs -n kubesphere-devops-system deployment/devops-controller |
| Escape characters in Jenkinsfile | Don't use \$class escape sequences in inline Jenkinsfile |
Check PipelineRun status:
kubectl get pipelinerun <name> -n <namespace> -o yaml
Check Jenkins build directly:
# Get admin token
TOKEN=$(kubectl -n kubesphere-devops-system get secret devops-jenkins -o jsonpath='{.data.jenkins-admin-token}' | base64 -d)
# Get console output
kubectl run curl-jenkins --rm -i --restart=Never --image=curlimages/curl \
-- "http://admin:${TOKEN}@devops-jenkins.kubesphere-devops-system:80/job/<project>/job/<pipeline>/<build>/consoleText"
List Jenkins agent labels:
kubectl run curl-jenkins --rm -i --restart=Never --image=curlimages/curl \
-- "http://admin:${TOKEN}@devops-jenkins.kubesphere-devops-system:80/labelsdashboard/labelsData"
| Mistake | Fix |
|---|---|
| PipelineRun not triggering | Check Pipeline exists and is synced to Jenkins |
| Agent not found | Verify Jenkins agent labels match pipeline's agent { label 'xxx' } |
| Permission denied | Check DevOps project membership and RBAC |
| Pipeline shows in KubeSphere but not Jenkins | Check sync status annotation: pipeline.devops.kubesphere.io/syncstatus |
| Run fails immediately | Check controller logs: kubectl logs -n kubesphere-devops-system deployment/devops-controller |
kubectl logs on the PipelineRun controller for debugging