some status stuff
This commit is contained in:
parent
9f7416e32b
commit
fa0c4ff0d2
6 changed files with 234 additions and 72 deletions
|
@ -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
102
app/Status.php
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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 =
|
||||
|
|
43
database/2016_12_09_225434_status_tables.php
Normal file
43
database/2016_12_09_225434_status_tables.php
Normal 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');
|
||||
}
|
||||
}
|
|
@ -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 %}
|
||||
|
|
|
@ -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
|
||||
|
|
Reference in a new issue