some status stuff

This commit is contained in:
flash 2016-12-09 23:28:25 +01:00
parent 9f7416e32b
commit fa0c4ff0d2
6 changed files with 234 additions and 72 deletions

View file

@ -6,6 +6,10 @@
namespace Sakura\Controllers;
use Carbon\Carbon;
use Sakura\DB;
use Sakura\Status;
/**
* The status page and related stuff.
* @package Sakura
@ -13,12 +17,56 @@ namespace Sakura\Controllers;
*/
class StatusController extends Controller
{
protected const EVENT_STATE = [
0 => 'Monitoring',
1 => 'Investigating',
2 => 'Resolved',
];
/**
* Renders the base status page.
* @return string
*/
public function index(): string
public function index()
{
return view('status/index');
$endpoints = array_keys(config('status.check'));
$events = DB::table('status_events')
->get();
$incidents = [];
foreach ($events as $row) {
$date = Carbon::createFromFormat('Y-m-d H:i:s', $row->event_date);
$incidents[$date->format('M j, Y')][] = [
'time' => $date->format('G:i'),
'state' => static::EVENT_STATE[$row->event_state],
'comment' => $row->event_text,
];
}
return view('status/index', compact('endpoints', 'incidents'));
}
/**
* Gets status information.
* @return string
*/
public function data()
{
$endpoints = config('status.check');
$name = $_GET['name'] ?? null;
if (!array_key_exists($name, $endpoints)) {
return $this->json(['error' => 'Unknown host.']);
}
[$address, $port, $protocol] = explode('/', $endpoints[$name]);
$status = new Status($address, $port, $protocol);
if ($status->state === null) {
$status->check();
$status->save();
}
return $this->json($status);
}
}

102
app/Status.php Normal file
View file

@ -0,0 +1,102 @@
<?php
/**
* Status checking.
* @package Sakura
*/
namespace Sakura;
/**
* Status checking.
* @package Sakura
* @author Julian van de Groep <me@flash.moe>
*/
class Status
{
private $address = '';
private $port = 0;
private $protocol = '';
public $state = null;
public $history = [];
public const OK = 2;
public const ERROR = 1;
public const FAIL = 0;
public function __construct(string $address, int $port, string $protocol = '', bool $populate = true)
{
$this->address = $address;
$this->port = $port;
$this->protocol = $protocol;
if ($populate) {
$this->populate();
}
}
public function populate(): void
{
$this->history = DB::table('status_history')
->where('history_name', $this->address)
->where('history_port', $this->port)
->where('history_protocol', $this->protocol)
->orderBy('history_date', 'desc')
->get();
$this->state = isset($this->history[0]) ? intval($this->history[0]->history_state) : null;
}
public function check(): int
{
$this->state = static::FAIL;
$sock = checkdnsrr($this->address) ? fsockopen($this->address, $this->port, $errno, $errstr, 1) : false;
if ($sock !== false) {
fclose($sock);
$this->state = static::OK;
if ($this->protocol === 'http' || $this->protocol === 'https') {
$header = strstr(
Net::request("{$this->protocol}://{$this->address}:{$this->port}/", 'head', null, 1),
"\r\n",
true
);
if ($header !== false && strtolower(substr($header, 0, 4)) == 'http') {
list($protocol, $response, $text) = explode(' ', $header, 3);
if ($response >= 400 && $response < 500) {
$this->state = static::ERROR;
}
if ($response >= 500 && $response < 600) {
$this->state = static::FAIL;
}
}
}
}
return $this->state;
}
public function save()
{
DB::table('status_history')
->insert([
'history_name' => $this->address,
'history_port' => $this->port,
'history_protocol' => $this->protocol,
'history_state' => $this->state
]);
$this->history = array_merge(DB::table('status_history')
->where('history_name', $this->address)
->where('history_port', $this->port)
->where('history_protocol', $this->protocol)
->orderBy('history_date', 'desc')
->limit(1)
->get(), $this->history);
}
}

View file

@ -203,12 +203,17 @@ min_length = 1
; Content for the contact page, the variables function like a normal associative array
[contact]
mail['Administrator'] = sakura@localghost
mail['Administrator'] = me@flash.moe
twit['smugwave'] = "Sakura's main developer"
repo['Sakura'] = https://github.com/flashwave/sakura
; Status settings
[status]
check['flash.moe http'] = "flash.moe/80/http"
check['flash.moe https'] = "flash.moe/443/https"
; LastFM settings
[lastfm]
api_key =

View file

@ -0,0 +1,43 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Sakura\DB;
class StatusTables extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
$schema = DB::getSchemaBuilder();
$schema->create('status_history', function (Blueprint $table) {
$table->string('history_name');
$table->smallInteger('history_port')->unsigned();
$table->string('history_protocol');
$table->tinyInteger('history_state')->unsigned();
$table->timestamp('history_date')->useCurrent = true;
});
$schema->create('status_events', function (Blueprint $table) {
$table->increments('event_id');
$table->timestamp('event_date')->useCurrent = true;
$table->tinyInteger('event_state')->unsigned();
$table->string('event_text');
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
$schema = DB::getSchemaBuilder();
$schema->drop('status_history');
$schema->drop('status_events');
}
}

View file

@ -10,7 +10,7 @@
<span class="status__overall-icon"></span> <span class="status__overall-text">all services are go!</span>
</div>
<div class="status__last-update">
this is a static design preview
this is an not as static as it was before design preview
</div>
</div>
{% endblock %}
@ -18,79 +18,42 @@
{% block content %}
<div class="platform status__response">
<div class="status__services">
<div class="status__service status__service--good status__service--selected">
<div class="status__service-icon"></div>
<div class="status__service-name">main site</div>
</div>
<div class="status__service status__service--good">
<div class="status__service-icon"></div>
<div class="status__service-name">test site</div>
</div>
<div class="status__service status__service--bad">
<div class="status__service-icon"></div>
<div class="status__service-name">api</div>
</div>
<div class="status__service status__service--good">
<div class="status__service-icon"></div>
<div class="status__service-name">chat server</div>
</div>
<div class="status__service status__service--good">
<div class="status__service-icon"></div>
<div class="status__service-name">chat client</div>
</div>
<div class="status__service status__service--bad">
<div class="status__service-icon"></div>
<div class="status__service-name">irc gateway</div>
</div>
<div class="status__service status__service--bad">
<div class="status__service-icon"></div>
<div class="status__service-name">tekkit</div>
</div>
{% for name in endpoints %}
<div class="status__service status__service--good">
<div class="status__service-icon"></div>
<div class="status__service-name">{{ name }}</div>
</div>
{% endfor %}
</div>
<div class="status__graph">graph goes here</div>
</div>
<div class="platform status__incidents">
<div class="status__incident">
<div class="status__incident-date">Aug 4, 2016</div>
<div class="status__updates">
<div class="status__update status__update--good">
<div class="status__update-meta">
<div class="status__update-time">9:01 UTC</div>
<div class="status__update-state">Resolved</div>
</div>
<div class="status__update-text">
That fixed it for some reason.
</div>
</div>
<div class="status__update status__update--busy">
<div class="status__update-meta">
<div class="status__update-time">8:45 UTC</div>
<div class="status__update-state">Monitoring</div>
</div>
<div class="status__update-text">
Dropkicking the server out of the window.
</div>
</div>
<div class="status__update status__update--bad">
<div class="status__update-meta">
<div class="status__update-time">8:30 UTC</div>
<div class="status__update-state">Investigating</div>
</div>
<div class="status__update-text">
Having connectivity issues with the server.
</div>
{% for date, events in incidents %}
<div class="status__incident">
<div class="status__incident-date">{{ date }}</div>
<div class="status__updates">
{% if events|length > 0 %}
{% for event in events %}
{% set state = event.state|lower %}
<div class="status__update status__update--{% if state == 'resolved' %}good{% elseif state == 'monitoring' %}bad{% else %}busy{% endif %}">
<div class="status__update-meta">
<div class="status__update-time">{{ event.time }} UTC</div>
<div class="status__update-state">{{ event.state }}</div>
</div>
<div class="status__update-text">
{{ event.comment }}
</div>
</div>
{% endfor %}
{% else %}
<div class="status__update status__update">
<div class="status__update-text">
No incidents occurred.
</div>
</div>
{% endif %}
</div>
</div>
</div>
<div class="status__incident">
<div class="status__incident-date">Aug 3, 2016</div>
<div class="status__updates">
<div class="status__update status__update">
<div class="status__update-text">
No incidents occurred.
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}

View file

@ -77,6 +77,7 @@ Router::group(['before' => 'maintenance'], function () {
// Status
Router::group(['prefix' => 'status'], function () {
Router::get('/', 'StatusController@index', 'status.index');
Router::get('/data', 'StatusController@data', 'status.data');
});
// News