eveseat/eveapi

View on GitHub
src/Commands/Seat/Admin/Diagnose.php

Summary

Maintainability
A
55 mins
Test Coverage
<?php

/*
 * This file is part of SeAT
 *
 * Copyright (C) 2015 to present Leon Jacobs
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

namespace Seat\Eveapi\Commands\Seat\Admin;

use Exception;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Str;
use Seat\Eseye\Exceptions\RequestFailedException;
use Seat\Services\Contracts\EsiClient;

/**
 * Class Diagnose.
 *
 * @package Seat\Eveapi\Commands\Seat\Admin
 */
class Diagnose extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'seat:admin:diagnose';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Diagnose potential SeAT installation problems';

    /**
     * @var \Seat\Services\Contracts\EsiClient
     */
    private EsiClient $esi;

    public function __construct(EsiClient $client)
    {
        parent::__construct();

        $this->esi = $client;
    }

    /**
     * Execute the console command.
     */
    public function handle()
    {
        $this->line('SeAT Diagnostics');
        $this->line('If you are not already doing so, it is recommended that you ' .
            'run this as the user the workers are running as.');
        $this->line('Eg:');
        $this->info('    sudo -u apache php artisan seat:admin:diagnose');
        $this->info('    su -c "php artisan seat:admin:diagnose" -s /bin/sh www-data');
        $this->line('This helps to check whether the permissions are correct.');
        $this->line('');

        $this->environment_info();
        $this->line('');

        $this->check_debug();
        $this->line('');

        $this->check_storage();
        $this->line('');

        $this->check_database();
        $this->line('');

        $this->check_redis();
        $this->line('');

        $this->check_eseye();
        $this->line('');

        $this->call('seat:version');

        $this->line('SeAT Diagnostics complete');
    }

    /**
     * Print some information about the current environment.
     */
    public function environment_info()
    {

        $this->line(' * Getting environment information');

        // Get the current user.
        $user = posix_getpwuid(posix_geteuid())['name'];

        // Warn if we are running as root.
        if ($user === 'root') {

            $this->warn('WARNING: This command is running as root!');
            $this->warn('WARNING: Running as root means that we will probably be able to access ' .
                'any file on your system. This command will not be able to help diagnose permission ' .
                'problems this way.');
        }

        $this->info('Current User: ' . $user);
        $this->info('PHP Version: ' . phpversion());
        $this->info('Host OS: ' . php_uname());
        $this->info('SeAT Basepath: ' . base_path());
    }

    /**
     * Check if DEBUG mode is enabled.
     */
    public function check_debug()
    {
        $this->line(' * Checking DEBUG mode');

        if (config('app.debug', false) == true)
            $this->warn('Debug mode is enabled. This is not recommended in production!');
        else
            $this->info('Debug mode disabled');
    }

    /**
     * Check access to some important storage paths.
     */
    public function check_storage()
    {

        $this->line(' * Checking storage');

        if (! File::isWritable(storage_path()))
            $this->error(storage_path() . ' is not writable');
        else
            $this->info(storage_path() . ' is writable');

        if (! File::isWritable(storage_path('sde')))
            $this->error(storage_path('sde') . ' is not writable');
        else
            $this->info(storage_path('sde') . ' is writable');

        if (! File::isWritable(storage_path(sprintf('logs/laravel-%s.log', carbon()->toDateString())))) {
            if (File::isWritable(storage_path('logs')))
                $this->warn(storage_path(sprintf('logs/laravel-%s.log might be not writable or is missing', carbon()->toDateString())));
            else
                $this->error(storage_path('logs is not writable'));
        } else
            $this->info(storage_path(sprintf('logs/laravel-%s.log is writable', carbon()->toDateString())));
    }

    /**
     * Check if database access is OK.
     */
    public function check_database()
    {
        $this->line(' * Checking Database');
        $this->table(['Setting', 'Value'], [
            ['Connection', config('database.default', 'mysql')],
            ['Host', config(sprintf('database.connections.%s.host', config('database.default', 'mysql')))],
            ['Database', config(sprintf('database.connections.%s.database', config('database.default')))],
            ['Username', config(sprintf('database.connections.%s.username', config('database.default', 'mysql')))],
            ['Password', str_repeat('*',
                strlen(config(sprintf('database.connections.%s.password', config('database.default', 'mysql')))))],
        ]);

        try {

            $this->info('Connection OK to database: ' .
                DB::connection()->getDatabaseName());

        } catch (Exception $e) {

            $this->error('Unable to connect to database server: ' . $e->getMessage());
        }
    }

    /**
     * Check of redis access is OK.
     */
    public function check_redis()
    {
        $this->line(' * Checking Redis');
        $this->table(['Setting', 'Value'], [
            ['Host', config('database.redis.default.host')],
            ['Port', config('database.redis.default.port')],
            ['Database', config('database.redis.default.database')],
        ]);

        $test_key = Str::random(64);
        $test_value = now()->toString();

        try {

            $this->info('Connected to Redis');

            Redis::set($test_key, $test_value);
            $this->info('Set random key of: ' . $test_key);

            Redis::expire($test_key, 10);
            $this->info('Set key to expire in 10 sec');

            if (Redis::get($test_key) === $test_value)
                $this->info('Read key OK');
            else
                $this->error('Unable to read key or returned value does not match with initially set one.');

        } catch (Exception $e) {

            $this->error('Redis test failed. ' . $e->getMessage());

        }
    }

    /**
     * Check if access to the EVE API OK.
     */
    public function check_eseye()
    {
        $this->line(' * Checking ESI Access');

        try {
            $result = $this->esi->setVersion('v1')->invoke('get', '/status/');
            $this->info('Server Online Since: ' . $result->getBody()->start_time);
            $this->info('Online Players: ' . $result->getBody()->players);

        } catch (RequestFailedException $e) {

            $this->error('ESI does not appear to be available: ' . $e->getMessage());
        }

        $this->info('ESI appears to be OK');
    }
}