A CloudFoundry buildpack that enables decomposition of buildpacks
Shell Python
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
bin Updated copyright notices Jun 20, 2016
ci Removed end-of-support versions Jan 12, 2018
lib Can't use stdout in detect step Jun 29, 2016
resources
test Typo in cf push option Oct 22, 2016
.gitignore
LICENSE Updated copyright notices Jun 20, 2016
NOTICE Updated copyright notices Jun 20, 2016
README.md
build Separated build from upload Oct 21, 2016
tile.yml
upload

README.md

NOTE: Meta-buildback is being deprecated
Changes to the core CloudFoundry lifecycle process are making it hard to guarantee on-going compatibility with meta-buildpack and decorators. Some of the use cases for decorators can now be solved by leveraging the new supply buildpack functionality. Some examples can be found at the bottom of this page.

If you are using meta-buildpack today and need to find an alternative, or have a use case that would have been addressed by decorators, please open an issue on this repo and we are happy to help you look for the right way to accomplish your task.

Meta-Buildpack

This is a Cloud Foundry buildpack that enables decomposition of buildpacks into "real" buildpacks (the ones that create a droplet from the submitted source), and "decorators" (buildpacks that inject other smarts into the droplet generated by the first buildpack).

Objective

The main objective of this buildpack is to reduce the NxM problem of having buildpacks for each programming language, and add-on features that support multiple languages. Specifically, I wanted to add Spring Cloud Config Service support to as many non-Java languages as possible, and prior to creating the meta-buildpack, I had to fork and modify the buildpack for each supported language in order to do that. The same issue applies to things like Application Performance Monitoring solutions that support multiple languages. If we separate the (N) language buildpacks from the (M) feature add-on buildpacks, we have reduced the problem to N+M instead.

It is entirely possible to do this without a meta-buildpack by including the recursive invocation of buildpacks in each decorator, and requiring decorators to be at the top of the list. But that's just plain ugly.

What is a Decorator

A decorator is a special Cloud Foundry buildpack. Unlike a "real" buildpack, a decorator doesn't produce a droplet from source. Instead, it "decorates" (hence the name) an already produced droplet to implement some kind of add-on feature. Good examples of such add-on features might be:

  • Monitoring Agents
  • Configuration Management
  • Service Registration and Discovery
  • Sidecar Applications like Gateways and Client-Side Routers

Basically anything that can be injected into containers with little or no dependency on what language the application was written in. Splitting out this functionality into decorators avoids the need to fork and modify "real" buildpacks to implement such add-on functionality for multiple languages.

How it works

The meta-buildpack should be pushed to the top of the list of installed buildpacks in Cloud Foundry (the provided upload script places it there for you). It is thus always invoked before any other buildpack, and is able to claim the build regardless of what language the submitted source is in. The meta-buildpack will then proceed to invoke the "real" buildpacks just as they would have been without the meta-buildpack present. The language buildpack will detect and claim the build, and its compile step will produce a droplet like it normally would.

After the real buildpack runs, control passes back to the meta-buildpack, and it will then proceed to invoke "decorator" buildpacks. Decorators are installed like any other buildpack (by convention at the bottom of the list of buildpacks), but their detect scripts always return false, and they instead are identified by having a decorate script that returns true if the decorator applies. If any decorator returns true, its compile step is invoked to modify the droplet.

Unlike language buildpacks, decorators are not mutually exclusive. The meta-buildpack will invoke all decorators that return true from their decorate scripts, so any number of them can be applied to a single droplet.

If your application requires you to specify a buildpack (either in the application manifest or when you cf push), the meta-buildpack will not be invoked and thus no decorators will be invoked either. If you are developing a custom decorator buildpack, you may want to provide an alternative method for leveraging your buildpack's functionality in the case when an application requires a specific buildpack to address this limitation.

How it should work

If this functionality is deemed useful by more people than just me, it should be implemented in the Cloud Foundry cloud controller, rather than requiring a special buildpack at the top of the list. But the meta-buildpack provides access to the feature before it's implemented in the core, so that we can prove the concept and gauge its appeal to other developers. Migrating support for this feature into Cloud Foundry later should have zero effect on decorators that have already been produced.

How to install the meta-buildpack

The meta-buildpack is continuously tested against all supported versions of Pivotal Cloud Foundry. Releases of the meta-buildpack are available both as a BOSH release (a .tgz file), and as a Pivotal Cloud Foundry tile (a .pivotal file). The latest release is available here:

For developers, to install the meta-buildpack directly from your clone of this repository to the top of the buildpack list, simply run the provided build and upload scripts. You must be logged in to Cloud Foundry with a role that allows buildpack installations.

git clone https://github.com/cf-platform-eng/meta-buildpack.git
cd meta-buildpack
./build
./upload

How to write a decorator

A decorator is installed and invoked just like any other buildpack, with a couple of significant differences.

  1. To prevent the decorator from being invoked as a buildpack, its bin/detect script should always return false. Here's a sample:

    #!/usr/bin/env bash
    # bin/detect <build-dir>
    # We are a decorator, not a buildpack, so we always decline to build
    exit 1
    
  2. Instead, the real detection for a decorator is done by the bin/decorate script. The presence of this script is what enables the meta-buildpack to identify decorators:

    #!/usr/bin/env bash
    # bin/decorate <build-dir>
    
    BIN_DIR=$(cd $(dirname $0); pwd)
    ROOT_DIR=$(dirname $BIN_DIR)
    BUILD_DIR=$1
    
    # Determine if the app meets the criteria to be decorated by this decorator
    # Exit 0 if you want the decorator to run, non-zero if not
    

    Remember that the decorate script is invoked during the detect stage, so the compile step of the real buildpack has not yet been run. But the full application environment is available (including things like VCAP_SERVICES to determine what services are bound to the application).

  3. If the bin/decorate script returns true (zero), the meta-buildpack will run the bin/compile script. The environment for that script looks exactly like it would for a real buildpack, except the real buildpack has already run, so the entire droplet is already present in BUILD_DIR.

REMEMBER that any number of decorators may be invoked for the same droplet. While decorators are invoked in the order in which they are in the buildpack list, it is best to make no assumptions about the order in which yours will be invoked.

Available decorators

NOTE: Meta-buildback and the decorator pattern are being deprecated
Changes to the core CloudFoundry lifecycle process are making it hard to guarantee on-going compatibility with meta-buildpack and decorators. Some of the use cases for decorators can now be solved by leveraging the new supply buildpack functionality. The following repositories provide examples equivalent to the above, but using the new, supported, method of delivering supply buildpacks: