Christian Seiler: apachectl - wie Server auf leichte Weise neustarten?

Beitrag lesen

Hallo Marc,

Welche Möglichkeit gibt es, in einem Shell-Skript zu ermitteln, ob alle notwendigen Apache-Instanzen *wirklich* komplett neu gestartet sind?

Für diesen Zweck ist es sinnvoll, einfach zu überprüfen, ob die Log-Dateien noch offen sind. Wenn dies der Fall ist, so ist der Apache noch nicht komplett neu gestartet - wenn alle Dateien bereits zu sind, schon.

Auf den SELF-Servern habe ich mir ein paar Python-Scripte für den Zweck programmiert. Hier die relevanten Ausschnitte:

lrutils.py: Hilfsfunktion, die überprüft, ob bestimmte Dateien noch offen sind:

#!/usr/bin/env python  
# -*- coding: utf-8 -*-  
#  
# Utility functions for rotating logfiles  
  
import os  
from stat import *  
  
# Check whether any of the specified files is still in use.  
# Will only work correctly if the files are only opened by programs run under  
# the current user or when this script is run as root.  
def filesInUse (files):  
        # Get Inode / Device number for all files to check and save them for  
        # later. Ignore non-existing files.  
        tocheck = []  
        for file in files:  
                try:  
                        statinfo = os.stat (file)  
                        tocheck.append ((statinfo[ST_INO], statinfo[ST_DEV]))  
                except OSError:  
                        pass  
  
        # Nothing to check? No file in use  
        if not len (tocheck):  
                return False  
  
        # Search /proc  
        for pid in os.listdir ("/proc"):  
                # Only enter PID-type directories  
                if not pid.isdigit(): continue  
                try:  
                        # Get all file descriptors for the process and compare  
                        # the inode and device numbers with the inode and  
                        # device numbers of the files we want to check. If at  
                        # least one file is already open, we're done.  
                        for fd in os.listdir ("/proc/%s/fd" % pid):  
                                try:  
                                        statinfo = os.stat ("/proc/%s/fd/%s" % (pid, fd))  
                                        if tocheck.count ((statinfo[ST_INO], statinfo[ST_DEV])) > 0:  
                                                return True  
                                except OSError:  
                                        # Ignore access errors  
                                        pass  
                except OSError:  
                        # Ignore access errors  
                        pass  
  
        # None of the files was found to be open  
        return False

rotatelogs.py (Teile davon zumindest): Rotieren von Logfiles

#!/usr/bin/env python  
# -*- coding: utf-8 -*-  
#  
# Rotate logfiles  
  
# Import needed modules  
import lrutils, os, time, glob, sys  
  
# Initial period to wait if not closed immediately  
interval1 = 20  
# Interval to wait subsequently  
interval = 60  
# The logfiles to copy  
logfiles = ['/var/log/apache2/access_log', '/var/log/apache2/error_log', '/var/log/apache2/access_log.*', '/var/log/apache2/error_log.*']  
  
# Get logfiles to rotate  
logfiles = reduce (lambda x, y: x+y, [glob.glob(y) for y in logfiles])  
rotated = [x + '.rotated' for x in logfiles]  
  
# Rotate all logfiles  
for logfile in logfiles:  
        os.rename (logfile, logfile + '.rotated')  
  
# Reload apache  
os.system ('/usr/sbin/apache2ctl graceful')  
  
# Now definitely sleep at least 1 second - Apache will *never* be  
# finished reloading *so* quickly  
time.sleep (1);  
  
# If logfiles are already closed: we're done  
if not lrutils.filesInUse (rotated):  
        # Stelle etwas mit den rotierten Logfiles an  
        sys.exit (0)  
  
# If not, wait first interval  
time.sleep (interval1)  
  
# While logfiles are still open: wait normal interval  
while lrutils.filesInUse (rotated):  
        # Do another reload because sometimes apache does not close the logs  
        # for some reason.  
        os.system ('/usr/sbin/apache2ctl graceful')  
        time.sleep (interval)  
  
# Stelle was mit den rotierten Logfiles an

Was macht der Code hier?

  1. Die Logfiles werden von $logfile nach $logfile.rotated umbenannt. Der Apache schreibt dann natürlich in die .rotated-Dateien, da der Kernel sich nur um die Inode-Nummern kümmert.

  2. Dem Apache wird ein graceful geschickt. Er macht dann auf jeden Fall die neuen Logfiles auf (d.h. im Verzeichnis existieren $logfile und $logfile.rotated).

  3. In mehreren regelmäßigen Intervallen überprüft das Script, ob die $logfile.rotated noch in Gebrauch sind. Wenn dies nicht der Fall ist, hat der Apache alle Logs zugemacht und das Script kann etwas mit den Logs anstellen (das habe ich hier ausgelassen, weil das SELF-Server-spezifisch ist - wir verschieben die alle auf einen einzigen Server, lassen dort das Statistikprogramm drüberlaufen und löschen die dann allesamt).

Was noch auf meiner TODO-Liste hierfür steht (allerdings ziemlich weit unten, da nicht kritisch), wäre eine Möglichkeit, nach soundsolanger Zeit (ein paar Stunden z.B.) auch einen restart zu schicken, wenn die Logs dann immer noch nicht freigegeben wurden.

Wenn jemand was mit dem Code anfangen will, ich stelle ihn (sofern er überhaupt eine Schöpfungshöhe erreicht) unter die MIT-Lizenz.

Viele Grüße,
Christian