├── .gitignore ├── .travis.yml ├── Berksfile ├── Changelog ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── attributes ├── default.rb ├── postgres.rb └── unicorn.rb ├── definitions └── monitrc.rb ├── files ├── debian-6 │ └── monit.default ├── debian │ └── monit.default ├── default │ └── init-monit-ubuntu12.sh ├── ubuntu-12.04 │ └── monit.default └── ubuntu │ └── monit.default ├── metadata.rb ├── recipes ├── default.rb ├── postfix.rb ├── postgresql.rb ├── rabbitmq.rb ├── resque.rb ├── resque_scheduler.rb ├── ssh.rb ├── ubuntu12fix.rb └── unicorn.rb ├── spec ├── spec_helper.rb └── unit │ └── recipes │ ├── default_spec.rb │ ├── postfix_spec.rb │ ├── postgres_spec.rb │ ├── resque_scheduler_spec.rb │ ├── resque_spec.rb │ ├── ubuntu12fix_spec.rb │ └── unicorn_spec.rb └── templates └── default ├── monitrc.erb ├── postfix.conf.erb ├── postgresql.conf.erb ├── rabbitmq.conf.erb ├── resque.conf.erb ├── resque_scheduler.conf.erb ├── ssh.conf.erb └── unicorn.conf.erb /.gitignore: -------------------------------------------------------------------------------- 1 | tmp/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 1.9.3 4 | - 2.0.0 5 | - 2.1.3 6 | script: bundle exec rake foodcritic 7 | -------------------------------------------------------------------------------- /Berksfile: -------------------------------------------------------------------------------- 1 | site :opscode 2 | 3 | metadata 4 | -------------------------------------------------------------------------------- /Changelog: -------------------------------------------------------------------------------- 1 | 0.7.5 2 | 72eaa42 update rspec 3 | 46e8a4a Add one more condition to contribution - make sure PR is safe to merge 4 | 645954f bump version in metadata.rb per Issue #60. Delete unmaintained History - to be replaced by Changelog or similar 5 | 009098f Removed 2nd line 6 | 20e7ad1 Add basic guidelines for submitting changes / PRs 7 | ca206d4 Add 'using hostname' test per PR #36 8 | d81f164 Manually backport changes in PR #36 9 | 798971c parameterize postgres, add attributes and add basic test for postgres monit file. Addresses issue #53 10 | d1af7b3 only configure outbound mail if notify_email is set, captures spirit of PR #46 11 | e9c405a Delete test/Gemfile to avoid having to keep the 2 Gemfiles in sync 12 | d290631 Merge pull request #30 from Lytro/resque 13 | d4eb885 support monit for resque workers and resque schedulers 14 | 7c0c2d7 Merge pull request #20 from Lytro/make_email_alerts_optional 15 | 65bf8eb don't set email alerts if node[:monit][:notify_email] is nil (defaults to nil) 16 | e0bc91e Add chef-spec to Rakefile so specs/tests are run during CI. Concerns #59 17 | f2adafc Merge pull request #59 from Lytro/fix_specs 18 | 58b872b fix the specs 19 | 6e47cfd Add Travis build status to project page. Closes #58 20 | ac1922e Travis config: exlude LWRP suggestion from foodcritic, Bump version of foodcritic to 4.0.0, Delete link to RDOC, Cleanup foodcriti 21 | 94b6958 Adding default file for debian systems. Two versions of file to support older Debian 6 releases and current Debian 7 (wheezy) rele 22 | fa5f017 set default alert blacklist 23 | 68a9e24 Merge pull request #45 from wadtech/master 24 | ca8ecf6 Merge pull request #51 from engineyard-cookbooks/disable-with-custom-template 25 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gem "chef", '>0.10' 4 | 5 | gem "foodcritic" 6 | gem "chefspec" 7 | gem "knife-spec" 8 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | chef (11.8.2) 5 | chef-zero (~> 1.6, >= 1.6.2) 6 | diff-lcs (~> 1.2, >= 1.2.4) 7 | erubis (~> 2.7) 8 | highline (~> 1.6, >= 1.6.9) 9 | json (>= 1.4.4, <= 1.7.7) 10 | mime-types (~> 1.16) 11 | mixlib-authentication (~> 1.3) 12 | mixlib-cli (~> 1.3) 13 | mixlib-config (~> 2.0) 14 | mixlib-log (~> 1.3) 15 | mixlib-shellout (~> 1.2) 16 | net-ssh (~> 2.6) 17 | net-ssh-multi (~> 1.1.0) 18 | ohai (~> 6.0) 19 | pry (~> 0.9) 20 | puma (~> 1.6) 21 | rest-client (>= 1.0.4, < 1.7.0) 22 | yajl-ruby (~> 1.1) 23 | chef-zero (1.7.2) 24 | hashie (~> 2.0) 25 | json 26 | mixlib-log (~> 1.3) 27 | moneta (< 0.7.0) 28 | rack 29 | chefspec (3.0.2) 30 | chef (~> 11.0) 31 | fauxhai (~> 2.0) 32 | rspec (~> 2.14) 33 | coderay (1.1.0) 34 | diff-lcs (1.2.5) 35 | erubis (2.7.0) 36 | fauxhai (2.0.0) 37 | net-ssh 38 | ohai 39 | foodcritic (4.0.0) 40 | erubis 41 | gherkin (~> 2.11) 42 | nokogiri (~> 1.5) 43 | rake 44 | rufus-lru (~> 1.0) 45 | treetop (~> 1.4) 46 | yajl-ruby (~> 1.1) 47 | gherkin (2.12.2) 48 | multi_json (~> 1.3) 49 | hashie (2.0.5) 50 | highline (1.6.20) 51 | ipaddress (0.8.0) 52 | json (1.7.7) 53 | knife-spec (1.0.0) 54 | chef 55 | method_source (0.8.2) 56 | mime-types (1.25.1) 57 | mini_portile (0.6.0) 58 | mixlib-authentication (1.3.0) 59 | mixlib-log 60 | mixlib-cli (1.3.0) 61 | mixlib-config (2.0.0) 62 | mixlib-log (1.6.0) 63 | mixlib-shellout (1.3.0) 64 | moneta (0.6.0) 65 | multi_json (1.10.1) 66 | net-ssh (2.7.0) 67 | net-ssh-gateway (1.2.0) 68 | net-ssh (>= 2.6.5) 69 | net-ssh-multi (1.1) 70 | net-ssh (>= 2.1.4) 71 | net-ssh-gateway (>= 0.99.0) 72 | nokogiri (1.6.3.1) 73 | mini_portile (= 0.6.0) 74 | ohai (6.20.0) 75 | ipaddress 76 | mixlib-cli 77 | mixlib-config 78 | mixlib-log 79 | mixlib-shellout 80 | systemu (~> 2.5.2) 81 | yajl-ruby 82 | polyglot (0.3.5) 83 | pry (0.9.12.4) 84 | coderay (~> 1.0) 85 | method_source (~> 0.8) 86 | slop (~> 3.4) 87 | puma (1.6.3) 88 | rack (~> 1.2) 89 | rack (1.5.2) 90 | rake (10.3.2) 91 | rest-client (1.6.7) 92 | mime-types (>= 1.16) 93 | rspec (2.99.0) 94 | rspec-core (~> 2.99.0) 95 | rspec-expectations (~> 2.99.0) 96 | rspec-mocks (~> 2.99.0) 97 | rspec-core (2.99.2) 98 | rspec-expectations (2.99.2) 99 | diff-lcs (>= 1.1.3, < 2.0) 100 | rspec-mocks (2.99.2) 101 | rufus-lru (1.0.5) 102 | slop (3.4.7) 103 | systemu (2.5.2) 104 | treetop (1.5.3) 105 | polyglot (~> 0.3) 106 | yajl-ruby (1.2.1) 107 | 108 | PLATFORMS 109 | ruby 110 | 111 | DEPENDENCIES 112 | chef (> 0.10) 113 | chefspec 114 | foodcritic 115 | knife-spec 116 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overview # 2 | Chef cookbook for the [monit](http://mmonit.com/monit/) monitoring and 3 | management tool. 4 | 5 | [![Build Status](https://travis-ci.org/apsoto/monit.svg?branch=master)](https://travis-ci.org/apsoto/monit) 6 | 7 | # Submitting a change # 8 | * Make sure your code follows existing conventions 9 | * Squash your PR into a single commit 10 | * Rebase onto master if needed 11 | * Add Chefspec test 12 | * Make sure foodcritic is happy 13 | * Make sure your PR is marked as "safe to merge" 14 | 15 | # Changelog # 16 | [Changelog](https://github.com/apsoto/monit/blob/master/Changelog) 17 | 18 | # How to add to your cookbook repository # 19 | 20 | ## Download the tarball ## 21 | It's up on the opscode 22 | [cookbook community](http://community.opscode.com/cookbooks/monit) site. 23 | 24 | ## Vendor via knife ## 25 | 26 | $ knife cookbook site download monit 27 | 28 | ## Track upstream changes via git ## 29 | I use git submodules for my chef repos so I can push/pull changes with minimal 30 | hassle. 31 | 32 | For more info, check out the [Pro Git](http://progit.org/book/ch6-6.html) book. 33 | 34 | #### Add the monit repo #### 35 | 36 | $ cd YOUR_REPO_ROOT 37 | $ git submodule add git://github.com/apsoto/monit.git cookbooks/monit 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | 3 | desc "Runs foodcritic linter" 4 | task :foodcritic do 5 | if Gem::Version.new("1.9.2") <= Gem::Version.new(RUBY_VERSION.dup) 6 | sandbox = File.join(File.dirname(__FILE__), %w{tmp foodcritic cookbook}) 7 | prepare_foodcritic_sandbox(sandbox) 8 | 9 | sh "foodcritic -f any -t ~FC015 #{File.dirname(sandbox)}" 10 | else 11 | puts "WARN: foodcritic run is skipped as Ruby #{RUBY_VERSION} is < 1.9.2." 12 | end 13 | end 14 | 15 | desc "Run spec/chefspec" 16 | task :chef_spec do 17 | sh "bundle exec rspec" 18 | end 19 | 20 | task :default => [:foodcritic, :chef_spec] 21 | 22 | private 23 | 24 | def prepare_foodcritic_sandbox(sandbox) 25 | files = %w{*.md *.rb attributes definitions files libraries providers 26 | recipes resources templates} 27 | 28 | rm_rf sandbox 29 | mkdir_p sandbox 30 | cp_r Dir.glob("{#{files.join(',')}}"), sandbox 31 | puts "\n\n" 32 | end 33 | -------------------------------------------------------------------------------- /attributes/default.rb: -------------------------------------------------------------------------------- 1 | default["monit"]["notify_email"] = nil 2 | default["monit"]["alert_blacklist"] = %w( action instance pid ppid ) 3 | 4 | default["monit"]["logfile"] = 'syslog facility log_daemon' 5 | 6 | default["monit"]["poll_period"] = 60 7 | default["monit"]["poll_start_delay"] = 120 8 | 9 | default["monit"]["mail_format"]["subject"] = "$SERVICE $EVENT" 10 | default["monit"]["mail_format"]["from"] = "monit@#{node['fqdn']}" 11 | default["monit"]["mail_format"]["message"] = <<-EOS 12 | Monit $ACTION $SERVICE at $DATE on $HOST: $DESCRIPTION. 13 | Yours sincerely, 14 | monit 15 | EOS 16 | 17 | default["monit"]["mailserver"]["host"] = "localhost" 18 | default["monit"]["mailserver"]["hostname"] = nil 19 | default["monit"]["mailserver"]["port"] = nil 20 | default["monit"]["mailserver"]["username"] = nil 21 | default["monit"]["mailserver"]["password"] = nil 22 | default["monit"]["mailserver"]["password_suffix"] = nil 23 | default["monit"]["mailserver"]["encryption"] = nil 24 | default["monit"]["mailserver"]["timeout"] = 60 25 | 26 | default["monit"]["port"] = 3737 27 | default["monit"]["address"] = nil 28 | default["monit"]["ssl"] = false 29 | default["monit"]["cert"] = "/etc/monit/monit.pem" 30 | default["monit"]["allow"] = [] 31 | default["monit"]["username"] = nil 32 | default["monit"]["password"] = nil 33 | default["monit"]["ssh_port"] = 22 34 | 35 | default["monit"]["eventqueue"]["set"] = true 36 | default["monit"]["eventqueue"]["basedir"] = "/var/monit" 37 | default["monit"]["eventqueue"]["slots"] = 1000 38 | -------------------------------------------------------------------------------- /attributes/postgres.rb: -------------------------------------------------------------------------------- 1 | default["monit"]["postgres"]["pid_file"] = '/var/run/postgresql/9.1-main.pid' 2 | default["monit"]["postgres"]["unix_socket_path"] = '/var/run/postgresql/.s.PGSQL' 3 | default["monit"]["postgres"]["port"] = 5432 4 | -------------------------------------------------------------------------------- /attributes/unicorn.rb: -------------------------------------------------------------------------------- 1 | default["monit"]["unicorn"]["pid_dir"] = '/path/to/pids' 2 | default["monit"]["unicorn"]["worker_count"] = 1 3 | -------------------------------------------------------------------------------- /definitions/monitrc.rb: -------------------------------------------------------------------------------- 1 | # reload: Reload monit so it notices the new service. :delayed (default) or :immediately. 2 | # action: :enable To create the monitoring config (default), or :disable to remove it. 3 | # variables: Hash of instance variables to pass to the ERB template 4 | # template_cookbook: the cookbook in which the configuration resides 5 | # template_source: filename of the ERB configuration template, defaults to .conf.erb 6 | define :monitrc, :action => :enable, :reload => :delayed, :variables => {}, :template_cookbook => "monit", :template_source => nil do 7 | params[:template_source] ||= "#{params[:name]}.conf.erb" 8 | if params[:action] == :enable 9 | template "/etc/monit/conf.d/#{params[:name]}.conf" do 10 | owner "root" 11 | group "root" 12 | mode 0644 13 | source params[:template_source] 14 | cookbook params[:template_cookbook] 15 | variables params[:variables] 16 | notifies :restart, "service[monit]", params[:reload] 17 | action :create 18 | end 19 | else 20 | file "/etc/monit/conf.d/#{params[:name]}.conf" do 21 | action :delete 22 | notifies :restart, "service[monit]", params[:reload] 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /files/debian-6/monit.default: -------------------------------------------------------------------------------- 1 | # Defaults for monit initscript 2 | # sourced by /etc/init.d/monit 3 | # installed at /etc/default/monit by chef 4 | 5 | # You must set this variable to for monit to start 6 | startup=1 7 | 8 | # To change the intervals which monit should run, 9 | # edit the configuration file /etc/monit/monitrc 10 | # It can no longer be configured here. 11 | 12 | -------------------------------------------------------------------------------- /files/debian/monit.default: -------------------------------------------------------------------------------- 1 | # Defaults for monit initscript 2 | # sourced by /etc/init.d/monit 3 | # installed at /etc/default/monit by chef 4 | 5 | # You must set this variable to for monit to start 6 | START=yes 7 | 8 | # To change the intervals which monit should run, 9 | # edit the configuration file /etc/monit/monitrc 10 | # It can no longer be configured here. 11 | 12 | -------------------------------------------------------------------------------- /files/default/init-monit-ubuntu12.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ### BEGIN INIT INFO 4 | # Provides: monit 5 | # Required-Start: $remote_fs 6 | # Required-Stop: $remote_fs 7 | # Should-Start: $all 8 | # Should-Stop: $all 9 | # Default-Start: 2 3 4 5 10 | # Default-Stop: 0 1 6 11 | # Short-Description: service and resource monitoring daemon 12 | # Description: monit is a utility for managing and monitoring 13 | # processes, programs, files, directories and filesystems 14 | # on a Unix system. Monit conducts automatic maintenance 15 | # and repair and can execute meaningful causal actions 16 | # in error situations. 17 | ### END INIT INFO 18 | 19 | set -e 20 | 21 | . /lib/lsb/init-functions 22 | 23 | DAEMON=/usr/bin/monit 24 | CONFIG="/etc/monit/monitrc" 25 | DELAY="/etc/monit/monit_delay" 26 | NAME=monit 27 | DESC="daemon monitor" 28 | MONIT_OPTS= 29 | PID="/var/run/$NAME.pid" 30 | 31 | # Check if DAEMON binary exist 32 | [ -f $DAEMON ] || exit 0 33 | 34 | [ -f "/etc/default/$NAME" ] && . /etc/default/$NAME 35 | 36 | # For backward compatibility, handle startup variable: 37 | if [ -n "$startup" ] 38 | then 39 | if [ "$1" = "start" ] 40 | then 41 | printf "\tPlease, use START variable in /etc/default/monit\n" 42 | printf "\tto enable/disable $NAME startup.\n" 43 | fi 44 | 45 | if [ -z "$START" ] && [ "$startup" -eq 1 ] 46 | then 47 | START="yes" 48 | fi 49 | fi 50 | 51 | # For backward compatibility, handle CHECK_INTERVALS variable: 52 | if [ -n "$CHECK_INTERVALS" ] 53 | then 54 | if [ "$1" = "start" ] 55 | then 56 | printf "\tPlease, use MONIT_OPTS variable in /etc/default/monit\n" 57 | printf "\tto specify command line options for $NAME.\n" 58 | fi 59 | 60 | MONIT_OPTS="$MONIT_OPTS -d $CHECK_INTERVALS" 61 | fi 62 | 63 | MONIT_OPTS="-c $CONFIG $MONIT_OPTS" 64 | 65 | monit_not_configured () { 66 | if [ "$1" != "stop" ] 67 | then 68 | printf "\tplease configure $NAME and then edit /etc/default/$NAME\n" 69 | printf "\tand set the \"START\" variable to \"yes\" in order to allow\n" 70 | printf "\t$NAME to start\n" 71 | fi 72 | exit 0 73 | } 74 | 75 | monit_check_config () { 76 | # Check for emtpy config. 77 | if [ "`grep -s -v \"^#\" $CONFIG`" = "" ] 78 | then 79 | echo "empty config, please edit $CONFIG." 80 | exit 0 81 | fi 82 | } 83 | 84 | monit_check_perms () { 85 | # Check the permission on configfile. 86 | # The permission must not have more than -rwx------ (0700) permissions. 87 | 88 | # Skip checking, fix perms instead. 89 | /bin/chmod go-rwx $CONFIG 90 | } 91 | 92 | monit_delayed_monitoring () { 93 | if [ -f $DELAY ] 94 | then 95 | printf "Warning: Please, set start delay for $NAME in config file\n" 96 | printf " and delete $DELAY file.\n" 97 | 98 | if [ ! -x $DELAY ] 99 | then 100 | printf "Warning: A delayed start file exists ($DELAY)\n" 101 | printf " but it is not executable.\n" 102 | else 103 | $DELAY & 104 | fi 105 | fi 106 | } 107 | 108 | monit_checks () { 109 | # Check if START variable is set to "yes", if not we exit. 110 | if [ "$START" != "yes" ] 111 | then 112 | monit_not_configured $1 113 | fi 114 | # Check for emtpy configfile 115 | monit_check_config 116 | # Check permissions of configfile 117 | monit_check_perms 118 | } 119 | 120 | case "$1" in 121 | start) 122 | log_daemon_msg "Starting $DESC" "$NAME" 123 | monit_checks $1 124 | if start-stop-daemon --start --quiet --oknodo \ 125 | --pidfile $PID --exec $DAEMON \ 126 | -- $MONIT_OPTS 127 | then 128 | log_end_msg 0 129 | else 130 | log_end_msg 1 131 | fi 132 | monit_delayed_monitoring 133 | ;; 134 | stop) 135 | log_daemon_msg "Stopping $DESC" "$NAME" 136 | if start-stop-daemon --retry TERM/5/KILL/5 --oknodo --stop --quiet \ 137 | --pidfile $PID --exec $DAEMON 138 | then 139 | log_end_msg 0 140 | else 141 | log_end_msg 1 142 | fi 143 | ;; 144 | reload) 145 | log_daemon_msg "Reloading $DESC configuration" "$NAME" 146 | if start-stop-daemon --stop --signal HUP --quiet \ 147 | --oknodo --pidfile $PID \ 148 | --exec $DAEMON -- $MONIT_OPTS 149 | then 150 | log_end_msg 0 151 | else 152 | log_end_msg 1 153 | fi 154 | ;; 155 | restart|force-reload) 156 | $0 stop 157 | $0 start 158 | ;; 159 | syntax) 160 | $DAEMON $MONIT_OPTS -t 161 | ;; 162 | status) 163 | status_of_proc -p $PID $DAEMON $NAME 164 | ;; 165 | *) 166 | log_action_msg "Usage: /etc/init.d/$NAME {start|stop|reload|restart|force-reload|syntax|status}" 167 | ;; 168 | esac 169 | 170 | exit 0 -------------------------------------------------------------------------------- /files/ubuntu-12.04/monit.default: -------------------------------------------------------------------------------- 1 | # Defaults for monit initscript 2 | # sourced by /etc/init.d/monit 3 | # installed at /etc/default/monit by chef 4 | 5 | # You must set this variable to for monit to start 6 | startup=1 7 | 8 | # To change the intervals which monit should run, 9 | # edit the configuration file /etc/monit/monitrc 10 | # It can no longer be configured here. 11 | 12 | -------------------------------------------------------------------------------- /files/ubuntu/monit.default: -------------------------------------------------------------------------------- 1 | # Defaults for monit initscript 2 | # sourced by /etc/init.d/monit 3 | # installed at /etc/default/monit by chef 4 | 5 | # You must set this variable to for monit to start 6 | START=yes 7 | 8 | # To change the intervals which monit should run, 9 | # edit the configuration file /etc/monit/monitrc 10 | # It can no longer be configured here. 11 | 12 | -------------------------------------------------------------------------------- /metadata.rb: -------------------------------------------------------------------------------- 1 | name "monit" 2 | maintainer "Alex Soto" 3 | maintainer_email "apsoto@gmail.com" 4 | license "MIT" 5 | description "Configures monit. Originally based off the 37 Signals Cookbook." 6 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) 7 | version "0.7.5" 8 | 9 | 10 | attribute 'monit/notify_email', 11 | :description => 'The email address to send alerts to.', 12 | :type => "string", 13 | :required => "recommended" 14 | 15 | attribute 'monit/poll_period', 16 | :description => 'How often to perform checks (in seconds)', 17 | :type => "string", 18 | :required => "recommended" 19 | 20 | attribute 'monit/poll_start_delay', 21 | :description => 'When monit first starts, how long to delay before it starts performing checks', 22 | :type => "string", 23 | :required => "recommended" 24 | 25 | -------------------------------------------------------------------------------- /recipes/default.rb: -------------------------------------------------------------------------------- 1 | package "monit" 2 | 3 | cookbook_file "/etc/default/monit" do 4 | source "monit.default" 5 | owner "root" 6 | group "root" 7 | mode 0644 8 | only_if { platform?("ubuntu") || platform?("debian") } 9 | end 10 | 11 | 12 | directory "/etc/monit/conf.d/" do 13 | owner 'root' 14 | group 'root' 15 | mode 0755 16 | action :create 17 | recursive true 18 | end 19 | 20 | template "/etc/monit/monitrc" do 21 | owner "root" 22 | group "root" 23 | mode 0700 24 | source 'monitrc.erb' 25 | notifies :restart, "service[monit]", :delayed 26 | end 27 | 28 | service "monit" do 29 | action [:enable, :start] 30 | supports [:start, :restart, :stop] 31 | end 32 | -------------------------------------------------------------------------------- /recipes/postfix.rb: -------------------------------------------------------------------------------- 1 | include_recipe "monit" 2 | 3 | monitrc "postfix" 4 | -------------------------------------------------------------------------------- /recipes/postgresql.rb: -------------------------------------------------------------------------------- 1 | include_recipe "monit" 2 | 3 | monitrc "postgresql" 4 | -------------------------------------------------------------------------------- /recipes/rabbitmq.rb: -------------------------------------------------------------------------------- 1 | include_recipe "monit" 2 | 3 | monitrc "rabbitmq" 4 | -------------------------------------------------------------------------------- /recipes/resque.rb: -------------------------------------------------------------------------------- 1 | include_recipe "monit" 2 | 3 | node['monit']['resque']['queues'].each do |queue| 4 | if queue['worker_count'] <= 0 5 | raise ArgumentError, 'The number of workers for a given queue must be a positive integer.' 6 | end 7 | end 8 | 9 | monitrc "resque" 10 | -------------------------------------------------------------------------------- /recipes/resque_scheduler.rb: -------------------------------------------------------------------------------- 1 | include_recipe "monit" 2 | 3 | monitrc "resque_scheduler" 4 | -------------------------------------------------------------------------------- /recipes/ssh.rb: -------------------------------------------------------------------------------- 1 | include_recipe "monit" 2 | 3 | monitrc "ssh" 4 | -------------------------------------------------------------------------------- /recipes/ubuntu12fix.rb: -------------------------------------------------------------------------------- 1 | # Working init script, fix for: https://bugs.launchpad.net/ubuntu/+source/monit/+bug/993381 2 | cookbook_file "/etc/init.d/monit" do 3 | source 'init-monit-ubuntu12.sh' 4 | owner 'root' 5 | group 'root' 6 | mode '0755' 7 | end -------------------------------------------------------------------------------- /recipes/unicorn.rb: -------------------------------------------------------------------------------- 1 | include_recipe 'monit' 2 | 3 | monitrc 'unicorn' 4 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'chefspec' 2 | -------------------------------------------------------------------------------- /spec/unit/recipes/default_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'monit::default' do 4 | context "with default attributes" do 5 | let(:chef_run) { ChefSpec::Runner.new.converge(described_recipe) } 6 | 7 | it 'creates /etc/monit/conf.d/' do 8 | expect(chef_run).to create_directory('/etc/monit/conf.d/').with(user: 'root', group: 'root', mode: 0755) 9 | end 10 | 11 | it 'creates /etc/monit/monitrc' do 12 | expect(chef_run).to create_template('/etc/monit/monitrc').with(user: 'root', group: 'root', mode: 0700) 13 | file = chef_run.template('/etc/monit/monitrc') 14 | expect(file).to notify('service[monit]').to(:restart) 15 | 16 | expect(chef_run).to render_file('/etc/monit/monitrc').with_content(/set daemon 60\n\s*with start delay 120$/) 17 | expect(chef_run).to render_file('/etc/monit/monitrc').with_content(/set httpd port 3737/) 18 | 19 | expect(chef_run).not_to render_file('/etc/monit/monitrc').with_content(/set mailserver/) 20 | expect(chef_run).not_to render_file('/etc/monit/monitrc').with_content(/set mail-format/) 21 | expect(chef_run).not_to render_file('/etc/monit/monitrc').with_content(/set alert/) 22 | end 23 | 24 | it 'enables the service' do 25 | expect(chef_run).to enable_service('monit') 26 | end 27 | 28 | it 'start the service' do 29 | expect(chef_run).to start_service('monit') 30 | end 31 | 32 | it 'does not email notifications' do 33 | expect(chef_run).not_to render_file('/etc/monit/monitrc').with_content(/set alert /) 34 | end 35 | end 36 | 37 | context "with configuration" do 38 | let(:chef_run) do 39 | runner = ChefSpec::Runner.new do |node| 40 | node.set[:monit][:notify_email] = 'johndoe@example.com' 41 | node.set[:monit][:logfile] = '/var/log/monit.log' 42 | node.set[:monit][:poll_period] = 30 43 | node.set[:monit][:poll_start_delay] = 90 44 | node.set[:monit][:mail_format][:subject] = 'Hello from monit' 45 | node.set[:monit][:mail_format][:from] = 'monit@example.com' 46 | node.set[:monit][:mail_format][:message] = 'Hello!' 47 | node.set[:monit][:mailserver][:host] = 'smtp.example.com' 48 | node.set[:monit][:mailserver][:hostname] = 'mail.hostname.com' 49 | node.set[:monit][:mailserver][:port] = 587 50 | node.set[:monit][:mailserver][:username] = 'johndoe' 51 | node.set[:monit][:mailserver][:password] = 'secret' 52 | node.set[:monit][:mailserver][:password_suffix] = 'smtp' 53 | node.set[:monit][:mailserver][:encryption] = 'SSLV2' 54 | node.set[:monit][:mailserver][:timeout] = 10 55 | node.set[:monit][:port] = 8000 56 | node.set[:monit][:address] = '192.168.0.1' 57 | node.set[:monit][:ssl] = true 58 | node.set[:monit][:allow] = ["localhost", '192.168.0.2'] 59 | node.set[:monit][:username] = 'johndoe' 60 | node.set[:monit][:password] = 'secret' 61 | end.converge(described_recipe) 62 | end 63 | 64 | it 'creates /etc/monit/monitrc' do 65 | expect(chef_run).to render_file('/etc/monit/monitrc').with_content(/set daemon 30\n\s*with start delay 90$/) 66 | expect(chef_run).to render_file('/etc/monit/monitrc').with_content(%r|set logfile /var/log/monit.log$|) 67 | expect(chef_run).to render_file('/etc/monit/monitrc').with_content(/set mailserver smtp.example.com port 587\n\s*using HOSTNAME "mail.hostname.com"\n\s*username "johndoe"\n\s*password "secret" smtp\n\s*using SSLV2\n\s*with timeout 10 seconds$/) 68 | expect(chef_run).to render_file('/etc/monit/monitrc').with_content(/set mail-format {\n\s*from: monit@example.com\n\s*subject: Hello from monit\n\s*message: Hello!$/) 69 | expect(chef_run).to render_file('/etc/monit/monitrc').with_content(/set alert johndoe@example.com NOT ON { action, instance, pid, ppid }$/) 70 | expect(chef_run).to render_file('/etc/monit/monitrc').with_content(/set httpd port 8000\n\s*use address 192.168.0.1\n\s*allow localhost\n\s*allow 192.168.0.2$/) 71 | expect(chef_run).to render_file('/etc/monit/monitrc').with_content(/allow johndoe:secret$/) 72 | expect(chef_run).to render_file('/etc/monit/monitrc').with_content(%r|ssl enable\n\s*pemfile /etc/monit/monit.pem$|) 73 | end 74 | end 75 | 76 | context "on ubuntu" do 77 | let(:chef_run) do 78 | runner = ChefSpec::Runner.new(:platform => 'ubuntu', :version => '12.04').converge(described_recipe) 79 | end 80 | 81 | it 'creates /etc/default/monit' do 82 | expect(chef_run).to create_cookbook_file('/etc/default/monit').with(user: 'root', group: 'root', mode: 0644) 83 | end 84 | end 85 | 86 | end 87 | -------------------------------------------------------------------------------- /spec/unit/recipes/postfix_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'monit::postfix' do 4 | let(:chef_run) do 5 | runner = ChefSpec::Runner.new.converge(described_recipe) 6 | end 7 | 8 | # Temporary soultion for testing definitions/monitrc.erb without monky patch. 9 | # See http://amespinosa.wordpress.com/2013/05/06/testing-recipe-definitions-with-chefspec/ 10 | it 'creates /etc/monit/conf.d/postfix.conf' do 11 | expect(chef_run).to create_template('/etc/monit/conf.d/postfix.conf').with(user: 'root', group: 'root', mode: 0644) 12 | file = chef_run.template('/etc/monit/conf.d/postfix.conf') 13 | expect(file).to notify('service[monit]').to(:restart) 14 | end 15 | 16 | end 17 | -------------------------------------------------------------------------------- /spec/unit/recipes/postgres_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'monit::postgresql' do 4 | let(:chef_run) { ChefSpec::Runner.new.converge described_recipe } 5 | 6 | it 'creates /etc/monit/conf.d/postgresql.conf' do 7 | expect(chef_run).to create_template('/etc/monit/conf.d/postgresql.conf').with(user: 'root', group: 'root', mode: 0644) 8 | 9 | expect(chef_run).to render_file('/etc/monit/conf.d/postgresql.conf').with_content('start program = "/etc/init.d/postgresql start"') 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/unit/recipes/resque_scheduler_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'monit::resque_scheduler' do 4 | let(:chef_run) do 5 | ChefSpec::Runner.new do |node| 6 | node.set[:monit][:resque][:app_root] = '/www/myapp-test/current' 7 | end.converge(described_recipe) 8 | end 9 | 10 | it "includes the default recipe" do 11 | expect(chef_run).to include_recipe 'monit::resque_scheduler' 12 | end 13 | 14 | it "creates the resque_scheduler.conf" do 15 | expect(chef_run).to render_file("/etc/monit/conf.d/resque_scheduler.conf") 16 | .with_content("check process resque_scheduler with pidfile /www/myapp-test/current") 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/unit/recipes/resque_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'monit::resque' do 4 | def chef_run(monit_resque_attrs = {}) 5 | @chef_run ||= ChefSpec::Runner.new do |node| 6 | node.set[:monit][:resque] = monit_resque_attrs 7 | end.converge described_recipe 8 | end 9 | 10 | it 'includes the default recipe' do 11 | chef_run({ queues: [{ worker_count: 1, queue_list: %w(apple) }] }) 12 | 13 | expect(chef_run).to include_recipe 'monit::resque' 14 | end 15 | 16 | it 'creates the resque.conf' do 17 | chef_run({ queues: [{ queue_list: %w(apple banana peanut), worker_count: 1 }]}) 18 | 19 | expect(chef_run).to render_file('/etc/monit/conf.d/resque.conf').with_content('check process resque_worker_0') 20 | expect(chef_run).to render_file('/etc/monit/conf.d/resque.conf').with_content('QUEUE=apple,banana,peanut') 21 | end 22 | 23 | it 'groups queues appropriately' do 24 | queues = [ 25 | { queue_list: %w(tomato), worker_count: 2 }, 26 | { queue_list: %w(apple banana carrot), worker_count: 3 }, 27 | { queue_list: %w(plum orange), worker_count: 1 } 28 | ] 29 | chef_run({ queues: queues }) 30 | 31 | expect(chef_run).to render_file('/etc/monit/conf.d/resque.conf').with_content('QUEUE=tomato') 32 | expect(chef_run).to render_file('/etc/monit/conf.d/resque.conf').with_content('QUEUE=plum,orange') 33 | expect(chef_run).to render_file('/etc/monit/conf.d/resque.conf').with_content('QUEUE=apple,banana,carrot') 34 | end 35 | 36 | it 'gives each worker a unique name' do 37 | queues = [ 38 | { queue_list: %w(tomato), worker_count: 2 } 39 | ] 40 | chef_run({ queues: queues }) 41 | 42 | expect(chef_run).to render_file('/etc/monit/conf.d/resque.conf').with_content('check process resque_worker_0') 43 | expect(chef_run).to render_file('/etc/monit/conf.d/resque.conf').with_content('check process resque_worker_1') 44 | end 45 | 46 | [0, -1].each do |worker_count| 47 | it 'should guard against an invalid number of workers' do 48 | lambda { 49 | chef_run({ queues: [{ queue_list: %w(apple), worker_count: worker_count }] }) 50 | }.should raise_error ArgumentError, 'The number of workers for a given queue must be a positive integer.' 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /spec/unit/recipes/ubuntu12fix_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'monit::ubuntu12fix' do 4 | let(:chef_run) do 5 | runner = ChefSpec::Runner.new.converge(described_recipe) 6 | end 7 | 8 | it 'overrides /etc/init.d/monit' do 9 | # I have no idea why mode doesn't work without single quotes. 10 | expect(chef_run).to create_cookbook_file('/etc/init.d/monit').with(user: 'root', group: 'root', mode: '0755') 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/unit/recipes/unicorn_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'monit::unicorn' do 4 | let(:chef_run) { ChefSpec::Runner.new.converge described_recipe } 5 | 6 | it 'creates /etc/monit/conf.d/unicorn.conf' do 7 | expect(chef_run).to create_template('/etc/monit/conf.d/unicorn.conf').with(user: 'root', group: 'root', mode: 0644) 8 | 9 | # Can't assert on definitions without a hairy monkey patch: http://amespinosa.wordpress.com/2013/05/06/testing-recipe-definitions-with-chefspec/ 10 | #expect(chef_run).to create_template('/etc/monit/conf.d/unicorn_master.conf').with_content('start program "/etc/init.d/unicorn start"') 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /templates/default/monitrc.erb: -------------------------------------------------------------------------------- 1 | set daemon <%= @node["monit"]["poll_period"] %> 2 | <% if @node["monit"]["poll_start_delay"] %> 3 | with start delay <%= @node["monit"]["poll_start_delay"] %> 4 | <% end %> 5 | 6 | set logfile <%= @node["monit"]["logfile"] %> 7 | 8 | <% if @node["monit"]["eventqueue"]["set"] %> 9 | set eventqueue 10 | basedir <%= @node["monit"]["eventqueue"]["basedir"] %> # set the base directory where events will be stored 11 | <%= "slots #{@node["monit"]["eventqueue"]["slots"]}" if @node["monit"]["eventqueue"]["slots"] %> 12 | <% end %> 13 | 14 | <% unless @node[:monit][:notify_email].nil? || @node[:monit][:notify_email] == '' %> 15 | 16 | set mailserver <%= @node["monit"]["mailserver"]["host"] %><%= " port #{@node["monit"]["mailserver"]["port"]}" if @node["monit"]["mailserver"]["port"] %> 17 | <% if @node["monit"]["mailserver"]["hostname"] %> 18 | using HOSTNAME "<%= @node["monit"]["mailserver"]["hostname"] %>" 19 | <% end %> 20 | <% if @node["monit"]["mailserver"]["username"] %> 21 | username "<%= @node["monit"]["mailserver"]["username"] %>" 22 | <% end %> 23 | <% if @node["monit"]["mailserver"]["password"] %> 24 | password "<%= @node["monit"]["mailserver"]["password"] %>"<%= " #{@node["monit"]["mailserver"]["password_suffix"]}" if @node["monit"]["mailserver"]["password_suffix"] %> 25 | <% end %> 26 | <% if @node["monit"]["mailserver"]["encryption"] %> 27 | using <%= @node["monit"]["mailserver"]["encryption"] %> 28 | <% end %> 29 | <% if @node["monit"]["mailserver"]["timeout"] %> 30 | with timeout <%= @node["monit"]["mailserver"]["timeout"] %> seconds 31 | <% end %> 32 | 33 | set mail-format { 34 | from: <%= @node["monit"]["mail_format"]["from"] %> 35 | subject: <%= @node["monit"]["mail_format"]["subject"] %> 36 | message: <%= @node["monit"]["mail_format"]["message"] %> 37 | } 38 | 39 | set alert <%= @node["monit"]["notify_email"] %><%= " NOT ON { #{@node["monit"]["alert_blacklist"].join(", ")} }" unless @node["monit"]["alert_blacklist"].empty? %> 40 | <% end %> 41 | 42 | set httpd port <%= @node["monit"]["port"] %> 43 | <%= "use address #{@node["monit"]["address"]}" if @node["monit"]["address"] %> 44 | <% @node["monit"]["allow"].each do |a| %> 45 | allow <%= a %> 46 | <% end %> 47 | <%= "allow #{@node["monit"]["username"]}:#{@node["monit"]["password"]}" if @node["monit"]["username"] %> 48 | <% if node["monit"]["ssl"] %> 49 | ssl enable 50 | pemfile <%= @node["monit"]["cert"] %> 51 | <% end %> 52 | 53 | include /etc/monit/conf.d/*.conf 54 | -------------------------------------------------------------------------------- /templates/default/postfix.conf.erb: -------------------------------------------------------------------------------- 1 | CHECK PROCESS postfix WITH PIDFILE /var/spool/postfix/pid/master.pid 2 | start program = "/etc/init.d/postfix start" 3 | stop program = "/etc/init.d/postfix stop" 4 | GROUP mail 5 | IF FAILED PORT 25 PROTOCOL smtp THEN restart 6 | IF 5 RESTARTS WITHIN 5 CYCLES THEN timeout 7 | -------------------------------------------------------------------------------- /templates/default/postgresql.conf.erb: -------------------------------------------------------------------------------- 1 | CHECK PROCESS postgresql WITH PIDFILE <%= node["monit"]["postgres"]["pid_file"] %> 2 | start program = "/etc/init.d/postgresql start" 3 | stop program = "/etc/init.d/postgresql stop" 4 | GROUP postgres 5 | IF FAILED UNIXSOCKET <%= node["monit"]["postgres"]["unix_socket_path"] %>.<%= node["monit"]["postgres"]["port"] %> PROTOCOL pgsql THEN RESTART 6 | IF FAILED HOST 127.0.0.1 PORT <%= node["monit"]["postgres"]["port"] %> PROTOCOL pgsql THEN RESTART 7 | IF 5 RESTARTS WITHIN 5 CYCLES THEN TIMEOUT 8 | -------------------------------------------------------------------------------- /templates/default/rabbitmq.conf.erb: -------------------------------------------------------------------------------- 1 | CHECK PROCESS rabbitmq-server WITH PIDFILE /var/run/rabbitmq/pid 2 | GROUP rabbitmq 3 | START PROGRAM "/usr/sbin/service rabbitmq-server start" 4 | STOP PROGRAM "/usr/sbin/service rabbitmq-server stop" 5 | IF DOES NOT EXIST FOR 3 CYCLES THEN RESTART 6 | IF FAILED PORT 5672 4 TIMES WITHIN 6 CYCLES THEN RESTART 7 | -------------------------------------------------------------------------------- /templates/default/resque.conf.erb: -------------------------------------------------------------------------------- 1 | <% counter = 0 %> 2 | 3 | <% node['monit']['resque']['queues'].each do |queue| %> 4 | <% queue['worker_count'].times do %> 5 | check process resque_worker_<%= counter %> with pidfile <%= @node['monit']['resque']['app_root'] %>/tmp/pids/resque_worker.<%= counter %>.pid 6 | 7 | group resque_workers 8 | 9 | # Note: the priority of queues is determined by their order in the following statement: 10 | 11 | start program = "/usr/bin/env PATH=/usr/local/bin:/usr/local/ruby/bin:/usr/bin:/bin:$PATH /bin/sh -l -c 'cd <%= @node['monit']['resque']['app_root'] %> && nohup bundle exec rake environment resque'work' RAILS_ENV=<%= node.chef_environment %> QUEUE=<%= 12 | queue['queue_list'].join(',') 13 | %> VERBOSE=1 PIDFILE=<%= @node['monit']['resque']['app_root'] %>/tmp/pids/resque_worker.<%= counter %>.pid >> log/resque_worker.<%= counter %>.log 2>&1 &'" with timeout 90 seconds 14 | 15 | stop program = "/bin/sh -c 'cd <%= @node['monit']['resque']['app_root'] %> && kill -TERM `cat tmp/pids/resque_worker.<%= counter %>.pid` && rm -f tmp/pids/resque_worker.<%= counter %>.pid; exit 0;'" 16 | 17 | if totalmem is greater than 1500 MB for 10 cycles then restart 18 | 19 | <% counter += 1 %> 20 | <% end %> 21 | <% end %> 22 | -------------------------------------------------------------------------------- /templates/default/resque_scheduler.conf.erb: -------------------------------------------------------------------------------- 1 | check process resque_scheduler with pidfile <%= @node[:monit][:resque][:app_root] %>/tmp/pids/resque_scheduler.pid 2 | group resque_scheduler 3 | start program = "/usr/bin/env PATH=/usr/local/bin:/usr/local/ruby/bin:/usr/bin:/bin:$PATH RACK_ENV=<%= node.chef_environment %> /bin/sh -l -c 'cd <%= @node[:monit][:resque][:app_root] %> && nohup bundle exec rake environment resque:scheduler RAILS_ENV=<%= node.chef_environment %> QUEUE=* VERBOSE=1 INITIALIZER_PATH=<%= @node[:monit][:resque][:app_root] %>/config/initializers/resque.rb PIDFILE=<%= @node[:monit][:resque][:app_root] %>/tmp/pids/resque_scheduler.pid & >> log/resque_scheduler.log 2>&1'" with timeout 90 seconds 4 | stop program = "/bin/sh -c 'cd <%= @node[:monit][:resque][:app_root] %> && kill -9 `cat tmp/pids/resque_scheduler.pid` && rm -f tmp/pids/resque_scheduler.pid; exit 0;'" 5 | if totalmem is greater than 300 MB for 10 cycles then restart 6 | -------------------------------------------------------------------------------- /templates/default/ssh.conf.erb: -------------------------------------------------------------------------------- 1 | # managed by chef, changes will be overwritten 2 | CHECK PROCESS sshd WITH PIDFILE /var/run/sshd.pid 3 | START PROGRAM "/usr/sbin/service ssh start" 4 | STOP PROGRAM "/usr/sbin/service ssh stop" 5 | # under load a check may fail intermittently, so give it a few tries before restarting 6 | IF FAILED PORT <%= @node[:monit][:ssh_port] %> PROTOCOL ssh 4 TIMES WITHIN 6 CYCLES THEN RESTART 7 | 8 | -------------------------------------------------------------------------------- /templates/default/unicorn.conf.erb: -------------------------------------------------------------------------------- 1 | check process unicorn with pidfile <%= node["monit"]["unicorn"]["pid_dir"] %>/unicorn.pid 2 | start program "/etc/init.d/unicorn start" 3 | stop program "/etc/init.d/unicorn stop" 4 | if 5 restarts within 5 cycles then timeout 5 | 6 | <% node["monit"]["unicorn"]["worker_count"].times do |i| %> 7 | check process unicorn_worker_<%= i %> with pidfile <%= File.join(node["monit"]["unicorn"]["pid_dir"], "unicorn.worker.#{i}.pid") %> 8 | <% unless node["monit"]["notify_email"].nil? || node["monit"]["notify_email"] == '' %> 9 | alert <%= node["monit"]["notify_email"] %> only on { pid } 10 | <% end %> 11 | if changed pid 2 times within 60 cycles then alert 12 | if memory usage > 16% for 1 cycles then 13 | exec "/etc/init.d/unicorn kill_worker 0" 14 | if cpu is greater than 50% for 2 cycles then 15 | exec "/etc/init.d/unicorn kill_worker 0" 16 | 17 | <% end %> 18 | --------------------------------------------------------------------------------