What's new with fabric8 featured image

The recent Fabric8 Kubernetes Java client 4.12.0 release includes many new features and bug fixes. This article introduces the major features we've added between the 4.11.0 and 4.12.0 releases.

I will show you how to get started with the new VolumeSnapshot extension, CertificateSigningRequests, and Tekton triggers in the Fabric8 Tekton client (to name just a few). I'll also point out several minor changes that break backward compatibility with older releases. Knowing about these changes will help you avoid problems when you upgrade to the latest version of Fabric8's Java client for Kubernetes or Red Hat OpenShift.

How to get the new Fabric8 Java client

You will find the most current Fabric8 Java client release on Maven Central. To start using the new Java client, add it as a dependency in your Maven pom.xml. For Kubernetes, the dependency is:

<dependency>
  <groupId>io.fabric8</groupId>
  <artifactId>kubernetes-client</artifactId>
  <version>4.12.0</version>
</dependency>

For OpenShift, it's:

<dependency>
  <groupId>io.fabric8</groupId>
  <artifactId>openshift-client</artifactId>
  <version>4.12.0</version>
</dependency>

Breaking changes in this release

We have moved several classes for this release, so upgrading to the new version of the Fabric8 Kubernetes Java client might not be completely smooth. The changes are as follows:

  • We moved the CustomResourceDefinition to io.fabric8.kubernetes.api.model.apiextensions.v1 and io.fabric8.kubernetes.api.model.apiextensions.v1beta1.
  • We moved SubjectAccessReview, SelfSubjectAccessReview, LocalSubjectAccessReview, and SelfSubjectRulesReview to io.fabric8.kubernetes.api.model.authorization.v1 and io.fabric8.kubernetes.api.model.authorization.v1beta1.
  • The io.fabric8.tekton.pipeline.v1beta1.WorkspacePipelineDeclaration is now io.fabric8.tekton.pipeline.v1beta1.PipelineWorkspaceDeclaration.
  • We introduced a new interface, WatchAndWaitable, which is used by WatchListDeletable and other interfaces. This change should not affect you if you are using the Fabric8 Kubernetes Java client's domain-specific language (DSL).

The new VolumeSnapshot extension

You might know about the Fabric8 Kubernetes Java client extensions for Knative, Tekton, Istio, and Service Catalog. In this release, we've added a new Container Storage Interface (CSI) VolumeSnapshot extension. VolumeSnapshots are in the snapshot.storage.k8s.io/v1beta1 directory. To start using the new extension, add the following dependency to your Maven pom.xml:

<dependency>
  <groupId>io.fabric8</groupId>
  <artifactId>volumesnapshot-client</artifactId>
  <version>4.12.0</version>
</dependency>

Once you've added the dependency, you can start using the VolumeSnapshotClient. Here's an example of how to create a VolumeSnapshot:

try (VolumeSnapshotClient client = new DefaultVolumeSnapshotClient()) {
      System.out.println("Creating a volume snapshot");
      client.volumeSnapshots().inNamespace("default").createNew()
        .withNewMetadata()
        .withName("my-snapshot")
        .endMetadata()
        .withNewSpec()
        .withNewSource()
        .withNewPersistentVolumeClaimName("my-pvc")
        .endSource()
        .endSpec()
        .done();
    }

Spin up a single pod with client.run()

Just like you would with kubectl run, you can quickly spin up a pod with the Fabric8 Kubernetes Java client. You only need to provide a name and image:

try (KubernetesClient client = new DefaultKubernetesClient()) {
    client.run().inNamespace("default").withName("hello-openshift")
            .withImage("openshift/hello-openshift:latest")
            .done();
}

Authentication API support

A new authentication API lets you use the Fabric8 Kubernetes Java client to query a Kubernetes cluster. You should be able to use the API for all operations equivalent to kubectl auth can-i. Here's an example:

try (KubernetesClient client = new DefaultKubernetesClient()) {
    SelfSubjectAccessReview ssar = new SelfSubjectAccessReviewBuilder()
            .withNewSpec()
            .withNewResourceAttributes()
            .withGroup("apps")
            .withResource("deployments")
            .withVerb("create")
            .withNamespace("dev")
            .endResourceAttributes()
            .endSpec()
            .build();

    ssar = client.authorization().v1().selfSubjectAccessReview().create(ssar);

    System.out.println("Allowed: "+  ssar.getStatus().getAllowed());
}

OpenShift 4 resources

The Fabric8 Kubernetes Java client now supports all of the new OpenShift 4 resources in its OpenShift model. Additional resources added in operators.coreos.com, operators.openshift.io, console.openshift.io, and monitoring.coreos.com are also available within the OpenShift model. Here is an example of using PrometheusRule to monitor a Prometheus instance:

try (OpenShiftClient client = new DefaultOpenShiftClient()) {
    PrometheusRule prometheusRule = new PrometheusRuleBuilder()
            .withNewMetadata().withName("foo").endMetadata()
            .withNewSpec()
            .addNewGroup()
            .withName("./example-rules")
            .addNewRule()
            .withAlert("ExampleAlert")
            .withNewExpr().withStrVal("vector(1)").endExpr()
            .endRule()
            .endGroup()
            .endSpec()
            .build();

    client.monitoring().prometheusRules().inNamespace("rokumar").createOrReplace(prometheusRule);
    System.out.println("Created");

    PrometheusRuleList prometheusRuleList = client.monitoring().prometheusRules().inNamespace("rokumar").list();
    System.out.println(prometheusRuleList.getItems().size() + " items found");
}

Certificate signing requests

We've added a new entry point, certificateSigningRequests(), in the main KubernetesClient interface. This means you can use CertificateSigningRequest resources in all of your applications developed with Fabric8:

try (KubernetesClient client = new DefaultKubernetesClient()) {

    CertificateSigningRequest csr = new CertificateSigningRequestBuilder()
            .withNewMetadata().withName("test-k8s-csr").endMetadata()
            .withNewSpec()
            .addNewGroup("system:authenticated")
            .withRequest("<your-req>")
            .addNewUsage("client auth")
            .endSpec()
            .build();
    client.certificateSigningRequests().create(csr);
}

Custom resource definitions

We've moved the apiextensions/v1 CustomResourceDefinition (CRD) to the io.fabric8.kubernetes.api.model.apiextensions.v1beta1 and io.fabric8.kubernetes.api.model.apiextensions.v1 packages. You can now use CustomResourceDefinition objects inside apiextensions() like this:

try (KubernetesClient client = new DefaultKubernetesClient()) {
    client.apiextensions().v1()
            .customResourceDefinitions()
            .list()
            .getItems().forEach(crd -> System.out.println(crd.getMetadata().getName()));
}

Creating bootstrap project templates

We've provided a new, built-in way to create a project with all of the role bindings you need. It works like OpenShift's oc adm create-bootstrap-project-template command. Specify the parameters that the template requires in the DSL method. The method then creates the Project and related RoleBindings for you:

try (OpenShiftClient client = new DefaultOpenShiftClient()) {
    client.projects().createProjectAndRoleBindings("default", "Rohan Kumar", "default", "developer", "developer");
}

Tekton model 0.15.1

We've updated the Tekton model to version 0.15.1 so that you can take advantage of all the newest upstream features and enhancements for Tekton. This example creates a simple Task and TaskRun to echo "hello world" in a pod. Instead of YAML, we use the Fabric8 TektonClient:

try (TektonClient tkn = new DefaultTektonClient()) {
    // Create Task
    tkn.v1beta1().tasks().inNamespace(NAMESPACE).createOrReplaceWithNew()
            .withNewMetadata().withName("echo-hello-world").endMetadata()
            .withNewSpec()
            .addNewStep()
            .withName("echo")
            .withImage("alpine:3.12")
            .withCommand("echo")
            .withArgs("Hello World")
            .endStep()
            .endSpec()
            .done();

    // Create TaskRun
    tkn.v1beta1().taskRuns().inNamespace(NAMESPACE).createOrReplaceWithNew()
            .withNewMetadata().withName("echo-hello-world-task-run").endMetadata()
            .withNewSpec()
            .withNewTaskRef()
            .withName("echo-hello-world")
            .endTaskRef()
            .endSpec()
            .done();
}

When you run this code, you will see the Task and TaskRun being created. The TaskRun, in turn, creates a pod, which prints the "Hello World" message:

tekton-java-client-demo : $ tkn taskrun list
NAME                        STARTED         DURATION     STATUS
echo-hello-world-task-run   2 minutes ago   19 seconds   Succeeded
tekton-java-client-demo : $ kubectl get pods
NAME                                  READY   STATUS      RESTARTS   AGE
echo-hello-world-task-run-pod-4gczw   0/1     Completed   0          2m17s
tekton-java-client-demo : $ kubectl logs pod/echo-hello-world-task-run-pod-4gczw
Hello World

Tekton triggers in the Fabric8 Tekton client

The Fabric8 Tekton client and model now support Tekton triggers. You can use triggers to automate the creation of Tekton pipelines. All you have to do is embed your triggers in the Tekton continuous deployment (CD) pipeline. Here is an example of using the Fabric8 Tekton client to create a Tekton trigger template:

try (TektonClient tkn = new DefaultTektonClient()) {
    tkn.v1alpha1().triggerTemplates().inNamespace(NAMESPACE).createOrReplaceWithNew()
            .withNewMetadata().withName("pipeline-template").endMetadata()
            .withNewSpec()
                .addNewParam()
                    .withName("gitrepositoryurl")
                    .withDescription("The git repository url")
                .endParam()
                .addNewParam()
                    .withName("gitrevision")
                    .withDescription("The git revision")
                .endParam()
                .addNewParam()
                    .withName("message")
                    .withDescription("The message to print")
                    .withDefault("This is default message")
                .endParam()
                .addNewParam()
                    .withName("contenttype")
                    .withDescription(" The Content-Type of the event")
                .endParam()
            .withResourcetemplates(Collections.singletonList(new PipelineRunBuilder()
                    .withNewMetadata().withGenerateName("simple-pipeline-run-").endMetadata()
                    .withNewSpec()
                        .withNewPipelineRef().withName("simple-pipeline").endPipelineRef()
                        .addNewParam()
                            .withName("message")
                            .withValue(new ArrayOrString("$(tt.params.message)"))
                        .endParam()
                        .addNewParam()
                            .withName("contenttype")
                            .withValue(new ArrayOrString("$(tt.params.contenttype)"))
                        .endParam()
                        .addNewResource()
                            .withName("git-source")
                            .withNewResourceSpec()
                                .withType("git")
                                .addNewParam()
                                .withName("revision")
                                .withValue("$(tt.params.gitrevision)")
                                .endParam()
                                .addNewParam()
                                .withName("url")
                                .withValue("$(tt.params.gitrepositoryurl)")
                                .endParam()
                            .endResourceSpec()
                        .endResource()
                    .endSpec()
                    .build()))
            .endSpec()
            .done();
}

Automatically refresh OpenID Connect tokens

If your Kubernetes provider uses OpenID Connect tokens (like IBM Cloud), you don't need to worry about your tokens expiring. The new Fabric8 Kubernetes Java client automatically refreshes your tokens by contacting the OpenID Connect provider, which is listed in the ~/.kube/config.

Support for Knative 0.17.2 and Knative Eventing Contrib

For this release, we've updated the Knative model to the latest version. We also added new support for the additional resources from Knative Eventing Contrib, which involves sources and channel implementations that integrate with Apache CouchDB, Apache Kafka, Amazon Simple Queue Service (AWS SQS), GitHub, GitLab, and so on.

Here's an example of creating an AwsSqsSource using KnativeClient:

try (KnativeClient client = new DefaultKnativeClient()) {
    AwsSqsSource awsSqsSource = new AwsSqsSourceBuilder()
            .withNewMetadata().withName("awssqs-sample-source").endMetadata()
            .withNewSpec()
            .withNewAwsCredsSecret("credentials", "aws-credentials", true)
            .withQueueUrl("QUEUE_URL")
            .withSink(new ObjectReferenceBuilder()
                    .withApiVersion("messaging.knative.dev/v1alpha1")
                    .withKind("Channel")
                    .withName("awssqs-test")
                    .build())
            .endSpec()
            .build();
    client.awsSqsSources().inNamespace("default").createOrReplace(awsSqsSource);
}

Get involved!

There are a few ways to get involved with the development of the Fabric8 Kubernetes Java client: