Cloud Foundry Plugin - Reference Documentation
Authors: Burt Beckwith
Version: 1.2.3
Table of Contents
1 Introduction to the Cloud Foundry Plugin
The Cloud Foundry plugin makes it easy to deploy, update and monitor Grails applications in Cloud Foundry. It has the same feature set as the "vmc" commandline Ruby client that Rails and Node.js users will be using. There's also support in SpringSource Tool Suite (STS) via a plugin.The benefit of using this plugin versus the vmc client or STS is that the plugin is very Grails-aware. It makes several assumptions that reduce the amount of typing you need to do, for example you don't need to type the application name since it defaults to your Grails application name (although you can configure the deployed name in Config.groovy, or override the application name with the--appname
commandline argument).
Use "interactive" mode (in Grails 2.0 or higher just run "grails
", and for pre-2.0 applications use the interactive script) when you're running multiple Cloud Foundry scripts - it will significantly reduce the startup time for each command you run once the initial JVM has started.
1.1 History
History
- August 10, 2012
- 1.2.3 release
- JIRA Issues
- May 21, 2012
- 1.2.2 release
- December 30, 2011
- 1.2.1 release
- October 4, 2011
- 1.2 release
- September 20, 2011
- 1.1.1 release
- August 30, 2011
- 1.1 release
- August 23, 2011
- 1.0.3 release
- August 23, 2011
- 1.0.2 release
- July 14, 2011
- 1.0.1 release
- July 13, 2011
- 1.0 release
- April 29, 2011
- 1.0.0.M3 release
- Fixed support for RabbitMQ
- April 21, 2011
- 1.0.0.M2 release
- Added cf-env, cf-env-add, cf-del, cf-frameworks, and cf-runtimes scripts
- April 12, 2011
- 1.0.0.M1 release
2 Getting Started
The first step is to install the plugin.
Ideally, add the plugin dependency intoBuildConfig.groovy
. It is important that the plugin is scoped as compile
, otherwise you may get some unexpected problems if you are letting the plugin manage your datasource config:plugins { compile ':cloud-foundry:1.2.3' }
grails install-plugin cloud-foundry
grails-app/conf/Config.groovy
, or an external config file referenced from Config.groovy
, or in $HOME/.grails/settings.groovy
:grails.plugin.cloudfoundry.username = 'your.email@server.com' grails.plugin.cloudfoundry.password = 's3kr3t'
grails.plugin.cloudfoundry.appname
property:grails.plugin.cloudfoundry.appname = 'my-cool-app'
If you're using the spring-security-core and/or the resources plugins, be sure to use a recent version (1.2.7+ for spring-security-core and 1.1.6+ for resources) and add an explicit dependency for the webxml plugin to BuildConfig.groovy to ensure that your application deploys correctly:There are other configuration options, but next you'll want to provision some services and deploy your application. See section 4 Deploying applications for details on that.compile ':webxml:1.4.1'
3 Configuration
There are a few configuration options for the plugin. All are specified in Config.groovy, but you can put the values forgrails.plugin.cloudfoundry.username
and/or grails.plugin.cloudfoundry.password
in $HOME/.grails/settings.groovy
to avoid storing this information in source control.Property | Default | Meaning |
---|---|---|
grails.plugin.cloudfoundry.username | none, must be specified | the username/email address for your account |
grails.plugin.cloudfoundry.password | none, must be specified | the password for your account |
grails.plugin.cloudfoundry.target | 'api.cloudfoundry.com' | the cloud API server, e.g. 'api.cloudfoundry.com' |
grails.plugin.cloudfoundry.appname | application name | the application name for scripts; defaults to the current application name but can be specified in Config.groovy or overridden from the commandline with the --appname attribute |
grails.plugin.cloudfoundry.showStackTrace | false | if true show error stack traces in the console |
grails.plugin.cloudfoundry.testStartWithGet | true | whether to test a start or restart with a GET request in addition to checking the reported status from the server to avoid false positives |
grails.plugin.cloudfoundry.testStartGetUrl | application url | the url to test if grails.plugin.cloudfoundry.testStartWithGet is true |
grails.plugin.cloudfoundry.datasource.disableTimeoutAutoconfiguration | false | disables auto-configuration of DataSource connection timeout checking if true |
4 Deploying applications
Initial state
When you initially start you won't have any configured services or applications. Running the cf-services script should display something similar to this:$ grails cf-services============== System Services ==============+------------+---------+---------------------------------------+
| Service | Version | Description |
+------------+---------+---------------------------------------+
| postgresql | 9.0 | PostgreSQL database service (vFabric) |
| mysql | 5.1 | MySQL database service |
| redis | 2.2 | Redis key-value store service |
| mongodb | 1.8 | MongoDB NoSQL store |
| rabbitmq | 2.4 | RabbitMQ messaging service |
+------------+---------+---------------------------------------+=========== Provisioned Services ============None provisioned yet.
No applications available.
VMware's Cloud Application Platform For support visit support@cloudfoundry.comTarget: http://api.cloudfoundry.com (v0.999)User: your.email@yourserver.com Usage: Memory (0B of 2.0G total) Services (0 of 16 total) Apps (0 of 20 total)
Services
Before deploying your application, you'll probably need to configure at least one service, e.g. a MySQL, PostgreSQL, MongoDB, or Redis database. Use the cf-create-service script for that, e.g.$ grails cf-create-service mysqlService 'mysql-2f5fb76' provisioned.
$ grails cf-create-service redisService 'redis-364841f' provisioned.
============== System Services ==============+------------+---------+---------------------------------------+
| Service | Version | Description |
+------------+---------+---------------------------------------+
| postgresql | 9.0 | PostgreSQL database service (vFabric) |
| mysql | 5.1 | MySQL database service |
| redis | 2.2 | Redis key-value store service |
| mongodb | 1.8 | MongoDB NoSQL store |
| rabbitmq | 2.4 | RabbitMQ messaging service |
+------------+---------+---------------------------------------+=========== Provisioned Services ============+-----------------+---------+
| Name | Service |
+-----------------+---------+
| mysql-2f5fb76 | mysql |
| redis-364841f | redis |
+-----------------+---------+
$ grails cf-delete-service redis-364841fSuccessfully removed service: redis-364841f
Applications
The cf-push script creates an application. It deploys a war file and optionally binds one or more services, and has options to configure the allocated memory and associated URLs. By default it also starts the application but you can deploy it without starting if you want to perform configuration steps after creating the application.The default memory allocation is 512MB but this can be overridden with the--memory
parameter when running the script$ grails prod cf-push --memory=1G
Most scripts are not environment-specific but cf-push builds a war file, so be sure to specify the environment.A typical deploy command would be
$ grails prod cf-push --services=mysql-2f5fb76
prod cf-push --services=mysql-2f5fb76
Environment set to production Building war file [gspc] Compiling 13 GSP files for package … … Building WAR file … [copy] Copying 633 files to … … [propertyfile] Updating property file: … … [jar] Building jar: .../target/cf-temp-1299173015209.war … Done creating WAR ...target/cf-temp-1299173015209.warApplication Deployed URL: 'myappname.cloudfoundry.com'?Uploading Application Information. Trying to start Application: 'myappname'. ..................Application 'myappname' started.
+-------------+----+---------+----------------------------+---------------+ | Application | # | Health | URLs | Services | +-------------+----+---------+----------------------------+---------------+ | myappname | 1 | RUNNING | myappname.cloudfoundry.com | mysql-2f5fb76 | +-------------+----+---------+----------------------------+---------------+
grails prod cf-push --no-start
grails prod cf-push --warfile=target/myappname.war
Automatic binding and provisioning
You can also let the plugin discover required services for you. The plugin will determine that you probably need a MySQL or PostgreSQL database if you have the Hibernate plugin, a MongoDB instance if you have the Mongo plugin, and a Redis instance if you have that plugin.If you specify a service of the correct type (with the--services
attribute) then it'll be used, otherwise if you need one and have one provisioned it will be suggested to you, e.g.Would you like to bind the 'mysql-2f5fb76' service? ([y], n)
Would you like to create and bind a redis service? ([y], n)
5 Updating applications and services
Updating applications
Once an application has been created, there are several options for making changes to it:- binding and unbinding services
- mapping and unmapping URLs
- increasing or decreasing the number of running instances
- increasing or decreasing the amount of memory allocated
Services
Use the cf-bind-service script to associate an existing service instance with your application:grails cf-bind-service mongodb-eaa5601
cf-bind-service mongodb-eaa5601
Creating new service binding to 'mongodb-eaa5601' for 'myappname'.Application 'myappname' updated Service 'mongodb-eaa5601' addedApplication 'myappname' stopped.Trying to start Application: 'myappname'. .Application 'myappname' started.
+-------------+----+---------+----------------------------+--------------------------------+ | Application | # | Health | URLs | Services | +-------------+----+---------+----------------------------+--------------------------------+ | myappname | 1 | RUNNING | myappname.cloudfoundry.com | mysql-2f5fb76, mongodb-eaa5601 | +-------------+----+---------+----------------------------+--------------------------------+
$ grails cf-unbind-service mongodb-eaa5601Removing service binding 'mongodb-eaa5601' from 'myappname'.Application 'myappname' updated Service 'serviceName' removedApplication 'myappname' stopped.Trying to start Application: 'myappname'. .Application 'myappname' started.
+-------------+----+---------+----------------------------+---------------+ | Application | # | Health | URLs | Service | +-------------+----+---------+----------------------------+---------------+ | myappname | 1 | RUNNING | myappname.cloudfoundry.com | mysql-2f5fb76 | +-------------+----+---------+----------------------------+---------------+
URLs
Use the cf-map script to associate an additional URL with your application:$ grails cf-map myotherappname.cloudfoundry.comSuccesfully mapped url
+-------------+----+---------+-------------------------------------------------------------+---------------+ | Application | # | Health | URLs | Service | +-------------+----+---------+-------------------------------------------------------------+---------------+ | myappname | 1 | RUNNING | myappname.cloudfoundry.com, myotherappname.cloudfoundry.com | mysql-2f5fb76 | +-------------+----+---------+-------------------------------------------------------------+---------------+
$ grails cf-unmap myotherappname.cloudfoundry.comSuccesfully unmapped url
+-------------+----+---------+----------------------------+---------------+ | Application | # | Health | URLs | Service | +-------------+----+---------+----------------------------+---------------+ | myappname | 1 | RUNNING | myappname.cloudfoundry.com | mysql-2f5fb76 | +-------------+----+---------+----------------------------+---------------+
Instances
Use the cf-update-instances script to increase or decrease the number of running instances of your application:$ grails cf-update-instances 3Scaled 'myappname' up to 3 instance(s).
+-------------+----+---------+----------------------------+---------------+ | Application | # | Health | URLs | Service | +-------------+----+---------+----------------------------+---------------+ | myappname | 3 | 33% | myappname.cloudfoundry.com | mysql-2f5fb76 | +-------------+----+---------+----------------------------+---------------+
+-------------+----+---------+----------------------------+---------------+ | Application | # | Health | URLs | Service | +-------------+----+---------+----------------------------+---------------+ | myappname | 3 | RUNNING | myappname.cloudfoundry.com | mysql-2f5fb76 | +-------------+----+---------+----------------------------+---------------+
VCAP_APP_HOST 10.114.110.207 VCAP_APP_PORT 48684
VCAP_APP_HOST 10.114.110.208 VCAP_APP_PORT 47793
VCAP_APP_HOST 10.114.110.209 VCAP_APP_PORT 58232
$ grails cf-show-instances+-------+---------+--------------------+ | Index | State | Start Time | +-------+---------+--------------------+ | 0 | RUNNING | 04/12/2011 11:33AM | +-------+---------+--------------------+ | 1 | RUNNING | 04/12/2011 11:33AM | +-------+---------+--------------------+ | 2 | RUNNING | 04/12/2011 11:33AM | +-------+---------+--------------------+
$ grails cf-stats+----------+-------------+----------------+--------------+--------------+ | Instance | CPU (Cores) | Memory (limit) | Disk (limit) | Uptime | +----------+-------------+----------------+--------------+--------------+ | 0 | 9.5% (4) | 372.7M (512M) | 52.6M (2G) | 0d:0h:1m:12s | | 1 | 3.3% (4) | 375.7M (512M) | 52.6M (2G) | 0d:0h:1m:53s | | 2 | 3.7% (4) | 383.2M (512M) | 52.6M (2G) | 0d:0h:1m:55s | +----------+-------------+----------------+--------------+--------------+
$ grails cf-update-instances 1Scaled 'myappname' down to 1 instance(s).
Memory
Use the cf-update-memory script to increase or decrease the allocated memory for your application:$ grails cf-update-memory 1GUpdated memory reservation to '1.0G'.Application 'myappname' stopped.Trying to start Application: 'myappname'. .Application 'myappname' started.
Start, stop, restart
Use the cf-stop script to stop your application:$ grails cf-stopApplication 'myappname' stopped.
$ grails cf-startTrying to start Application: 'myappname'. .Application 'myappname' started.
$ grails cf-restartApplication 'myappname' stopped.Trying to start Application: 'myappname'. .Application 'myappname' started.
Updating
Use the cf-update script to redeploy an application after making code changes:$ grails prod cf-updateUploading Application. Building war file [gspc] Compiling 13 GSP files for package … … Building WAR file … [copy] Copying 635 files to … … [propertyfile] Updating property file: … … [jar] Building jar: .../target/cf-temp-1299178697861.war … Done creating WAR ...target/cf-temp-1299178697861.warApplication 'myappname' stopped.Trying to start Application: 'myappname'. .Application 'myappname' started.
Most scripts are not environment-specific but cf-update builds a war file, so be sure to specify the environment.Like the cf-push script you can either let the script create a war file for you, or specify an existing one.
Deleting applications
Use the cf-delete-app script to delete an application:$ grails cf-delete-appApplication 'myappname' deleted.
$ grails cf-delete-all-appsApplication 'myappname1' deleted.Application 'myappname2' deleted.Application 'myappname3' deleted.
6 Monitoring
Crashes
If a deployment or update fails, the script will display the application logs but you can view crash information and logs at any time.Use the cf-crashes script to check if there have been recent crashes:$ grails cf-crashes+-------------+--------------------------------------+--------------------+ | Name | Instance ID | Crashed Time | +-------------+--------------------------------------+--------------------+ | myappname-1 | 9f3e61c9-7c64-4e57-ab3e-8d7e892dd722 | 04/11/2011 02:43PM | | myappname-2 | 17b6470c-6444-49f4-8981-d3bd7d7796dc | 04/11/2011 02:43PM | | myappname-3 | d1b99f31-203c-48e3-aa17-17ca26178a49 | 04/11/2011 02:44PM | +----------+-------------+----------------+--------------+--------------+
$ grails cf-crashlogs==== logs/stdout.log ====2011-03-03 14:50:23,904 [main] ERROR context.ContextLoader - Context initialization failed org.springframework.beans.factory.access.BootstrapException: Error executing bootstraps; nested exception is java.lang.NullPointerException at org.codehaus.groovy.grails.web.context.GrailsContextLoader.createWebApplicationContext(GrailsContextLoader.java:87) … Caused by: java.lang.NullPointerException at $Proxy13.save(Unknown Source) … Stopping Tomcat because the context stopped.
Logs
Use the cf-logs script to view log files:$ grails cf-logs==== logs/stderr.log ====Mar 3, 2011 2:51:32 PM org.apache.coyote.http11.Http11Protocol init INFO: Initializing Coyote HTTP/1.1 on http-50478 … INFO: Server startup in 9169 ms ==== logs/stdout.log ====
$ grails cf-logs --stderr==== logs/stderr.log ====Mar 3, 2011 2:51:32 PM org.apache.coyote.http11.Http11Protocol init INFO: Initializing Coyote HTTP/1.1 on http-50478 … INFO: Server startup in 9169 ms
$ grails cf-logs target/myapp.stderr.log --stderrWrote logs/stderr.log to target/myapp.stderr.log
Viewing files
Use the cf-list-files script to view directory listings:$ grails cf-list-files /logs/ - tomcat/ -
$ grails cf-list-files tomcatbin/ - conf/ - lib/ - logs/ - temp/ - webapps/ - work/ -
$ grails cf-list-files tomcat/webappsROOT/ -
$ grails cf-list-files tomcat/webapps/ROOTMETA-INF/ - WEB-INF/ - css/ - images/ - js/ - plugins/
$ grails cf-get-file tomcat/webapps/ROOT/css/main.csshtml * { margin: 0; /*padding: 0; SELECT NOT DISPLAYED CORRECTLY IN FIREFOX */ }...
$ grails cf-get-file tomcat/webapps/ROOT/css/main.css target/main.cssWrote tomcat/webapps/ROOT/css/main.css to target/main.css
Caldecott tunnels
The plugin has support for Caldecott tunnels to connect directly to Cloud Foundry services directly. Use the cf-tunnel and cf-tunnel-disconnect scripts to connect and disconnect.To create a tunnel, enter interactive mode:$ grails
grails> cf-tunnel --service=mysql-38874c4 | Tunnel is running on localhost port 10000
grails> cf-tunnel | You have the following services defined: | 1: mysql-38874c4 > Please select a service (or 0 to quit):[0,1]
| Caldecott server app not found, deploying ...
Connect your client with username=uLQYDu4OmR9U password=pz6pQ4zxX7Jr name=d30bcdb2254a457e9c3662da8f5da089 Example mysql client usage: mysql -h 127.0.0.1 -P 10000 -u uLQYDu4OmR9U -ppz6pQ4zxX7Jr -D d30bcdb2254a457e9c3662da8f5da089
7 Service Configuration
When you provision a service and bind it to an application, an environment variableVCAP_SERVICES
is set for your server instance(s). This is a JSON string and you can use it to configure your DataSource, MongoDB, and Redis connections and will look something like this (formatted for readability):{"redis-2.2": [{"name":"redis-1d8e28a", "label":"redis-2.2", "plan":"free", "credentials":{ "node_id":"redis_node_3", "hostname":"172.30.48.42", "port":5004, "password":"1463d9d0-4e35-4f2e-be2f-01dc5536f183", "name":"redis-1a69a915-6522-496c-93d5-1271d2b3118e"} }], "mongodb-1.8": [{"name":"mongodb-3854dbe", "label":"mongodb-1.8", "plan":"free", "credentials":{ "hostname":"172.30.48.63", "port":25003, "username":"b6877670-da98-4124-85ca-84357f042797", "password":"f53e6a4b-f4b8-497d-ac81-43cb22cf1e88", "name":"mongodb-9dda2cfb-9672-4d58-8786-98c3abcb21ec", "db":"db"} }], "mysql-5.1": [{"name":"mysql-497b12e", "label":"mysql-5.1", "plan":"free", "credentials":{ "node_id":"mysql_node_8", "hostname":"172.30.48.27", "port":3306, "password":"p3rO5K5lRZaEU", "name":"d887d4f5664f64dde86f3ce42c6333962", "user":"umuPIJ8IzSKVA"} }] }
System.getenv('VCAP_SERVICES')
and parse the JSON.DataSource
In addition to replacing the username, password, and JDBC url for your DataSource, the plugin will configure database connection testing, using the following settings:removeAbandoned = true removeAbandonedTimeout = 300 // 5 minutes testOnBorrow = true validationQuery = '/* ping */ SELECT 1'
org.apache.commons.dbcp.BasicDataSource
that Grails configures since we assume that if you have customized the DataSource, you will configure connection testing yourself. You can also tell the plugin to not make these changes withgrails.plugin.cloudfoundry.datasource.disableTimeoutAutoconfiguration = true
Config.groovy
.You should specify the Dialect
to ensure that the correct table type is used. In MySQL InnoDB tables are preferred since MyISAM tables do not support transactions, so it's a good idea to use the MySQLInnoDBDialect
. In addition you can customize the JDBC url (for example to use UTF-8). The best way to configure these is to populate the production
settings (or whichever environment you're using for deployment) with these values, for example:production {
dataSource {
dialect = org.hibernate.dialect.MySQLInnoDBDialect
driverClassName = 'com.mysql.jdbc.Driver'
username = 'n/a'
password = 'n/a'
url = 'jdbc:mysql://localhost/db?useUnicode=true&characterEncoding=utf8'
dbCreate = 'update'
}
}
username
and password
will be replaced but can't be blank or missing, so they're set to dummy values. In addition the part of the URL to the left of the ? character will be replaced, so that just has to be valid syntax but doesn't need to be a real database. The part to the right of the ? ("useUnicode=true&characterEncoding=utf8"
) will be appended to the auto-generated URL.Searchable
Although there's no explicit support for Compass in Cloud Foundry, the plugin does detect that the Searchable plugin is installed and will configure it to write its Lucene index to a writeable directory on your server.8 Troubleshooting
You can enable logging of the JSON responses from client calls by setting thegrails.plugin.cloudfoundry.Scripts
category to the debug
level in your log4j configuration, e.g.debug 'grails.plugin.cloudfoundry.Scripts'
trace 'grails.plugin.cloudfoundry.ClientWrapper'
trace 'grails.plugin.cloudfoundry' trace 'grails.plugin.cloudsupport' trace 'org.cloudfoundry'
Config.groovy
grails.plugin.cloudfoundry.showStackTrace = true
console and dbconsole plugins
The console and dbconsole plugins are very helpful in diagnosing issues. The console plugin allows you to run arbitrary Groovy code from a web-based console (similar to the Grails/Groovy Swing-based console) and the dbconsole plugin exposes the H2 database's web-based database console (the H2 database console is available in Grails 2.0 by default, so you only need the plugin in pre-2.0 apps). The great thing about H2's database console is that it doesn't work for just H2 - it works for any JDBC database you have a driver for.These plugins are very dangerous if left exposed to the public. Be sure to guard them with security if you use them.One issue you'll see is that it's tricky to know how to connect to your Cloud Foundry MySQL/PostgreSQL database from the database console. You can use the console plugin to inspect the config settings, but it's more convenient to add this code to your application's
BootStrap.groovy
:import grails.converters.JSONclass BootStrap { def init = { servletContext -> String VCAP_SERVICES = System.getenv('VCAP_SERVICES') println "VCAP_SERVICES: ${System.getenv('VCAP_SERVICES')}n" try { def servicesMap = JSON.parse(VCAP_SERVICES) servicesMap.each { key, services -> if (key.startsWith('mysql')) { for (service in services) { print "MySQL service $service.name: " print "url='jdbc:mysql://$service.credentials.hostname:$service.credentials.port/$service.credentials.name', " print "user='$service.credentials.user', " println "password='$service.credentials.password'n" } } else if (key.startsWith('postgresql')) { for (service in services) { print "PostgreSQL service $service.name: " print "url='jdbc:postgresql://$service.credentials.hostname:$service.credentials.port/$service.credentials.name', " print "user='$service.credentials.user', " println "password='$service.credentials.password'n" } } } } catch (e) { println "Error occurred parsing VCAP_SERVICES: $e.message" } } }
Config.groovy
with the grails.dbconsole.enabled
attribute (it's only enabled by default in development):environments {
production {
grails.dbconsole.enabled = true
}
…
}
grails.dbconsole.urlRoot
attribute:environments {
production {
grails.dbconsole.enabled = true
grails.dbconsole.urlRoot = '/admin/dbconsole'
}
…
}
grails cf-logs --stdout