Programming

basic programming

Create Async HTTP Process with Red Hat Fuse on Top of Openshift 3.11

Got a unique requirement yesterday where one process on Red Hat Fuse consuming a very long time, therefore creating lots of timeout error from frontend. It happen because some process on Fuse performing a very complicated task and we cannot modified existing api flow due to business requirements.

For this example, i want to simulate the same slowness on my Fuse + Spring Boot app,

package com.redhat.edw;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

A simple camel route,

package com.redhat.edw;

import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.model.rest.RestBindingMode;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class Routes extends RouteBuilder {
    @Override
    public void configure() throws Exception {
        restConfiguration("servlet")
                .bindingMode(RestBindingMode.json)
        ;

        rest()
                .get("hello")
                .route()
                .setBody(method("helloRouteHandler", "setHelloWithName"))
                .endRest()
        ;
    }
}

A placeholder bean,

package com.redhat.edw;

import lombok.*;

@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class HelloResponse {
    private String content;
}

And a Handler class,

package com.redhat.edw;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Slf4j
@Component("helloRouteHandler")
public class HelloRouteHandler {

    @Value("${name}")
    private String name;

    public HelloResponse setHelloWithName() throws Exception {

        /*
         * simulate a very long process (10second)
         */
        Thread.sleep(10000);

        /*
         * this process will still getting called after 10 second regardless of sync or async
         */
        log.info("calling hello for "+name);

        return HelloResponse.builder().content(name).build();
    }
}

And two simple properties file,

# The Camel context name
camel.springboot.name=FuseHelloWorld

# enable all management endpoints
endpoints.enabled=true
management.security.enabled=false

camel.component.servlet.mapping.contextPath=/api/*

name=Edwin
# OpenShift ConfigMap name
spring.application.name=fuse-hello-world

spring.cloud.kubernetes.reload.enabled=true
spring.cloud.kubernetes.reload.strategy=restart_context
spring.cloud.kubernetes.reload.monitoring-config-maps=true
spring.cloud.kubernetes.reload.monitoring-secrets=true
spring.cloud.kubernetes.reload.mode=polling

Run the project and try calling /api/hello api and see how much time is needed to give response time.

As you can see, 10seconds is not an acceptable response for a regular web user and wee need to improve it. The workaround is quite simple, Spring have an @Async method which we will utilize on Handler class,

package com.redhat.edw;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Slf4j
@Component("helloRouteHandler")
public class HelloRouteHandler {

    @Value("${name}")
    private String name;

    @Async
    public HelloResponse setHelloWithName() throws Exception {

        /*
         * simulate a very long process (10second)
         */
        Thread.sleep(10000);

        /*
         * this process will still getting called after 10 second regardless of sync or async
         */
        log.info("calling hello for "+name);

        return HelloResponse.builder().content(name).build();
    }
}

Which will give a faster response,

And we can deploy our code to Openshift by using this command,

mvn fabric8:deploy -Pfabric8

A successful deployment will looks like this,

And finally, the complete code can be downloaded from this url,

https://github.com/edwin/fuse-with-async-http

Do A Maven Owasp Library Scan from A Restricted Network

When we talk about DevSecOps, we are talking about a continous integration and delivery but embedded with a security scanning along the way. And one of the best tool for doing a security scanning for your application library is OWASP dependency-check, and thankfully we can embed it to our application and run it thru pipeline by using a Maven plugin.

There is a downside tho, Owasp Maven plugin need to update its vulnerability database regularly online from NVD database which is perhaps not convenient for most enterprise environment where online network access is very-very limited.

But there is one workaround, we can use our repository such as Nexus or JFrog to host our NVD vulnerability database. The concept is pretty much we can see on below diagram,

There are two repository needed to build for fulfilling Maven Owasp requirement. One for java library, and another one for javascript.

Once done, we can check our Maven Owasp scan by using this command,

mvn org.owasp:dependency-check-maven:check -DfailBuildOnCVSS=8 \
 -DcveUrlModified=http://nexus.example.com/repository/nvd/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz \
 -DcveUrlBase=http://nexus.example.com/repository/nvd/feeds/json/cve/1.1/nvdcve-1.1-%d.json.gz \
 -DretireJsUrl=http://nexus.example.com/repository/retireJsUrl/jsrepository.json -DretireJsAnalyzerEnabled=false \ 
 -DossindexAnalyzerEnabled=false

If build is success, we can see that both our newly-created repository folder is now have multiple files there,

And if failed, we can see this error happen

And if you want to ignore Owasp scan result, you can change failBuildOnCVSS parameter to 11.

[Openshift] Adding a NodeSelector on the Fly

This is snippet code for adding a specific nodeselector to a rc (ReplicationConfig)

oc patch rc simple-helloworld -p '{"spec": {"template": {"spec": {"nodeSelector": {"infra": "my-infra-node"}}}}}' -n dev

The same code should work for other type, such as Deployment, or DeploymentConfig.

[Openshift] Changing revisionHistoryLimit on DeploymentConfig using OC Command

DeploymentConfig on Openshift, and Kubernetes, have revisionHistoryLimit variable which shows how many history a DeploymentConfig should keep. By default it stores 10 last version of application deployment, but sometimes we have to stores less number of revision for saving storage space. Therefore we need to create a hard limit for number of revisionHistoryLimit allowed.

Given below yaml structure on DC,

Based on above image we can change directly on deploymentconfig’s Yml file, but for you who allergic to Yaml (such as me), OC command is much more convenient. This is how i change existing deploymentconfig’s configuration by utilizing OC patch command

oc patch dc starter-v0 -p '{"spec":{"revisionHistoryLimit":2}}'

It will reduce number of revision to two version before,

And this is what happen when changed into one version,

oc patch dc starter-v0 -p '{"spec":{"revisionHistoryLimit":1}}'

How to Display How Many Images are Available on Our Openshift Image Registry

Openshift is a very convenient platform, not only it provides an enterprise kubernetes cluster, but also provide its own image registry bundled within it. So we can push images and deploy it to our namescpace within our cluster in a timely manner. But there are times when i need to count how many images are resides in my existing Openshift cluster. After googling quite some time, i found the solution and write it here.

First we need to check where is our Openshift image registry url,

C:\>oc project default
Already on project "default" on server "https://console.example.com:8443".

C:\>oc get route
NAME               HOST/PORT                                                PATH      SERVICES           PORT       TERMINATION   WILDCARD
docker-registry    docker-registry-default.apps.example.com              docker-registry    5000-tcp   reencrypt     None
registry-console   registry-console-default.apps.example.com             registry-console   <all>      passthrough   None

Next step is login to our oc cluster by using this command, and insert the right username and password.

oc login https://console.example.com:8443 

And see the oc login token

oc whoami -t

Use both username and token to do a simple curl to your docker registry url,

C:\>curl -X GET https://docker-registry-default.apps.example.com/v2/_catalog -k -u <my-username>:<my-token>

The result of that api contains list of images available on your Openshift’s Image Registry.