Tuesday, 20 December 2016

Script to tally Application Instance Counts for Pivotal Cloud Foundry

I was recently asked how to determine how many application instances exist in a given ORG at a point in time. The script below can do this using CF CURL command which means you must be logged into your Pivotal Cloud Foundry instance for this to work. You can use the CF REST API itself but I find the CF CURL much easier.

CF REST API https://apidocs.cloudfoundry.org/249/

The script below is assuming an ORG name of "apples-pivotal-org" so it would make sense to pass this in as a script variable which is easy enough to do

Prior to running this script it's worth checking your current TARGET endpoints as shown below.

pasapicella@pas-macbook:~/pivotal/PCF/scripts$ cf target

API endpoint:   https://api.run.pivotal.io (API version: 2.65.0)
User:           papicella@pivotal.io
Org:            apples-pivotal-org
Space:          development

Script:

echo "AI Count for applications in a organization.."
echo ""

guids=$(cf curl /v2/apps?q=organization_guid:`cf org apples-pivotal-org --guid` | jq -r ".resources[].metadata.guid")
total=0
for guid in $guids; do
  name=$(cf curl /v2/apps/$guid | jq -r ".entity.name")
  count=$(cf curl /v2/apps/$guid | jq -r ".entity.instances")
  echo -e "App Name: $name , Instances: $count"
  total=$(( $total + $count ))
done

echo "-----"
echo "Total AI's = $total"
echo ""

Output:

pasapicella@pas-macbook:~/pivotal/PCF/scripts$ ./ai-count-org-details.sh
AI Count for applications in a organization..

App Name: pas-telstrawifiapi-client , Instances: 1
App Name: springboot-bootstrap-employee , Instances: 2
App Name: springboot-employee-feign-client , Instances: 1
App Name: greeting-config , Instances: 1
App Name: employee-feign-client-hystrix , Instances: 1
App Name: pas-albums , Instances: 2
App Name: pas-springboot-pcf , Instances: 2
App Name: springboot-typeahead , Instances: 1
-----
Total AI's = 11

Wednesday, 14 December 2016

Spring Boot with Feign and Twitter Typeahead JS library

I previously blogged about a demo using Spring Boot and Feign making an external based REST call to a service I had created. The real purpose of that demo "http://theblasfrompas.blogspot.com.au/2016/12/spring-boot-feign-client-accessing.html" was to use Twitter Typeahead for auto completion which is the demo on Github below. The returned data is now used in an INPUT text input for auto completion as the user types in the Country Name

https://github.com/papicella/FeignClientExternalSpringBoot


Friday, 9 December 2016

Spring Boot / Feign Client accessing external service

Previously we used Feign to create clients for our own services, which are registered on our Eureka Server using a service name as shown in the previous blog post http://theblasfrompas.blogspot.com.au/2016/11/declarative-rest-client-feign-with_8.html. It's not unusual that you'd want to implement an external rest endpoint, basically an endpoint that's not discoverable by Eureka. In that case, you can use the url property on the @FeignClient annotation,
which gracefully supports property injection. His an example of this.

Full example on GitHub as follows

https://github.com/papicella/FeignClientExternalSpringBoot

1. Start by adding the correct maven dependencies and the one you need is as follows, there would be others if you want to use a web based spring boot project etc.

  
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>

2. We are going to consume this external service as follows

http://country.io/names.json

To do that we create a simple interface as follows
  
package pas.au.pivotal.feign.external;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@FeignClient(name = "country-service-client", url = "http://country.io")
public interface CountryServiceClient {

    @RequestMapping(method = RequestMethod.GET, value = "/names.json")
    String getCountries();
}

3. In this example I have created a RestController to consume this REST service and test it because it's the easiest way to do this. We simply AutoWire the CountryServiceClient interface into the RestController to make those external calls through FEIGN.
  
package pas.au.pivotal.feign.external.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.json.JsonParser;
import org.springframework.boot.json.JsonParserFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import pas.au.pivotal.feign.external.CountryServiceClient;

import java.util.Map;

@RestController
public class CountryRest
{
    Logger logger = LoggerFactory.getLogger(CountryRest.class);
    private static final JsonParser parser = JsonParserFactory.getJsonParser();

    @Autowired
    private CountryServiceClient countryServiceClient;

    @RequestMapping(value = "/countries", method = RequestMethod.GET, 
                         produces = "application/json")
    public String allCountries()
    {
        String countries = countryServiceClient.getCountries();

        return countries;
    }

    @RequestMapping(value = "/country_names", method = RequestMethod.GET)
    public String[] countryNames ()
    {
        String countries = countryServiceClient.getCountries();

        Map<String, Object> countryMap = parser.parseMap(countries);

        String countryArray[] = new String[countryMap.size()];
        logger.info("Size of countries " + countryArray.length);

        int i = 0;
        for (Map.Entry<String, Object> entry : countryMap.entrySet()) {
            countryArray[i] = (String) entry.getValue();
            i++;
        }

        return countryArray;

    }
}

4. Of course we will have our main class to boot strap the application and it includes the "spring-boot-starter-web" maven repo to start a tomcat server for us.
  
package pas.au.pivotal.feign.external;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class FeignClientExternalSpringBootApplication {

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

5. Ensure your application.properties or application.yml has the following properties to disable timeouts.

feign:
  hystrix:
    enabled: false

hystrix:
  command:
    choose:
      default:
        execution:
          timeout:
            enabled: false

6. Run the main class "FeignClientExternalSpringBootApplication"

Access as follows

http://localhost:8080/countries