Browse Source

First commit

master
Erik Hollensbe 10 years ago
commit
7946b8f239
  1. 72
      README.md
  2. 1
      attributes/default.rb
  3. 67
      files/default/unicorn_rack
  4. 13
      metadata.rb
  5. 37
      recipes/default.rb

72
README.md

@ -0,0 +1,72 @@
unicorn2: Control processes running the unicorn server software
--------------------------------------------------------------------------------
One recipe at this time -- unicorn::default. This recipe:
* installs a `unicorn_rack` service meant to manage several unicorn services
(see more below)
* configures any hosts in the `/etc/default/unicorn.json` file from databags
(see examples) and node configuration.
* restarts the service if the above has changed in any way.
The `unicorn_rack` script
--------------------------------------------------------------------------------
This script lives in `/etc/init.d/unicorn_rack`, and is installed as service.
The script itself takes two arguments: the directive (stop, start, restart,
reload) and the name of the app. **If the name of the app is omitted all apps
will recieve the actions taken for the directive.**
databags and the `unicorn.json` file
--------------------------------------------------------------------------------
The `unicorn.json` file is generated by the recipe, and looks a bit like this:
{
"/www/stuff": {
"config_path": "/www/stuff/config/unicorn.rb",
"bin": "unicorn_rails"
},
"/www/jsonip": {
"config_path": "/www/jsonip/config/unicorn.rb",
"bin": "unicorn"
}
}
The key is the path to the application, it will be started from that directory.
Databags and node configuration are used to generate this file. Instead of
mimicing the structure for the init script, we've provided something a little
more streamlined:
{
"id": "jsonip",
"path": "/www/jsonip",
"bin": "unicorn",
"config_path": "/www/jsonip/config/unicorn.rb",
"hosts": [ "coffee" ]
}
Where `hosts` is an array of node names, and the path is the key of the data
structure above. Note that node configuration looks exactly the same and the
key for the node and the databag name searched are both `applications`.
User accounts (aka BUGS)
--------------------------------------------------------------------------------
Currently the recipes expect a `rails` user and group to exist. **It does not
create it**. This will be rectified in the future, and the author is happy to
accept pull requests that do so.
Contributing
--------------------------------------------------------------------------------
* Fork the project
* Make your edits
* Be sure to not change anything in metadata.rb without prior permission.
* Send a pull request.
Author
--------------------------------------------------------------------------------
Erik Hollensbe <erik+chef@hollensbe.org>

1
attributes/default.rb

@ -0,0 +1 @@
default["applications"] = []

67
files/default/unicorn_rack

@ -0,0 +1,67 @@
#!/usr/bin/env ruby
require 'sys/proctable'
require 'etc'
require 'json'
$0 = File.expand_path($0)
ENV["PATH"] = "/usr/local/bin:/usr/local/bin:#{ENV["PATH"]}"
def get_apps
JSON.load(File.read("/etc/default/unicorn.json"))
end
pids = Sys::ProcTable.ps.select { |x| x.cmdline =~ /^unicorn/ && x.ppid == 1 }
app = ARGV[1]
if app
pid = pids.find { |x| x.cmdline =~ /#{Regexp.quote app}/ }
if pid
pids = [pid]
else
pids = []
end
end
case ARGV[0]
when "restart"
system("#{Gem.ruby} #{$0} stop #{app}")
system("#{Gem.ruby} #{$0} start #{app}")
when "reload"
pids.each do |pid|
puts "reloading '#{pid.cmdline}'"
Process.kill(:USR2, pid.pid)
sleep 1
Process.kill(:QUIT, pid.pid)
end
when "start"
apps = get_apps
if app
apps = { app => apps[app] }
end
unless apps.keys.size > 0
raise ArgumentError, "Could not find any applications; aborting"
end
apps.each do |key, value|
puts "Attempting to start '#{key}'"
fork do
user = Etc.getpwnam("rails")
Process.uid = user.uid
Process.gid = user.gid
Process.euid = user.uid
Process.egid = user.gid
Dir.chdir(key) do
exec("bundle exec '#{value["bin"]}' -c '#{value["config_path"]}' -E production -D")
end
end
end
when "stop"
pids.each do |pid|
puts "stopping '#{pid.cmdline}'"
Process.kill(:INT, pid.pid)
end
end

13
metadata.rb

@ -0,0 +1,13 @@
maintainer "Erik Hollensbe"
maintainer_email "erik+chef@hollensbe.org"
license "Apache 2.0"
description "Maintain applications running the unicorn server software"
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version "0.1.0"
recipe "unicorn::default",
"Installs the unicorn_rack service and any applications definitions for the host"
%w{ debian ubuntu }.each do |os|
supports os
end

37
recipes/default.rb

@ -0,0 +1,37 @@
require 'yajl'
gem_package "sys-proctable" do
action :install
end
cookbook_file "/etc/init.d/unicorn_rack" do
source 'unicorn_rack'
mode 00750
owner "root"
group "root"
end
service "unicorn_rack" do
supports [:restart, :reload]
action :enable
end
host_applications = { }
filter_proc = proc do |x|
host_applications[x['path']] = {
"config_path" => x['config_path'],
"bin" => x['bin']
}
end
search('applications', "hosts:#{node.name}").each(&filter_proc)
node["applications"].each(&filter_proc)
file "/etc/default/unicorn.json" do
content Yajl.dump(host_applications, :pretty => true)
mode 00640
owner "root"
group "root"
notifies :restart, "service[unicorn_rack]"
end
Loading…
Cancel
Save