Implement the system status api endpoint. Closes #1936

This commit is contained in:
James Brooks
2016-07-12 19:29:45 +01:00
parent 0cd3ea0e92
commit fdfebc18fb
8 changed files with 217 additions and 37 deletions

View File

@@ -11,13 +11,38 @@
namespace CachetHQ\Cachet\Composers; namespace CachetHQ\Cachet\Composers;
use CachetHQ\Cachet\Integrations\Core\System;
use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\ComponentGroup; use CachetHQ\Cachet\Models\ComponentGroup;
use CachetHQ\Cachet\Models\Incident; use CachetHQ\Cachet\Models\Incident;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
/**
* This is the status page composer.
*
* @author James Brooks <james@alt-three.com>
*/
class StatusPageComposer class StatusPageComposer
{ {
/**
* The system instance.
*
* @var \CachetHQ\Cachet\Integrations\Contracts\System
*/
protected $system;
/**
* Create a new status page composer instance.
*
* @param \CachetHQ\Cachet\Integrations\Contracts\System $system
*
* @return void
*/
public function __construct(System $system)
{
$this->system = $system;
}
/** /**
* Index page view composer. * Index page view composer.
* *
@@ -27,42 +52,7 @@ class StatusPageComposer
*/ */
public function compose(View $view) public function compose(View $view)
{ {
$totalComponents = Component::enabled()->count(); $status = $this->system->getStatus();
$majorOutages = Component::enabled()->status(4)->count();
$isMajorOutage = $totalComponents ? ($majorOutages / $totalComponents) >= 0.5 : false;
// Default data
$withData = [
'system_status' => 'info',
'system_message' => trans_choice('cachet.service.bad', $totalComponents),
'favicon' => 'favicon-high-alert',
];
if ($isMajorOutage) {
$withData = [
'system_status' => 'danger',
'system_message' => trans_choice('cachet.service.major', $totalComponents),
'favicon' => 'favicon-high-alert',
];
} elseif (Component::enabled()->notStatus(1)->count() === 0) {
// If all our components are ok, do we have any non-fixed incidents?
$incidents = Incident::notScheduled()->orderBy('created_at', 'desc')->get()->filter(function ($incident) {
return $incident->status > 0;
});
$incidentCount = $incidents->count();
if ($incidentCount === 0 || ($incidentCount >= 1 && (int) $incidents->first()->status === 4)) {
$withData = [
'system_status' => 'success',
'system_message' => trans_choice('cachet.service.good', $totalComponents),
'favicon' => 'favicon',
];
}
} else {
if (Component::enabled()->whereIn('status', [2, 3])->count() > 0) {
$withData['favicon'] = 'favicon-medium-alert';
}
}
// Scheduled maintenance code. // Scheduled maintenance code.
$scheduledMaintenance = Incident::scheduled()->orderBy('scheduled_at')->get(); $scheduledMaintenance = Incident::scheduled()->orderBy('scheduled_at')->get();
@@ -72,7 +62,7 @@ class StatusPageComposer
$componentGroups = ComponentGroup::whereIn('id', $usedComponentGroups)->orderBy('order')->get(); $componentGroups = ComponentGroup::whereIn('id', $usedComponentGroups)->orderBy('order')->get();
$ungroupedComponents = Component::enabled()->where('group_id', 0)->orderBy('order')->orderBy('created_at')->get(); $ungroupedComponents = Component::enabled()->where('group_id', 0)->orderBy('order')->orderBy('created_at')->get();
$view->with($withData) $view->with($status)
->withComponentGroups($componentGroups) ->withComponentGroups($componentGroups)
->withUngroupedComponents($ungroupedComponents) ->withUngroupedComponents($ungroupedComponents)
->withScheduledMaintenance($scheduledMaintenance); ->withScheduledMaintenance($scheduledMaintenance);

View File

@@ -0,0 +1,47 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Foundation\Providers;
use CachetHQ\Cachet\Integrations\Contracts\System as SystemContract;
use CachetHQ\Cachet\Integrations\Core\System;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\ServiceProvider;
/**
* This is the integration service provider.
*
* @author James Brooks <james@alt-three.com>
*/
class IntegrationServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->registerSystem();
}
/**
* Register the system class.
*
* @return void
*/
protected function registerSystem()
{
$this->app->singleton(SystemContract::class, function (Container $app) {
return new System();
});
}
}

View File

@@ -11,6 +11,7 @@
namespace CachetHQ\Cachet\Http\Controllers\Api; namespace CachetHQ\Cachet\Http\Controllers\Api;
use CachetHQ\Cachet\Integrations\Contracts\System;
use CachetHQ\Cachet\Integrations\Releases; use CachetHQ\Cachet\Integrations\Releases;
/** /**
@@ -44,4 +45,16 @@ class GeneralController extends AbstractApiController
'latest' => $latest, 'latest' => $latest,
])->item(CACHET_VERSION); ])->item(CACHET_VERSION);
} }
/**
* Get the system status message.
*
* @return \Illuminate\Http\JsonResponse
*/
public function status()
{
$system = app()->make(System::class)->getStatus();
return $this->item($system['system_message']);
}
} }

View File

@@ -33,6 +33,7 @@ class ApiRoutes
$router->group(['middleware' => ['auth.api']], function (Registrar $router) { $router->group(['middleware' => ['auth.api']], function (Registrar $router) {
$router->get('ping', 'GeneralController@ping'); $router->get('ping', 'GeneralController@ping');
$router->get('version', 'GeneralController@version'); $router->get('version', 'GeneralController@version');
$router->get('status', 'GeneralController@status');
$router->get('components', 'ComponentController@getComponents'); $router->get('components', 'ComponentController@getComponents');
$router->get('components/groups', 'ComponentGroupController@getGroups'); $router->get('components/groups', 'ComponentGroupController@getGroups');

View File

@@ -0,0 +1,27 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Integrations\Contracts;
/**
* This is the system interface.
*
* @author James Brooks <james@alt-three.com>
*/
interface System
{
/**
* Get the entire system status.
*
* @return array
*/
public function getStatus();
}

View File

@@ -0,0 +1,70 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Integrations\Core;
use CachetHQ\Cachet\Integrations\Contracts\System as SystemContract;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\Incident;
/**
* This is the core system class.
*
* @author James Brooks <james@alt-three.com>
*/
class System implements SystemContract
{
/**
* Get the entire system status.
*
* @return array
*/
public function getStatus()
{
$enabledScope = Component::enabled();
$totalComponents = Component::enabled()->count();
$majorOutages = Component::enabled()->status(4)->count();
$isMajorOutage = $totalComponents ? ($majorOutages / $totalComponents) >= 0.5 : false;
// Default data
$status = [
'system_status' => 'info',
'system_message' => trans_choice('cachet.service.bad', $totalComponents),
'favicon' => 'favicon-high-alert',
];
if ($isMajorOutage) {
$status = [
'system_status' => 'danger',
'system_message' => trans_choice('cachet.service.major', $totalComponents),
'favicon' => 'favicon-high-alert',
];
} elseif (Component::enabled()->notStatus(1)->count() === 0) {
// If all our components are ok, do we have any non-fixed incidents?
$incidents = Incident::notScheduled()->orderBy('created_at', 'desc')->get()->filter(function ($incident) {
return $incident->status > 0;
});
$incidentCount = $incidents->count();
if ($incidentCount === 0 || ($incidentCount >= 1 && (int) $incidents->first()->status === 4)) {
$status = [
'system_status' => 'success',
'system_message' => trans_choice('cachet.service.good', $totalComponents),
'favicon' => 'favicon',
];
}
} elseif (Component::enabled()->whereIn('status', [2, 3])->count() > 0) {
$status['favicon'] = 'favicon-medium-alert';
}
return $status;
}
}

View File

@@ -184,6 +184,7 @@ return [
'CachetHQ\Cachet\Foundation\Providers\ComposerServiceProvider', 'CachetHQ\Cachet\Foundation\Providers\ComposerServiceProvider',
'CachetHQ\Cachet\Foundation\Providers\ConsoleServiceProvider', 'CachetHQ\Cachet\Foundation\Providers\ConsoleServiceProvider',
'CachetHQ\Cachet\Foundation\Providers\ConfigServiceProvider', 'CachetHQ\Cachet\Foundation\Providers\ConfigServiceProvider',
'CachetHQ\Cachet\Foundation\Providers\IntegrationServiceProvider',
'CachetHQ\Cachet\Foundation\Providers\EventServiceProvider', 'CachetHQ\Cachet\Foundation\Providers\EventServiceProvider',
'CachetHQ\Cachet\Foundation\Providers\RepositoryServiceProvider', 'CachetHQ\Cachet\Foundation\Providers\RepositoryServiceProvider',
'CachetHQ\Cachet\Foundation\Providers\RouteServiceProvider', 'CachetHQ\Cachet\Foundation\Providers\RouteServiceProvider',

View File

@@ -0,0 +1,31 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Tests\Cachet\Foundation\Providers;
use AltThree\TestBench\ServiceProviderTrait;
use CachetHQ\Cachet\Integrations\Contracts\System;
use CachetHQ\Tests\Cachet\AbstractTestCase;
/**
* This is the integration service provider test class.
*
* @author James Brooks <james@alt-three.com>
*/
class IntegrationServiceProviderTest extends AbstractTestCase
{
use ServiceProviderTrait;
public function testSystemIsInjectable()
{
$this->assertIsInjectable(System::class);
}
}