DevSimulate   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 16
eloc 56
c 2
b 0
f 0
dl 0
loc 121
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A handle() 0 28 4
A completeArgument() 0 11 3
A addDevice() 0 20 4
A queueRemoval() 0 12 2
A started() 0 4 2
1
<?php
2
3
namespace App\Console\Commands;
4
5
use App\Console\LnmsCommand;
6
use App\Models\Device;
7
use Illuminate\Support\Str;
8
use LibreNMS\Util\Snmpsim;
9
use Symfony\Component\Console\Input\InputArgument;
10
use Symfony\Component\Console\Input\InputOption;
11
use Symfony\Component\Process\Process;
12
13
class DevSimulate extends LnmsCommand
14
{
15
    protected $name = 'dev:simulate';
16
    protected $developer = true;
17
    /**
18
     * @var Snmpsim
19
     */
20
    protected $snmpsim = null;
21
22
    /**
23
     * The console command description.
24
     *
25
     * @var string
26
     */
27
    protected $description = 'Simulate devices using test data';
28
29
    /**
30
     * Create a new command instance.
31
     *
32
     * @return void
33
     */
34
    public function __construct()
35
    {
36
        parent::__construct();
37
38
        $this->addArgument('file', InputArgument::OPTIONAL);
39
        $this->addOption('multiple', 'm', InputOption::VALUE_NONE);
40
        $this->addOption('remove', 'r', InputOption::VALUE_NONE);
41
    }
42
43
    /**
44
     * Execute the console command.
45
     *
46
     * @return int
47
     */
48
    public function handle()
49
    {
50
        $this->snmpsim = new Snmpsim();
51
        $snmprec_dir = $this->snmpsim->getDir();
52
        $listen = $this->snmpsim->getIp() . ':' . $this->snmpsim->getPort();
53
54
        $snmpsim = new Process([
55
            $this->snmpsim->findSnmpsimd(),
56
            "--data-dir=$snmprec_dir",
57
            "--agent-udpv4-endpoint=$listen",
58
        ]);
59
        $snmpsim->setTimeout(null);
60
61
        $snmpsim->run(function ($type, $buffer) use ($listen) {
62
            if (Process::ERR === $type) {
63
                if (Str::contains($buffer, $listen)) {
64
                    $this->line(trim($buffer));
65
                    $this->started();
66
                    $this->line(trans('commands.dev:simulate.exit'));
0 ignored issues
show
Bug introduced by
It seems like trans('commands.dev:simulate.exit') can also be of type array and array; however, parameter $string of Illuminate\Console\Command::line() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

66
                    $this->line(/** @scrutinizer ignore-type */ trans('commands.dev:simulate.exit'));
Loading history...
67
                }
68
            }
69
        });
70
71
        if (! $snmpsim->isSuccessful()) {
72
            $this->line($snmpsim->getErrorOutput());
73
        }
74
75
        return 0;
76
    }
77
78
    private function started()
79
    {
80
        if ($file = $this->argument('file')) {
81
            $this->addDevice($file);
82
        }
83
    }
84
85
    private function addDevice($community)
86
    {
87
        $hostname = $this->option('multiple') ? $community : 'snmpsim';
88
        $device = Device::firstOrNew(['hostname' => $hostname]);
89
        $action = $device->exists ? 'updated' : 'added';
90
91
        $device->overwrite_ip = $this->snmpsim->getIp();
92
        $device->port = $this->snmpsim->getPort();
93
        $device->snmpver = 'v2c';
94
        $device->transport = 'udp';
95
        $device->community = $community;
96
        $device->last_discovered = null;
97
        $device->status_reason = '';
98
        $device->save();
99
100
        $this->info(trans("commands.dev:simulate.$action", ['hostname' => $device->hostname, 'id' => $device->device_id]));
0 ignored issues
show
Bug introduced by
It seems like trans('commands.dev:simu...=> $device->device_id)) can also be of type array and array; however, parameter $string of Illuminate\Console\Command::info() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

100
        $this->info(/** @scrutinizer ignore-type */ trans("commands.dev:simulate.$action", ['hostname' => $device->hostname, 'id' => $device->device_id]));
Loading history...
101
102
        // set up removal shutdown function if requested
103
        if ($this->option('remove')) {
104
            $this->queueRemoval($device->device_id);
105
        }
106
    }
107
108
    private function queueRemoval($device_id)
109
    {
110
        if (function_exists('pcntl_signal')) {
111
            pcntl_signal(SIGINT, function () {
112
                exit(); // exit normally on SIGINT
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
113
            });
114
        }
115
116
        register_shutdown_function(function () use ($device_id) {
117
            Device::findOrNew($device_id)->delete();
118
            $this->info(trans('commands.dev:simulate.removed', ['id' => $device_id]));
0 ignored issues
show
Bug introduced by
It seems like trans('commands.dev:simu...ay('id' => $device_id)) can also be of type array and array; however, parameter $string of Illuminate\Console\Command::info() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

118
            $this->info(/** @scrutinizer ignore-type */ trans('commands.dev:simulate.removed', ['id' => $device_id]));
Loading history...
119
            exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
120
        });
121
    }
122
123
    public function completeArgument($name, $value)
124
    {
125
        if ($name == 'file') {
126
            return collect(glob(base_path('tests/snmpsim/*.snmprec')))->map(function ($file) {
127
                return basename($file, '.snmprec');
128
            })->filter(function ($snmprec) use ($value) {
129
                return ! $value || Str::startsWith($snmprec, $value);
130
            })->all();
131
        }
132
133
        return false;
134
    }
135
}
136