Stack Configurations ==================== Examples -------- Examples of Bang config files are available with the source code: https://github.com/fr33jc/bang/tree/master/examples 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: - `General Stack Properties`_ - `Configuration Scopes`_ - `Stack Resource Definitions`_ 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 :meth:`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: .. code-block:: yaml 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: .. code-block:: yaml 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: .. code-block:: yaml 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: .. code-block:: yaml 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: .. code-block:: yaml # 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: .. code-block:: jinja {{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: .. code-block:: yaml 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: .. code-block:: python { '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: .. code-block:: jinja {{webapp.port}} {{reverse_proxy.server_name}} {{this}} {{a_config_scope}} {{inline}]