Tuesday 1 October 2019

My Journey with Gradle

In this blog, I will write about my experience in working with Gradle; most of the samples I have kept it in below github link for reference


https://github.com/venkatesh-mohanram/gradle-experiments

Converting the maven project in gradle:

Gradle has its utility which can easily convert maven project into a gradle project with one command. This will be very useful when we want to move from maven to a gradle build system. However at the time of writing, it does not support multi-project environments.
$gradle init
We need to execute the above command where we have the pom.xml file

Push to artifactory


Pushing to JFrog artifactory can be done either by using the JFrog Arifactory plugin or if we are using maven repo in artifactory then we can use the default maven plugin to push the jar into the artifactory which I found it to be simple and easy.


https://github.com/venkatesh-mohanram/gradle-experiments/tree/master/gradle-maven-publish

Force download dependency


If we want to download the dependencies everytime we build the code, then use the 'refresh-dependencies' option along with the build
$gradle build --refresh-dependencies


gradle wrapper


Gradle wrapper is a useful tool and helps in using the same gradle version anywhere we build our source code. Also, t works in the system where gradle is not installed as well.

Instead of using 'gradle' as a command use './gradlew'
$./gradlew build


.gitignore

By default, the .gitignore will contain build and .gradle file which we do not want to source control it


Setting the proxy while running

$./gradlew -Dhttps.proxyHost=<HOST> -Dhttps.proxyPort=<PORT> build

Thursday 12 September 2019

Goa in the Monsoon

We went to Goa, India in the monsoon season. Initially, we thought will it be the right time or we should change but it seems to be a good time to visit as we get good discounts in stay, car rentals and water sports. Yes, water sports are there even in monsoon; I think not all are available but they have a good water sports package for monsoon.

Even we should be a little lucky when visiting in monsoon, if there are unfrequent showers then it will be good but if it is a non-stop rain then we will be forced to stay in the room. 


Car/Bike Rentals:

When it comes to car rentals, I would say in my experience that Goa is one the cheapest. The least it comes for Rs 1000 per day. There are plenty of providers, I went with https://saiyuri-travel-solutions.business.site/. If we want them to deliver the car to our preferred location, for example, like from Airport/RailwayStation then they have a fixed delivery/pick-up charge of Rs 300. You can book over the phone before you arrive but you will be paying only when you take the car.


Stay:

When we talk about Goa actually we refer/imagine to Beaches, shacks, night-life etc., and all these are very far away from the capital Panaji. So it is good if we book a stay near Baga or Calangute, from these places the beaches are walkable and we can come out at any time of the day and chill. Based on the budget and preference they are plenty of lodges, home-stay, serviced apartments are available. We preferred serviced apartment and booked in https://www.eternalwave.in/. They have very well maintained rooms but they do not have a good restaurant inside


Beaches and Shacks:

Beaches are open 24 hours and we can play, take a bath, dip the leg any time of the day. There are very good paid bathrooms and change rooms available at a very nominal cost. Parking is also available on almost all the beaches, but the parking near the Tito club is very expensive and it is Rs100 for 4 hours in other areas it would be just Rs20 for 4 hours. Shacks are the awesome experience in Goa, they just don't provide drinks they serve tasty, yummy, mouth-watering and delicious foods. We went almost every day to Shacks for food and relaxation. 

Baga beach has shallow water where kids can sit and enjoy the waves hitting them.






Water Sports:

We wanted to try something adventurous and not tried before sports and chose "Fly Board", the experience cannot be explained in words. It is a joy when we fly but a pain when we fell in the water. This is not in the sea but in the Chapora river. Definitely difficult for first-timer but we shouldn't give up and try the next time. In India, Goa is the only place where they have "Flyboard" activity.





Souvenirs:

We can buy cashews, dresses etc when we come back as a memory of the visit

Friday 23 August 2019

Writing Custom Tasks in Gradle

Writing custom tasks in Gradle is very easy if we understand the lifecycle of its execution https://docs.gradle.org/current/userguide/build_lifecycle.html

Sample custom tasks from build.gradle file 

Copy of the build.gradle available in https://github.com/venkatesh-mohanram/gradle-experiments/blob/master/gradle-custom-tasks/build.gradle


class CustomParentTask extends DefaultTask {
String cv_var1
@TaskAction
void build() {
println "CustomParentTask:build() $cv_var1"
cv_var1 = "CHANGE IN BUILD"
}
}
task customParent(type: CustomParentTask) {
// Initialization
customParent.ext.var1 = 'INITIAL'
cv_var1 = customParent.ext.var1
println "customParent:Initialization"

// Execution
// doFirst -> build() -> doLast
doFirst {
custom.var1 = 'hello'
customParent.ext.var1 = 'World'
cv_var1 = customParent.ext.var1
println "customParent:doFirst"
}
doLast {
println "customParent:doLast"
}
}

class CustomTask extends DefaultTask {
@TaskAction
void build() {
println "CustomTask:build()"
}
}
task custom(type: CustomTask, dependsOn: customParent) {
// Initialization
custom.ext.var1 = ''
println "custom:Initialization"

// Execution
// doFirst -> build() -> doLast
doFirst {
println "custom:doFirst $custom.ext.var1 $customParent.var1"
}
doLast {
println "custom:doLast"
}
}


Execution of the custom task will result in the following output; if we notice the first execution all are the initialization code, followed by the execution phase. Within execution, it executes in the following order doFirst, class method and finally doLast

$ gradle custom

> Configure project :
customParent:Initialization
custom:Initialization

> Task :customParent
customParent:doFirst
CustomParentTask:build() World
customParent:doLast

> Task :custom
custom:doFirst hello World
CustomTask:build()
custom:doLast

BUILD SUCCESSFUL in 2s
2 actionable tasks: 2 executed


Monday 27 May 2019

02 Kubernetes Service Definition

Kubernetes service is an abstraction above the pods, the pods cannot be accessed/exposed outside the cluster. Inorder to expose the pods outside the cluster, we need to define service.


Service Definition yaml


https://raw.githubusercontent.com/venkatesh-mohanram/microservices/master/01-microservices-starter-kit/add-service/k8s-service.yaml

The selector tells which deployment needs to be abstracted. The port specifies the service port and the targetPort specify the port in which the deployment is exposed. 

Use the below command to execute the service definition


$kubectl apply -f k8s-service.yaml


We can use the below command to see the clusterIP in which the service is made available. The default IP is clusterIP, this IP will be accessible within the cluster.


$kubectl get service





In order to test the service, we can run the CURL command with the service IP


$curl http://10.107.33.6/addservice/application.wadl




We can do a roling update of containers inside the pod, any rolling update on the pod will not affect the service IP and we can still use the same IP.

01 Kubernetes Deployment Definition

Let's begin with writing a 'deployment.yaml' file, we can directly write yaml for a pod but that is not recommended. In the deployment yaml, we can specify the pod template and even the replication factor

Deployment Definition Yaml




Here the "Kind:" specifies what kind of k8s resource it is, in this case it is 'Deployment'. It has the metadata and the spec information inside the definition document. 


Applying the deployment

Execute the deployment yaml using the below command

$ kubectl apply -f k8s-deployment.yaml

Upon executing, we should see something like below


Monitoring container logs

$kubectl logs -f add-service-deployment-59996d5779-5q8kj
We can use above log command to see the container logs inside the particular pod.


Rolling update

$ kubectl set image deployments/add-service-deployment add-service=venkateshm/add-service:3

For rolling updates, we can execute the above commands to recreate the pods with new version of the container. The old pods will be gracefully terminated while the new one is gradually created.





Friday 24 May 2019

Kubernetes Commands

There are various basic commands which are helpful to begin. Along with that, it will be good, if we know the hierarchy of different resources in Kubernetes



Let's start from the micro level of K8S resources


1. POD

The POD is the logical group of containers. The containers will not directly run inside the node instead, it will be running inside a POD. It is always a good idea to group tightly coupled containers in a single POD along with any shared storage volumes if needed. Each POD in the node will have its unique IP.

Useful commands


$ kubectl get pods 
$ kubectl describe pods [pod-name]
$ kubectl describe pods --help 
$ kubectl logs [pod-name]
$ kubectl delete pod <>pod-name 
$ kubectl delete pods -all

The usual structure of all the K8S command is kubectl <action> <resource>

The very interesting command which I like most is 
$kubectl exec -ti <pod_name> bash

The above command actually takes us inside the POD and we can execute the commands inside it.


Deployment Vs PODS:

We can think of deployment as a template and the PODs are the actual deployments. In java language, the deployment is a class and PODS are objects, the replicas of deployment will create those many numbers of pods.


$ kubectl get deployments 
$ kubectl scale deployments/<deployment-name> --replicas=4 
$ kubectl describe deployment


2. Node

The node could be a VM or a real machine in K8S, the collection of nodes form a cluster. The K8S master monitors PODs and Nodes health and recreates the PODs in another node if the if one of the nodes is not healthy.


$ kubectl get nodes 
$ kubectl describe nodes [nodename]


3. Services

Is an abstraction which defines a logical set of PODs. It enables loose coupling between pods, it is preferred to be defined using YAML or JSON. The PODS are actually accessible only inside the cluster using their unique IP, if we want to expose the PODs outside then we need to define services. Also the service acts like a load balancer and distributes the load across multiple replicas.

There are different ways in which a service can be exposed in different ways by specifying the type

  1. Cluster IP - Using the default cluster IP, accessible only inside the cluster
  2. NodePort - Can be accessed outside by using the node IP and the port number specifies in NodePort
  3. LoadBalancer - In exposed a public IP if the cloud provider supports
  4. External name - using a CNAME
$ kubectl get services 
$ kubectl describe services/<service name> 
$ kubectl delete service



Other general commands

To get the cluster information
$ kubectl cluster-info

Rolling updates
$ kubectl rollout
If we have the definitions in yaml file then 
$ kubectl apply -f <loc of yaml>

Below link are good to get started with learning K8S
https://www.katacoda.com/courses/kubernetes/playground
https://kubernetes.io/docs/tutorials/kubernetes-basics/

In the next blog, I will mention sample yaml file all the resources

Friday 8 February 2019

FONS0004: no namespace found for prefix

Are you seeing the below exception stack while executing the countNodes() function,

FONS0004: no namespace found for prefix...
        at oracle.xml.xpath.JXPathExpression.evaluate(JXPathExpression.java:269)
        at oracle.xml.xpath.JXPath.evaluate(JXPath.java:383)
        at com.collaxa.cube.xml.xpath.BPELXPathUtil.selectNodes(BPELXPathUtil.java:533)
        at com.collaxa.cube.xml.xpath.BPELXPathUtil.selectNodes(BPELXPathUtil.java:517)
        at com.collaxa.cube.xml.xpath.functions.xml.CountNodesFunction.evaluate(CountNodesFunction.java:143)
        at com.collaxa.cube.xml.xpath.functions.xml.CountNodesFunction.call(CountNodesFunction.java:78)
        at com.collaxa.cube.xml.xpath.BPELXPathFunctionWrapper.evaluate(BPELXPathFunctionWrapper.java:80)
        at oracle.xml.xpath.JXPathContext$JXFunction.invoke(JXPathContext.java:213)
        at oracle.xml.xpath.JXPathContext$JXFunction.invoke(JXPathContext.java:182)
        at oracle.xml.xpath.XPathExtFunction.evaluate(XPathExtFunction.java:335)

Then you need to check whether you are using the namespace defined in the root element for your xsi:type extension usage,

eg;

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="http://xmlns.oracle.com/cloud/adapter/erp/FindItem_REQUEST/types" xmlns:typ1="http://xmlns.oracle.com/adf/svc/types/">
   <soapenv:Body>
      <typ:findItem>
         <typ:findCriteria xsi:type="typ1:ChildFindCriteria" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <typ1:fetchStart>10</typ1:fetchStart>
         </typ:findCriteria>
      </typ:findItem>
   </soapenv:Body>
</soapenv:Envelope>

Instead, add another namespace definition in <findCriteria>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="http://xmlns.oracle.com/cloud/adapter/erp/FindItem_REQUEST/types" xmlns:typ1="http://xmlns.oracle.com/adf/svc/types/">
   <soapenv:Body>
      <typ:findItem>
         <typ:findCriteria xsi:type="typ3:ChildFindCriteria" xmlns:typ3="http://xmlns.oracle.com/adf/svc/types/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <typ1:fetchStart>10</typ1:fetchStart>
         </typ:findCriteria>
      </typ:findItem>
   </soapenv:Body>
</soapenv:Envelope>