Issues (2963)

LibreNMS/Validator.php (1 issue)

1
<?php
2
/**
3
 * Validator.php
4
 *
5
 * Class to run validations.  Also allows sharing data between ValidationGroups.
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19
 *
20
 * @link       https://www.librenms.org
21
 *
22
 * @copyright  2017 Tony Murray
23
 * @author     Tony Murray <[email protected]>
24
 */
25
26
namespace LibreNMS;
27
28
use Illuminate\Support\Str;
29
use LibreNMS\Interfaces\ValidationGroup;
30
use LibreNMS\Util\Laravel;
31
use ReflectionClass;
32
33
class Validator
34
{
35
    private $validation_groups = [];
36
    private $results = [];
37
38
    // data cache
39
    private $username;
40
    private $versions;
41
42
    /**
43
     * Validator constructor.
44
     */
45
    public function __construct()
46
    {
47
        // load all validations
48
        $pattern = $this->getBaseDir() . '/LibreNMS/Validations/*.php';
49
50
        foreach (glob($pattern) as $file) {
51
            $class_name = basename($file, '.php');
52
            $class = '\LibreNMS\Validations\\' . $class_name;
53
54
            $rc = new ReflectionClass($class);
55
            if (! $rc->isAbstract()) {
56
                $validation_name = strtolower($class_name);
57
                $this->validation_groups[$validation_name] = new $class();
58
                $this->results[$validation_name] = [];
59
            }
60
        }
61
    }
62
63
    /**
64
     * Run validations. An empty array will run all default validations.
65
     *
66
     * @param  array  $validation_groups  selected validation groups to run
67
     * @param  bool  $print_group_status  print out group status
68
     */
69
    public function validate($validation_groups = [], $print_group_status = false)
70
    {
71
        foreach ($this->validation_groups as $group_name => $group) {
72
            // only run each group once
73
            if ($group->isCompleted()) {
74
                continue;
75
            }
76
77
            if ((empty($validation_groups) && $group->isDefault()) || in_array($group_name, $validation_groups)) {
78
                if ($print_group_status && Laravel::isCli()) {
79
                    echo "Checking $group_name:";
80
                }
81
82
                /** @var ValidationGroup $group */
83
                $group->validate($this);
84
85
                if (Laravel::isCli()) {
86
                    if ($print_group_status) {
87
                        $status = ValidationResult::getStatusText($this->getGroupStatus($group_name));
88
                        c_echo(" $status\n");
89
                    }
90
91
                    $this->printResults($group_name);
92
                }
93
94
                // validation is complete for this group
95
                $group->markCompleted();
96
            }
97
        }
98
    }
99
100
    /**
101
     * Get the overall status of a validation group.
102
     *
103
     * @param  string  $validation_group
104
     * @return int
105
     */
106
    public function getGroupStatus($validation_group)
107
    {
108
        $results = $this->getResults($validation_group);
109
110
        $status = array_reduce($results, function ($compound, $result) {
111
            /** @var ValidationResult $result */
112
            return min($compound, $result->getStatus());
113
        }, ValidationResult::SUCCESS);
114
115
        return $status;
116
    }
117
118
    /**
119
     * Get the ValidationResults for a specific validation group.
120
     *
121
     * @param  string  $validation_group
122
     * @return ValidationResult[]
123
     */
124
    public function getResults($validation_group = null)
125
    {
126
        if (isset($validation_group)) {
127
            if (isset($this->results[$validation_group])) {
128
                return $this->results[$validation_group];
129
            } else {
130
                return [];
131
            }
132
        }
133
134
        return array_reduce($this->results, 'array_merge', []);
135
    }
136
137
    /**
138
     * Get all of the ValidationResults that have been submitted.
139
     * ValidationResults will be grouped by the validation group.
140
     *
141
     * @return array
142
     */
143
    public function getAllResults()
144
    {
145
        return $this->results;
146
    }
147
148
    /**
149
     * Print all ValidationResults or a group of them.
150
     *
151
     * @param  string  $validation_group
152
     */
153
    public function printResults($validation_group = null)
154
    {
155
        $results = $this->getResults($validation_group);
156
157
        foreach ($results as $result) {
158
            /** @var ValidationResult $result */
159
            $result->consolePrint();
160
        }
161
    }
162
163
    /**
164
     * Submit a validation result.
165
     * This allows customizing ValidationResults before submitting.
166
     *
167
     * @param  ValidationResult  $result
168
     * @param  string  $group  manually specify the group, otherwise this will be inferred from the callers class name
169
     */
170
    public function result(ValidationResult $result, $group = null)
171
    {
172
        // get the name of the validation that submitted this result
173
        if (empty($group)) {
174
            $group = 'unknown';
175
            $bt = debug_backtrace();
176
            foreach ($bt as $entry) {
177
                if (Str::startsWith($entry['class'], 'LibreNMS\Validations')) {
178
                    $group = str_replace('LibreNMS\Validations\\', '', $entry['class']);
179
                    break;
180
                }
181
            }
182
        }
183
184
        $this->results[strtolower($group)][] = $result;
185
    }
186
187
    /**
188
     * Submit an ok validation result.
189
     *
190
     * @param  string  $message
191
     * @param  string  $fix
192
     * @param  string  $group  manually specify the group, otherwise this will be inferred from the callers class name
193
     */
194
    public function ok($message, $fix = null, $group = null)
195
    {
196
        $this->result(new ValidationResult($message, ValidationResult::SUCCESS, $fix), $group);
197
    }
198
199
    /**
200
     * Submit a warning validation result.
201
     *
202
     * @param  string  $message
203
     * @param  string  $fix
204
     * @param  string  $group  manually specify the group, otherwise this will be inferred from the callers class name
205
     */
206
    public function warn($message, $fix = null, $group = null)
207
    {
208
        $this->result(new ValidationResult($message, ValidationResult::WARNING, $fix), $group);
209
    }
210
211
    /**
212
     * Submit a failed validation result.
213
     *
214
     * @param  string  $message
215
     * @param  string  $fix
216
     * @param  string  $group  manually specify the group, otherwise this will be inferred from the callers class name
217
     */
218
    public function fail($message, $fix = null, $group = null)
219
    {
220
        $this->result(new ValidationResult($message, ValidationResult::FAILURE, $fix), $group);
221
    }
222
223
    /**
224
     * Submit an informational validation result.
225
     *
226
     * @param  string  $message
227
     * @param  string  $group  manually specify the group, otherwise this will be inferred from the callers class name
228
     */
229
    public function info($message, $group = null)
230
    {
231
        $this->result(new ValidationResult($message, ValidationResult::INFO), $group);
232
    }
233
234
    /**
235
     * Get version_info() array.  This will cache the result and add remote data if requested and not already existing.
236
     *
237
     * @param  bool  $remote
238
     * @return array
239
     */
240
    public function getVersions($remote = false)
241
    {
242
        if (! isset($this->versions)) {
243
            $this->versions = version_info($remote);
244
        } else {
245
            if ($remote && ! isset($this->versions['github'])) {
246
                $this->versions = version_info($remote);
247
            }
248
        }
249
250
        return $this->versions;
251
    }
252
253
    /**
254
     * Execute a command, but don't run it as root.  If we are root, run as the LibreNMS user.
255
     * Arguments match exec()
256
     *
257
     * @param  string  $command  the command to run
258
     * @param  array  $output  will hold the output of the command
259
     * @param  int  $code  will hold the return code from the command
260
     */
261
    public function execAsUser($command, &$output = null, &$code = null)
262
    {
263
        if (self::getUsername() === 'root') {
0 ignored issues
show
Bug Best Practice introduced by
The method LibreNMS\Validator::getUsername() is not static, but was called statically. ( Ignorable by Annotation )

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

263
        if (self::/** @scrutinizer ignore-call */ getUsername() === 'root') {
Loading history...
264
            $command = 'su ' . \config('librenms.user') . ' -s /bin/sh -c "' . $command . '"';
265
        }
266
        exec($command, $output, $code);
267
    }
268
269
    /**
270
     * Get the username of the user running this and cache it for future requests.
271
     *
272
     * @return string
273
     */
274
    public function getUsername()
275
    {
276
        if (! isset($this->username)) {
277
            if (function_exists('posix_getpwuid')) {
278
                $userinfo = posix_getpwuid(posix_geteuid());
279
                $this->username = $userinfo['name'];
280
            } else {
281
                $this->username = getenv('USERNAME') ?: getenv('USER');
282
            }
283
        }
284
285
        return $this->username;
286
    }
287
288
    /**
289
     * Get the base url for this LibreNMS install, this will only work from web pages.
290
     * (unless base_url is set)
291
     *
292
     * @return string the base url without a trailing /
293
     */
294
    public function getBaseURL()
295
    {
296
        $url = function_exists('get_url') ? get_url() : Config::get('base_url');
297
298
        return rtrim(str_replace('validate', '', $url), '/');  // get base_url from current url
299
    }
300
301
    public function getBaseDir()
302
    {
303
        return realpath(__DIR__ . '/..');
304
    }
305
}
306