1#!/bin/sh
2#
3# Salt minion
4###################################
5
6# LSB header
7
8### BEGIN INIT INFO
9# Provides:          salt-minion
10# Required-Start:    $all
11# Required-Stop:
12# Default-Start:     2 3 4 5
13# Default-Stop:      0 1 6
14# Short-Description: Salt minion daemon
15# Description:       This is the Salt minion daemon that can be controlled by the
16#                    Salt master.
17### END INIT INFO
18
19
20# chkconfig header
21
22# chkconfig: 345 97 04
23# description:  This is the Salt minion daemon that can be controlled by the Salt master.
24#
25# processname: /usr/bin/salt-minion
26
27# Allow these to be overridden for tests
28: "${SALTMINION_BINDIR:=/usr/bin}"
29: "${SALTMINION_SYSCONFDIR:=/etc}"
30
31# Default values (can be overridden in settings file)
32: "${USER:=$(id -nu)}"
33SALTMINION="${SALTMINION_BINDIR}/salt-minion"
34SALTCALL="${SALTMINION_BINDIR}/salt-call"
35# SALTMINION_CONFIGS are newline-separated entries of: MINION_USER CONFIG_DIR
36: "${SALTMINION_CONFIGS:="
37$USER ${SALTMINION_SYSCONFDIR}/salt
38"}"
39SALTMINION_ARGS=""
40SALTMINION_TIMEOUT=30
41SALTMINION_TICK=1
42
43SERVICE="salt-minion"
44
45# Read in settings file
46if [ -f "${SALTMINION_SYSCONFDIR}/default/salt" ]; then
47    . "${SALTMINION_SYSCONFDIR}/default/salt"
48elif [ -f "${SALTMINION_SYSCONFDIR}/sysconfig/salt" ]; then
49    . "${SALTMINION_SYSCONFDIR}/sysconfig/salt"
50fi
51
52RETVAL=0
53NS_NOTRIM="--notrim"
54ERROR_TO_DEVNULL="/dev/null"
55
56
57_su_cmd() {
58    local user="$1"
59    shift
60
61    if [ "X$USER" = "X$user" ]; then
62        eval $1
63    else
64        su -l -c "$1" "$user"
65    fi
66}
67
68
69_get_pid() {
70    cat $PID_FILE 2>/dev/null
71}
72
73
74_is_running() {
75    [ -n "$(_get_pid)" ] && ps wwwaxu | grep '[s]alt-minion' | awk '{print $2}' | grep -qi "\b$(_get_pid)\b"
76}
77
78
79_get_salt_config_value() {
80    _su_cmd \
81        "$MINION_USER" \
82        "\
83            \"$SALTCALL\" \
84            -c \"$CONFIG_DIR\" \
85            --no-color \
86            --skip-grains \
87            --local config.get \
88            \"$1\" \
89        " \
90        2>$ERROR_TO_DEVNULL \
91        | sed -r -e '2!d; s/^\s*//;'
92}
93
94
95_make_id_hash() {
96    # $1 - minion_id
97    local hasher=''
98
99    case "$(_get_salt_config_value hash_type)" in
100        (md5) hasher="md5sum";;
101        (sha1) hasher="sha1sum";;
102        (sha224) hasher="sha224sum";;
103        (sha256) hasher="sha256sum";;
104        (sha384) hasher="sha384sum";;
105        (sha512) hasher="sha512sum";;
106        (*) echo "ERROR: No salt hash_type specified";;
107    esac
108
109    if [ -n "$hasher" ]; then
110        printf "$1" | "$hasher" | cut -c 1-10
111    fi
112}
113
114
115start() {
116    # $1 - config dir
117    local retval=0
118
119    if _is_running; then
120        echo "Service $SERVICE:$MINION_USER:$MINION_ID already running"
121        return 0
122    fi
123
124    echo -n "Starting $SERVICE:$MINION_USER:$MINION_ID daemon: "
125
126    _su_cmd \
127        "$MINION_USER" \
128        "\
129            \"$SALTMINION\" \
130            -c \"$CONFIG_DIR\" \
131            -d $SALTMINION_ARGS \
132            ${SALTMINION_DEBUG:+-l debug} \
133        " \
134        2>$ERROR_TO_DEVNULL \
135        || retval=$?
136
137    if [ 0 -eq "$retval" ]; then
138        local endtime=$(($(date '+%s')+$SALTMINION_TIMEOUT))
139        while ! _is_running; do
140            if [ "$endtime" -lt "$(date '+%s')" ]; then
141                echo -n "TIMEOUT "
142                retval=1
143                break
144            fi
145            sleep $SALTMINION_TICK
146        done
147    fi
148
149    if [ 0 -eq "$retval" ]; then
150        echo -n "OK"
151    else
152        echo -n "FAIL"
153        if [ -n "$SALTMINION_DEBUG" ]; then
154            printf "\nPROCESSES:\n" >&2
155            ps wwwaxu | grep '[s]alt-minion' >&2
156            printf "\nSOCKETS:\n" >&2
157            netstat -n $NS_NOTRIM -ap --protocol=unix | grep 'salt.*minion' >&2
158            printf "\nLOG_FILE:\n" >&2
159            tail -n 20 "$LOG_FILE" >&2
160            printf "\nENVIRONMENT:\n" >&2
161            env >&2
162        fi
163    fi
164    echo
165
166    return $retval
167}
168
169
170stop() {
171    # $1 - config dir
172    local retval=0
173
174    if ! _is_running; then
175        echo "Service $SERVICE:$MINION_USER:$MINION_ID is not running"
176        return 0
177    fi
178
179    echo -n "Stopping $SERVICE:$MINION_USER:$MINION_ID daemon: "
180    local pid="$(_get_pid)"
181
182    # pid below is intentionally not quoted in case there are *multiple*
183    # minions running with the same configuration.
184    _su_cmd "$MINION_USER" "kill -TERM $pid 2>/dev/null" || retval=$?
185    if [ 0 -eq "$retval" ]; then
186        local endtime=$(($(date '+%s')+$SALTMINION_TIMEOUT))
187        while _is_running; do
188            if [ "$endtime" -lt "$(date '+%s')" ]; then
189                # Try one more time with a big hammer
190                _su_cmd "$MINION_USER" "kill -KILL $pid 2>/dev/null" || :
191                sleep $SALTMINION_TICK
192                if _is_running; then
193                    echo -n "TIMEOUT "
194                    retval=1
195                fi
196                break
197            fi
198            sleep 1
199        done
200
201    fi
202
203    if [ 0 -eq "$retval" ]; then
204        rm -f "$PID_FILE"
205        echo -n "OK"
206    else
207        echo -n "FAIL"
208    fi
209
210    echo
211
212    return $retval
213}
214
215
216status() {
217    local retval=0
218    local pid="$(_get_pid)"
219
220    if _is_running; then
221        # Unquote $pid here to display multiple PIDs in one line
222        echo "$SERVICE:$MINION_USER:$MINION_ID is running:" $pid
223    else
224        retval=3
225        echo "$SERVICE:$MINION_USER:$MINION_ID is stopped."
226        if [ -e "$PID_FILE" ]; then
227            echo "$SERVICE:$MINION_USER:$MINION_ID has orphaned pid file: $PID_FILE."
228            retval=1
229        fi
230    fi
231    return $retval
232}
233
234restart() {
235    # $1 - config dir
236    stop "$1"
237    start "$1"
238}
239
240
241main() {
242    if [ -n "$SALTMINION_DEBUG" ]; then
243        set -x
244        ERROR_TO_DEVNULL="&2"
245    fi
246
247    # Check to see if --notrim is a valid netstat option
248    if ! ( netstat --help 2>&1 | grep -wq '\-\-notrim') ; then
249        NS_NOTRIM=''
250    fi
251
252    # Pre-filter for unhandled commands
253    case "$1" in
254        (start|stop|status|restart|condrestart|try-restart) ;;
255        (reload)
256            echo "Can't reload $SERVICE - you must restart it"
257            exit 3
258            ;;
259        (*)
260            echo "Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload}"
261            exit 2
262            ;;
263    esac
264
265    while read MINION_USER CONFIG_DIR; do
266        if [ -z "$CONFIG_DIR" ]; then
267            continue
268        fi
269
270        if ! [ -d "$CONFIG_DIR" ]; then
271            echo "ERROR: non-existent $SERVICE config directory: $CONFIG_DIR"
272            RETVAL=1
273            continue
274        fi
275
276        SOCK_DIR="$(_get_salt_config_value sock_dir)"
277        PID_FILE="$(_get_salt_config_value pidfile)"
278        LOG_FILE="$(_get_salt_config_value log_file)"
279        MINION_ID="$(_get_salt_config_value id)"
280        MINION_ID_HASH="$(_make_id_hash "$MINION_ID")"
281        if [ \
282            -z "$SOCK_DIR" \
283            -o -z "$PID_FILE" \
284            -o -z "$LOG_FILE" \
285            -o -z "$MINION_ID" \
286            -o -z "$MINION_ID_HASH" \
287        ]; then
288            echo "ERROR: Unable to look-up config values for $CONFIG_DIR"
289            RETVAL=1
290            continue
291        fi
292
293        # See how we were called.
294        case "$1" in
295            (start|stop|restart|status)
296                "$1" || RETVAL=$?
297                ;;
298            (condrestart|try-restart)
299                if ! _is_running; then
300                    RETVAL=7
301                else
302                    stop
303                    start || RETVAL=$?
304                fi
305                ;;
306            (*)
307                echo "Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload}"
308                RETVAL=2
309                ;;
310        esac
311    done <<EOF
312$SALTMINION_CONFIGS
313EOF
314
315    exit $RETVAL
316}
317
318
319if [ "$#" = 0 ]; then
320    main
321else
322    main "$@"
323fi
324