Stack Configurations

Examples

Examples of Bang config files are available with the source code:

Config File Structure

The configuration file is a YAML document. Like a play in an Ansible playbook, the outermost data structure is a YAML mapping.

Like Python, blocks/sections/stanzas in a Bang config file are visually defined by indentation level. Each top-level section name is a key in the outermost mapping structure.

There are some reserved Top-Level Keys that have special meaning in Bang and there is an implicit, broader grouping of these top-level keys/sections. The broader groups are:

Any string that is a valid YAML identifier and is not a reserved top-level key is available for use as a custom configuration scope. It is up to the user to avoid name collisions between keys, especially between reserved keys and custom configuration scope keys.

Top-Level Keys

General Stack Properties

The attributes in this section apply to the entire stack.

The following top-level section names are reserved:

name
This is the unique stack name. E.g. myblog-prod, myblog-staging, monitoring, etc...
version
The overall stack version. A stack may be made up of many components each with their own release cycle and versioning scheme. This version could be used as the umbrella version for an entire product/project release.
logging
Contains configuration values for Bang’s logging.
deployer_credentials
See bang.providers.hpcloud.HPCloud.authenticate()
playbooks
A list of playbook filenames to execute.

Stack Resource Definitions

These configuration stanzas describe the building blocks for a project. Examples of stack resources include:

  • Cloud resources

    • Virtual servers
    • Load balancers
    • Firewalls and/or security groups
    • Object storage
    • Block storage
    • Message queues
    • Managed databases
  • Traditional server room/data center resources

    • Physical or virtual servers
    • Load balancers
    • Firewalls

Users can use Bang to manage stacks that span across traditional and cloud boundaries. For example, a single stack might comprise:

  • Legacy database servers in a datacenter
  • Web application servers in an OpenStack public cloud
  • Message queues and object storage from AWS (i.e. SQS)

Every stack resource key maps to a dictionary for that particular resource type, where the keys are resource names. Each value of the dictionary is a key-value map of attributes. Most attributes are specific to the type of resource being deployed.

Every cloud resource definition must contain a provider key whose value is the name of a Bang-supported cloud provider.

Server definitions that do not contain a provider key are assumed to be already provisioned. Instead of a set of cloud server attributes, these definitions merely contain hostname values and the appropriate configuration scopes.

The reserved stack resource keys are described below:

queues
E.g. SQS
buckets
E.g. S3, OpenStack Swift
databases
E.g. RDS, OpenStack RedDwarf
server_security_groups
E.g. EC2 and OpenStack Nova security groups
servers
E.g. EC2, OpenStack Nova, VPS virtual machines.
load_balancers:
E.g. ElasticLoadBalancer, HP cloud LBaaS

Configuration Scopes

Configuration scopes typically define high-level attributes and values that you might want to alter between instantiations of a stack. For example, a blog stack might be made up of some frontend load balancers running haproxy 1.4 that distribute requests to an array of web app servers running version 1.1 of your custom application called my_blog_app. The production Bang config would have config scopes like this:

my_blog_app:
  version: '1.1'

haproxy:
  version: '1.4'

You would reuse the same infrastructure configuration and set of Ansible playbooks to stand up a QA or development stack. When you release version 1.2 of my_blog_app you just adjust the value in the config scope like this:

my_blog_app:
  version: '1.2'

haproxy:
  version: '1.4'

In this example, if you then wanted to test out haproxy 1.5, the config scopes would look like this:

my_blog_app:
  version: '1.2'

haproxy:
  version: '1.5'

Config scopes can be used for more than just component versions. When deciding what attributes to put in config scopes and what attributes to put into your Ansible variables, consider that Bang config scopes are ideal for values that you might vary per environment or per iteration of an environment.

Since the Bang config files and all of the associated playbooks are just text files, they can be managed the same way you manage your code in a revision control system. You can branch, merge, and tag the same way you do with your application code. With the right tags, it’s trivial to compare the config scope values that are in production with those that are in your QA or development environments.

Reusable Definition

Any top-level section name that is not specified above as a reserved key in General Stack Properties or in Stack Resource Definitions, is parsed and categorized as a custom configuration scope. For example, a media transcoding web service might have the following config scopes:

apache:
  preforks: 4
  modules:
  - rewrite
  - wsgi

my_web_frontend:
  version: '1.2.0'
  log_level: WARN

my_transcoder_app:
  version: '1.1.5'
  log_level: INFO
  src_types:
  - h.264+aac
  - theora+vorbis

The key names and the values are arbitrary and defined solely by the user.

When running the on-server configuration phase of a Bang run, Bang uses the config_scopes in a server definition to determine what to pass to Ansible as inventory variables for a particular host. To refer to a top-level, reusable config scope in a server definition, list its name like this:

# Config Scopes
# -------------
apache:
  preforks: 4
  modules:
  - rewrite
  - wsgi

my_web_frontend:
  version: '1.2.0'
  log_level: WARN


# Resource Definitions
# --------------------
servers:
  web_server:
    # other server attributes go here
    config_scopes:
    - apache
    - my_web_frontend

When Ansible runs on the web_server hosts, the following references to the config scope variables will be evaluated to their associated values:

{{apache.preforks}}          <-- evaluates to 4
{{my_web_frontend.version}}  <-- evaluates to 1.2.0

Inline Definition

In addition to the top-level definitions, config scopes for a server may be defined inline. This is mainly useful for simple stacks where reusing config scopes might not be needed. For example:

webapp:
  port: 8001
  app_dir: /opt/foo/app

reverse_proxy:
  server_name: newapp.company.com

servers:
  blah:
    config_scopes:
    - webapp
    - reverse_proxy
    - this: is
      a_config_scope: defined
      inline: yo

The config scopes above would make the following inventory variables available to Ansible:

{
    'webapp': {
        'port': 8001,
        'app_dir': '/opt/foo/app',
        },

    'reverse_proxy': {
        'server_name': 'huismans.kief.io',
        },

    'this': 'is',

    'a_config_scope': 'defined',

    'inline': 'yo',
}

Which would let you use any of the following in playbooks and templates:

{{webapp.port}}
{{reverse_proxy.server_name}}
{{this}}
{{a_config_scope}}
{{inline}]

Navigation