How to add a system service to Cloud Foundry step by step guide

cloudfoundry-collaboration edited this page Jul 22, 2011 · 2 revisions

Overview

This guide will walk you through the process of adding a new service to your Cloud Foundry landscape and will show you how to consume it from a web application. For the purpose of this guide we have provided a simple echo service and a simple consumer web application that sends messages to be echoed. Both are written in java, but you can write your own services in any language you want and the consuming applications in any language supported by Cloud Foundry. Each service has a service node, a provisioner and a service gateway. The service node is the Cloud Foundry service implementation. The provisioner is the agent that does domain specific actions when the service is being provisioned or unprovisioned. For example the standard MySQL service creates a new user and schema when it is provisioned. The service gateway is a REST interface to the service provisioner. Here is a small picture illustrating these basic components:

services

Services in Cloud Foundry

In Cloud Foundry you have two basic states of the services - System services and Provisioned services. System services are all types of services available to the system. Services of these types can be provisioned and bound to applications. When you provision a service you give it a name. This name is later used by applications to lookup metadata about the provisioned services. You can list both system and provisioned services by logging in to vmc and typing vmc services

services

Adding the echo service to the system services

After completing this section our echo service will appear as a system service in the table printed by vmc services. This guide can be used for both single-machine and distributed setup of Cloud Foundry. Note that by ellipsis (...) we mean the directory where your Cloud Foundry installation resides. Here are the steps you need to execute:

1) On the cloud controller host go to .../cloudfoundry/vcap/bin/vcap and add echo to the list of available services:

   # Module 'Tail'
   def self.services
       %w(redis mysql mongodb echo)
   end

2) Optional: On the cloud controller host go to .../cloudfoundry/vcap/cloud_controller/app/models/service.rb to define service type for backwards compatibility.

   # Service types no longer exist, synthesize one if possible to be legacy API compliant
   def synthesize_service_type
      case self.name
       when /mysql/
         'database'
       when /redis/  
         'key-value'
       when /mongodb/
         'key-value'  
       when /echo/ 
         'key-value'
       else
         'generic'
      end
   end

3) Add service token configuration at .../cloudfoundry/vcap/cloud_controller/config/cloud_controller.yml on the cloud controller host.

   # Services we provide, and their tokens. Avoids bootstrapping DB.
   builtin_services:
     mysql:
       token: "0xdeadbeef"
     redis:
       token: "0xdeadbeef"
     mongodb:
       token: "0xdeadbeef"
     rabbitmq:
       token: "0xdeadbeef"
     echo:
       token: "0xdeadbeef"

4) On the services host go to .../cloudfoundry/vcap/services/common/nuke_service.rb and add the path to the echo service configuration

   default_configs = {
     :mongodb => File.expand_path("../../mongodb/config/mongodb_gateway.yml", __FILE__),
     :redis   => File.expand_path("../../redis/config/redis_gateway.yml", __FILE__),
     :mysql   => File.expand_path("../../mysql/config/mysql_gateway.yml", __FILE__),
     :echo   => File.expand_path("../../echo/config/echo_gateway.yml", __FILE__)
   }

5) Create start scripts for '_node' and '_gateway' on the services host at .../cloudfoundry/vcap/bin/services/

5.1) Content of 'echo_node':

   #!/usr/bin/env ruby
   exec(File.expand_path("../../../services/echo/bin/echo_node", __FILE__), *ARGV)

5.2) Content of 'echo_gateway':

   #!/usr/bin/env ruby
   exec(File.expand_path("../../../services/echo/bin/echo_gateway", __FILE__), *ARGV)

These scripts just delegate to the real scripts provided with the service.

6) Add the echo service provisioner implementation on the services host
Download and extract the implementation of the echo service provisioner from here and copy the extracted directory structure to .../cloudfoundry/vcap/services/. When you do that you only have to adjust two configuration files:

.../cloudfoundry/vcap/services/echo_gateway.yml

   ---
   cloud_controller_uri: api.myfoundry.com # uncomment and add valid cloud controller uri
   service:
     name: echo
     version: "1.0"
     description: 'Echo key-value store service'
     plans: ['free']
     tags: ['echo', 'echo-1.0', 'key-value', 'echobased']
   host: <FQDN_of_the_services_host>
   token: "0xdeadbeef"
   log_level: DEBUG
   echo_mbus: nats://<nats_host>:<nats_port>
   service_mbus: nats://<nats_host>:<nats_port>
   pid: /var/vcap/sys/run/echo_service.pid  

.../cloudfoundry/vcap/services/echo_node.yml

   ---
   base_dir: /var/vcap/services/echo/
   local_db: sqlite3:/var/vcap/services/echo/echo_node.db
   mbus: nats://<nats_host>:<nats_port>
   ip_route: <services_host_ip>
   log_level: INFO
   pid: /var/vcap/sys/run/echo_node.pid
   node_id: echo_node_1
   port: <echo_service_port> # port where echo service listens
   host: <echo_service_host> # host where echo service resides. May be different from services host

Prefer using real IP addresses over localhost as some of these variables may become part of environment on other hosts!

7) Restart cloud controller and services node Execute .../cloudfoundry/vcap/bin/vcap restart on the cloud controller host and then on the services host. After you have done that execute the command vmc services. Our new echo service should be available in the upper table. Congratulations! You have just provided your first Cloud Foundry service! Now, let's do something with it!

Consuming the echo service

1) Provision an echo service Execute vmc create-service echo myecho
This will provision an echo service with the name of 'myecho'. This name will be used by the test application later on to look up the host and port we configured fot the echo service. After you provision myecho execute vmc services. This will output something like this:

echo_service

Now we have our service provisioned!

2) Push a test application and bind the provisioned echo service Download the test application war from here. Place it in a folder somewhere and push it to vmc.

vmc push

   Would you like to deploy from the current directory? [Yn]:
   Application Name: echotest
   Application Deployed URL: 'echotest.myfoundry.com'?
   Detected a Java Web Application, is this correct? [Yn]:
   Memory Reservation [Default:512M] (64M, 128M, 256M, 512M or 1G) 64M
   Creating Application: OK
   Would you like to bind any services to 'echotest'? [yN]: y
   Would you like to use an existing provisioned service [yN]? y
   The following provisioned services are available:
   1. db
   2. myecho
   Please select one you wish to provision: 2
   Binding Service: OK
   Uploading Application:
     Checking for available resources: OK
     Processing resources: OK
     Packing application: OK
     Uploading (1K): OK
   Push Status: OK
   Staging Application: OK
   Starting Application: OK

Beware: if you have other applications in the same directory vmc will sort them in lexicographical order and will opt for the first one. You can use vmc push <app_name> --path <path_to_app> instead.

3) Start the echo service and access the application
Now it is time to test the consumer application. But we have to start the service first. What we did up to now was to provide service metadata, not a physical service. The application will read the service host and port from an environment variable called VCAP_SERVICES and will hope that there is something listening there. It is our responsibility to ensure that there really is. Otherwise we will leave our application disappointed. So let's start the service. Go to the host you configured in echo_node.yml. Download the echo service jar from here and execute the following
java -jar echo_serviice.jar -port <echo_service_port>

The port you pass as a parameter should be the same as the one you configured in echo_node.yml.
After you have started the service open your favorite web browser and go to http://echotest.myfoundry.com/ or whatever URI you have chosen when pushing. Enter some message in the text area and click on the 'Echo message' button. The echo service will echo your message:

helloworld

Resources

You can find all needed binaries and sources in this section:

  • echo service [src | bin]
  • test app [src | bin]
  • echo service provisioner [src]