[+] automatyczne uruchamianie procesów na serwerze

Konfiguracja serwerów, usług, itp.
wenu
Posty: 57
Rejestracja: 04 grudnia 2009, 15:15

[+] automatyczne uruchamianie procesów na serwerze

Post autor: wenu »

Witam.
Zastanawiam się jak zrobić takie coś?
Skrypt/program sprawdza co XX czasu, czy dany proces istnieje, jeśli nie, uruchamia go w programie screen. Czytałem o tym kiedyś ale za ,,cukierka'' nie mogę sobie przypomnieć nazwy.
Chcę tego używać do automatyczne uruchamiania serwerów Counter-Strike po zaniku ich działania.

Pozdrawiam.

Edycja:

Znalazłem coś takiego

Kod: Zaznacz cały

 #!/usr/bin/perl -X  
 use Socket;
 
 #-----------------------------------------------------------
 # Konfiguracja (Do ustawienia według opisu)
 #-----------------------------------------------------------
 
 my $host = "x.x.x.x"; # Adres IP serwera do sprawdzania (To jest ten zbindowany).
 my $port = "27015";   # Port serwera, na którym chodzi.
 use constant CHECKEVERY => 90; # Jak często sprawdzać serwer ? (Tutaj ustawiono co 90 sekund).
 use constant TIMEOUT => 20;    # Jak długo czekać na jego odpowiedź zanim go zrestartujemy.
 
 # Poniżej podaj ścieżkę do skryptu uruchamiającego/restartującego serwer.
 # Oczywiście może to być także zwykła komenda zawierające odpowiednie opcje.
  
 my $cmd  = "/home/hlds_l/scripts/hlds restart";
 
 #-----------------------------------------------------------
 # Nie edytuj tego poniżej, chyba, że wiesz co robisz :)
 #-----------------------------------------------------------
 
 my $MAXLEN = 128;
 my $msg="\xFF\xFF\xFF\xFF\x54\x53\x6F\x75\x72\x63\x65\x20\x45\x6E\x67\x69\x6E\x65\x20\x51\x75\x65\x72\x79\x00";
 my $RET = "NONE!";
 $SIG{ALRM} = sub { &TimeOut };
 &Start;
 sub CheckServer {
     my $ipaddr = inet_aton($host);
     my $portaddr = sockaddr_in($port, $ipaddr);
     $RET = "NONE!";
     socket(SOCKET, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or die "socket: $!";
     send(SOCKET, $msg, 0, $portaddr) == length($msg) or die "Error Sending Query.\n";
     alarm(TIMEOUT);
     recv(SOCKET, $RET, $MAXLEN, 0);
     close SOCKET;
         sleep(CHECKEVERY);
 }
 sub Start {
     while (1) {
         &CheckServer;
         }
     }
 sub TimeOut {
 if ($RET eq "NONE!") {
     print "SERVER DOWN, RESTARTING!\n";
         $STARTSERV = `/usr/bin/perl -w $cmd`;
         print $STARTSERV . "\n";
     }
     sleep(CHECKEVERY);
     close SOCKET;
 }
Tylko jak to skonsumować, nadać prawa dostępu?

http://hlds.pl/ServerChecker tu opis.


Edycja:2

Zrobiłem tak, skrypt status, czyli uruchamia skrypt restart, czyli:

Kod: Zaznacz cały

NAME=Game_Server_1 EXECUTABLE=./game_server PARAMS="+set dedicated 2 +set net_ip 192.168.1. +set net_port 27733 +set sv_punkbuster 1 +set fs_homepath /path/to/server/ +exec server.cfg +map_rotate" DIR=/path/to/server/     case "$1" in     start)         if [[ `screen -ls |grep $NAME` ]]         then             echo "Error: $NAME is already running, use '$0 stop' to stop it"         else             cd $DIR             screen -dmS $NAME $EXECUTABLE $PARAMS             echo "$NAME was started."         fi     ;;     stop)         if [[ `screen -ls |grep $NAME` ]]         then             kill `screen -ls |grep $NAME |awk -F . '{print $1}'|awk '{print $1}'`             echo "$NAME was stopped"         else             echo "Error: $NAME isn't currently running"         fi     ;;     restart)         if [[ `screen -ls |grep $NAME` ]]         then             kill `screen -ls |grep $NAME |awk -F . '{print $1}'|awk '{print $1}'`         fi         cd $DIR         screen -dmS $NAME $EXECUTABLE $PARAMS         echo "$NAME was restarted"     ;;         status)         if [[ `screen -ls |grep $NAME` ]]         then             echo "$NAME is currently running"         else             echo "$NAME is NOT running"         fi     ;;     *)         echo "Usage: $0 {start|stop|restart|status}"         exit 1 esac exit 0
Skrypt drugi jak uruchomię ręcznie działa ładnie.
Problem jest z tym pierwszym, nadałem mu prawa dostępu, jak chcę uruchomić to wyświetla

Kod: Zaznacz cały

./status: line 2: use: command not found
./status: line 8: my: command not found
./status: line 9: my: command not found
./status: line 10: use: command not found
./status: line 11: use: command not found
./status: line 16: my: command not found
./status: line 22: my: command not found
./status: line 23: my: command not found
./status: line 24: my: command not found
./status: line 25: {ALRM}: command not found
./status: line 25: TimeOut: command not found
./status: line 26: syntax error near unexpected token `&'
./status: line 26: ` &Start;'
czakll
Posty: 90
Rejestracja: 22 listopada 2008, 18:57

Post autor: czakll »

Też miałem problemy z tym skryptem, darowałem sobie go. Stworzyłem prosty skrypcik w php, który sprawdza status serwera co X sekund.
Jako że kod php może być wykonany z poziomu konsoli świetnie się sprawdza.

Proszę, jeśli chcesz skorzystaj z mojego rozwiązania:

check.sh

Kod: Zaznacz cały

#!/bin/bash
czas=33 #co ile sekund ma sprawdzac czy serwer online
sciezka=/home/serwery/ #sciezka do odpalenia skryptu serwera
skrypt=serwer.sh # nazwa skryptu
screenname=cs16 #nazwa poszukiwanego screena
log=/home/serwery/cs16/logi
while [ true ] ; do # petla nieskonczonosci
status=$(php status.php) #odwolanie do skryptu w php
if [ $status = 1 ]
then
	echo "`date +%d/%m/%Y--%H:%M:%S` Serwer dziala!"
else 
	echo "`date +%d/%m/%Y--%H:%M:%S` Serwer nie dziala! Uruchamianie ponowne"
	pid=`screen -ls |grep $screenname |awk -F . '{print $1}'|awk '{print $1}'`
	if [ ! -z $pid ]
	then
		kill $pid
		
	fi 
	cd $sciezka && sh -c $sciezka$skrypt&
	echo "Serwer zrestartowany o `date +%d/%m/%Y--%H:%M:%S`" >> $log/restarty.txt #logowanie restartu serwera
fi
sleep $czas
done
counterstrike.php

Kod: Zaznacz cały

<?
// **********************************************************************************************
// Class CounterStrike
// Author : Henrik Schack ( http://henrik.schack.dk/ )
// 
// Changelog:
// Version 1.01        03/11/2001     Removed ASP style tags
//                                                         Removed usort warning
//                                                        Fixed error on empty server    
// Version 1.00        03/05/2001 Initial (& a bit messy ) release
// 
// A utilityclass (PHP4 only) to do serverstatus-queries against Halflife/Counterstrike servers
//
// The following functions are available:
// 
// Function getServerInfo(serveraddress,serverport)
// Get info about servername,serveraddress,mapname,currentplayers & maxplayers.
//
// Function getServerPlayers(serveraddress,serverport)
// Get info about players currently playing on the server.
// Players are sortet by frags.
//    
// Function getServerRules(serveraddress,serverport)
// Get info about serverrules/settings.
//
// All results are returned in membervariables:
//
//
// Demosource is available at http://www.gameserver.dk/
// **********************************************************************************************
// 
// Function used to sort players by frags
// Needs to be defined globally in order for usort to call it
//     

function fragsort ($a, $b) {   
    if ($a["frags"] == $b["frags"]) return 0;
    if ($a["frags"] > $b["frags"]) {
        return -1;
    } else {
        return 1;
    }
}    


Class CounterStrike {
    var $m_playerinfo        ="";        // Info about players
    var $m_servervars        ="";        // Info about the server current map, players etc
    var $m_serverrules  ="";        // Serverrules
    
    //
    // Get exact time, used for timeout counting
    //
    function timenow() {
        return doubleval(ereg_replace('^0\.([0-9]*) ([0-9]*)$','\\2.\\1',microtime()));
    }
    
    //
    // Read raw data from server
    //
    function getServerData($command,$serveraddress,$portnumber,$waittime) {
        $serverdata        ="";
        $serverdatalen=0;
        
        if ($waittime< 500) $waittime= 500;
        if ($waittime>2000) $waittime=2000;
        $waittime=doubleval($waittime/1000.0);

            
        if (!$cssocket=fsockopen("udp://".$serveraddress,$portnumber,$errnr)) {
            $this->errmsg="No connection";
            return "";
        }
        
        socket_set_blocking($cssocket,true);
        socket_set_timeout($cssocket,0,500000);
        fwrite($cssocket,$command,strlen($command));    
        // Mark
        $starttime=$this->timenow();
        do {
            $serverdata.=fgetc($cssocket);
            $serverdatalen++;
            $socketstatus=socket_get_status($cssocket);
            if ($this->timenow()>($starttime+$waittime)) {
                $this->errmsg="Connection timed out";
                fclose($cssocket);
                return "";
            }
        } while ($socketstatus["unread_bytes"] );
        fclose($cssocket);
        return $serverdata;        
    }
    
    function getnextstring(&$data) {
        $temp="";
        $counter=0;
        while (ord($data[$counter++])!=0) $temp.=$data[$counter-1];
        $data=substr($data,strlen($temp)+1);
         return $temp;
    }

    function getnextbytevalue(&$data) {
        $temp=ord($data[0]);
      $data=substr($data,1);
      return $temp;
    }

    function getnextfragvalue(&$data) {
        $frags=ord($data[0])+(ord($data[1])<<8)+(ord($data[2])<<16)+(ord($data[3])<<24);
        if ($frags>=4294967294) $frags-=4294967296;
        $data=substr($data,4);
        return $frags;
    }

    function getnextplaytime(&$data) {
        $decnumber=ord($data[0])+(ord($data[1])<<8)+(ord($data[2])<<16)+(ord($data[3])<<24);
        $binnumber=base_convert($decnumber,10,2);
        while (strlen($binnumber) < 32) $binnumber="0".$binnumber;
        $exp=abs(base_convert(substr($binnumber,1,8),2,10))-127;
        if (substr($binnumber,0,1)=="1") $exp=0-$exp;
        $man=1;$manadd=0.5;
        for ($counter=9;$counter<32;$counter++) {
            if (substr($binnumber,$counter,1)=="1") $man+=$manadd;
            $manadd=$manadd/2;
        }
        $time=round(pow(2,$exp)*$man);
        $playtime="";
        if ($time>3600) {
            $playtime=sprintf("%2dh",$time/3600);
        } 
        $time%=3600;
        $playtime=$playtime.sprintf("%2dm",$time/60);    
        $time%=60;
        $playtime=$playtime.sprintf("%2ds",$time);
        $data=substr($data,5);
        return $playtime;
    }

    // **********************************************************************
    // getServerRules
    // Read rules/setup from the gameserver into m_serverrules
    // Return true if successful
    // **********************************************************************
    function getServerRules($serveraddress,$portnumber,$waittime) {
        $cmd="\xFF\xFF\xFF\xFFrules\x00";        
        $serverdata=$this->getServerData($cmd,$serveraddress,$portnumber,$waittime)    ;
        // Check length of returned data, if < 5 something went wrong
        if (strlen($serverdata)<5) return false;            
        // Figure out how many rules there are
        $rules=(ord($serverdata[5]))+(ord($serverdata[6])*256);
        if ($rules!=0) {
            // Strip OOB data                
            $serverdata=substr($serverdata,7);
            for ($i=1;$i<=$rules;$i++) {
                $rulename        =$this->getnextstring($serverdata);
                $rulevalue    =$this->getnextstring($serverdata);
                $this->m_serverrules[$rulename]=$rulevalue;
            }
            return true;
        } else {
            return false;
        }
    }    

    
    // **********************************************************************
    // getServerinfo
    // Read information about the gameserver into m_servervars
    // Serveraddress,servername,current map etc etc
    // Return true if successful
    // **********************************************************************
    function getServerInfo($serveraddress,$portnumber,$waittime) {
	  $cmd="\xFF\xFF\xFF\xFF\x54\x53\x6F\x75\x72\x63\x65\x20\x45\x6E\x67\x69\x6E\x65\x20\x51\x75\x65\x72\x79\x00";
       // $cmd="\xFF\xFF\xFF\xFFinfo\x00";        
        $serverdata=$this->getServerData($cmd,$serveraddress,$portnumber,$waittime)    ;
        // Check length of returned data, if < 5 something went wrong
        if (strlen($serverdata)<5) return false;        
        // Strip OOB data                
        $serverdata=substr($serverdata,5);
        $this->m_servervars["serveraddress"]    =$this->getnextstring($serverdata);
        $this->m_servervars["servername"]            =$this->getnextstring($serverdata);
        $this->m_servervars["mapname"]                =$this->getnextstring($serverdata);
        $this->m_servervars["game"]                        =$this->getnextstring($serverdata);
        $this->m_servervars["gamename"]                =$this->getnextstring($serverdata);
        $this->m_servervars["currentplayers"]    =$this->getnextbytevalue($serverdata);
        $this->m_servervars["maxplayers"]            =$this->getnextbytevalue($serverdata);    
        return true;
}    


    // **********************************************************************
    // Get Playerinfo
    // Read information about the players into m_playerinfo
    // Name,frags,playtime
    // Return true if successful
    // **********************************************************************
    function getServerPlayers($serveraddress,$portnumber,$waittime) {
        // Servercommand
        $cmd="\xFF\xFF\xFF\xFFplayers\x00";
        $serverdata=$this->getServerData($cmd,$serveraddress,$portnumber,$waittime);
        
        // Check length of returned data, if < 5 something went wrong
        if (strlen($serverdata)<5) return false;
        
        // Check number of players to read data for
        $players=ord($serverdata[5]);
        
         // Strip OOB data and other stuff
        $serverdata=substr($serverdata,7);
        for ($i=1;$i<=$players;$i++) {
            $playername                            =htmlspecialchars($this->getnextstring($serverdata));
            $frags                                    =$this->getnextfragvalue($serverdata);
            $playtime                                =$this->getnextplaytime($serverdata);
            $this->m_playerinfo[$i] =array("name"=>$playername,"frags"=>$frags,"time"=>$playtime);
        }
        // Sort players in fragorder
        if ($players>1) usort($this->m_playerinfo,"fragsort");
        return true;
    }
}
?>
status.php

Kod: Zaznacz cały

<? require("counterstrike.php");
  $serveradr ="188.165.201.116";
  $serverport="27001";
  $csinfo=new CounterStrike;
  $status=$csinfo->getServerInfo($serveradr,$serverport,3000);
  if ($status) {
	echo "1";
} else {
echo "0";
}
?>
Uruchamiasz w screenie check.sh i masz spokój ;)
Pozdrawiam i mam nadzieję że pomogłem.
Pacek
Beginner
Posty: 315
Rejestracja: 18 sierpnia 2009, 15:17
Lokalizacja: Gdynia

Post autor: Pacek »

To skrypt, który napisałem w oparciu o jakiś znaleziony w internecie. Należy w nim zdefiniować nazwę demona oraz nazwę procesu. Pozycja demona w nawiasie musi odpowiadać pozycji procesu. Niestety jest często tak, że nazwa usługi jest inna od nazwy procesu. Jeżeli doda się wykonanie skryptu w cronie co 10 minut, to co 10 minut skrypt sprawdza czy usługi działają. Jeżeli któraś nie działa, to jest wysyłany e-mail na podany adres e-mail oraz usługa jest ponownie uruchamiana. Informacje są zapisywane we wskazanym logu.

Kod: Zaznacz cały

#!/bin/sh
######### Check Service and Restart ############
SERVICE_DAEMON=(mysql apache2 bind9 proftpd)
SERVICE_PROCESS=(mysqld apache2 named proftpd)
LOG_FILE=/var/log/service_monitor.log
#Ustawienia wiadomości e-mail
RECIPIENTS="twoj@adres.domena.com"
SUBJECT="Wystąpił problem z usługą"
MAIL_TEMP="/tmp/service.fail.$$"

i=0
SEND_FLAG=0
echo "" >$MAIL_TEMP
echo "Raport z dnia: "`date +'%Y-%m-%d %H:%M:%S'`>>$MAIL_TEMP
for n in ${SERVICE_PROCESS[@]}
do

    if ps ax | grep -v grep | grep $n > /dev/null
    then
        echo `date +'%Y-%m-%d %H:%M:%S'` Usługa ${SERVICE_DAEMON[$i]} jest uruchomiona >> $LOG_FILE
    else
        SEND_FLAG=1
        echo `date +'%Y-%m-%d %H:%M:%S'` Usługa ${SERVICE_DAEMON[$i]} nie jest uruchomiona >>$LOG_FILE
        echo `date +'%Y-%m-%d %H:%M:%S'` Usługa ${SERVICE_DAEMON[$i]} jest w trakcie uruchamiania >>$LOG_FILE
        /etc/init.d/${SERVICE_DAEMON[$i]} start 2>/dev/null 1>/dev/null
        echo "Usługa " ${SERVICE_DAEMON[$i]} nie działa! >>$MAIL_TEMP
        if ps ax | grep -v grep | grep $n>/dev/null
        then
            echo `date +'%Y-%m-%d %H:%M:%S'` Usługa ${SERVICE_DAEMON[$i]} została uruchomiona >>$LOG_FILE
        else
            echo `date +'%Y-%m-%d %H:%M:%S'` Usługa ${SERVICE_DAEMON[$i]} NIE została uruchomiona >>$LOG_FILE
        fi
    fi
    i=$(($i+1))
done
if [ $SEND_FLAG -eq 1 ];
then
    mail -s "${SUBJECT}" $RECIPIENTS < $MAIL_TEMP
fi
rm -f $MAIL_TEMP

exit 0
wenu
Posty: 57
Rejestracja: 04 grudnia 2009, 15:15

Post autor: wenu »

czakll, skrypt ciągle nie widzi serwera, mimo że jest on włączony i odpowiada, to skrypt informuje o braku odpowiedzi z serwera i uruchamia kolejne sesje screena. Skrypt jest z 2001 roku, serwery Counter Strike zmieniły protokół z 47 na 48 i myślę, że w tym jest problem.

pacek, a co jeśli na maszynie działają dwa serwery do Counter Strike? będzie uruchamiało dwa na raz?
czakll
Posty: 90
Rejestracja: 22 listopada 2008, 18:57

Post autor: czakll »

pacek, Twój skrypt monitoruje usługi WWW, MYSQL, serwery CS 1.6 nie są uruchamiane jako demony.

wenu
, do działania mojego skryptu wymagane jest php na serwerze.
wenu
Posty: 57
Rejestracja: 04 grudnia 2009, 15:15

Post autor: wenu »

Czyli muszę mieć serwer apache z php5, na przykład?
Pacek
Beginner
Posty: 315
Rejestracja: 18 sierpnia 2009, 15:17
Lokalizacja: Gdynia

Post autor: Pacek »

Przepraszam. Nie doczytałem, że to jest sam proces. Jeżeli napisany skrypt w PHP działa dobrze to ok ;) Minus to to, że trzeba mieć PHP. Ja poprawiłem mój w bashu. Dla przykładu wykorzystałem apache'a bo nie mam serwera CS'a a nie chce mi się go pobierać. Filozofia jest taka, że definiuje się wszystkie porty na których działa dany proces (w tym przypadku port 80 i 8080) oraz nazwę procesu. Skrypt sprawdza, czy serwer nasłuchuje na danym porcie. Jeżeli nie to należy go uruchomić (tutaj to już niestety popis dla CSowców jak się uruchamia proces CS'a).

Kod: Zaznacz cały

#!/bin/sh
SERVICE_PORT=(80 8080)
PROCESS_NAME=apache2

i=0
for n in ${SERVICE_PORT[@]}
do

    if netstat -n --tcp --listening --program |grep $n |grep $PROCESS_NAME > /dev/null #ps ax | grep -v grep | grep $n > /dev/null
        then
        echo `date +'%Y-%m-%d %H:%M:%S'` Proces ${PROCESS_NAME} na porcie $n jest uruchomiony
        else
        echo `date +'%Y-%m-%d %H:%M:%S'` Proces ${PROCESS_NAME} na porcie $n NIE jest uruchomiony
        #TUTAJ WSTAW URUCHAMIANIE PROCESU 2>/dev/null 1>/dev/null
        fi
i=$(($i+1))
done
exit 0
Awatar użytkownika
timor
Beginner
Posty: 111
Rejestracja: 18 sierpnia 2009, 23:40

Post autor: timor »

Nie ma po co wyważać otwartych drzwi.

Kod: Zaznacz cały

apt-cache search monit | grep -E '^monit'
Było jeszcze jedno narzędzie, trochę prostsze w obsłudze ale nie mogę sobie przypomnieć w tej chwili nazwy...


Już mam:

Kod: Zaznacz cały

apt-cache search daemontools
Wiedziałem, że nazwa była jakaś chwytliwa :)

Kod: Zaznacz cały

a collection of tools for managing UNIX services

supervise monitors a service. It starts the service and restarts the service if it dies.
Setting up a new service is easy: all supervise needs is a directory with a run script that runs the service. 
wenu
Posty: 57
Rejestracja: 04 grudnia 2009, 15:15

Post autor: wenu »

Cały myk polega na tym, że serwer do CS-a potrafi się zawiesić i wisieć z błędem. Proces nadal żyje i serwer chodzi ale wisi i tu właśnie potrzebny jest np. kod php, który sprawdza jego status.
Awatar użytkownika
timor
Beginner
Posty: 111
Rejestracja: 18 sierpnia 2009, 23:40

Post autor: timor »

monit pozwala zdefiniować "sprawdzanie" usługi.

P.S. Co do pierwszego posta... Błąd:

Kod: Zaznacz cały

./status: line 2: use: command not found
wskazuje, że albo nie masz perla w systemie albo nie ma go w podanej w pierwszej linii ścieżce.
ODPOWIEDZ