Skip to content

Instantly share code, notes, and snippets.

@pmuellr
Created March 12, 2014 12:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pmuellr/9506226 to your computer and use it in GitHub Desktop.
Save pmuellr/9506226 to your computer and use it in GitHub Desktop.
readme for cf-env

cf-env - access your CloudFoundry environment objects

The cf-env package provides parsing of Cloud Foundry-provided environment variables when you app is running. Provides easy access to your port, http binding host name/ip address, URL of the application, etc. Also provides useful default values when you're running locally.

quick start

cfEnv = require("cf-env")           // use the cf-env package
pkg   = require("./package.json")   // read your package.json file

// get the core data using the package name as the default app name

cfCore = cfEnv.getCore({name: pkg.name})

...

// start the server on the given port and binding host, and print
// url to server when it starts

server.listen(cfCore.port, cfCore.bind, function() {
    console.log("server starting on " + cfCore.url)
})

This code snippet will get the port, binding host, and full URL to your HTTP server and use them to bind the server and print the server URL when starting.

running in Cloud Foundry vs locally

This package makes use of a number of environment variables that are set when your application is running in Cloud Foundry. These include:

  • VCAP_SERVICES
  • VCAP_APPLICATION
  • PORT

If these aren't set, the getCore() API will still return useful values, as appropriate. This means you can use this package in your program and it will provide useful values when you're running in Cloud Foundry AND when you're running locally.

api

The cf-env package exports the following functions.

getCore(options)

Get the core bits of Cloud Foundry data as an object.

The options parameter is optional, and can contain the following properties:

  • name - name of the application

    This value is used as the default name property in the returned object, and as the name passed to the ports package getPort() function to get a default port.

  • protocol - protocol used in the generated URLs

    This value is to override the default protocol used when generating the URLs in the returned object. It should be the same format as node's url protocol property.

This function returns an object with properties:

  • app: object version of VCAP_APPLICATION env var
  • services: object version of VCAP_SERVICES env var
  • name: name of the application
  • port: HTTP port
  • bind: hostname/ip address for binding
  • urls: URLs used to access the servers
  • url: first URL in urls

If no value can be determined for port, and the name property on the options parameter is not set, a port of 3000 will be used.

If no value can be determined for port, and the name property on the options parameter is set, that name will be passed to the ports package getPort() function to get a default port.

The protocol used for the URLs will be https: if the app is running in Cloud Foundry, and http: otherwise; you can force a particular protocol by using the protocol property on the options parameter.

getServices()

Return all services in an object keyed by service name.

Note that this is different than the services property returned from getCore().

For example, assume VCAP_SERVICES was set to the following:

{
    "user-provided": [
        {
            "name": "cf-env-test",
            "label": "user-provided",
            "tags": [],
            "credentials": {
                "database": "database",
                "password": "passw0rd",
                "url": "https://example.com/",
                "username": "userid"
            },
            "syslog_drain_url": "http://example.com/syslog"
        }
    ]
}

In this case, getCore().services would be set to that same object, but getServices() would return

{
    "cf-env-test": {
        "name": "cf-env-test",
        "label": "user-provided",
        "tags": [],
        "credentials": {
            "database": "database",
            "password": "passw0rd",
            "url": "https://example.com/",
            "username": "userid"
        },
        "syslog_drain_url": "http://example.com/syslog"
    }
}

getService(spec)

Return a service object by name.

The spec parameter should be a regular expression, or a string which is the exact name of the service. For a regular expression, the first service name which matches the regular expression will be returned.

Returns the service object from VCAP_SERVICES or null if not found.

getServiceURL(spec, replacements)

Returns a service URL by name.

The spec parameter should be a regular expression, or a string which is the exact name of the service. For a regular expression, the first service name which matches the regular expression will be returned.

The replacements parameter is an object with the properties used in node's url function url.format().

Returns a URL generated from VCAP_SERVICES or null if not found.

To generate the URL, processing first starts with a url property in the service credentials. You can override the url property in the service credentials (if no such property exists), with a replacements property of url, and a value which is the name of the property in the service credentials whose value contains the base URL.

That url is parsed with node's url function url.parse() to get a set of initial url properties. These properties are then overridden by entries in replacements, using the following operation, for a given replacement key and value.

 url[key] = service.credentials[value]

The URL auth replacement is a bit special, in that it's value should be a two-element array of [userid, password], where those values are keys in the service.credentials

For example, assume VCAP_SERVICES was set to the following:

{
    "user-provided": [
        {
            "name": "cf-env-test",
            "label": "user-provided",
            "tags": [],
            "credentials": {
                "database": "database",
                "password": "passw0rd",
                "url": "https://example.com/",
                "username": "userid"
            },
            "syslog_drain_url": "http://example.com/syslog"
        }
    ]
}

Assume you run the following code:

url = cfEnv.getServiceURL("cf-env-test", {
    pathname: "database",
    auth:     ["username", "password"]
})

The url result will be https://userid:passw0rd@example.com/database

testing with Cloud Foundry

You can push this project as a Cloud Foundry project to try it out.

First, you should edit the manifest.yml file to use a unique host value.

Next, do an initial push of the app with cf push.

Next, you should create a service name cf-env-test with the following command:

cf cups cf-env-test -p "url, username, password, database"

Next, you will be prompted for these values; enter something reasonable like:

url>      http://example.com
username> userid
password> passw0rd
database> the-db

Next, bind the service with the command:

cf bind-service cf-env-test cf-env-test

Finally, push the app again with cf push

When you visit the site, you'll see the output of various cf-env calls.

hacking

If you want to modify the source to play with it, you'll also want to have the jbuild program installed.

To install jbuild on Windows, use the command

npm -g install jbuild

To install jbuild on Mac or Linux, use the command

sudo npm -g install jbuild

The jbuild command runs tasks defined in the jbuild.coffee file. The task you will most likely use is watch, which you can run with the command:

jbuild watch

When you run this command, the application will be built from source, the server started, and tests run. When you subsequently edit and then save one of the source files, the application will be re-built, the server re-started, and the tests re-run. For ever. Use Ctrl-C to exit the jbuild watch loop.

You can run those build, server, and test tasks separately. Run jbuild with no arguments to see what tasks are available, along with a short description of them.

license

Apache License, Version 2.0

http://www.apache.org/licenses/LICENSE-2.0.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment