Friday, 19 August 2016

Variable substitution for a manifest.yml for Cloud Foundry

Pushed applications to CF or PCF you would of most likely used a manifest.yml file and at some point wanted to use variable substitution. manifest.yml files don't support that and a feature request has been asked for this as follows

https://github.com/cloudfoundry/cli/issues/820

With a recent customer we scripted the creation of a manifest.yml file from a Jenkins job  which would inject the required ROUTE to the application by creating the manifest.yml through a script as follows as shown below.

manifest-demo.sh

export ROUTE=$1

echo ""
echo "Setting route to $ROUTE ..."
echo ""

cat > manifest.yml <<!
---
applications:
- name: gs-rest-service
  memory: 256M
  instances: 1
  host: $ROUTE
  path: target/gs-rest-service-0.1.0.jar
!

cat manifest.yml

Script tested as follows

pasapicella@pas-macbook:~/bin/manifest-demo$ ./manifest-demo.sh apples-route-pas

Setting route to apples-route-pas ...

---
applications:
- name: gs-rest-service
  memory: 256M
  instances: 1
  host: apples-route-pas
  path: target/gs-rest-service-0.1.0.jar

Tuesday, 16 August 2016

HttpSessionListener with Spring Boot Application

I had a requirement to implement a HttpSessionListener in my Spring Boot application which has no web.xml. To achieve this I did the following

1. My HttpSessionListener was defined as follows

 
package com.pivotal.pcf.mysqlweb.utils;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import org.apache.log4j.Logger;

public class SessionListener implements HttpSessionListener
{
    protected static Logger logger = Logger.getLogger("controller");
    private HttpSession session = null;

    public void sessionCreated(HttpSessionEvent event)
    {
        // no need to do anything here as connection may not have been established yet
        session  = event.getSession();
        logger.info("Session created for id " + session.getId());
    }

    public void sessionDestroyed(HttpSessionEvent event)
    {
        session  = event.getSession();
     /*
      * Need to ensure Connection is closed from ConnectionManager
      */

        ConnectionManager cm = null;

        try
        {
            cm = ConnectionManager.getInstance();
            cm.removeConnection(session.getId());
            logger.info("Session destroyed for id " + session.getId());
        }
        catch (Exception e)
        {
            logger.info("SesssionListener.sessionDestroyed Unable to obtain Connection", e);
        }
    }
}

2. Register the listener from a @Configration class as shown below
  
package com.pivotal.pcf.mysqlweb;

import com.pivotal.pcf.mysqlweb.utils.SessionListener;
import org.springframework.boot.context.embedded.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.http.HttpSessionListener;

@Configuration
public class ApplicationSessionConfiguration
{
    @Bean
    public ServletListenerRegistrationBean<HttpSessionListener> sessionListener()
    {
        return new ServletListenerRegistrationBean<HttpSessionListener>(new SessionListener());
    }
} 
Thats all you have to do to achieve this


Friday, 12 August 2016

Simple Spring Boot Application Deployed through Concourse UI to Pivotal Cloud Foundry

The demo below is a full working example of using Spring Boot Application which will build/deploy to Pivotal Cloud Foundry using Concourse. Concourse pipelines can easily be created within your source code as this demo shows and hence created / executed quite easily. Concourse limits itself to three core concepts: tasks, resources, and the jobs that compose them.

https://github.com/papicella/SpringBootSimpleRest

Detailed instructions on how to setup/run this demo using Concourse see the link referenced above which is as follows

https://dl.dropboxusercontent.com/u/15829935/platform-demos/concourse-demo/index.html



It's worth reading the details on this link around Concourse Concepts

https://concourse.ci/concepts.html

More Information

https://concourse.ci/

Sunday, 31 July 2016

PCFDev application accessing an Oracle 11g RDBMS

PCF Dev is a small footprint distribution of Pivotal Cloud Foundry (PCF) intended to be run locally on a developer machine. It delivers the essential elements of the Pivotal Cloud Foundry experience quickly through a condensed set of components. PCF Dev is ideally suited to developers wanting to explore or evaluate PCF, or those already actively building cloud native applications to be run on PCF. Working with PCF Dev, developers can experience the power of PCF - from the accelerated development cycles enabled by consistent, structured builds to the operational excellence unlocked through integrated logging, metrics and health monitoring and management.


In this example we show how you can use PCFDev to access an Oracle RDBMS from a PCFDev deployed Spring Boot Application. The application is using the classic Oracle EMP database table found in the SCOTT schema

Source Code as follows


In order to use the steps below you have to have installed PCFDev on your laptop or desktop as per the link below.

Download from here:

Instructions to setup as follows:

Steps

1. Clone as shown below

$ git clone https://github.com/papicella/PCFOracleDemo.git


2. Edit "./PCFOracleDemo/src/main/resources/application.properties" and add your oracle EMP schema connection details

error.whitelabel.enabled=false

oracle.username=scott
oracle.password=tiger
oracle.url=jdbc:oracle:thin:@//192.168.20.131:1521/ora11gr2

3. Define a local MAVEN repo for Oracle 11g JDBC driver as per what is in the pom.xml

  
<!--
  Installed as follows to allow inclusion into pom.xml
  mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.3 -Dpackaging=jar -Dfile=ojdbc6.jar
    -DgeneratePom=true
  -->
  <dependency>
   <groupId>com.oracle</groupId>
   <artifactId>ojdbc6</artifactId>
   <version>11.2.0.3</version>
  </dependency> 


4. Package as per below

$ cd PCFOracleDemo
$ mvn package

5. Deploy as follows

pasapicella@pas-macbook:~/pivotal/DemoProjects/spring-starter/pivotal/PCFOracleDemo$ cf push
Using manifest file /Users/pasapicella/pivotal/DemoProjects/spring-starter/pivotal/PCFOracleDemo/manifest.yml

Creating app springboot-oracle in org pcfdev-org / space pcfdev-space as admin...
OK

Creating route springboot-oracle.local.pcfdev.io...
OK

Binding springboot-oracle.local.pcfdev.io to springboot-oracle...
OK

Uploading springboot-oracle...
Uploading app files from: /var/folders/c3/27vscm613fjb6g8f5jmc2x_w0000gp/T/unzipped-app506692756
Uploading 26.3M, 154 files
Done uploading
OK

Starting app springboot-oracle in org pcfdev-org / space pcfdev-space as admin...
Downloading binary_buildpack...
Downloading python_buildpack...
Downloading staticfile_buildpack...
Downloading java_buildpack...
Downloading php_buildpack...
Downloading ruby_buildpack...
Downloading go_buildpack...
Downloading nodejs_buildpack...
Downloaded staticfile_buildpack
Downloaded binary_buildpack (8.3K)
Downloaded php_buildpack (262.3M)
Downloaded java_buildpack (241.6M)
Downloaded go_buildpack (450.3M)
Downloaded ruby_buildpack (247.7M)
Downloaded python_buildpack (254.1M)
Downloaded nodejs_buildpack (60.7M)
Creating container
Successfully created container
Downloading app package...
Downloaded app package (23.5M)
Staging...
-----> Java Buildpack Version: v3.6 (offline) | https://github.com/cloudfoundry/java-buildpack.git#5194155
-----> Downloading Open Jdk JRE 1.8.0_71 from https://download.run.pivotal.io/openjdk/trusty/x86_64/openjdk-1.8.0_71.tar.gz (found in cache)
       Expanding Open Jdk JRE to .java-buildpack/open_jdk_jre (1.2s)
-----> Downloading Open JDK Like Memory Calculator 2.0.1_RELEASE from https://download.run.pivotal.io/memory-calculator/trusty/x86_64/memory-calculator-2.0.1_RELEASE.tar.gz (found in cache)
       Memory Settings: -XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=64M -Xss995K -Xmx382293K -Xms382293K
-----> Downloading Spring Auto Reconfiguration 1.10.0_RELEASE from https://download.run.pivotal.io/auto-reconfiguration/auto-reconfiguration-1.10.0_RELEASE.jar (found in cache)
Exit status 0
Staging complete
Uploading droplet, build artifacts cache...
Uploading build artifacts cache...
Uploading droplet...
Uploaded build artifacts cache (109B)
Uploaded droplet (68.4M)
Uploading complete

1 of 1 instances running

App started


OK

App springboot-oracle was started using this command `CALCULATED_MEMORY=$($PWD/.java-buildpack/open_jdk_jre/bin/java-buildpack-memory-calculator-2.0.1_RELEASE -memorySizes=metaspace:64m.. -memoryWeights=heap:75,metaspace:10,native:10,stack:5 -memoryInitials=heap:100%,metaspace:100% -totMemory=$MEMORY_LIMIT) && JAVA_OPTS="-Djava.io.tmpdir=$TMPDIR -XX:OnOutOfMemoryError=$PWD/.java-buildpack/open_jdk_jre/bin/killjava.sh $CALCULATED_MEMORY" && SERVER_PORT=$PORT eval exec $PWD/.java-buildpack/open_jdk_jre/bin/java $JAVA_OPTS -cp $PWD/.:$PWD/.java-buildpack/spring_auto_reconfiguration/spring_auto_reconfiguration-1.10.0_RELEASE.jar org.springframework.boot.loader.JarLauncher`

Showing health and status for app springboot-oracle in org pcfdev-org / space pcfdev-space as admin...
OK

requested state: started
instances: 1/1
usage: 512M x 1 instances
urls: springboot-oracle.local.pcfdev.io
last uploaded: Sun Jul 31 01:23:03 UTC 2016
stack: unknown
buildpack: java-buildpack=v3.6-offline-https://github.com/cloudfoundry/java-buildpack.git#5194155 java-main open-jdk-like-jre=1.8.0_71 open-jdk-like-memory-calculator=2.0.1_RELEASE spring-auto-reconfiguration=1.10.0_RELEASE

     state     since                    cpu    memory      disk        details
#0   running   2016-07-31 11:24:26 AM   0.0%   0 of 512M   0 of 512M
pasapicella@pas-macbook:~/pivotal/DemoProjects/spring-starter/pivotal/PCFOracleDemo$ cf apps
Getting apps in org pcfdev-org / space pcfdev-space as admin...
OK

name                requested state   instances   memory   disk   urls
springboot-oracle   started           1/1         512M     512M   springboot-oracle.local.pcfdev.io

6. Access deployed application at the end point "http://springboot-oracle.local.pcfdev.io" or using the application route you set in the manifest.yml



Monday, 25 July 2016

Telstra WIFI API Consumer on Pivotal Cloud Foundry

If you heard of Telstra WIFI API you will know it will allow you to search for WIFI Hotspots within a given radius and can be used after signing in for Telstra.dev account at https://dev.telstra.com/ to obtain the Hotpots within a given Radius and Lat/Long location.

The WIFI API for Telstra is described at the link below.

  https://dev.telstra.com/content/wifi-api

The following application I built on Pivotal Cloud Foundry consumes this Telstra WIFI API service and using the Google Map API along with Spring Boot will show you all the WIFI Hotspots Telstra provides from a mobile device or a Web Browser at your current location. The live URL is as follows. You will need to agree to share your location and enable Location services from your browser when on a mobile device for the MAP to be of any use. Lastly this is only useful within Australia of course.

http://pas-telstrawifi.cfapps.io/



Source Code as follows:

https://github.com/papicella/TelstraWIFIAPIPublic

More Information

https://dev.telstra.com/content/wifi-api

Thursday, 14 July 2016

Billing/Metering on Pivotal Cloud Foundry using the Usage Service API's

Pivotal Cloud Foundry (PCF) provides a REST API to provide billing/metering data for application and service usage. Although this usage can we viewed in the applications manager dashboard UI in this post below we will show how to use the REST based API using PCF 1.7.

Below we will show how to use the cf CLI to retrieve information about your app and service instances via the Cloud Controller and Usage service APIs.

Obtain Usage Information for an Organization

To obtain individual org usage information, use the following procedure. You must log in as an admin or as an Org Manager or Org Auditor for the org you want to view.

1. Target the end point of the cloud controller as follows

papicella@papicella:~/apps/ENV$ cf api https://api.system.yyyy.net --skip-ssl-validation
Setting api endpoint to https://api.system.yyyy.net...
OK

API endpoint:   https://api.system.yyyy.net (API version: 2.54.0)
User:           papicella@pivotal.io
Org:            system
Space:          pas

2. Login as shown below

papicella@papicella:~/apps/ENV$ cf login -u papicella@pivotal.io -o system -s pas
API endpoint: https://api.system.yyyy.net

Password>
Authenticating...
OK

Targeted org system

Targeted space pas

API endpoint:   https://api.system.yyyy.net (API version: 2.54.0)
User:           papicella@pivotal.io
Org:            system
Space:          pas

Now if your using CURL for example you can inject the GUID of your organization as part of the command as well as the "oauth-token". Here is an example on how that is done.

Endpoint format: 

https://app-usage.YOUR-DOMAIN/organizations/{ORG_GUID}/app_usages?start=YYYY-MM-DD&end=YYYY-MM-DD

3. Issue REST call as shown below.

papicella@papicella:~$ curl "https://app-usage.system.yyyy.net/organizations/`cf org system --guid`/app_usages?start=2016-06-01&end=2016-06-30" -k -v -H "authorization: `cf oauth-token`" | python -m json.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 222.237.99.147...
* Connected to app-usage.system.yyyy.net (222.237.99.147) port 443 (#0)
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: *.system.yyyy.net
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0> GET /organizations/b75c9069-83b4-4130-a98e-a5eb4c5454c5/app_usages?start=2016-06-01&end=2016-06-30 HTTP/1.1
> Host: app-usage.system.yyyy.net
> User-Agent: curl/7.43.0
> Accept: */*
> authorization: bearer AwZi1lYjYGVyIMPPO-06eUG1FM12DY964Eh5AA_6Ga8P7IoB4Qr2OVx_vHh6o35IFKw .....
>
< HTTP/1.1 200 OK
< Cache-Control: max-age=0, private, must-revalidate
< Content-Type: application/json; charset=utf-8
< Etag: "16161b20edbc072ab63f8f8acf6ff251"
< Server: thin
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-Request-Id: 3ef758d1-3f8d-4942-b0bc-44666c2797e5
< X-Runtime: 0.167997
< X-Vcap-Request-Id: 01794681-8e29-4a07-463c-3660d0c3b349
< X-Xss-Protection: 1; mode=block
< Date: Thu, 14 Jul 2016 00:41:55 GMT
< Content-Length: 1766
<
{ [1766 bytes data]
100  1766  100  1766    0     0    755      0  0:00:02  0:00:02 --:--:--   755
* Connection #0 to host app-usage.system.yyyy.net left intact
{
    "app_usages": [
        {
            "app_guid": "17eee541-051a-44b5-83ae-bbbba5519af7",
            "app_name": "springboot-telstrasms",
            "duration_in_seconds": 0,
            "instance_count": 1,
            "memory_in_mb_per_instance": 512,
            "space_guid": "7a0cfa11-d71d-4dd6-a706-b5eff622fb66",
            "space_name": "pas"
        },
        {
            "app_guid": "1f102a77-ce84-4cf4-93d1-e015abdf65b5",
            "app_name": "company",
            "duration_in_seconds": 1622,
            "instance_count": 1,
            "memory_in_mb_per_instance": 512,
            "space_guid": "85d952b4-1acb-45fa-bd8b-d440de745a6f",
            "space_name": "development"
        },
        {
            "app_guid": "2d05970c-3f94-4329-a92a-5b81f95a9365",
            "app_name": "jay-test",
            "duration_in_seconds": 448,
            "instance_count": 1,
            "memory_in_mb_per_instance": 512,
            "space_guid": "85d952b4-1acb-45fa-bd8b-d440de745a6f",
            "space_name": "development"
        },
        {
            "app_guid": "2d05970c-3f94-4329-a92a-5b81f95a9365",
            "app_name": "jay-test",
            "duration_in_seconds": 692,
            "instance_count": 1,
            "memory_in_mb_per_instance": 1024,
            "space_guid": "85d952b4-1acb-45fa-bd8b-d440de745a6f",
            "space_name": "development"
        },
        {
            "app_guid": "4b771593-5032-41f9-84ff-1ecfec9a7f4d",
            "app_name": "company",
            "duration_in_seconds": 18430,
            "instance_count": 1,
            "memory_in_mb_per_instance": 512,
            "space_guid": "85d952b4-1acb-45fa-bd8b-d440de745a6f",
            "space_name": "development"
        },
        {
            "app_guid": "a5435de0-1dd3-49ba-a551-94e921a5999b",
            "app_name": "springboot-telstrasms",
            "duration_in_seconds": 677,
            "instance_count": 1,
            "memory_in_mb_per_instance": 512,
            "space_guid": "7a0cfa11-d71d-4dd6-a706-b5eff622fb66",
            "space_name": "pas"
        },
        {
            "app_guid": "f9c7f387-d008-4541-b093-92fb23e01aee",
            "app_name": "company",
            "duration_in_seconds": 0,
            "instance_count": 1,
            "memory_in_mb_per_instance": 512,
            "space_guid": "85d952b4-1acb-45fa-bd8b-d440de745a6f",
            "space_name": "development"
        }
    ],
    "organization_guid": "b75c9069-83b4-4130-a98e-a5eb4c5454c5",
    "period_end": "2016-06-30T23:59:59Z",
    "period_start": "2016-06-01T00:00:00Z"

}

4. To obtain usage information about services you would issue a REST call as follows

Use cf curl to retrieve service instance information. The service_instances? endpoint retrieves details about both bound and unbound service instances:

Endpoint format: 

https://app-usage.YOUR-DOMAIN/organizations{ORG_GUID}/service_usages?start=YYYY-MM-DD&end=YYYY-MM-DD

papicella@papicella:~$ curl "https://app-usage.system.yyyy.net/organizations/b75c9069-83b4-4130-a98e-a5eb4c5454c5/service_usages?start=2016-06-01&end=2016-06-30" -k -v -H "authorization: `cf oauth-token`" | python -m json.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 222.237.99.147...
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to app-usage.system.yyyy.net (222.237.99.147) port 443 (#0)
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: *.system.yyyy.net
> GET /organizations/b75c9069-83b4-4130-a98e-a5eb4c5454c5/service_usages?start=2016-06-01&end=2016-06-30 HTTP/1.1
> Host: app-usage.system.yyyy.net
> User-Agent: curl/7.43.0
> Accept: */*
> authorization: bearer eyJhbGciOiJSUzI1NiJ9.....
>
  0     0    0     0    0     0      0      0 --:--:--  0:00:03 --:--:--     0< HTTP/1.1 200 OK
< Cache-Control: max-age=0, private, must-revalidate
< Content-Type: application/json; charset=utf-8
< Etag: "909824b589cbed6c3d19c2f36bec985e"
< Server: thin
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-Request-Id: 2255821e-116c-4651-b483-1939f0f1f866
< X-Runtime: 0.137921
< X-Vcap-Request-Id: 3991c5f9-11c2-4c0e-5f2b-d1f94be87ef4
< X-Xss-Protection: 1; mode=block
< Date: Thu, 14 Jul 2016 00:53:47 GMT
< Transfer-Encoding: chunked
<
{ [3632 bytes data]
100  3978    0  3978    0     0   1283      0 --:--:--  0:00:03 --:--:--  1283
* Connection #0 to host app-usage.system.yyyy.net left intact
{
    "organization_guid": "b75c9069-83b4-4130-a98e-a5eb4c5454c5",
    "period_end": "2016-06-30T23:59:59Z",
    "period_start": "2016-06-01T00:00:00Z",
    "service_usages": [
        {
            "deleted": false,
            "duration_in_seconds": 2592000.0,
            "service_guid": "5c03686a-6748-4b76-bb6f-cbd116d5d87e",
            "service_instance_creation": "2016-05-10T01:58:01.000Z",
            "service_instance_deletion": null,
            "service_instance_guid": "bd09176c-483c-4011-b329-fba717abfc27",
            "service_instance_name": "spring-cloud-broker-db",
            "service_instance_type": "managed_service_instance",
            "service_name": "p-mysql",
            "service_plan_guid": "b3525660-1a74-452f-9564-65a2556895bd",
            "service_plan_name": "100mb-dev",
            "space_guid": "8a9788b2-8405-4312-99fc-6854a2972616",
            "space_name": "p-spring-cloud-services"
        },
        {
            "deleted": false,
            "duration_in_seconds": 2592000.0,
            "service_guid": "b0a9fb4e-325b-402b-8a99-d53d7f7df80c",
            "service_instance_creation": "2016-05-10T01:58:03.000Z",
            "service_instance_deletion": null,
            "service_instance_guid": "ad82aa5b-fd7c-4e7d-b56f-523f7b285c5d",
            "service_instance_name": "spring-cloud-broker-rmq",
            "service_instance_type": "managed_service_instance",
            "service_name": "p-rabbitmq",
            "service_plan_guid": "0cfd01c4-aea0-4ab0-9817-a312d91eee8d",
            "service_plan_name": "standard",
            "space_guid": "8a9788b2-8405-4312-99fc-6854a2972616",
            "space_name": "p-spring-cloud-services"
        },
        {
            "deleted": false,
            "duration_in_seconds": 2592000.0,
            "service_guid": "5c03686a-6748-4b76-bb6f-cbd116d5d87e",
            "service_instance_creation": "2016-05-11T06:53:19.000Z",
            "service_instance_deletion": null,
            "service_instance_guid": "9c306f43-b17d-4a59-964d-828db5047e04",
            "service_instance_name": "mydb",
            "service_instance_type": "managed_service_instance",
            "service_name": "p-mysql",
            "service_plan_guid": "b3525660-1a74-452f-9564-65a2556895bd",
            "service_plan_name": "100mb-dev",
            "space_guid": "7938ae22-6a1c-49bc-9cf4-08b9b6281e83",
            "space_name": "autoscaling"
        },
        {
            "deleted": false,
            "duration_in_seconds": 2592000.0,
            "service_guid": "23a0f05f-fed6-4873-b0f5-77457b721626",
            "service_instance_creation": "2016-05-11T06:57:01.000Z",
            "service_instance_deletion": null,
            "service_instance_guid": "75a4f233-25a4-4fb2-b205-354716c6c081",
            "service_instance_name": "auto",
            "service_instance_type": "managed_service_instance",
            "service_name": "app-autoscaler",
            "service_plan_guid": "5e0285ad-92b5-4cda-95e7-36db4a16fa05",
            "service_plan_name": "bronze",
            "space_guid": "7938ae22-6a1c-49bc-9cf4-08b9b6281e83",
            "space_name": "autoscaling"
        },
        {
            "deleted": false,
            "duration_in_seconds": 2592000.0,
            "service_guid": "5c03686a-6748-4b76-bb6f-cbd116d5d87e",
            "service_instance_creation": "2016-05-20T08:39:09.000Z",
            "service_instance_deletion": null,
            "service_instance_guid": "9b69e1d0-2f93-48d2-a0b0-fc009ebbfe1d",
            "service_instance_name": "account-db",
            "service_instance_type": "managed_service_instance",
            "service_name": "p-mysql",
            "service_plan_guid": "b3525660-1a74-452f-9564-65a2556895bd",
            "service_plan_name": "100mb-dev",
            "space_guid": "7938ae22-6a1c-49bc-9cf4-08b9b6281e83",
            "space_name": "autoscaling"
        },
        {
            "deleted": false,
            "duration_in_seconds": 1947572.0,
            "service_guid": "f603ea87-9b24-4114-9bdc-c4e8154b549c",
            "service_instance_creation": "2016-06-08T11:00:28.000Z",
            "service_instance_deletion": null,
            "service_instance_guid": "3d75b148-ee78-4f91-aa49-a1b2aa511fd1",
            "service_instance_name": "service-registry",
            "service_instance_type": "managed_service_instance",
            "service_name": "p-service-registry",
            "service_plan_guid": "ee6a7f19-f4d2-44f8-b8a2-08246c5d9a5d",
            "service_plan_name": "standard",
            "space_guid": "85d952b4-1acb-45fa-bd8b-d440de745a6f",
            "space_name": "development"
        },
        {
            "deleted": false,
            "duration_in_seconds": 67559.0,
            "service_guid": "23da6824-3ee0-4d87-b031-6223e69327ed",
            "service_instance_creation": "2016-06-30T05:14:01.000Z",
            "service_instance_deletion": null,
            "service_instance_guid": "fd8d2f19-6a8c-43ad-81c1-205e6a29d2b8",
            "service_instance_name": "api-connectors-service",
            "service_instance_type": "managed_service_instance",
            "service_name": "apigee-edge",
            "service_plan_guid": "36ae6841-9eb3-42b7-b40b-aa44ee72a14c",
            "service_plan_name": "org",
            "space_guid": "7a0cfa11-d71d-4dd6-a706-b5eff622fb66",
            "space_name": "pas"
        }
    ]
}

The following screen shots show how this is done using a REST client from a browser.





More Information

http://docs.pivotal.io/pivotalcf/1-7/opsguide/accounting-report.html

Tuesday, 12 July 2016

Creating a Service within IntelliJ IDEA to be used by the Service Registry for Pivotal Cloud Foundry

In this example I am going to show how to use IntelliJ IDEA 15 to create a service application from the IDE to be consumed by the Service Registry service in Pivotal Cloud Foundry (PCF). For more information on this service view the docs page below.

http://docs.pivotal.io/spring-cloud-services/service-registry/index.html

Service Registry for Pivotal Cloud Foundry® (PCF) provides your applications with an implementation of the Service Discovery pattern, one of the key tenets of a microservice-based architecture. Trying to hand-configure each client of a service or adopt some form of access convention can be difficult and prove to be brittle in production. Instead, your applications can use the Service Registry to dynamically discover and call registered services

1. Start IntelliJ IDEA and either "Create a New project" or add a "New Module" to an existing project.

2. Ensure you select "Spring Initializer" as shown below


3. Click Next

4. Describe your project or module, I normally use Maven and generate a JAR file



5. Click Next

6. At the minimum here we only need to select "Service Registry (PCF)" as shown below for the dependency. Of course you would select other options dependncies depending on what the service needed such as REST, JPA, H2 or MySQL etc


7. Click Next

8. Name your new model or project


9. Click Finish

10. Click Finish

11. Your service application must include the @EnableDiscoveryClient annotation on a configuration class. To do that we simply add the annotation to our main class as follows


Java Code
  
package pas.au.pivotal.service.hr;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

import javax.annotation.PostConstruct;

@SpringBootApplication
@EnableDiscoveryClient
public class EmployeeServiceApplication
{
 @Autowired
 private EmployeeRepository employeeRepository;

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

 @PostConstruct
 public void init()
 {
  employeeRepository.save(new Employee("pas"));
  employeeRepository.save(new Employee("lucia"));
  employeeRepository.save(new Employee("siena"));
  employeeRepository.save(new Employee("lucas"));
 }
}

12. Set the spring.application.name property in application.yml. It might be an application.properties file BUT rename it to YML as I know that works. below I not only set the application name I also set the registrationMethod to "route" which is the default and then turn off security as it is enabled by default.

spring:
  application:
    name: employee-service

cloud:
  services:
    registrationMethod: route

security:
  basic:
    enabled: false

So that's all we really need to do here. Of course we will need to add code to our service to do what it needs to do BUT all the config required to enable this service to automatically register itself with the "Service Registry" in PCF is done.

13. Before we deploy this to out PCF instance we have to be sure we have a "Service Registry" service created as shown below using the CF CLI mine is already created.


14. Create a manifest.yml file for the service to be deployed, notice how it binds to the service registry "apples-service-registery", this will ensure it automatically gets registered on deployment with the Service Registry service

---
applications:
- name: apples-employee-service
  memory: 512M
  instances: 1
  host: apples-employee-service-${random-word}
  path: ./target/EmployeeService-0.0.1-SNAPSHOT.jar
  services:
    - apples-service-registery

15. Push the service application to PCF as shown below


.....


16. Login into your PCF instance App Manager UI, in this demo I am using PWS instance run.pivotal.io and find your "Service Registry" service and click on it as shown below



17. Click on the "Manage" link as shown below


18. Verify your service is registered as shown below


More Information

http://docs.pivotal.io/spring-cloud-services/service-registry/index.html

https://docs.pivotal.io/spring-cloud-services/service-registry/resources.html

http://docs.pivotal.io/spring-cloud-services/service-registry/writing-client-applications.html

Monday, 4 July 2016

Pivotal Cloud Foundry Spring Boot JPA demo written in Kotlin

I created the following demo for PCF using spring boot / PCF. After showing a colleague he decided he would write a Kotlin version of the same application. It's interesting to see how the Kotlin classes differ to those of Java.

https://github.com/papicella/PivotalSpringBootJPA

The Kotlin version of the same application is here.

https://github.com/papicella/Kotlin-PivotalSpringBootJPA

Kotlin is a functional language developed by the JetBrains guys. Its main benefits are:

  • Conciseness of code
  • Code safety - Null safety by not allowing nulls values unless one specifies variables to be null.
  • Interoptability - 100% Java interop.
  • Ease of use and reduced learning curve
  • Great tooling - As support in Intellij Idea is brilliant




Thursday, 30 June 2016

Integrating Telstra SMS API with the Apigee Edge Service Broker for Pivotal Cloud Foundry (PCF)

Apigee and Pivotal partnered to provide comprehensive API management capabilities that expedite the scalable delivery of apps on the powerful Pivotal Cloud Foundry platform. Apigee Edge is available for rapid deployment as a partner service in the Pivotal Network

The following link talks about this service in detail

http://apigee.com/about/solutions/pivotal-cloud-foundry-apigee

In this blog post we walk through how we would use this Service on Pivotal Cloud Foundry 1.7 to expose Telstra SMS Api.


1. First we have to deploy our application which provides access to the Public SMS Api from Telstra. This is deployed to Pivotal Cloud Foundry (PCF). The GitHub project is as follows.

https://github.com/papicella/TelstraSMSAPIPublic



2. Once deployed the application provides two REST endpoints that also includes swagger UI

Note: This Telstra API only works for Australian based mobile numbers and you will need a https://dev.telstra.com/ account to invoke the free Telstra SMS Service. The API is explained in detail at this link https://dev.telstra.com/content/sms-api-0






3. Now at this point we will need to add "Apigee Edge Service Broker for PCF" tile to Pivotal Ops Manager. You can download it from the URL below and follow the instructions to install the Tile onto the

  https://network.pivotal.io/products/apigee-edge-for-pcf-service-broker

4. Once installed it will be shown as a tile on Pivotal Ops Manager as per the image below



5. To ensure it's part of our marketplace services we simply log into our PCF instance using the command line as shown below



OR from the Pivotal Apps Manager



6. Use the create-service command to create an instance of the Apigee Edge service broker as shown below

papicella@papicella:~/pivotal/services/apigee$ cf create-service apigee-edge org api-connectors-service -c api-connectors.json
Creating service instance api-connectors-service in org system / space pas as papicella@pivotal.io...
OK

api-connectors.json

{"org":"papicella", "env":"prod", "user":"papicella@pivotal.io", "pass":"yyyyyyy", "host": "apigee.net", "hostpattern": "${apigeeOrganization}-${apigeeEnvironment}.${proxyHost}"}


The JSON specifies the Apigee Edge details needed to route traffic:

  • org -- Organization of the Apigee Edge proxy through which requests should be routed. You'll find this value at the top of the Edge UI while looking at the Dashboard.
  • env -- Environment of the Apigee Edge proxy through which requests should be routed. You'll find this value at the top of the Edge UI while looking at the Dashboard.
  • user -- Username of an Edge user who has access to create proxies. This is the username you use to log into the Edge UI.
  • pass -- Password of an Edge user who has access to create proxies. The password you use to log into the Edge UI.
  • host -- Edge host name to which requests to your API proxies can be sent.
  • hostpattern -- Pattern for generating the API proxy URL. For example, #{apigeeOrganization}-#{apigeeEnvironment}.#{proxyHost} for cloud accounts.
7. Use the bind-route-service command to create an Edge API proxy and bind your Cloud Foundry application to the proxy. This tells the Go router to redirect requests to the Apigee Edge proxy before sending them to the Cloud Foundry application.

papicella@papicella:~/pivotal/services/apigee$ cf bind-route-service pcfdemo.net api-connectors-service --hostname apples-springboot-telstrasms
Binding route apples-springboot-telstrasms.pcfdemo.net to service instance api-connectors-service in org system / space pas as papicella@pivotal.io...
OK

Note: The hostname is the name of your REST based application

8. With the service created it will then exist within the space as per the image below



9. Click on the service as shown below



10. Click on Manage as shown below



11. In the Apigee management console, under APIs > API proxies, locate the name of the proxy you just created as shown below



12. Click the PCF proxy's name to view its overview page.

13. Click the Trace tab, the click the Start Trace Session button.

14. Back at the command line, access the REST based application endpoint for the Telstra SMS Service as shown below.

papicella@papicella:~/pivotal/services/apigee$ curl "http://apples-springboot-telstrasms.pcfdemo.net/telstra/sms?to=0411151350&appkey=apples-key&appsecret=apples-password"
{"messageId":"5188529E91E847589079BAFDBF8B63FF"}

15. Return to the Apigee Management Console to verify Trace Output and a Successful HTTP 200 call. The new proxy is just a pass-through. But it's ready for you or someone on your team to add policies to define security, traffic management, and more.



More Information

Pivotal Cloud Foundry and Apigee - http://apigee.com/about/solutions/pivotal-cloud-foundry-apigee
Pivotal Cloud Foundry - http://pivotal.io/platform

Monday, 16 May 2016

IBM Bluemix Liberty Buildpack and Spring Boot Applications for "Auto-Scale" and "Monitoring" Services

Working with a customer last week we determined that Spring Boot applications using Liberty Buildpack failed to allow the "Auto-Scale" service to show up "Throughput" metrics and essentially mean we couldn't scale out or down application instances using Throughput metrics.

https://console.ng.bluemix.net/docs/runtimes/liberty/index.html

It turns out the Agent within the IBM Liberty buildpack isn't quite picking up application WAR files created using Spring Boot and hence "Monitoring and Analytics" and "Auto-Scale" service have limited functionality.

IBM Bluemix Services



To solve this we simply need to select the correct generated WAR file. Spring Boot along with Maven produces two WAR files as shown below when the application packaged as a WAR is packaged using "mvn package"

Eg:

-rw-r--r--   1 pasapicella  staff  12341953 13 May 14:17 demo-sb-war-0.0.1-SNAPSHOT.war.original
-rw-r--r--   1 pasapicella  staff  17229369 13 May 14:17 demo-sb-war-0.0.1-SNAPSHOT.war

The WAR file "demo-sb-war-0.0.1-SNAPSHOT.war.original" is the one that is originally generated using maven and it's this file which we should push to IBM Bluemix using the IBM Liberty buildpack
 
If there’s a Main-Class defined in the manifest it attempts to start it up using the war file, thats the WAR file "demo-sb-war-0.0.1-SNAPSHOT.war". Once you push the version of our war without the Main-Class Manifest entry defined "demo-sb-war-0.0.1-SNAPSHOT.war.original" everything starts up correctly and is now happily recording both throughput and monitoring. If the WAR has a Main-Class app, the buildpack will only install the JDK for the app, and the app embeds Tomcat (by default for Spring Boot), so essentially the app is running on Tomcat; if it's a WAR app without Main-Class manifest entry, the buildpack installs Liberty as well and the app will run on Liberty.

Simply push the correct WAR file and your Spring Boot WAR files using Liberty Buildpack can take advantage of the Liberty Buildpack agent for extra "Monitoring" and "Auto-Scale" service support.

Screen Shots for Monitoring and Analytics service with Spring Boot WAR file




To verify this you can use the Basic Spring Boot Application at the following URL. It simply exposes one REST end point service displaying "helloworld".

https://github.com/papicella/SpringBootWARDemo