From fa0c4ff0d243e4c2c908664a145873948a1f4213 Mon Sep 17 00:00:00 2001 From: flashwave Date: Fri, 9 Dec 2016 23:28:25 +0100 Subject: [PATCH] some status stuff --- app/Controllers/StatusController.php | 52 +++++++++- app/Status.php | 102 +++++++++++++++++++ config/config.example.ini | 7 +- database/2016_12_09_225434_status_tables.php | 43 ++++++++ resources/views/yuuno/status/index.twig | 101 ++++++------------ routes.php | 1 + 6 files changed, 234 insertions(+), 72 deletions(-) create mode 100644 app/Status.php create mode 100644 database/2016_12_09_225434_status_tables.php diff --git a/app/Controllers/StatusController.php b/app/Controllers/StatusController.php index cbe683b..0caf481 100644 --- a/app/Controllers/StatusController.php +++ b/app/Controllers/StatusController.php @@ -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); } } diff --git a/app/Status.php b/app/Status.php new file mode 100644 index 0000000..1439dc3 --- /dev/null +++ b/app/Status.php @@ -0,0 +1,102 @@ + + */ +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); + } +} diff --git a/config/config.example.ini b/config/config.example.ini index ff5a53b..9afccfe 100644 --- a/config/config.example.ini +++ b/config/config.example.ini @@ -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 = diff --git a/database/2016_12_09_225434_status_tables.php b/database/2016_12_09_225434_status_tables.php new file mode 100644 index 0000000..ad1bf48 --- /dev/null +++ b/database/2016_12_09_225434_status_tables.php @@ -0,0 +1,43 @@ +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'); + } +} diff --git a/resources/views/yuuno/status/index.twig b/resources/views/yuuno/status/index.twig index 7a86681..1d95df4 100644 --- a/resources/views/yuuno/status/index.twig +++ b/resources/views/yuuno/status/index.twig @@ -10,7 +10,7 @@ all services are go!
- this is a static design preview + this is an not as static as it was before design preview
{% endblock %} @@ -18,79 +18,42 @@ {% block content %}
-
-
-
main site
-
-
-
-
test site
-
-
-
-
api
-
-
-
-
chat server
-
-
-
-
chat client
-
-
-
-
irc gateway
-
-
-
-
tekkit
-
+ {% for name in endpoints %} +
+
+
{{ name }}
+
+ {% endfor %}
graph goes here
-
-
Aug 4, 2016
-
-
-
-
9:01 UTC
-
Resolved
-
-
- That fixed it for some reason. -
-
-
-
-
8:45 UTC
-
Monitoring
-
-
- Dropkicking the server out of the window. -
-
-
-
-
8:30 UTC
-
Investigating
-
-
- Having connectivity issues with the server. -
+ {% for date, events in incidents %} +
+
{{ date }}
+
+ {% if events|length > 0 %} + {% for event in events %} + {% set state = event.state|lower %} +
+
+
{{ event.time }} UTC
+
{{ event.state }}
+
+
+ {{ event.comment }} +
+
+ {% endfor %} + {% else %} +
+
+ No incidents occurred. +
+
+ {% endif %}
-
-
-
Aug 3, 2016
-
-
-
- No incidents occurred. -
-
-
-
+ {% endfor %}
{% endblock %} diff --git a/routes.php b/routes.php index 2d93a16..792f344 100644 --- a/routes.php +++ b/routes.php @@ -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