Skip to content
bluepojo edited this page Mar 22, 2013 · 18 revisions

Getting Started

Install

gem install motherbrain

Configure:

mb configure

Writing Mother Brain Plugins

MotherBrain plugins are a part of a cookbook and are distributed in the same way cookbooks are distributed. To create a new motherbrain plugin:

cd $COOKBOOK_REPO
$EDITOR ./motherbrain.rb

This is the simplest possible plugin (and where we will start building our first plugin):

component "web_server"

Congrats! You've written your first Mother Brain plugin.

Run mb plugins to see that the plugin is auto-loaded:

mb plugins

** listing local plugins...

first_app: 0.1.0

first_app is named such because the cookbook the motherbrain.rb is a part of is named first_app.

The existance of the plugin in the current directory automatically provides the mb my_app sub command:

mb first_app
using first_app (0.1.0)

Tasks:
  mb first_app help [COMMAND]     # Describe subcommands or one specific subcommand
  mb first_app nodes ENVIRONMENT  # List all nodes grouped by Component and Group
  mb first_app web_server [COMMAND]   # server component commands

This is all great, but currently our plugin doesn't do anything, nor does it know what nodes it can talk to to orchestrate.

We can fix that by fleshing out our "server" component.

Defining Components

A component is any unit of your application that must be managed independently and serves as a way to identify which nodes are required to be modified by various actions, something we identified as lacking in the previous step. For instance, in a rails application, you might have components including nginx and unicorn or a service monitor such as bluepill or upstart.

We added the component web_server to the plugin when we created it.

The next step is to tell Mother Brain how to identify nodes that contain this component:

component "web_server" do
+   description "Serves as a reverse proxy for the application process"

+   group "web_server" do
+     recipe "first_app::reverse_proxy"
+   end
+ end

In this case, we're identifying nodes via their run list, however you can also use roles or attributes or a combination of all three:

  group "web_server" do
+    role "first_app_web_server"
  end
  group "database_master" do
+    chef_attribute "first_app.db_master", true
  end

Now Mother Brain can identify nodes, time to do things with them:

The web server is a running service on the node, so tell Mother Brain that:

component "web_server" do
  description "Serves as a reverse proxy for the application process"

  group "web_server" do
    recipe "first::reverse_proxy"
  end

+  service "web_server" do
+  end
end

The web server service should be able to start, so add a start action:

component "web_server" do
  description "Serves as a reverse proxy for the application process"

  group "web_server" do
    recipe "first::reverse_proxy"
  end

  service "first" do
+    action :start do
+    end
  end
end

How you start your service is up to the specific requirements of the application, however often the logic for the service can be relegated to the cookbook in the component's node's runlist. In this case, we can set an attribute and let Chef take care of the rest in the recipes:

(While you're at it, create a stop action as well)

component "web_server" do
  description "Serves as a reverse proxy for the application process"

  group "web_server" do
    recipe "first::reverse_proxy"
  end

  service "first" do
    action :start do
+      node_attribute 'first_app.web_server.start', true
    end

+    action :stop do
+      node_attribute 'first_app.web_server.start', false
+    end
  end
end

Now create commands on the component to control this service so we can trigger starts and stops from the command line:

component "web_server" do
  description "Serves as a reverse proxy for the application process"

  group "web_server" do
    recipe "first::reverse_proxy"
  end

  service "first" do
    action :start do
      node_attribute 'first_app.web_server.start', true
    end

    action :stop do
      node_attribute 'first_app.web_server.start', false
    end
  end

+  command "start" do
+    description "Start the web server"
+    execute do
+      on("web_server") do
+        service("first").run(:start)
+      end
+    end
+  end

+  command "stop" do
+    description "Stop the web server"
+    execute do
+      on("web_server") do
+        service("first").run(:stop)
+      end
+    end
+  end
end

That's it, check it out:

# Note that the output here is bugged. See: https://github.com/RiotGames/motherbrain/issues/33
# This is the corrected output:
$ mb first_app web_server
Tasks:
  mb first_app web_server help [COMMAND]     # Describe subcommands or one specific subcommand
  mb first_app web_server nodes ENVIRONMENT  # List all nodes grouped by Group
  mb first_app web_server start ENVIRONMENT  # Start the web server
  mb first_app web_server stop ENVIRONMENT   # Start the web server

Now we can start and stop our web_server with the following commands:

$ mb first_app web_server start
$ mb first_app web_server stop

Nice!

Up next:

Clone this wiki locally