Uruchamianie dowolnego programu jako demona ze skryptu inicjującego

10

Muszę zainstalować program jako usługę w Red Hat. Nie stanowi tła, nie zarządza plikiem PID ani nie zarządza własnymi dziennikami. Po prostu działa i drukuje do STDOUT i STDERR.

Używając standardowych skryptów inicjujących jako przewodników, opracowałem:

#!/bin/bash
#
#   /etc/rc.d/init.d/someprog
#
# Starts the someprog daemon
#
# chkconfig: 345 80 20
# description: the someprog daemon
# processname: someprog
# config: /etc/someprog.conf

# Source function library.
. /etc/rc.d/init.d/functions

prog="someprog"
exec="/usr/local/bin/$prog"
[ -e "/etc/sysconfig/$prog" ] && . "/etc/sysconfig/$prog"
lockfile="/var/lock/subsys/$prog"
RETVAL=0

check() {
    [ `id -u` = 0 ] || exit 4
    test -x "$exec" || exit 5
}

start() {
    check
    if [ ! -f "$lockfile" ]; then
        echo -n $"Starting $prog: " 
        daemon --user someproguser "$exec"
        RETVAL=$?
        [ $RETVAL -eq 0 ] && touch "$lockfile"
        echo
    fi
    return $RETVAL
}

stop() {
    check
    echo -n $"Stopping $prog: "
    killproc "exec"
    RETVAL=$?
    [ $RETVAL -eq 0 ] && rm -f "$lockfile"
    echo
    return $RETVAL
}

restart() {
    stop
    start
}   

case "$1" in
start)
    start
    ;;
stop)
    stop
    ;;
restart)
    restart
    ;;
status)
    status "$prog"
    RETVAL=$?
    ;;
*)
    echo $"Usage: $0 {start|stop|restart|status}"
    RETVAL=2
esac

exit $RETVAL

Być może moim błędem było skopiowanie-wklejenie i zmodyfikowanie niektórych istniejących skryptów w /etc/init.d. W każdym razie wynikowa usługa zachowuje się dziwnie:

  • kiedy go uruchamiam, service someprog startprogram drukuje na terminalu, a polecenie nie kończy się.
  • jeśli I CTRL-C, wyświetli „Sesja zakończona, zabijanie powłoki ... ... zabite. NIEUDANE”. Muszę to zrobić, aby ponownie wyświetlić monit powłoki.
  • teraz, kiedy uruchamiam service someprog status, mówi, że działa i wyświetla swój PID. Widzę to, pswięc działa.
  • teraz kiedy uruchamiam service someprog stop, nie przestaje. Mogę sprawdzić, czy nadal działa ps.

Co muszę zmienić, aby someprogzostało wysłane w tle i zarządzane jako usługa?

Edycja: Znalazłem teraz kilka powiązanych pytań, z których żadne nie ma rzeczywistej odpowiedzi innej niż „zrób coś innego”:

Edycja: ta odpowiedź przy podwójnym rozwidleniu mogła rozwiązać mój problem, ale teraz mój program podwójnie rozwidla i to działa: https://stackoverflow.com/a/9646251/898699

Baron Schwartz
źródło
Czy uruchamiasz program za pomocą narzędzia „daemon” dostarczonego przez libslack. libslack.org/daemon/#documentation W tym przypadku program może zostać zatrzymany jako demon -n nazwa -stop. Spróbuj także przekierować dane wyjściowe (podczas uruchamiania programu) do pliku lub / dev / null i sprawdź.
Ankit
2
W zależności od wersji redhat, możesz po prostu zrobić dla niego prosty otok podczas uruchamiania i wywoływać go bezpośrednio. Następnie upstart będzie zarządzał usługą za Ciebie. Jest to jednak kwestia EL6.
Matthew Ife

Odpowiedzi:

1

Polecenie „nie zostało ukończone”, ponieważ daemonfunkcja nie uruchamia aplikacji w tle. Musisz dodać &na końcu daemonpolecenia w następujący sposób:

daemon --user someproguser $exec &

Jeśli someprognie obsługuje SIGHUP, powinieneś uruchomić polecenie z, nohupaby upewnić się, że proces nie odbierze, SIGHUPco każe procesowi zakończyć działanie po wyjściu powłoki nadrzędnej. To by wyglądało tak:

daemon --user someproguser "nohup $exec" &

W twojej stopfunkcji killproc "exec"nic nie robisz, aby zatrzymać twój program. Powinno to brzmieć tak:

killproc $exec

killprocwymaga pełnej ścieżki do Twojej aplikacji, aby ją poprawnie zatrzymać. W przeszłości miałem pewne problemy killproc, więc możesz po prostu zabić PID w pliku PIDFILE, do którego powinieneś pisać someprogPID za pomocą czegoś takiego:

cat $pidfile | xargs kill

Możesz zapisać plik PIDFILE w następujący sposób:

ps aux | grep $exec | grep -v grep | tr -s " " | cut -d " " -f2 > $pidfile

gdzie $pidfilewskazuje /var/run/someprog.pid.

Jeśli chcesz [OK] lub [FAILED] w swojej stopfunkcji, powinieneś użyć funkcji successi failurez /etc/rc.d/init.d/functions. Nie potrzebujesz ich w startfunkcji, ponieważ daemonwywołuje odpowiednią dla Ciebie.

Potrzebujesz także tylko cudzysłowu wokół ciągów ze spacjami. Jest to jednak wybór stylu, więc to zależy od Ciebie.

Wszystkie te zmiany wyglądają następująco:

#!/bin/bash
#
#   /etc/rc.d/init.d/someprog
#
# Starts the someprog daemon
#
# chkconfig: 345 80 20
# description: the someprog daemon
# processname: someprog
# config: /etc/someprog.conf

# Source function library.
. /etc/rc.d/init.d/functions

prog=someprog
exec=/usr/local/bin/$prog
[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog
lockfile=/var/lock/subsys/$prog
pidfile=/var/run/$prog
RETVAL=0

check() {
    [ `id -u` = 0 ] || exit 4
    test -x $exec || exit 5
}

start() {
    check
    if [ ! -f $lockfile ]; then
        echo -n $"Starting $prog: " 
        daemon --user someproguser "nohup $exec" &
        RETVAL=$?
        if [ $RETVAL -eq 0 ]; then
          touch $lockfile
          ps aux | grep $exec | grep -v grep | tr -s " " | cut -d " " -f2 > $pidfile
        fi
        echo
    fi
    return $RETVAL
}

stop() {
    check
    echo -n $"Stopping $prog: "
    killproc $exec && cat $pidfile | kill
    RETVAL=$?
    if [ $RETVAL -eq 0 ]; then
      rm -f $lockfile
      rm -f $pidfile
      success; echo
    else
      failure; echo
    fi
    echo
    return $RETVAL
}

restart() {
    stop
    start
}   

case "$1" in
start)
    start
    ;;
stop)
    stop
    ;;
restart)
    restart
    ;;
status)
    status $prog
    RETVAL=$?
    ;;
*)
    echo $"Usage: $0 {start|stop|restart|status}"
    RETVAL=2
esac

exit $RETVAL
Stuporman
źródło
Przepraszamy, zajęło ci prawie 4,5 roku, aby uzyskać właściwą odpowiedź.
Stuporman
-1

Jeśli to twój program, napisz go jako właściwego demona. Zwłaszcza jeśli chodzi o redystrybucję. :)

Możesz spróbować monitorować . A może coś takiego jak runit lub daemontools. Te potężne nie mają łatwo dostępnych pakietów. Daemontools pochodzi od DJB, jeśli ma to wpływ na twoją decyzję (w dowolnym kierunku).

toppledwagon
źródło
-1

Zrobiłem trochę więcej badań i wydaje się, że odpowiedź brzmi „nie możesz tego zrobić”. Program, który ma zostać uruchomiony, musi się właściwie właściwie zdemonizować: rozwidlić i odłączyć swoje standardowe uchwyty plików, odłączyć od terminala i rozpocząć nową sesję.

Edycja: najwyraźniej się mylę - podwójne rozwidlenie działałoby. https://stackoverflow.com/a/9646251/898699

Baron Schwartz
źródło
Możesz to zrobić za pomocą upstartu, jak podano w komentarzach.