Contao-Monitoring mit Icinga

von Kirsten Roschanski

Motivation

Mit jedem neuen Contao Update wird die Sicherheit verbessert, Fehler werden behoben und neue Funktionen hinzugefügt. Daher ist es zu empfehlen, dass man seine Contao Installation immer auf dem neusten Stand hält. Vor allem wenn man sich um mehrere Installationen kümmert, kann dies sehr unübersichtlich werden. Daher überprüfen wir unsere Installationen über Icinga2.

Voraussetzung

Man braucht hier für:

  • einen github-Token um die Versionsnummern auszulesen
  • einen Contao-Mananger-Token

github-Token

Diesen kann man ganz einfach unter https://github.com/settings/tokens erstellen.

Dieser wird in der config.php gespeichert.

<?php
# https://github.com/settings/tokens
$github_token = 'GITHUB_TOKEN';
$contaoVersions = [
    "4.9" => [
       "start" =>  '20200215',
       "end"   =>  '20240214' 
    ], 
    "4.13" => [
       "start" =>  '20220215',
       "end"   =>  '20260214' 
    ],
   "5.0" => [
      "start" =>  '20220815',
      "end"   =>  '20230214' 
   ],
   "5.1" => [
      "start" =>  '20230215',
      "end"   =>  '20230814' 
   ],
   "5.2" => [
      "start" =>  '20230815',
      "end"   =>  '20240214' 
   ] ,
   "5.3" => [
      "start" =>  '20240215',
      "end"   =>  '20280814' 
   ] ,
   "5.4" => [
      "start" =>  '20240815',
      "end"   =>  '20250214' 
   ] ,
   "5.5" => [
      "start" =>  '20250215',
      "end"   =>  '20250814' 
   ] 
];

Contao-Manager-Link

Diesen kann man ganz einfach selbst erstellen. Entweder direkt per ansible oder wie in der Doku beschrieben per URL.

Das Check-Contao-Update-Skript

# Angeregt von Admin Intelligence https://blog.admin-intelligence.de/nextcloud-mit-icinga2-auf-updates-ueberpruefen/
#!/usr/bin/php
<?php

# Source
# 

$shortopts  = "";
$shortopts .= "H:";  // Hostname
$shortopts .= "T:";  // Token
$shortopts .= "S";   // noSSL
$shortopts .= "c";   // no contao-manager via href
$shortopts .= "p";   // perfdata output
$longopts = array(
  "help"
);

$options = getopt($shortopts, $longopts);

if(array_key_exists("help",$options)){
  echo "HELP:\n";
  echo " -H hostname (required)\n";
  echo " -T token (required)\n";
  echo " -S SSL\n";
  echo " -c contao-manager via href\n";
  echo " -p perfdata output\n";
  exit(3);
}
if (!function_exists('curl_exec')){
  echo "Please install curl";
  exit(3);
}

if(!array_key_exists("H",$options)){
  echo "Please Specify a Host";
  exit(3);
}

if(!array_key_exists("T",$options)){
  echo "Please Specify a Token";
  exit(3);
}

if(!array_key_exists("S",$options)){
  $contao_server = "https://".$options["H"];
}else{
  $contao_server = "http://".$options["H"];
}
$contao_status_url = "$contao_server/contao-manager.phar.php/api/server/contao";

function error($e){
  echo "Something went wrong: $e";
  exit(3);
}

function get_newest_version($contao_releases = "https://api.github.com/repos/contao/contao/tags?per_page=100"){
  require_once realpath( dirname( __FILE__ ) )."/config.php";

  $headers = array(
    'Content-Type: application/json',
    'Accept: application/vnd.github+json',
    'Authorization: Bearer ' . $github_token,
  );

  $curl = curl_init($contao_releases);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($curl, CURLOPT_USERAGENT, 'Icinga');
  curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
  
  try{
    $response = curl_exec ($curl);
    curl_close($curl);
  }catch(Exception $e){
    error($e);
  }

  $arrData = json_decode($response, true);
  if(is_array($arrData)){
    $return = [];
    foreach ($arrData as $data) {
      $arrVersion = explode('.', $data['name']);
      $strMainVersion = $arrVersion[0] . '.' . $arrVersion[1];
      $return[$strMainVersion][] = $data['name'];
    }
    foreach ($return as $strMainVersion => $data) {
      $arrMainVersions = array_keys($contaoVersions);
      if(!in_array($strMainVersion, $arrMainVersions)) {
        unset($return[$strMainVersion]);
      }
    }
    foreach ($return as $strMainVersion => $data) {
      $return[$strMainVersion] = $data[0];
    }
    return $return;
  }
  return false;
}

function get_installed_version($contao_status_url , $token){

  $headers = array(
    'Content-Type: application/json',
    'Connection: Close',
    'Authorization: Bearer ' . $token,
  );  

  $curl = curl_init($contao_status_url);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($curl, CURLOPT_USERAGENT, 'Icinga');
  curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
  
  try{
    $response = curl_exec ($curl);
    curl_close($curl);
  }catch(Exception $e){
    error($e);
  }

  $arrData = json_decode($response, true);
  if(is_array($arrData)){
    return $arrData["version"];
  }
  return false;
}

# get data
$newer=get_newest_version();
$actual=get_installed_version($contao_status_url, $options["T"]);

$arrVersion = explode('.', $actual);
$strMainVersion = $arrVersion[0] . '.' . $arrVersion[1];
$newer = $newer[$strMainVersion];

# perfdata
if(array_key_exists("p",$options)){
  $perfdata = "running=".str_replace(".", "", $actual)." stable=".str_replace(".", "", $newer);
}
else {
  $perfdata = "";
}

# output
if (version_compare($newer,$actual,"eq")) {
  if (!array_key_exists("c",$options)) {
    echo "<a href='$contao_server/contao-manager.phar.php' target=_blank>Current version is ($actual). (channel: stable, version: $newer)|$perfdata</a>";
  } else {
    echo "Current version is ($actual). (channel: stable, version: $newer)|$perfdata";
  }
  exit(0);
} else {
  if (!array_key_exists("c",$options)) {
    echo "<a href='$contao_server/contao-manager.phar.php' target=_blank>Current version is ($actual). Update to contao $newer available. (channel: stable)|$perfdata</a>";
  } else {
    echo "Current version is ($actual). Update to contao $newer available. (channel: stable)|$perfdata";
  }
  exit(1);
}

Das Checkskript sollte unter check_contao_update gespeichert werden.
Zuerst muss das Skript ausführbar gemacht werden
chmod +x check_nextcloud_update.php

So führt man das Skript aus:
./check_contao_update.php -H kirsten-roschanski.de -T CONATO-MANGER-TOKEN

Das Checkskript muss nun in den Nagios-Plugin-Ordner verschoben werden und anschließend muss ein neuer Icinga-Command dafür geschrieben werden.

Icinga-Command

object CheckCommand "check_contao_updates" {
  import "plugin-check-command"
  command = [PluginDir + "/check_contao_update.php" ]
  arguments += {	
     "-H" = {
      required = true
      value = "$contao_host$"
     }
     "-T" = {
      required = true
      value = "$contao_managertoken$"
     }
  }
}

Icinga-Service

Damit wir den Check in einen Host aktivieren können, müssen wir dafür einen neuen Service schreiben. Der Service kann folgendermaßen aussehen.

/// *** check_contao_updates *** ///
apply Service for (contao_name => config in host.vars.check_contao_updates) {
	import "24/7"
	
	check_timeout = "900"
	
	name = "check_contao_updates_" + contao_name
	display_name = "Contao Updates " + contao_name
	
	vars += config
	
	check_command = "check_contao_updates"
	
	assign where host.vars.check_contao_updates
	ignore where host.vars.check_contao_updates.enable_check == false
}

Aktivierung im Host

Zu guter Letzt aktivieren wir den Check in der Hostconfig. Das kann man mit folgender Zeile erreichen:

vars.check_contao_updates["kirsten-roschanski.de (Update)"] = {
 contao_host = "kirsten-roschanski.de"
 contao_managertoken = "123456789123456789"
 contao_ssl = true
}

Icinga noch einmal neu laden:

/etc/init.d/icinga2 reload

Jetzt können wir unseren neuen Contao-Check auf unserer Icingaweb2 Oberfläche finden.