Skip to content
Snippets Groups Projects
Server.php 8.95 KiB
Newer Older
Tibo's avatar
Tibo committed
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;
Tibo's avatar
Tibo committed

class Server extends Model
{

    protected $fillable = ["token"];

Tibo's avatar
Tibo committed
    /**
     * Last record from this server (used for caching).
     * @var String
     */
    private $last_record = null;

Tibo's avatar
Tibo committed
    private static $sensors = [
        \App\Sensor\LoadAvg::class,
Tibo's avatar
Tibo committed
        \App\Sensor\MemInfo::class,
        \App\Sensor\Ifconfig::class,
        \App\Sensor\Netstat::class,
Tibo's avatar
Tibo committed
        \App\Sensor\ListeningPorts::class,
        \App\Sensor\Reboot::class,
Tibo's avatar
Tibo committed
        \App\Sensor\Updates::class,
Tibo's avatar
Tibo committed
        \App\Sensor\Disks::class,
Tibo's avatar
Tibo committed
        \App\Sensor\Inodes::class,
Tibo's avatar
Tibo committed
        \App\Sensor\Ssacli::class,
Tibo's avatar
Tibo committed
        \App\Sensor\Perccli::class,
        \App\Sensor\Date::class,
Tibo's avatar
Tibo committed
        \App\Sensor\ClientVersion::class,
        \App\Sensor\Heartbeat::class,
        \App\Sensor\DiskEvolution::class,
        \App\Sensor\CPUtemperature::class,
Tibo's avatar
Tibo committed
        \App\Sensor\USBtemperature::class
Tibo's avatar
Tibo committed
    public function __construct(array $attributes = array())
    {
Tibo's avatar
Tibo committed
        $attributes["token"] = str_random(32);
        parent::__construct($attributes);
    }

Tibo's avatar
Tibo committed
    public function organization()
    {
Tibo's avatar
Tibo committed
        return $this->belongsTo("App\Organization");
    }
Tibo's avatar
Tibo committed

Tibo's avatar
Tibo committed
    public function lastRecord()
    {
Tibo's avatar
Tibo committed
        if ($this->last_record == null) {
            $collection = \Mongo::get()->monitoring->records;
            $this->last_record =  $collection->findOne(
Tibo's avatar
Tibo committed
                ["server_id" => $this->id],
                ["sort" => ["_id" => -1]]
            );
Tibo's avatar
Tibo committed
        }

        return $this->last_record;
Tibo's avatar
Tibo committed
    }

Tibo's avatar
Tibo committed
    /**
     * Get the last $count records containing $field.
     * !! $count is the MAXIMUM number of returned records.
     * To optimize mongo's usage of index, we get the last $count records
     * then filter locally for records containing this record
     * Records are returned in chronological order
     * @param type $field
     * @param type $count
     * @return type
     */
    public function lastRecords(string $field, int $count)
    {
        $records = \Mongo::get()->monitoring->records->find(
            ["server_id" => $this->id],
            ["limit" => $count, "sort" => ["_id" => -1]]
        );

        $results = [];
        foreach ($records as $record) {
            if (isset($record->$field)) {
                $results[] = $record;
            }
        }

        usort($results, function ($r1, $r2) {
            return $r1->time  > $r2->time ? 1 : -1;
        });

        return $results;
    }

    public function hasData() : bool
    {
        return $this->lastRecord() != null;
    }

Tibo's avatar
Tibo committed
    /**
     *
Tibo's avatar
Tibo committed
     * @return \Carbon\Carbon
Tibo's avatar
Tibo committed
     */
Tibo's avatar
Tibo committed
    public function lastRecordTime()
    {
        $last_record = $this->lastRecord();
        if ($last_record === null) {
            return \Carbon\Carbon::createFromTimestamp(0);
        }

        return \Carbon\Carbon::createFromTimestamp($last_record->time);
Tibo's avatar
Tibo committed
    }

Tibo's avatar
Tibo committed
    public function clientVersion()
    {
        $last_record = $this->lastRecord();
        if ($last_record == null) {
            return "none";
        }

        return $last_record->version;
Tibo's avatar
Tibo committed
    }
    public function lastClientUrl()
    {
Tibo's avatar
Tibo committed
        $client_sensor = new \App\Sensor\ClientVersion($this);
        return $client_sensor->latestUrl();
    }
Tibo's avatar
Tibo committed

Tibo's avatar
Tibo committed
    /**
     * Get integer status of server.
     * @return int
     */
Tibo's avatar
Tibo committed
    public function status()
    {
Tibo's avatar
Tibo committed
        return max($this->statusArray());
    }

Tibo's avatar
Tibo committed
    public function statusBadge()
    {
Tibo's avatar
Tibo committed
        return AbstractSensor::getBadgeForStatus($this->status());
    }

Tibo's avatar
Tibo committed
    public function statusArray()
    {
Tibo's avatar
Tibo committed
        $status_array = [];
Tibo's avatar
Tibo committed
        foreach ($this->getSensors() as $sensor) {
            $sensor_name = \get_class($sensor);
            try {
                $status_array[$sensor_name] = $sensor->status();
            } catch (\Exception $ex) {
                $status_array[$sensor_name] = Sensor::STATUS_UNKNOWN;
                Log::error("Sensor $sensor_name failed : " . $ex->getTraceAsString());
            }
Tibo's avatar
Tibo committed
        }
Tibo's avatar
Tibo committed
        return $status_array;
Tibo's avatar
Tibo committed
    }

Tibo's avatar
Tibo committed
    public function getSensorsNOK()
    {
Tibo's avatar
Tibo committed
        $sensorsNOK = [];
        foreach ($this->getSensors() as $sensor) {
            if ($sensor->status() > 0) {
                $sensorsNOK[] = $sensor;
            }
        }
        return $sensorsNOK;
    }

Tibo's avatar
Tibo committed
    public function statusString()
    {
        return self::getNameForStatus($this->status());
    }

    public static function getNameForStatus($status)
    {
        switch ($status) {
Tibo's avatar
Tibo committed
            case 0:
                return "OK";
            case 10:
                return "WARNING";
            case 20:
                return "ERROR";
            default:
                return "Unknown";
        }
Tibo's avatar
Tibo committed
    }
Tibo's avatar
Tibo committed
    public function getBadge()
    {
Tibo's avatar
Tibo committed
        return AbstractSensor::getBadgeForStatus($this->status());
    }

Tibo's avatar
Tibo committed
    public function color()
    {
Tibo's avatar
Tibo committed
        return AbstractSensor::getColorForStatus($this->status());
    }

Tibo's avatar
Tibo committed
    public function getSensors()
    {

        $sensors = [];
        foreach (self::$sensors as $sensor) {
            $sensors[] = new $sensor($this);
        }
        return $sensors;
    }
Tibo's avatar
Tibo committed
    /**
     * Human readable uptime.
     *
     * @return string
     */
    public function uptime() : string
Tibo's avatar
Tibo committed
    {
Tibo's avatar
Tibo committed
        $record = $this->lastRecord();
        if (! isset($record["upaimte"])) {
            return "unknown";
Tibo's avatar
Tibo committed
        }

Tibo's avatar
Tibo committed
        return $this->parseUptime($record->upaimte);
Tibo's avatar
Tibo committed
    }

Tibo's avatar
Tibo committed
    public function parseUptime(string $string) : string
Tibo's avatar
Tibo committed
    {
        $pieces = explode(' ', $string);
        $uptime = \Carbon\Carbon::now()->subSeconds($pieces[0]);
        return $uptime->diffForHumans(null, true);
    }
Tibo's avatar
Tibo committed

Tibo's avatar
Tibo committed
    public function uuid()
    {
Tibo's avatar
Tibo committed
        $record = $this->lastRecord();
        if (! isset($record["system"])) {
Tibo's avatar
Tibo committed
            return "";
        }

        return $this->parseUUID($record->system);
    }

    const UUID = "/\s*UUID: (.*)/m";

    public function parseUUID(string $string) : string
Tibo's avatar
Tibo committed
    {
        $matches = array();
        preg_match(self::UUID, $string, $matches);
        if (! isset($matches[1])) {
            return "unknown";
        }
Tibo's avatar
Tibo committed
        return $matches[1];
    }

Tibo's avatar
Tibo committed

Tibo's avatar
Tibo committed
    public function cpuinfo() : array
Tibo's avatar
Tibo committed
    {
Tibo's avatar
Tibo committed
        $record = $this->lastRecord();
        if (! isset($record["cpu"])) {
            return ["threads" => 0,
                "cpu" => "unknown"];
Tibo's avatar
Tibo committed
        }

Tibo's avatar
Tibo committed
        return $this->parseCpuinfo($record->cpu);
Tibo's avatar
Tibo committed
    }

    const CPU_INFO = "/^model name	: (.+)$/m";
Tibo's avatar
Tibo committed
    public function parseCpuinfo($string) : array
Tibo's avatar
Tibo committed
    {
Tibo's avatar
Tibo committed
        $matches = array();
        preg_match_all(self::CPU_INFO, $string, $matches);

        $result["threads"] = count($matches[0]);
Tibo's avatar
Tibo committed
        $result["cpu"] = $matches[1][0];
Tibo's avatar
Tibo committed
        return $result;
Tibo's avatar
Tibo committed
    public function meminfo()
    {
Tibo's avatar
Tibo committed
        return round($this->memoryTotal() / 1000 / 1000) . " GB";
    }

    /**
     *
     * @return int total memory (in KB)
     */
Tibo's avatar
Tibo committed
    public function memoryTotal()
    {
Tibo's avatar
Tibo committed
        $record = $this->lastRecord();
        if (! isset($record["memory"])) {
Tibo's avatar
Tibo committed
            return null;
Tibo's avatar
Tibo committed
        }

Tibo's avatar
Tibo committed
        return $this->parseMeminfo($record->memory);
Tibo's avatar
Tibo committed
    }

    const MEMINFO = "/^MemTotal:\\s+([0-9]+) kB$/m";
Tibo's avatar
Tibo committed
    public function parseMeminfo($string)
    {
Tibo's avatar
Tibo committed
        $matches = array();
        preg_match(self::MEMINFO, $string, $matches);
        $total = $matches[1];
        return $total;
Tibo's avatar
Tibo committed
    public function lsb()
    {
Tibo's avatar
Tibo committed
        $record = $this->lastRecord();
        if (! isset($record["lsb"])) {
            return "unknown";
        }

        return $this->parseLsb($record->lsb);
    }

    const LSB = "/^Description:	(.+)$/m";
Tibo's avatar
Tibo committed
    public function parseLsb($string) : string
Tibo's avatar
Tibo committed
    {
        $matches = [];
        preg_match(self::LSB, $string, $matches);
        return $matches[1];


    const REGEX_MANUFACTURER = "/^\s*Manufacturer: (.*)$/m";
    public function parseManufacturer(string $string) : string
Tibo's avatar
Tibo committed
    {
        $matches = [];
        preg_match(self::REGEX_MANUFACTURER, $string, $matches);

        if (!isset($matches[1])) {
            return "unkwnown";
        }
        return $matches[1];
    }

Tibo's avatar
Tibo committed
    public function manufacturer()
    {
Tibo's avatar
Tibo committed
        $record = $this->lastRecord();
        if (! isset($record["system"])) {
            return "unknown";
        }

        return $this->parseManufacturer($record->system);
    }

    const REGEX_PRODUCT_NAME = "/^\s*Product Name: (.*)$/m";
    public function parseProductName(string $string) : string
Tibo's avatar
Tibo committed
    {
        $matches = [];
        preg_match(self::REGEX_PRODUCT_NAME, $string, $matches);
        if (!isset($matches[1])) {
            return "unkwnown";
        }
        return $matches[1];
    }

Tibo's avatar
Tibo committed
    public function productName()
    {
Tibo's avatar
Tibo committed
        $record = $this->lastRecord();
        if (! isset($record["system"])) {
            return "unknown";
        return $this->parseProductName($record->system);
Tibo's avatar
Tibo committed

Tibo's avatar
Tibo committed
    public function getChanges($count = 10)
    {
Tibo's avatar
Tibo committed
        return \App\StatusChange::getLastChangesForServer($this->id, $count);
    }
Tibo's avatar
Tibo committed
    public static function id($id) : Server
    {
Tibo's avatar
Tibo committed
        return self::where("id", $id)->first();
    }
Tibo's avatar
Tibo committed
}