Translate

Dynamically provisioning Jenkins slaves with Jenkins Docker plugin

In Jenkins we have the master slave architecture where we have configured one machine as master, and some other machines as slaves. We can have a preferred number of executors in each of these machines. Following illustrates that deployment architecture.


In this approach, the concurrent builds in a given Jenkins slave are not isolated. All the concurrent builds in a given slave would be running in the same environment. If we need several builds to be run inside the same slave those builds should need same environment and actions should have taken to avoid issues such as port conflicts. This prevents us from utilizing the resources in a given slave.

With Docker we can address the above problems which are caused by the inability to isolate the builds. Jenkins Docker plugin allows a docker host to dynamically provision a slave, run a single build, then tear-down that slave. Following illustrates the deployment architecture.



I'll list down the steps to follow to get this done.

First let's see what needs to be done in Jenkins master.
1. Install Jenkins in one node which would be the master node. To install Jenkins, you could either run Jenkins jar directly or deploy the jar in tomcat.

2. Install Jenkins Docker Plugin[1]

Now lets see how to configure nodes which you are using to put up slave containers in.

3. Install Docker engine in each of the nodes. Please note that due to a bug[2] in Docker plugin you need to use a docker version below 1.12. Note that I was using Docker plugin version 0.16.1.

eg:
echo deb [arch=amd64] https://apt.dockerproject.org/repo ubuntu-trusty main > /etc/apt/sources.list.d/docker.list

apt-get update

apt-get install docker-engine=1.11.0-0~trusty


4.  Add the current user to the docker group - not a required step. If this is not done you will need to use root privileges(use sudo) to issue docker commands. And once step 3 is done anyone with the keys can give any instructions to Docker daemon. No need of sudo or being in docker group.

You can test if the installation is successful by running hello-world container
docker run hello-world

5. This is not a mandatory step but if you need to protect the docker daemon, by following [3] create a CA, server and client keys.
(Note that by default Docker runs via a non-networked Unix socket. It can also optionally communicate using an HTTP socket, and in order to do our job we need it to be able to communicate through an HTTP socket. And for Docker to be reachable via the network in a safe manner, you can enable TLS by specifying the tlsverify flag and pointing Docker’s tlscacert flag to a trusted CA certificate which is what are doing in this step)

6.  configure /etc/default/docker as follows.
DOCKER_OPTS="--tlsverify --tlscacert=/path/to/ca.pem --tlscert=/path/to/server-cert.pem --tlskey=/path/to/server-key.pem -H tcp://0.0.0.0:2376"

Now let's see what are the configurations to be done in Jenkins master. We need jenkins master know about the nodes we previously configured to run slave containers in.

7. Go to https://yourdomain/jenkins/configure.
What Docker plugin does is adding Docker as a jenkins cloud provider. So each node we have will be a new “cloud”. Therefore for each node, throught “Add new cloud” section, add a clould of the type “Docker”. Then we need to fill configuration options as appropriate. Note that the Docker URL should be something like https://ip:2376 or https://thedomain:2376 where ip/thedomain are the ip or the domain of the node you are adding. 

8. If you did follow step 3, in credentials section, we need to “Add” new credentials of the type “Docker certificates directory”. This directory should contain the server keys/CA/certs. Please note that you will need to have the ca,cert, client key names exactly as ca.pem, cert.pem and key.pem because I think those names are hardcoded in docker plugin source code therefore if custom names are put it won't work (I experienced it!)

9. You can press “Test Connection” button to test if the docker plugin could successfully communicate with our remote docker host. If it is successful, the docker version of the remote host should appear once the button is pressed. Note that if you have docker 1.12* installed, you will still see the the connection is successful but once you try building a job, you will get an exception since docker plugin has an issue with that version.

10. Under “Images” section, we need to add our docker image by “Add Docker template”. Note that you must have this image in your nodes you previously configured or need to have it in docker hub so that it can be pulled. 
Here also there are some other configurations to be done. Under, “Launch method” choose, “Docker SSH Computer Launcher” and add the credentials of the docker container which is created by our docker image. Note that these are NOT the credentials for the node itself but the credentials of our dynamically provisioned docker jenkins slaves.
Here, you can add a label to your docker image. This is a normal jenkins label which can be used to bind jobs to a given label.

11. Ok now we are good to try running one of our jenkins build jobs in a Docker container! Bind the job you prefer to a docker image using the label you previously put and click "Build Now"! 

You should see something similar to following. (Look at the bottom left corner)



Here we can see a new node named "docker-e86492df7c41" where "docker" is the  name I put for the docker cloud I had created and "e86492df7c41" is the ID of the docker container which was dynamically spawned to build the project.

[1] https://issues.jenkins-ci.org/browse/JENKINS-36080
[2] https://wiki.jenkins-ci.org/display/JENKINS/Docker+Plugin
[3] https://docs.docker.com/engine/security/https/



WSO2 ESB Foreach mediator example

Say you have a payload. For example,

Here, you have an array with the root elemet "data". And you need to perform some processing for each of these objects in the array and send the resulting payload to an endpoint. I'm going to use foreach mediator to achieve this.
Lets say following is the resulting payload you want.

This payload contains, a root element "info" under which there is an array of objects having,
1. id element which is created using value of "name" element from original payload, converted to uppercase , value of "id" element from original payload, and the string "ID"
2. classid element which is the value of "id" element from the original payload
3. The "name" from original payload in uppercase.
4. university element which is hard-coded
5. department element which is also hard-coded

And you need to send this resulting payload to some endpoint in JSON format.

Inside foreach mediator I use script mediator to convert the name to uppercase. Then using payload factory mediator I create the payload. And outside the foreach mediator I use send mediator to send the resulting payload to the endpoint.

Here is the sequence.
Let's use the following API to call my-in-seq.
Add both above API and sequence to synapse config. We can send a curl request as follows and see how it works.

References
[1] https://docs.wso2.com/display/ESB490/ForEach+Mediator

Creating a Carbon Component using WSO2 Carbon Component Archetype

A Carbon Component is an OSGi bundle which has a dependency on Carbon Kernel.
Using WSO2 Carbon Component Archetype which has been published to maven central, you can create a simple Carbon Component with one command.

Eg:
mvn archetype:generate -DarchetypeGroupId=org.wso2.carbon -DarchetypeArtifactId=org.wso2.carbon.archetypes.component -DarchetypeVersion=5.0.0  -DgroupId=org.sample -DartifactId=org.sample.project -Dversion=1.0.0 -Dpackage=org.sample.project


Above command will create a Carbon Component with the following structure.

org.sample.project
├── pom.xml
└── src
    └── main
        └── java
            └── org
                └── sample
                    └── project
                        ├── GreeterImpl.java
                        ├── Greeter.java
                        └── internal
                            ├── DataHolder.java
                            └── ServiceComponent.java

This Carbon Component consumes an OSGi service which is exposed from Carbon Core and also registers an OSGi service of its own.

If you do not pass the parameters for the project then the default values will be applied.

You can find the source for this archetype here.

Creating a generic OSGi bundle using WSO2 Carbon Bundle Archetype

You can create a generic OSGi bundle using one command with WSO2 Carbon Bundle Archetype.
Even though the name is WSO2 Carbon Bundle Archetype which has been published to maven central, this is a generic OSGi bundle.

Eg:
Execute the following command. The groupID of the archetype is org.wso2.carbon,
The artifactID of the archetype is org.wso2.carbon.archetypes.bundle  and the version of the archetype is  5.0.0

mvn archetype:generate -DarchetypeGroupId=org.wso2.carbon -DarchetypeArtifactId=org.wso2.carbon.archetypes.bundle -DarchetypeVersion=5.0.0  -DgroupId=org.sample -DartifactId=org.sample.project -Dversion=1.0.0 -Dpackage=org.sample.project


 This will create a project with the following structure.

org.sample.project
├── pom.xml
└── src
    ├── main
    │   └── java
    │       └── org
    │           └── sample
    │               └── project
    │                   ├── Greeter.java
    │                   └── internal
    │                       └── Activator.java
    └── test
        └── java
            └── org
                └── sample
                    └── project
                        └── GreeterTest.java

If you do not pass the parameters for the project then the default values will be applied.

The source for the archetype can be found here.

Unmarshalling an XML file with JAXB

This is a simple example for unmarshalling an XML file.

This is the XML file we are going to unmarshall
This is the schema of the above XML file
Now let's create Order.java
Here for each complex type I have created an inner class.
And for the element "item-name" which has the maxOccurs=unbounded, I have used a List.
Another thing is @XmlAccessorType(XmlAccessType.FIELD) is needed only if the annotated fields inside the class have public setters.  If you don't have public setters for the annotated fields inside the class you don't need to annotate the class.

Now let's write the code for unmarshalling.
  

Google Summer of Code 2015



This year also I'm participating Google Summer of Code with Eclipse foundation.

My project is Implementing translation between Proj4 and Well-Known-Text in Geotrellis which is a high performance geoprocessing engine and programming toolkit.

Project description in Google Melange can be found here.

Writing a simple web service and a client with Axis2

1. The service

Here a simple POJO service will be created. For simplicity the service will have only two operations.

1. Save an order which consists of an index(String) and a price(Double)
The order will be saved to an xml file.

2. Retrieve the price given the index.



First create a Java Project.

Now inside package orderprocessing.data I create the Order POJO.

Inside the package orderprocessing.service I create OrderProcessingService Class.

In order to save orders to an XML file I create XMLWriterDOM.java.
To retrieve orders from the XML file I create XMLReader.java
Create an XML file orders.xml somewhere and change the "savePath", and "retrievePath" attributes inside the above two classes according to that.


Now create a folder META-INF at the src folder level and create services.xml inside META-INF.

Here, If you do not specify the message receiver, then the default message receiver which is RawXMLINOutMessageReceiver will perform the operation[1]

And since the service implementation class is in Java, all the public methods in that service will be exposed. No need to specifically include them in services.xml[1]


This is the folder structure of my service.


Now export the project as a jar. In eclipse this can be done by, right click on the project->export
Save it to somewhere and change it's extension to .aar (eg: if your jar is OrderProcessingService.jar rename it as OrderProcessingService.aar ) and save it to axis2-1.6.2/repository/services
(I am using axis2-1.6.2)

Start the axis2server. (In linux run axis2server.sh inside axis2-1.6.2/bin)



Now if you go to http://localhost:8080/axis2/services/ it should be shown as below.



And you can access the wsdl at, http://localhost:8080/axis2/services/OrderProcessingService?wsdl


2. The client

Create another Java project.

Now in order to use the service we need to create the stub.

Go to axis2-1.6.2/bin in the terminal and run,
Now create another package orderprocessing.client inside your client project and create OrderProcessingClient.java

This is my folder structure of the client

Run the client and see if it works.