PagerDuty / blender

A modular orchestration engine
https://github.com/PagerDuty/blender
Other
183 stars 8 forks source link

Built on Travis

Blender

Blender is a modular remote command execution framework. Blender provides few basic primitives to automate across server workflows. Workflows can be expressed in plain ruby DSL and executed using the CLI.

Following is an example of a simple blender script that will update the package index of three ubuntu servers.

# example.rb
ssh_task 'update' do
  execute 'sudo apt-get update -y'
  members ['ubuntu01', 'ubuntu02', 'ubuntu03']
end

Which can execute it as:

blend -f example.rb

Output:

Run[example.rb] started
 3 job(s) computed using 'Default' strategy
  Job 1 [update on ubuntu01] finished
  Job 2 [update on ubuntu02] finished
  Job 3 [update on ubuntu03] finished
Run finished (42.228923876 s)

An workflow can have multiple tasks, individual tasks can have different members which can be run in parallel.

# example.rb
ssh_task 'update' do
  execute 'sudo apt-get update -y'
  members ['ubuntu01', 'ubuntu02', 'ubuntu03']
end

ssh_task 'install' do
  execute 'sudo apt-get install screen -y'
  members ['ubuntu01', 'ubuntu03']
end

concurrency 2

Output:

Run[blends/example.rb] started
 5 job(s) computed using 'Default' strategy
  Job 1 [update on ubuntu01] finished
  Job 2 [update on ubuntu02] finished
  Job 4 [install on ubuntu01] finished
  Job 3 [update on ubuntu03] finished
  Job 5 [install on ubuntu03] finished
Run finished (4.462043017 s)

Blender provides various types of task execution (like arbitrary ruby code, commands over ssh, serf handlers etc) which can ease automating large cluster maintenance, multi stage provisioning, establishing cross server feedback loops etc.

Installation

Blender is published as pd-blender in rubygems. And you can install it as:

gem install pd-blender

Or declare it as a dependency in your Gemfile, if you are using bundler.

gem 'pd-blender'

Concepts

Blender is composed of two components:

Tasks

Tasks and drivers compliment each other. Tasks act as front end, where we declare what needs to be done, while drivers are used to interpret how those tasks can be done. For example ssh_task can be used to declare tasks, while ssh and ssh_multi driver can execute ssh_tasks. Blender core ships with following tasks and drivers:

As mentioned earlier tasks are executed using drivers. Tasks can declare their preferred driver or Blender will assign a driver to them automatically. Blender will reuse the global driver if its compatible, else it will create one. By default the global_driver is a shell_out driver. Drivers can expose host concurrency, stdout/stderr streaming and various other customizations, specific to their own implementations.

Scheduling strategies

Scheduling strategies are the most crucial part of a blender script. They decide the order of command execution across distributed nodes in blender. Each blender script is invoked using one strategy. Consider them as a transformation, where the input is tasks and ouput is jobs. Tasks and job are pretty similar in their structures (both holds command and hosts), except a jobs can hold multiple tasks within them. We'll come to this later, but first, let's see how the default strategy work.

Its fairly easy to write custom scheduling strategies and they can be used to rewrite or rearrange hosts/tasks as you wish. For example, null strategy that return 0 jobs irrespective of what tasks or members you pass, or a custome strategy that takes the hosts lists of every tasks and considers only one of them dynamically based on some metrics for jobs, etc.

Host discovery

For workflows that depends on dynamic infrastructure, where host names are changing, Blender provides abstractions that facilitate discovering them. blender-chef and blender-serf uses this and allows remote job orchestration for chef or serf managed infrastructure.

Following are some examples:

Invoking blender periodially with Rufus scheduler

Blender is designed to be used as a standalone script that can be invoked on-demand or consumed as a library, i.e. workflows are written in plain Ruby objects and invoked from other tools or application. Apart from these, Blender can be use for periodic job execution also. Underneath it uses Rufus::Scheduler to trigger Blender run, after a fixed interval (can be expressed via cron syntax as well, thanks to Rufus).

Following will run example.rb blender script after every 4 hours.

  schedule '/path/to/example.rb' do
    cron '* */4 * * *'
  end

Ignore failure

Blender will fail the execution immediately if any of the job fails. ignore_failure attribute can be used to proceed execution even after failure. This can be declared both per task level as well as globally.

  shell_task 'fail' do
    command 'ls /does/not/exists'
    ignore_failure true
  end
  shell_task 'will be executed' do
    command 'echo "Thrust is what we need"'
  end

Event handlers

Blender provides an event dispatchment facility (inspired from Chef), where arbitrary logic can be hooked into the event system (e.g. HipChat notification handlers, statsd handlers, etc) and blender will automatically invoke them during key events. As of now, events are available before and after run and per job execution. Event dispatch system is likely to get more elaborate and blender might have few common event handlers (metric, notifications etc) in near future.

Ancillary projects

Blender has a few ancillary projects for integration with other systems, following are few of them:

Supported ruby versions

Blender currently support the following Ruby implementations:

License

Apache 2

Contributing

  1. Fork it ( https://github.com/PagerDuty/blender/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request