Zabbix integration

This commit is contained in:
JonatanRek 2024-08-16 23:37:42 +02:00
parent f3a3dcb566
commit b749cdf591
13 changed files with 214 additions and 67 deletions

View File

@ -15,22 +15,15 @@ class HostController extends BaseController
public function sync()
{
$zabbix = new ZabbixService("https://zabbix.itego.cz");
$zabbix->connect("spaninger", "*");
foreach ( $zabbix->maintenances([ "selectTimeperiods" => "extend" ]) as $maintennace ) {
if(Carbon::createFromTimestamp($maintennace['active_till'])->isPast()){
continue;
}
dd(Carbon::createFromTimestamp($maintennace['active_till']));
}
$zabbix = new ZabbixService(config('zabbix.url'));
$zabbix->connect(config('zabbix.username'), config('zabbix.password'));
foreach ($zabbix->hosts() as $host) {
Host::updateOrCreate([
"hostname" => $host['host'],
], [
"display_name" => $host['name'],
"external_id" => $host['hostid'],
]);
}

View File

@ -21,6 +21,8 @@ class MaintenanceController extends BaseController
public function plannedDetail(MaintenanceHistory $maintenance_history)
{
if (!empty($maintenance_history->finished_at)) {
abort(404);
}
@ -96,4 +98,73 @@ class MaintenanceController extends BaseController
'maintenance_history' => $maintenance_history ?? []
]);
}
public function start(Request $request, MaintenanceHistory $maintenance_history)
{
$hostsForMaintenance = [];
foreach ($maintenance_history->historyHosts as $historyHost) {
if (empty($historyHost->host->external_id)) {
continue;
}
$hostsForMaintenance[] = [
"hostid" => (int) $historyHost->host->external_id,
];
}
$zabbix = new ZabbixService(config('zabbix.url'));
$zabbix->connect(config('zabbix.username'), config('zabbix.password'));
if (empty($maintenance_history->maintenance->external_id)) {
$maintenance_history->maintenance->external_id = $zabbix->maintenancesCreate([
"name" => $maintenance_history->maintenance->name . ' - ' . $maintenance_history->start_at->format('Y'),
"description" => strip_tags($maintenance_history->maintenance->description),
"active_since" => $maintenance_history->start_at->startofyear()->timestamp,
"active_till" => $maintenance_history->start_at->endofyear()->timestamp,
"tags_evaltype" => 0,
"hosts" => $hostsForMaintenance,
"timeperiods" => [[
"timeperiod_type" => 0,
"start_date" => $maintenance_history->start_at->timestamp,
"period" => (($maintenance_history->maintenance->duration * 60) * 60),
]],
])['maintenanceids'][0];
$maintenance_history->maintenance->save();
} else {
$createPeriode = true;
$timePeriodes = $zabbix->maintenances([
"selectTimeperiods" => "extend",
'maintenanceids' => $maintenance_history->maintenance->external_id,
])[0]['timeperiods'];
foreach ($timePeriodes as $periode) {
if ((int) $periode['start_date'] === $maintenance_history->start_at->timestamp) {
$createPeriode = false;
}
}
if ($createPeriode) {
for ($i=0; $i < count($timePeriodes); $i++) {
unset($timePeriodes[$i]['every']);
unset($timePeriodes[$i]['month']);
unset($timePeriodes[$i]['dayofweek']);
unset($timePeriodes[$i]['day']);
unset($timePeriodes[$i]['start_time']);
}
$timePeriodes[] = [
"timeperiod_type" => 0,
"start_date" => $maintenance_history->start_at->timestamp,
"period" => (($maintenance_history->maintenance->duration * 60) * 60),
];
$zabbix->maintenancesUpdate([
"maintenanceid" => $maintenance_history->maintenance->external_id,
"timeperiods" => $timePeriodes,
]);
}
}
return redirect()->back();
}
}

View File

@ -36,7 +36,7 @@ class ScheduleNextMaintenance implements ShouldQueue
$cron = new CronCronExpression($maintenance->schedule);
$nextRunTime = Carbon::createFromTimestamp($cron->getNext());
if(MaintenanceHistory::where('hash', md5($maintenance->id . $nextRunTime))->first() === null){
if(MaintenanceHistory::where('hash', md5($maintenance->id . $nextRunTime))->first() !== null){
continue;
};

View File

@ -12,6 +12,7 @@ class Host extends Model
protected $fillable = [
'hostname',
'display_name',
'external_id',
];
public function tasks()

View File

@ -17,6 +17,7 @@ class Maintenance extends Model
'blocking_maintenance_id',
'duration',
'blocking_maintenance_offset',
'external_id',
];
public function hosts()

View File

@ -17,6 +17,10 @@ class MaintenanceHistory extends Model
'guestor_id',
];
protected $casts = [
'start_at' => 'datetime',
'finished_at' => 'datetime',
];
protected static function booted()
{

View File

@ -2,6 +2,7 @@
namespace App\Services;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Facades\Http;
@ -11,13 +12,14 @@ class ZabbixService
public string $url = "";
public int $id = 1;
function __construct($url) {
function __construct($url)
{
$this->url = $url;
}
public function connect( $username, $password)
public function connect($username, $password)
{
$response = Http::withoutVerifying()->post($this->url . "/api_jsonrpc.php", [
$this->token = $this->request([
"jsonrpc" => "2.0",
"method" => "user.login",
"params" => [
@ -27,76 +29,34 @@ class ZabbixService
"id" => $this->id,
"auth" => null,
]);
if (!$response->successful()) {
throw new Exception("Unable To Authenticated", 1);
}
$responseObject = $response->json();
if (isset($responseObject['error'])) {
throw new Exception($responseObject['error']['data'], $responseObject['error']['code']);
}
$this->token = $response['result'];
$this->id++;
return $this->token;
}
public function hosts($params = [])
{
if (empty($this->token)) {
throw new Exception("you need to connect first", 1);
}
$response = Http::withoutVerifying()->post($this->url . "/api_jsonrpc.php", [
return $this->request([
"jsonrpc" => "2.0",
"method" => "host.get",
"params" => $params,
"id" => $this->id,
"auth" => $this->token,
]);
if (!$response->successful()) {
throw new Exception("Unable To Request", 1);
}
$responseObject = $response->json();
if (isset($responseObject['error'])) {
throw new Exception($responseObject['error']['data'], $responseObject['error']['code']);
}
$this->id++;
return collect($responseObject["result"]);
}
public function hostGroups($params = [])
{
if (empty($this->token)) {
throw new Exception("you need to connect first", 1);
}
$response = Http::withoutVerifying()->post($this->url . "/api_jsonrpc.php", [
return $this->request([
"jsonrpc" => "2.0",
"method" => "hostgroup.get",
"params" => $params,
"id" => $this->id,
"auth" => $this->token,
]);
if (!$response->successful()) {
throw new Exception("Unable To Request", 1);
}
$responseObject = $response->json();
if (isset($responseObject['error'])) {
throw new Exception($responseObject['error']['data'], $responseObject['error']['code']);
}
$this->id++;
return collect($responseObject["result"]);
}
public function maintenances($params = []){
return $this->request( [
public function maintenances($params = [])
{
return $this->request([
"jsonrpc" => "2.0",
"method" => "maintenance.get",
"params" => $params,
@ -105,11 +65,33 @@ class ZabbixService
]);
}
public function maintenancesCreate($params = [])
{
return $this->request([
"jsonrpc" => "2.0",
"method" => "maintenance.create",
"params" => $params,
"id" => $this->id,
"auth" => $this->token,
]);
}
public function maintenancesUpdate( $params = [])
{
return $this->request([
"jsonrpc" => "2.0",
"method" => "maintenance.update",
"params" => $params,
"id" => $this->id,
"auth" => $this->token,
]);
}
/*Helpers*/
private function request($body = []){
if (empty($this->token)) {
private function request($body = [])
{
if (empty($this->token) && $body['auth'] != null) {
throw new Exception("you need to connect first", 1);
}
@ -125,6 +107,6 @@ class ZabbixService
}
$this->id++;
return collect($responseObject["result"]);
return is_array($responseObject["result"]) ? collect($responseObject["result"]) : $responseObject["result"];
}
}

7
config/zabbix.php Normal file
View File

@ -0,0 +1,7 @@
<?php
return [
'url' => env('ZBX_URL', ''),
'username' => env('ZBX_USERNAME', ''),
'password' => env('ZBX_PASSWORD', ''),
];

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('hosts', function (Blueprint $table) {
$table->string('external_id')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('hosts', function (Blueprint $table) {
});
}
};

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('maintenances', function (Blueprint $table) {
$table->string('external_id')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('maintenances', function (Blueprint $table) {
//
});
}
};

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('maintenance_histories', function (Blueprint $table) {
$table->string('external_id')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('maintenance_histories', function (Blueprint $table) {
//
});
}
};

View File

@ -2,6 +2,9 @@
<div class="container-xl">
<div class="page-header">
<h1>{{ __('Planned Maintenance') }}</h1>
<a class="btn btn-primary" href="{{ route('maintenance.start', ['maintenance_history' => $maintenance_history->id]) }}" disabled>
<i class="me-2 fas fa-play"></i><span>{{ __('Zahájit') }}</span>
</a>
</div>
<p>{!! $maintenance_history->maintenance->description !!}</p>
<x-form::form action="{{ route('maintenance.planned.detail.put', ['maintenance_history' => $maintenance_history->id]) }}" method="PUT">

View File

@ -10,6 +10,7 @@ Route::get('/', function () {
Route::get('/maintenance/planned', [App\Http\Controllers\MaintenanceController::class, 'planned'])->name('maintenance.planned');
Route::get('/maintenance/planned/{maintenance_history}', [App\Http\Controllers\MaintenanceController::class, 'plannedDetail'])->name('maintenance.planned.detail');
Route::put('/maintenance/planned/{maintenance_history}', [App\Http\Controllers\MaintenanceController::class, 'plannedDetailPut'])->name('maintenance.planned.detail.put');
Route::get('/maintenance/planned/{maintenance_history}/start', [App\Http\Controllers\MaintenanceController::class, 'start'])->name('maintenance.start');
Route::post('/maintenance/planned/{maintenance_history}/finished', [App\Http\Controllers\MaintenanceController::class, 'plannedDetailFinishPost'])->name('maintenance.planned.finished');
Route::get('/maintenance/history/', [App\Http\Controllers\MaintenanceController::class, 'history'])->name('maintenance.history');
Route::get('/maintenance/history/{maintenance_history}', [App\Http\Controllers\MaintenanceController::class, 'historyDetail'])->name('maintenance.history.detail');