Check If Systemd Services Are Running

Created by CecilWesterhof.

In the past I wrote a script to check if systemd services where running and if not tried to restart them. I rewrote this script into Tcl and added some functionalities.

The main code is:

init
foreach service $services {
    debugOutput $debug "Checking: $service"
    if {! [isServiceActive $service]} {
        puts "$service is not running"
        giveStatus   $service
        if {[startService $service]} {
            puts "    $service started"
        } else {
            puts "    $service NOT started"
            giveStatus
        }
    }
}

It checks all the services and if one is not running it tries to start it.

To check if a service is running I use:

proc isServiceActive {service} {
    if {[catch {exec systemctl status $service} result]} {
        if {([lindex $::errorCode 0] == "CHILDSTATUS") &&
            ([lindex $::errorCode 2] == 3)} {
            return False
        }
        error $result
    }
    return True
}

The call 'systemctl status SERVICE' returns 0 if the service is running and 3 if it is not running. Anything else is an error.

If the service is not running I give the status:

proc giveStatus {service} {
    set  status [getCleanOutput "systemctl status $service" {3}]
    puts "\nStatus:\n$status"
}

Which uses: Getting Cleaned Up Output from a Command.

It then tries to start the service:

proc startService {service} {
    puts "\nTrying to start:"
    exec systemctl start $service
    sleep $::startTime
    isServiceActive $service
}

If that is successful it says that, otherwise it says it was not successful and displays the status of the service.

The initialisation is done with:

proc init {} {
    set ::debug     False
    set ::startTime 5
    set parameters  $::argv

    switch [lindex $parameters 0] {
        --debug {
            set ::debug    True
            set parameters [lrange $parameters 1 end]
        }
        --active {
            puts "Active services:"
            foreach service [getServices] {
                puts "    $service"
            }
            exit
        }
        --inactive {
            puts "Inactive services:"
            foreach service [getServices F] {
                puts "    $service"
            }
            exit
        }
    }
    if {[llength $parameters] > 0} {
        set ::services $parameters
    } else {
        set ::services [getServices]
    }
}

Default the services to check are retrieved from the database, but you can also give them on the command-line. It is possible to activate debugging. And a list with the active or inactive services can be shown.

To get the list with (in)active services:

proc getServices {{active T}} {
    getDefaultDB
    set services [db eval {
        SELECT   service
        FROM     checkServices
        WHERE    active = :active
        ORDER BY service
    }]
    db close
    return $services
}

I will share getDefaultDB later.

To create the table:

CREATE TABLE checkServices (
    service TEXT    PRIMARY KEY,
    active  TEXT    NOT NULL DEFAULT 'T' CHECK(active IN ('T', 'F'))
);

To sleep a few seconds (to give the service time to start):

proc sleep {seconds} {
    after [expr {$seconds * 1000}]
}

The proc debugOutput is very simple:

proc debugOutput {giveOutput Message} {
    if {$giveOutput} {
        puts $Message
    }
}

As always: comments, tips and questions are appreciated.