diff --git a/puppet/modules/supervisor/README.md b/puppet/modules/supervisor/README.md new file mode 100644 index 0000000..58f1dd7 --- /dev/null +++ b/puppet/modules/supervisor/README.md @@ -0,0 +1,24 @@ +Puppet Supervisor +================= + +Install and manage apps in supervisord + + +Usage +================= + +Include supervisor class +```puppet +include supervisor +``` + +Install your app using defined type supervisor::app + +```puppet +supervisor::app { 'your-app-title': + app_name => 'your-app-name' # Default to 'your-app-title' + command => 'The command that will be run this app', # required + directory => 'Path where your command will be run' # required + user => 'User to execute this app' # Default to ubuntu +} +``` \ No newline at end of file diff --git a/puppet/modules/supervisor/files/debian-isnok b/puppet/modules/supervisor/files/debian-isnok new file mode 100755 index 0000000..01fd900 --- /dev/null +++ b/puppet/modules/supervisor/files/debian-isnok @@ -0,0 +1,217 @@ +#! /bin/sh +# +# supervisor built from skeleton /etc/init.d/ script. +# +# skeleton by Miquel van Smoorenburg . +# Modified for Debian by Ian Murdock . +# Further changes by Javier Fernandez-Sanguino . +# More changes by Konstantin Martini . +# +# Version: @(#)supervisor 0.8 25-Jun-2013 isnok@tuxcode.org +# +### BEGIN INIT INFO +# Provides: supervisor +# Required-Start: $remote_fs $network $named +# Required-Stop: $remote_fs $network $named +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start/stop supervisord +# Description: Start/stop supervisor daemon and its configured +# subprocesses. +### END INIT INFO + + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +#DAEMON=/usr/bin/supervisord # Debian package version (presently 3.0a8-1) +DAEMON=/usr/local/bin/supervisord # Python package index (pypi) version (3.0b1) +NAME=supervisord +DESC="supervisord" + +CONFIGFILE=/etc/supervisord.conf # the supervisord config file +SUPERVISORCTL=/usr/local/bin/supervisorctl # used for reload command(s) +#SUPERVISORCTL=/usr/bin/supervisorctl # again: official deb version + +if [ ! -x $DAEMON ]; then + echo "ERROR: Not executable: $DAEMON" + exit 0 +fi + +LOGDIR=/var/log/supervisor +PIDFILE=/var/run/$NAME.pid +DODTIME=5 # Time to wait for the server to die, in seconds + # If this value is set too low you might not + # let some servers to die gracefully and + # 'restart' will not work. + +# fix some args for certain commands +DAEMON_ARGS="-c$CONFIGFILE" +CTL_ARGS="-c$CONFIGFILE" +STARTSTOP_ARGS="--quiet --pidfile $PIDFILE --exec $DAEMON" + +# Include supervisor defaults if available +if [ -r /etc/default/supervisor ]; then + . /etc/default/supervisor +fi + +set -e + +dod_sleep () { + if [ -n "$DODTIME" ]; then + sleep "$DODTIME"s + fi +} + +running_pid () { + # Check if a pid's cmdline contains a string (name). + # This should work for all users. + pid="$1" + name="$2" + if [ -z "$pid" ]; then + return 1 # no pid given + fi + if [ ! -d /proc/"$pid" ]; then + return 1 # no /proc/$pid directory + fi + if cat /proc/"$pid"/cmdline | tr "\000" "\n"| grep -q "$name"; then + return 0 + else + return 1 # $pid does not match $name + fi +} + +running () { + # Check if DAEMON is running by examining $PIDFILE. + # If this succeeds, it sets $pid (a side effect being used). + + if [ ! -f "$PIDFILE" ]; then + return 1 # No pidfile, probably no daemon present. + fi + # Now, obtain the pid and check it's /proc cmdline: + pid="$(cat $PIDFILE)" + if running_pid "$pid" "$DAEMON"; then + return 0 + else + return 1 + fi +} + +normal_start () { + start-stop-daemon $STARTSTOP_ARGS --start \ + -- "$DAEMON_ARGS" $DAEMON_OPTS + if [ ! -f "$PIDFILE" ]; then + sleep 1 # grace time to create PIDFILE + fi +} + +normal_stop () { + #start-stop-daemon $STARTSTOP_ARGS --stop --oknodo + "$SUPERVISORCTL" $CTL_ARGS shutdown +} + +force_stop () { + # Forcefully stop a running DAEMON. + if running; then + kill -15 "$pid" + dod_sleep + # Check again, try harder if needed. + if running; then + kill -9 "$pid" + dod_sleep + if running; then + echo "Unable to kill running $NAME process (pid=$pid)!" + exit 1 + fi + fi + fi + rm -f "$PIDFILE" + return 0 +} + +ctl_reload () { + # make supervisord reload it's config + if [ -x "$SUPERVISORCTL" ]; then + "$SUPERVISORCTL" $CTL_ARGS reload + else + return 1 + fi +} + +ctl_status () { + # show stati of supervised processes. + # do not mind if this fails. + "$SUPERVISORCTL" $CTL_ARGS status +} + +case "$1" in + start) + echo -n "Starting $DESC: " + normal_start + if running; then + echo "$NAME." + else + echo "ERROR." + fi + ;; + stop) + echo -n "Stopping $DESC: " + if normal_stop; then + echo "$NAME." + else + echo "ERROR." + fi + ;; + restart) + echo "Restarting $DESC..." + "$0" stop && "$0" start + ;; + force-stop) + echo -n "Forcefully stopping $DESC: " + force_stop + if running; then + echo "$NAME." + else + echo "ERROR." + fi + ;; + reload|force-reload) + # + # If the daemon can reload its config files on the fly + # for example by sending it SIGHUP, do it here. + # + # If the daemon responds to changes in its config file + # directly anyway, make this a do-nothing entry. + # + echo "Reloading $DESC: " + if ctl_reload; then + echo "$NAME." + else + echo "ERROR." + fi + ;; + #force-reload) + # + # If the "reload" option is implemented, move the "force-reload" + # option to the "reload" entry above. If not, "force-reload" is + # just the same as "restart" except that it does nothing if the + # daemon isn't already running. + # Check wether $DAEMON is running. If so, restart. + #echo "Not implemented." + #;; + status) + echo -n "$NAME is " + if running; then + echo "running" +# ctl_status + else + echo "not running." + exit 1 + fi + ;; + *) + N=/etc/init.d/"$NAME" + echo "Usage: $N {start|stop|restart|reload|status|force-stop}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/puppet/modules/supervisor/files/supervisord.conf b/puppet/modules/supervisor/files/supervisord.conf new file mode 100644 index 0000000..d90a127 --- /dev/null +++ b/puppet/modules/supervisor/files/supervisord.conf @@ -0,0 +1,139 @@ +; Sample supervisor config file. +; +; For more information on the config file, please see: +; http://supervisord.org/configuration.html +; +; Note: shell expansion ("~" or "$HOME") is not supported. Environment +; variables can be expanded using this syntax: "%(ENV_HOME)s". + +[unix_http_server] +file=/tmp/supervisor.sock ; (the path to the socket file) +;chmod=0700 ; socket file mode (default 0700) +;chown=nobody:nogroup ; socket file uid:gid owner +;username=user ; (default is no username (open server)) +;password=123 ; (default is no password (open server)) + +;[inet_http_server] ; inet (TCP) server disabled by default +;port=127.0.0.1:9001 ; (ip_address:port specifier, *:port for all iface) +;username=user ; (default is no username (open server)) +;password=123 ; (default is no password (open server)) + +[supervisord] +logfile=/var/log/supervisord.log ; (main log file;default $CWD/supervisord.log) +logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB) +logfile_backups=10 ; (num of main logfile rotation backups;default 10) +loglevel=info ; (log level;default info; others: debug,warn,trace) +pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) +nodaemon=false ; (start in foreground if true;default false) +minfds=1024 ; (min. avail startup file descriptors;default 1024) +minprocs=200 ; (min. avail process descriptors;default 200) +;umask=022 ; (process file creation umask;default 022) +;user=chrism ; (default is current user, required if root) +;identifier=supervisor ; (supervisord identifier, default is 'supervisor') +;directory=/tmp ; (default is not to cd during start) +;nocleanup=true ; (don't clean up tempfiles at start;default false) +;childlogdir=/tmp ; ('AUTO' child log dir, default $TEMP) +;environment=KEY="value" ; (key value pairs to add to environment) +;strip_ansi=false ; (strip ansi escape codes in logs; def. false) + +; the below section must remain in the config file for RPC +; (supervisorctl/web interface) to work, additional interfaces may be +; added by defining them in separate rpcinterface: sections +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[supervisorctl] +serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket +;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket +;username=chris ; should be same as http_username if set +;password=123 ; should be same as http_password if set +;prompt=mysupervisor ; cmd line prompt (default "supervisor") +;history_file=~/.sc_history ; use readline history if available + +; The below sample program section shows all possible program subsection values, +; create one or more 'real' program: sections to be able to control them under +; supervisor. + +;[program:theprogramname] +;command=/bin/cat ; the program (relative uses PATH, can take args) +;process_name=%(program_name)s ; process_name expr (default %(program_name)s) +;numprocs=1 ; number of processes copies to start (def 1) +;directory=/tmp ; directory to cwd to before exec (def no cwd) +;umask=022 ; umask for process (default None) +;priority=999 ; the relative start priority (default 999) +;autostart=true ; start at supervisord start (default: true) +;autorestart=unexpected ; whether/when to restart (default: unexpected) +;startsecs=1 ; number of secs prog must stay running (def. 1) +;startretries=3 ; max # of serial start failures (default 3) +;exitcodes=0,2 ; 'expected' exit codes for process (default 0,2) +;stopsignal=QUIT ; signal used to kill process (default TERM) +;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10) +;stopasgroup=false ; send stop signal to the UNIX process group (default false) +;killasgroup=false ; SIGKILL the UNIX process group (def false) +;user=chrism ; setuid to this UNIX account to run the program +;redirect_stderr=true ; redirect proc stderr to stdout (default false) +;stdout_logfile=/a/path ; stdout log path, NONE for none; default AUTO +;stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB) +;stdout_logfile_backups=10 ; # of stdout logfile backups (default 10) +;stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0) +;stdout_events_enabled=false ; emit events on stdout writes (default false) +;stderr_logfile=/a/path ; stderr log path, NONE for none; default AUTO +;stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB) +;stderr_logfile_backups=10 ; # of stderr logfile backups (default 10) +;stderr_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0) +;stderr_events_enabled=false ; emit events on stderr writes (default false) +;environment=A="1",B="2" ; process environment additions (def no adds) +;serverurl=AUTO ; override serverurl computation (childutils) + +; The below sample eventlistener section shows all possible +; eventlistener subsection values, create one or more 'real' +; eventlistener: sections to be able to handle event notifications +; sent by supervisor. + +;[eventlistener:theeventlistenername] +;command=/bin/eventlistener ; the program (relative uses PATH, can take args) +;process_name=%(program_name)s ; process_name expr (default %(program_name)s) +;numprocs=1 ; number of processes copies to start (def 1) +;events=EVENT ; event notif. types to subscribe to (req'd) +;buffer_size=10 ; event buffer queue size (default 10) +;directory=/tmp ; directory to cwd to before exec (def no cwd) +;umask=022 ; umask for process (default None) +;priority=-1 ; the relative start priority (default -1) +;autostart=true ; start at supervisord start (default: true) +;autorestart=unexpected ; whether/when to restart (default: unexpected) +;startsecs=1 ; number of secs prog must stay running (def. 1) +;startretries=3 ; max # of serial start failures (default 3) +;exitcodes=0,2 ; 'expected' exit codes for process (default 0,2) +;stopsignal=QUIT ; signal used to kill process (default TERM) +;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10) +;stopasgroup=false ; send stop signal to the UNIX process group (default false) +;killasgroup=false ; SIGKILL the UNIX process group (def false) +;user=chrism ; setuid to this UNIX account to run the program +;redirect_stderr=true ; redirect proc stderr to stdout (default false) +;stdout_logfile=/a/path ; stdout log path, NONE for none; default AUTO +;stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB) +;stdout_logfile_backups=10 ; # of stdout logfile backups (default 10) +;stdout_events_enabled=false ; emit events on stdout writes (default false) +;stderr_logfile=/a/path ; stderr log path, NONE for none; default AUTO +;stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB) +;stderr_logfile_backups ; # of stderr logfile backups (default 10) +;stderr_events_enabled=false ; emit events on stderr writes (default false) +;environment=A="1",B="2" ; process environment additions +;serverurl=AUTO ; override serverurl computation (childutils) + +; The below sample group section shows all possible group values, +; create one or more 'real' group: sections to create "heterogeneous" +; process groups. + +;[group:thegroupname] +;programs=progname1,progname2 ; each refers to 'x' in [program:x] definitions +;priority=999 ; the relative start priority (default 999) + +; The [include] section can just contain the "files" setting. This +; setting can list multiple files (separated by whitespace or +; newlines). It can also contain wildcards. The filenames are +; interpreted as relative to this file. Included files *cannot* +; include files themselves. + +[include] +files = /etc/supervisor/conf.d/*.conf diff --git a/puppet/modules/supervisor/manifests/app.pp b/puppet/modules/supervisor/manifests/app.pp new file mode 100644 index 0000000..7155062 --- /dev/null +++ b/puppet/modules/supervisor/manifests/app.pp @@ -0,0 +1,31 @@ +define supervisor::app ( + $app_name = $title, + $command, + $directory, + $user = 'ubuntu', +) { + + $conf_file = "supervisor_${app_name}" + $service_name = $conf_file + + file { $conf_file: + path => "/etc/supervisor/conf.d/${app_name}.conf", + ensure => present, + content => template('supervisor/supervisor.conf.erb'), + require => Package['supervisor'], + notify => Service['supervisord'], + } + + service { $service_name: + ensure => running, + path => ['/usr/bin'], + start => "supervisorctl start $app_name", + restart => "supervisorctl restart $app_name", + stop => "supervisorctl stop $app_name", + status => "supervisorctl status | awk '/^${name}[: ]/{print \$2}' | grep '^RUNNING$'", + subscribe => File[$conf_file], + hasrestart => false, + hasstatus => false, + provider => base + } +} diff --git a/puppet/modules/supervisor/manifests/init.pp b/puppet/modules/supervisor/manifests/init.pp new file mode 100644 index 0000000..7fc3b06 --- /dev/null +++ b/puppet/modules/supervisor/manifests/init.pp @@ -0,0 +1,40 @@ +class supervisor { + + package { "supervisor": + ensure => installed, + provider => pip, + } + + service { "supervisord": + ensure => running, + enable => true, + require => [Package['supervisor'], + File['/etc/init.d/supervisord']], + stop => '/etc/init.d/supervisord stop', + start => '/etc/init.d/supervisord start', + restart => '/etc/init.d/supervisord restart', + subscribe => File['/etc/supervisord.conf'], + } + + file { '/etc/init.d/supervisord': + source => 'puppet:///modules/supervisor/debian-isnok', + mode => '0755', + } + + file { '/etc/supervisor': + ensure => directory, + } + + file { '/etc/supervisord.conf': + source => 'puppet:///modules/supervisor/supervisord.conf', + require => File['/etc/supervisor'], + } + + file { '/etc/supervisor/conf.d/': + ensure => directory, + recurse => true, + purge => true, + notify => Service['supervisord'], + require => File['/etc/supervisor'], + } +} diff --git a/puppet/modules/supervisor/templates/supervisor.conf.erb b/puppet/modules/supervisor/templates/supervisor.conf.erb new file mode 100644 index 0000000..c8be1dd --- /dev/null +++ b/puppet/modules/supervisor/templates/supervisor.conf.erb @@ -0,0 +1,7 @@ +[program:<%= @app_name %>] +command=<%= @command %> +directory=<%= @directory %> +user=<%= @user %> +autostart=true +autorestart=true +redirect_stderr=True diff --git a/puppet/modules/supervisor/tests/init.pp b/puppet/modules/supervisor/tests/init.pp new file mode 100644 index 0000000..91c0893 --- /dev/null +++ b/puppet/modules/supervisor/tests/init.pp @@ -0,0 +1,7 @@ + +include supervisor + +supervisor::app { 'fake_service': + command => '/bin/cat', + directory => '/tmp/', +} -- libgit2 0.21.2