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')); |
||
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])); |
||
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
|
|||
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])); |
||
119 | exit(); |
||
0 ignored issues
–
show
|
|||
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 |
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.