Skip to content

Commit f50069a

Browse files
committed
Added site health check job
1 parent a08b590 commit f50069a

File tree

15 files changed

+491
-95
lines changed

15 files changed

+491
-95
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use App\Jobs\CheckSiteHealth;
6+
use App\Models\Site;
7+
use Illuminate\Console\Command;
8+
9+
class PerformSiteHealthCheck extends Command
10+
{
11+
/**
12+
* The name and signature of the console command.
13+
*
14+
* @var string
15+
*/
16+
protected $signature = 'app:check-site-health {siteId}';
17+
18+
/**
19+
* The console command description.
20+
*
21+
* @var string
22+
*/
23+
protected $description = 'Check site health for given site id';
24+
25+
/**
26+
* Execute the console command.
27+
*/
28+
public function handle()
29+
{
30+
CheckSiteHealth::dispatchSync(
31+
Site::findOrFail($this->input->getArgument('siteId'))
32+
);
33+
}
34+
}

app/Http/Controllers/Controller.php renamed to app/Controllers/Controller.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace App\Http\Controllers;
3+
namespace app\Controllers;
44

55
abstract class Controller
66
{

app/Enum/HttpMethod.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace App\Enum;
4+
5+
enum HttpMethod
6+
{
7+
case POST;
8+
case GET;
9+
case PATCH;
10+
case HEAD;
11+
case PUT;
12+
case DELETE;
13+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace App\Http\Middleware;
4+
5+
use Closure;
6+
7+
class HorizonBasicAuthMiddleware
8+
{
9+
/**
10+
* Handle an incoming request.
11+
*
12+
* @param \Illuminate\Http\Request $request
13+
* @param \Closure $next
14+
* @return mixed
15+
*/
16+
public function handle($request, Closure $next)
17+
{
18+
$authenticationHasPassed = false;
19+
20+
if ($request->header('PHP_AUTH_USER', null) && $request->header('PHP_AUTH_PW', null)) {
21+
$username = $request->header('PHP_AUTH_USER');
22+
$password = $request->header('PHP_AUTH_PW');
23+
24+
if ($username === config('horizon.basic_auth.username')
25+
&& $password === config('horizon.basic_auth.password')) {
26+
$authenticationHasPassed = true;
27+
}
28+
}
29+
30+
if ($authenticationHasPassed === false) {
31+
return response()->make('Invalid credentials.', 401, ['WWW-Authenticate' => 'Basic']);
32+
}
33+
34+
return $next($request);
35+
}
36+
}

app/Jobs/CheckSiteHealth.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace App\Jobs;
4+
5+
use App\Enum\HttpMethod;
6+
use App\Models\Site;
7+
use GuzzleHttp\Exception\RequestException;
8+
use Illuminate\Contracts\Queue\ShouldQueue;
9+
use Illuminate\Foundation\Queue\Queueable;
10+
11+
class CheckSiteHealth implements ShouldQueue
12+
{
13+
use Queueable;
14+
15+
/**
16+
* Create a new job instance.
17+
*/
18+
public function __construct(protected readonly Site $site)
19+
{
20+
}
21+
22+
/**
23+
* Execute the job.
24+
*/
25+
public function handle(): void
26+
{
27+
$response = $this->site->performWebserviceRequest(
28+
HttpMethod::GET,
29+
'health.json'
30+
);
31+
32+
$healthData = collect($response);
33+
34+
// Perform a sanity check
35+
if (!$healthData->has('cms_version')) {
36+
throw new \Exception("Invalid health response content");
37+
}
38+
39+
// Write updated data to DB
40+
$this->site->update($healthData->only([
41+
'php_version',
42+
'db_type',
43+
'db_version',
44+
'cms_version',
45+
'server_os'
46+
])->toArray());
47+
}
48+
}

app/Jobs/UpdateSite.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace App\Jobs;
4+
5+
use Illuminate\Contracts\Queue\ShouldQueue;
6+
use Illuminate\Foundation\Queue\Queueable;
7+
8+
class UpdateSite implements ShouldQueue
9+
{
10+
use Queueable;
11+
12+
/**
13+
* Create a new job instance.
14+
*/
15+
public function __construct()
16+
{
17+
//
18+
}
19+
20+
/**
21+
* Execute the job.
22+
*/
23+
public function handle(): void
24+
{
25+
//
26+
}
27+
}

app/Models/Site.php

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
1-
<?php
1+
<?php declare(strict_types=1);
22

33
namespace App\Models;
44

5+
use App\Enum\HttpMethod;
6+
use App\Exceptions\RemotesiteCommunicationException;
7+
use GuzzleHttp\Client;
8+
use GuzzleHttp\Exception\RequestException;
9+
use GuzzleHttp\Psr7\Request;
10+
use GuzzleHttp\Psr7\Response;
511
use Illuminate\Database\Eloquent\Factories\HasFactory;
612
use Illuminate\Foundation\Auth\User as Authenticatable;
713
use Illuminate\Notifications\Notifiable;
14+
use Illuminate\Support\Facades\App;
15+
use Psr\Http\Message\RequestInterface;
16+
use Psr\Http\Message\ResponseInterface;
817

918
class Site extends Authenticatable
1019
{
@@ -34,4 +43,77 @@ protected function casts(): array
3443
'update_major' => 'bool'
3544
];
3645
}
46+
47+
public function getUrlAttribute(string $value): string
48+
{
49+
return rtrim($value, "/") . "/";
50+
}
51+
52+
53+
protected function performRequest(
54+
RequestInterface $request,
55+
array $options = []
56+
): array {
57+
/** @var Client $httpClient */
58+
$httpClient = App::make(Client::class);
59+
60+
/** @var Response $response */
61+
$response = $httpClient->send(
62+
$request,
63+
$options
64+
);
65+
66+
// Validate response
67+
if (!json_validate((string) $response->getBody())) {
68+
throw new RequestException(
69+
"Invalid JSON body",
70+
$request,
71+
$response
72+
);
73+
}
74+
75+
// Return decoded body
76+
return json_decode(
77+
(string) $response->getBody(),
78+
true,
79+
512,
80+
JSON_THROW_ON_ERROR
81+
);
82+
}
83+
84+
public function performExtractionRequest(array $data, string $password): array
85+
{
86+
$request = new Request(
87+
'POST',
88+
$this->url . 'extract.php'
89+
);
90+
91+
$data['password'] = $password;
92+
93+
return $this->performRequest(
94+
$request,
95+
[
96+
'form_params' => $data,
97+
'timeout' => 300.0
98+
]
99+
);
100+
}
101+
102+
public function performWebserviceRequest(HttpMethod $method, string $endpoint, array $data = []): array
103+
{
104+
$request = new Request(
105+
$method->name,
106+
$this->url . $endpoint,
107+
[
108+
'Authorization' => 'JUpdate-Token ' . $this->key
109+
]
110+
);
111+
112+
return $this->performRequest(
113+
$request,
114+
[
115+
"json" => $data
116+
]
117+
);
118+
}
37119
}

app/Models/User.php

Lines changed: 0 additions & 32 deletions
This file was deleted.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace App\Providers;
4+
5+
use Laravel\Horizon\Horizon;
6+
use Laravel\Horizon\HorizonApplicationServiceProvider;
7+
8+
class HorizonServiceProvider extends HorizonApplicationServiceProvider
9+
{
10+
/**
11+
* Overload authorization method from \Laravel\Horizon\HorizonApplicationServiceProvider
12+
* to allow access to Horizon without having a logged in user.
13+
*
14+
* @return void
15+
*/
16+
protected function authorization()
17+
{
18+
Horizon::auth(function () {
19+
return true;
20+
});
21+
}
22+
}

bootstrap/app.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
health: '/up',
1212
)
1313
->withMiddleware(function (Middleware $middleware) {
14-
//
14+
$middleware->alias([
15+
'horizonBasicAuth' => \App\Http\Middleware\HorizonBasicAuthMiddleware::class
16+
]);
1517
})
1618
->withExceptions(function (Exceptions $exceptions) {
1719
//

0 commit comments

Comments
 (0)