Tekton Pipelines Java Client and Integration
/**
* POST TITLE: Tekton Pipelines Integration in Java
* 
* Complete Java client for Tekton CI/CD pipelines with Kubernetes integration
*/
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
import io.fabric8.tekton.client.TektonClient;
import io.fabric8.tekton.client.DefaultTektonClient;
import io.fabric8.tekton.pipeline.v1.*;
import io.fabric8.kubernetes.api.model.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
public class TektonPipelineManager {
private static final Logger logger = Logger.getLogger(TektonPipelineManager.class.getName());
private TektonClient tektonClient;
private KubernetesClient kubernetesClient;
private ObjectMapper objectMapper;
public TektonPipelineManager() {
this.kubernetesClient = new KubernetesClientBuilder().build();
this.tektonClient = new DefaultTektonClient(kubernetesClient);
this.objectMapper = new ObjectMapper();
}
/**
* Pipeline Definition Builder
*/
public static class PipelineBuilder {
private String name;
private String namespace = "default";
private String description;
private List<TaskRef> tasks = new ArrayList<>();
private Map<String, Param> params = new HashMap<>();
private Map<String, Workspace> workspaces = new HashMap<>();
public PipelineBuilder(String name) {
this.name = name;
}
public PipelineBuilder namespace(String namespace) {
this.namespace = namespace;
return this;
}
public PipelineBuilder description(String description) {
this.description = description;
return this;
}
public PipelineBuilder addParam(String name, String description, String defaultValue) {
this.params.put(name, new Param(name, description, defaultValue));
return this;
}
public PipelineBuilder addWorkspace(String name, String description) {
this.workspaces.put(name, new Workspace(name, description));
return this;
}
public PipelineBuilder addTask(String name, String taskRef, Map<String, String> params) {
this.tasks.add(new TaskRef(name, taskRef, params));
return this;
}
public Pipeline build() {
Pipeline pipeline = new Pipeline();
pipeline.setMetadata(new ObjectMeta());
pipeline.getMetadata().setName(name);
pipeline.getMetadata().setNamespace(namespace);
if (description != null) {
pipeline.getMetadata().setAnnotations(Map.of("description", description));
}
// Set parameters
if (!params.isEmpty()) {
List<io.fabric8.tekton.pipeline.v1.ParamSpec> paramSpecs = new ArrayList<>();
for (Param param : params.values()) {
io.fabric8.tekton.pipeline.v1.ParamSpec paramSpec = new io.fabric8.tekton.pipeline.v1.ParamSpec();
paramSpec.setName(param.name);
paramSpec.setDescription(param.description);
paramSpec.setType("string");
paramSpec.setDefault(new ParamValue(param.defaultValue));
paramSpecs.add(paramSpec);
}
pipeline.setSpec(new PipelineSpec());
pipeline.getSpec().setParams(paramSpecs);
}
// Set workspaces
if (!workspaces.isEmpty()) {
List<io.fabric8.tekton.pipeline.v1.PipelineWorkspaceDeclaration> workspaceDeclarations = new ArrayList<>();
for (Workspace workspace : workspaces.values()) {
io.fabric8.tekton.pipeline.v1.PipelineWorkspaceDeclaration workspaceDecl = 
new io.fabric8.tekton.pipeline.v1.PipelineWorkspaceDeclaration();
workspaceDecl.setName(workspace.name);
workspaceDecl.setDescription(workspace.description);
workspaceDeclarations.add(workspaceDecl);
}
pipeline.getSpec().setWorkspaces(workspaceDeclarations);
}
// Set tasks
List<PipelineTask> pipelineTasks = new ArrayList<>();
for (TaskRef taskRef : tasks) {
PipelineTask pipelineTask = new PipelineTask();
pipelineTask.setName(taskRef.name);
TaskRefBuilder taskRefBuilder = new TaskRefBuilder();
taskRefBuilder.withName(taskRef.taskRef);
pipelineTask.setTaskRef(taskRefBuilder.build());
if (taskRef.params != null && !taskRef.params.isEmpty()) {
List<Param> taskParams = new ArrayList<>();
for (Map.Entry<String, String> entry : taskRef.params.entrySet()) {
Param param = new Param();
param.setName(entry.getKey());
param.setValue(new ParamValue(entry.getValue()));
taskParams.add(param);
}
pipelineTask.setParams(taskParams);
}
pipelineTasks.add(pipelineTask);
}
pipeline.getSpec().setTasks(pipelineTasks);
return pipeline;
}
private static class Param {
String name;
String description;
String defaultValue;
Param(String name, String description, String defaultValue) {
this.name = name;
this.description = description;
this.defaultValue = defaultValue;
}
}
private static class Workspace {
String name;
String description;
Workspace(String name, String description) {
this.name = name;
this.description = description;
}
}
private static class TaskRef {
String name;
String taskRef;
Map<String, String> params;
TaskRef(String name, String taskRef, Map<String, String> params) {
this.name = name;
this.taskRef = taskRef;
this.params = params;
}
}
}
/**
* Create a new Pipeline
*/
public Pipeline createPipeline(PipelineBuilder builder) {
Pipeline pipeline = builder.build();
return tektonClient.v1().pipelines().inNamespace(builder.namespace).create(pipeline);
}
/**
* Create and run a PipelineRun
*/
public PipelineRun runPipeline(String pipelineName, String namespace, 
Map<String, String> params, 
Map<String, String> workspaces) {
String runName = pipelineName + "-run-" + System.currentTimeMillis();
PipelineRun pipelineRun = new PipelineRun();
pipelineRun.setMetadata(new ObjectMeta());
pipelineRun.getMetadata().setName(runName);
pipelineRun.getMetadata().setNamespace(namespace);
PipelineRunSpec spec = new PipelineRunSpec();
spec.setPipelineRef(new PipelineRefBuilder().withName(pipelineName).build());
// Set parameters
if (params != null && !params.isEmpty()) {
List<io.fabric8.tekton.pipeline.v1.Param> runParams = new ArrayList<>();
for (Map.Entry<String, String> entry : params.entrySet()) {
io.fabric8.tekton.pipeline.v1.Param param = new io.fabric8.tekton.pipeline.v1.Param();
param.setName(entry.getKey());
param.setValue(new ParamValue(entry.getValue()));
runParams.add(param);
}
spec.setParams(runParams);
}
// Set workspaces
if (workspaces != null && !workspaces.isEmpty()) {
List<WorkspaceBinding> workspaceBindings = new ArrayList<>();
for (Map.Entry<String, String> entry : workspaces.entrySet()) {
WorkspaceBinding workspaceBinding = new WorkspaceBinding();
workspaceBinding.setName(entry.getKey());
PersistentVolumeClaimVolumeSource pvc = new PersistentVolumeClaimVolumeSource();
pvc.setClaimName(entry.getValue());
Volume volume = new Volume();
volume.setPersistentVolumeClaim(pvc);
workspaceBinding.setVolume(volume);
workspaceBindings.add(workspaceBinding);
}
spec.setWorkspaces(workspaceBindings);
}
pipelineRun.setSpec(spec);
return tektonClient.v1().pipelineRuns().inNamespace(namespace).create(pipelineRun);
}
/**
* Monitor PipelineRun status
*/
public PipelineRunStatus monitorPipelineRun(String runName, String namespace, long timeoutMinutes) 
throws InterruptedException {
long startTime = System.currentTimeMillis();
long timeoutMs = timeoutMinutes * 60 * 1000;
while (System.currentTimeMillis() - startTime < timeoutMs) {
PipelineRun pipelineRun = tektonClient.v1().pipelineRuns()
.inNamespace(namespace)
.withName(runName)
.get();
if (pipelineRun == null) {
throw new RuntimeException("PipelineRun not found: " + runName);
}
PipelineRunStatus status = pipelineRun.getStatus();
if (status != null) {
String completionTime = status.getCompletionTime();
if (completionTime != null) {
logger.info("PipelineRun " + runName + " completed");
return status;
}
List<Condition> conditions = status.getConditions();
if (conditions != null && !conditions.isEmpty()) {
Condition condition = conditions.get(0);
if ("False".equals(condition.getStatus())) {
throw new RuntimeException("PipelineRun failed: " + condition.getMessage());
}
}
}
logger.info("PipelineRun " + runName + " still running...");
TimeUnit.SECONDS.sleep(30);
}
throw new RuntimeException("PipelineRun timeout after " + timeoutMinutes + " minutes");
}
/**
* Get PipelineRun logs
*/
public String getPipelineRunLogs(String runName, String namespace) {
// This would integrate with Kubernetes log retrieval
// Implementation depends on your logging setup
return "Logs for PipelineRun: " + runName;
}
/**
* Task Definition Builder
*/
public static class TaskBuilder {
private String name;
private String namespace = "default";
private String description;
private List<Step> steps = new ArrayList<>();
private Map<String, Param> params = new HashMap<>();
private Map<String, Workspace> workspaces = new HashMap<>();
public TaskBuilder(String name) {
this.name = name;
}
public TaskBuilder namespace(String namespace) {
this.namespace = namespace;
return this;
}
public TaskBuilder description(String description) {
this.description = description;
return this;
}
public TaskBuilder addParam(String name, String description, String defaultValue) {
this.params.put(name, new Param(name, description, defaultValue));
return this;
}
public TaskBuilder addWorkspace(String name, String description) {
this.workspaces.put(name, new Workspace(name, description));
return this;
}
public TaskBuilder addStep(String name, String image, List<String> command, List<String> args) {
this.steps.add(new Step(name, image, command, args));
return this;
}
public Task build() {
Task task = new Task();
task.setMetadata(new ObjectMeta());
task.getMetadata().setName(name);
task.getMetadata().setNamespace(namespace);
if (description != null) {
task.getMetadata().setAnnotations(Map.of("description", description));
}
TaskSpec spec = new TaskSpec();
// Set parameters
if (!params.isEmpty()) {
List<io.fabric8.tekton.pipeline.v1.ParamSpec> paramSpecs = new ArrayList<>();
for (Param param : params.values()) {
io.fabric8.tekton.pipeline.v1.ParamSpec paramSpec = new io.fabric8.tekton.pipeline.v1.ParamSpec();
paramSpec.setName(param.name);
paramSpec.setDescription(param.description);
paramSpec.setType("string");
paramSpec.setDefault(new ParamValue(param.defaultValue));
paramSpecs.add(paramSpec);
}
spec.setParams(paramSpecs);
}
// Set workspaces
if (!workspaces.isEmpty()) {
List<io.fabric8.tekton.pipeline.v1.WorkspaceDeclaration> workspaceDeclarations = new ArrayList<>();
for (Workspace workspace : workspaces.values()) {
io.fabric8.tekton.pipeline.v1.WorkspaceDeclaration workspaceDecl = 
new io.fabric8.tekton.pipeline.v1.WorkspaceDeclaration();
workspaceDecl.setName(workspace.name);
workspaceDecl.setDescription(workspace.description);
workspaceDeclarations.add(workspaceDecl);
}
spec.setWorkspaces(workspaceDeclarations);
}
// Set steps
List<io.fabric8.tekton.pipeline.v1.Step> taskSteps = new ArrayList<>();
for (Step step : steps) {
io.fabric8.tekton.pipeline.v1.Step taskStep = new io.fabric8.tekton.pipeline.v1.Step();
taskStep.setName(step.name);
taskStep.setImage(step.image);
taskStep.setCommand(step.command);
taskStep.setArgs(step.args);
taskSteps.add(taskStep);
}
spec.setSteps(taskSteps);
task.setSpec(spec);
return task;
}
private static class Step {
String name;
String image;
List<String> command;
List<String> args;
Step(String name, String image, List<String> command, List<String> args) {
this.name = name;
this.image = image;
this.command = command;
this.args = args;
}
}
}
/**
* Create a Task
*/
public Task createTask(TaskBuilder builder) {
Task task = builder.build();
return tektonClient.v1().tasks().inNamespace(builder.namespace).create(task);
}
/**
* Pipeline Service for common CI/CD workflows
*/
public static class PipelineService {
private TektonPipelineManager manager;
public PipelineService(TektonPipelineManager manager) {
this.manager = manager;
}
/**
* Create a Java Maven build pipeline
*/
public Pipeline createJavaMavenPipeline(String name, String namespace) {
// First create tasks
createMavenBuildTask(namespace);
createDockerBuildTask(namespace);
createKubernetesDeployTask(namespace);
// Then create pipeline
PipelineBuilder builder = new PipelineBuilder(name)
.namespace(namespace)
.description("Java Maven Build and Deploy Pipeline")
.addParam("git-url", "Git repository URL", "")
.addParam("image-tag", "Docker image tag", "latest")
.addWorkspace("source", "Source code workspace")
.addWorkspace("maven-cache", "Maven cache workspace")
.addTask("clone", "git-clone", Map.of("url", "$(params.git-url)", "subdirectory", "source"))
.addTask("test", "maven-test", Map.of())
.addTask("build", "maven-build", Map.of())
.addTask("docker-build", "docker-build", Map.of("IMAGE", "$(params.image-tag)"))
.addTask("deploy", "kubernetes-deploy", Map.of("image", "$(params.image-tag)"));
return manager.createPipeline(builder);
}
private void createMavenBuildTask(String namespace) {
TaskBuilder builder = new TaskBuilder("maven-build")
.namespace(namespace)
.description("Maven build task for Java applications")
.addWorkspace("source", "Source code")
.addWorkspace("maven-cache", "Maven cache")
.addStep("maven-test", "maven:3.8.4-openjdk-17",
List.of("mvn", "clean", "test"),
List.of())
.addStep("maven-package", "maven:3.8.4-openjdk-17",
List.of("mvn", "clean", "package", "-DskipTests"),
List.of());
manager.createTask(builder);
}
private void createDockerBuildTask(String namespace) {
TaskBuilder builder = new TaskBuilder("docker-build")
.namespace(namespace)
.description("Docker build task")
.addParam("IMAGE", "Image name", "")
.addWorkspace("source", "Source code with Dockerfile")
.addStep("build", "gcr.io/kaniko-project/executor:latest",
List.of("/kaniko/executor"),
List.of("--dockerfile=$(workspaces.source.path)/Dockerfile",
"--destination=$(params.IMAGE)",
"--context=$(workspaces.source.path)"));
manager.createTask(builder);
}
}
/**
* Demo usage
*/
public static void main(String[] args) {
try {
TektonPipelineManager manager = new TektonPipelineManager();
PipelineService pipelineService = new PipelineService(manager);
// Create a Java pipeline
Pipeline pipeline = pipelineService.createJavaMavenPipeline("java-app-pipeline", "default");
logger.info("Created pipeline: " + pipeline.getMetadata().getName());
// Run the pipeline
Map<String, String> params = Map.of(
"git-url", "https://github.com/example/java-app.git",
"image-tag", "myapp:v1.0.0"
);
Map<String, String> workspaces = Map.of(
"source", "pipeline-source-pvc",
"maven-cache", "maven-cache-pvc"
);
PipelineRun pipelineRun = manager.runPipeline("java-app-pipeline", "default", params, workspaces);
logger.info("Started PipelineRun: " + pipelineRun.getMetadata().getName());
// Monitor the pipeline run (commented out for demo)
// PipelineRunStatus status = manager.monitorPipelineRun(
//     pipelineRun.getMetadata().getName(), "default", 30);
// logger.info("PipelineRun completed with status: " + status.getConditions());
} catch (Exception e) {
logger.severe("Error in Tekton pipeline demo: " + e.getMessage());
e.printStackTrace();
}
}
}

Maven Dependencies

<!-- pom.xml -->
<dependencies>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>tekton-client</artifactId>
<version>6.3.0</version>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client</artifactId>
<version>6.3.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
</dependencies>

Spring Boot Integration

/**
* Spring Boot Configuration for Tekton
*/
@Configuration
public class TektonConfig {
@Value("${kubernetes.namespace:default}")
private String namespace;
@Bean
public TektonPipelineManager tektonPipelineManager() {
return new TektonPipelineManager();
}
@Bean
public PipelineService pipelineService(TektonPipelineManager manager) {
return new PipelineService(manager);
}
}
/**
* REST Controller for Pipeline Management
*/
@RestController
@RequestMapping("/api/pipelines")
public class PipelineController {
@Autowired
private TektonPipelineManager pipelineManager;
@PostMapping
public ResponseEntity<Pipeline> createPipeline(@RequestBody PipelineRequest request) {
PipelineBuilder builder = new PipelineBuilder(request.getName())
.namespace(request.getNamespace())
.description(request.getDescription());
for (PipelineRequest.Task task : request.getTasks()) {
builder.addTask(task.getName(), task.getTaskRef(), task.getParams());
}
Pipeline pipeline = pipelineManager.createPipeline(builder);
return ResponseEntity.ok(pipeline);
}
@PostMapping("/{pipelineName}/run")
public ResponseEntity<PipelineRun> runPipeline(
@PathVariable String pipelineName,
@RequestParam String namespace,
@RequestBody Map<String, String> params) {
PipelineRun pipelineRun = pipelineManager.runPipeline(pipelineName, namespace, params, null);
return ResponseEntity.ok(pipelineRun);
}
@GetMapping("/runs/{runName}")
public ResponseEntity<PipelineRun> getPipelineRun(
@PathVariable String runName,
@RequestParam String namespace) {
PipelineRun pipelineRun = pipelineManager.tektonClient.v1().pipelineRuns()
.inNamespace(namespace)
.withName(runName)
.get();
return ResponseEntity.ok(pipelineRun);
}
}
/**
* Request DTOs
*/
class PipelineRequest {
private String name;
private String namespace;
private String description;
private List<Task> tasks;
// Getters and setters
public static class Task {
private String name;
private String taskRef;
private Map<String, String> params;
// Getters and setters
}
}

This Tekton Pipelines Java integration provides:

  1. Complete Tekton Client for pipeline and task management
  2. Builder Patterns for easy pipeline/task creation
  3. PipelineRun Management with monitoring capabilities
  4. Common CI/CD Templates for Java applications
  5. Spring Boot Integration for web applications
  6. Error Handling and status monitoring
  7. Workspace and Parameter management

The implementation follows Kubernetes/Tekton best practices and can be extended for complex CI/CD workflows.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper