Issues (48)

library/Trapdirector/IcingaApi/IcingaApiBase.php (2 issues)

1
<?php
2
3
4
namespace Icinga\Module\Trapdirector\IcingaApi;
5
6
use RuntimeException;
7
use Exception;
8
9
class IcingaApiBase
10
{
11
    protected $version = 'v1';      //< icinga2 api version
12
    
13
    protected $host;                //< icinga2 host name or IP
14
    protected $port;                //< icinga2 api port
15
    
16
    protected $user;                //< user name
17
    protected $pass;                //< user password
18
    protected $usercert;            //< user key for certificate auth (NOT IMPLEMENTED)
19
    protected $authmethod='pass';   //< Authentication : 'pass' or 'cert'
20
21
    protected $queryURL=array(
22
        'host'  => 'objects/hosts',
23
        'hostgroup' => 'objects/hostgroups',
24
        'service' => 'objects/services'
25
    );
26
    
27
    protected $curl;
28
    // http://php.net/manual/de/function.json-last-error.php#119985
29
    protected $errorReference = [
30
        JSON_ERROR_NONE => 'No error has occurred.',
31
        JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded.',
32
        JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON.',
33
        JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded.',
34
        JSON_ERROR_SYNTAX => 'Syntax error.',
35
        JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded.',
36
        JSON_ERROR_RECURSION => 'One or more recursive references in the value to be encoded.',
37
        JSON_ERROR_INF_OR_NAN => 'One or more NAN or INF values in the value to be encoded.',
38
        JSON_ERROR_UNSUPPORTED_TYPE => 'A value of a type that cannot be encoded was given.',
39
    ];
40
    const JSON_UNKNOWN_ERROR = 'Unknown error.';
41
    
42
    /**
43
     * Creates Icinga2API object
44
     * 
45
     * @param string $host host name or IP
46
     * @param number $port API port
47
     */
48
    public function __construct($host, $port = 5665)
49
    {
50
        $this->host=$host;
51
        $this->port=$port;
52
    }
53
    /**
54
     * Set user & pass
55
     * @param string $user
56
     * @param string $pass
57
     */
58
    public function setCredentials($user,$pass)
59
    {
60
        $this->user=$user;
61
        $this->pass=$pass;
62
        $this->authmethod='pass';
63
    }
64
    
65
    /**
66
     * Set user & certificate (NOT IMPLEMENTED @throws RuntimeException)
67
     * @param string $user
68
     * @param string $usercert
69
     */
70
    public function setCredentialskey($user,$usercert)
71
    {
72
        $this->user=$user;
73
        $this->usercert=$usercert;
74
        $this->authmethod='cert';
75
        throw new RuntimeException('Certificate auth not implemented');
76
    }
77
78
    /**
79
     * Test API connection
80
     * @param array $permissions : check permissions if not null or empty
81
     * @return array (bool,string) : bool = false is all OK, else true with message
82
     * */
83
    public function test(array $permissions)
84
    {
85
       try
86
        {
87
            $result=$this->request('GET', "", NULL, NULL);
88
        } 
89
        catch (Exception $e)
90
        {
91
            return array(true, 'Error with API : '.$e->getMessage());
92
        }
93
        //var_dump($result);
94
        $permOk=1;
95
        $permMissing='';
96
        if ($permissions === NULL || count($permissions) == 0) // If no permission check return OK after connexion
97
        {
98
            return array(false,'OK');
99
        }
100
        if (property_exists($result, 'results') && property_exists($result->results[0], 'permissions'))
101
        {
102
            
103
            foreach ( $permissions as $mustPermission)
104
            {
105
                $curPermOK=0;
106
                foreach ( $result->results[0]->permissions as $curPermission)
107
                {
108
                    $curPermission=preg_replace('/\*/','.*',$curPermission); // put * as .* to created a regexp
109
                    if (preg_match('#'.$curPermission.'#',$mustPermission))
110
                    {
111
                        $curPermOK=1;
112
                        break;
113
                    }
114
                }
115
                if ($curPermOK == 0)
116
                {
117
                    $permOk=0;
118
                    $permMissing=$mustPermission;
119
                    break;
120
                }
121
            }
122
            if ($permOk == 0)
123
            {
124
                return array(true,'API connection OK, but missing permission : '.$permMissing);
125
            }
126
            return array(false,'API connection OK');
127
            
128
        }
129
        return array(true,'API connection OK, but cannot get permissions');
130
    }
131
    
132
    
133
    protected function url($url) {
134
        return sprintf('https://%s:%d/%s/%s', $this->host, $this->port, $this->version, $url);
135
    }
136
    
137
    /**
138
     * Create or return curl ressource
139
     * @throws Exception
140
     * @return resource
141
     */
142
    protected function curl() {
143
        if ($this->curl === null) {
144
            $this->curl = curl_init(sprintf('https://%s:%d', $this->host, $this->port));
145
            if ($this->curl === false) {
146
                throw new Exception('CURL INIT ERROR');
147
            }
148
        }
149
        return $this->curl;
150
    }
151
152
    /**
153
     * Send a passive service check
154
     * @param string $host : host name 
155
     * @param string $service : service name
156
     * @param int $state : state of service
157
     * @param string $display : service passive check output
158
     * @param string $perfdata : performance data as string
159
     * @return array (status = true (oK) or false (nok), string message)
160
     */
161
    public function serviceCheckResult($host,$service,$state,$display,$perfdata='')
162
    {
163
        //Send a POST request to the URL endpoint /v1/actions/process-check-result
164
        //actions/process-check-result?service=example.localdomain!passive-ping6
165
        $url='actions/process-check-result';
166
        $body=array(
167
            "filter"        => 'service.name=="'.$service.'" && service.host_name=="'.$host.'"',
168
            'type'          => 'Service',
169
            "exit_status"   => $state,
170
            "plugin_output" => $display,
171
            "performance_data" => $perfdata
172
        );
173
        try 
174
        {
175
            $result=$this->request('POST', $url, null, $body);
176
        } catch (Exception $e) 
177
        {
178
            return array(false, $e->getMessage());
179
        }
180
        if (property_exists($result,'error') )
181
        {
182
            if (property_exists($result,'status'))
183
            {
184
                $message=$result->status;
185
            }
186
            else 
187
            {
188
                $message="Unkown status";
189
            }
190
            return array(false , 'Ret code ' .$result->error.' : '.$message);
191
        }
192
        if (property_exists($result, 'results'))
193
        {
194
            if (isset($result->results[0]))
195
            {
196
                return array(true,'code '.$result->results[0]->code.' : '.$result->results[0]->status);
197
            }
198
            else
199
            {
200
                return array(false,'Service not found');
201
            }
202
            
203
        }
204
        return array(false,'Unkown result, open issue with this : '.print_r($result,true));
205
    }
206
  
207
    /**
208
     * Check 'result' exists and check for errors/status
209
     * @param \stdClass $result
210
     * @throws Exception 
211
     */
212
    public function checkResultStatus(\stdClass $result) 
213
    {
214
        if (property_exists($result,'error') )
215
        {
216
            if (property_exists($result,'status'))
217
            {
218
                throw new Exception('Ret code ' .$result->error.' : ' . $result->status);
219
            }
220
            else
221
            {
222
                throw new Exception('Ret code ' .$result->error.' : Unkown status');
223
            }
224
        }
225
        if ( ! property_exists($result, 'results'))
226
        {
227
            throw new Exception('Unkown result');
228
        }
229
    }
230
    
231
    /**
232
     * Send request to API
233
     * @param string $method get/post/...
234
     * @param string $url (after /v1/ )
235
     * @param array $headers
236
     * @param array $body 
237
     * @throws Exception
238
     * @return array
239
     */
240
    public function request($method, $url, $headers, $body) {
241
        $auth = sprintf('%s:%s', $this->user, $this->pass);
242
        $curlHeaders = array("Accept: application/json");
243
        if ($body !== null) {
0 ignored issues
show
The condition $body !== null is always true.
Loading history...
244
            $body = json_encode($body);
245
            array_push($curlHeaders, 'Content-Type: application/json');
246
            //array_push($curlHeaders, 'X-HTTP-Method-Override: GET');
247
        }
248
        //var_dump($body);
249
        //var_dump($this->url($url));
250
        if ($headers !== null) {
0 ignored issues
show
The condition $headers !== null is always true.
Loading history...
251
            $curlFinalHeaders = array_merge($curlHeaders, $headers);
252
        } else 
253
        {
254
            $curlFinalHeaders=$curlHeaders;
255
        }
256
        $curl = $this->curl();
257
        $opts = array(
258
            CURLOPT_URL		=> $this->url($url),
259
            CURLOPT_HTTPHEADER 	=> $curlFinalHeaders,
260
            CURLOPT_USERPWD		=> $auth,
261
            CURLOPT_CUSTOMREQUEST	=> strtoupper($method),
262
            CURLOPT_RETURNTRANSFER 	=> true,
263
            CURLOPT_CONNECTTIMEOUT 	=> 10,
264
            CURLOPT_SSL_VERIFYHOST 	=> false,
265
            CURLOPT_SSL_VERIFYPEER 	=> false,
266
        );
267
        if ($body !== null) {
268
            $opts[CURLOPT_POSTFIELDS] = $body;
269
        }
270
        curl_setopt_array($curl, $opts);
271
        $res = curl_exec($curl);
272
        if ($res === false) {
273
            throw new Exception('CURL ERROR: ' . curl_error($curl));
274
        }
275
        $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
276
        if ($statusCode === 401) {
277
            throw new Exception('Unable to authenticate, please check your API credentials');
278
        }
279
        return $this->fromJsonResult($res);
280
    }
281
    
282
    /**
283
     * 
284
     * @param string $json json encoded 
285
     * @throws Exception
286
     * @return array json decoded
287
     */
288
    protected function fromJsonResult($json) {
289
        $result = @json_decode($json);
290
        //var_dump($json);
291
        if ($result === null) {
292
            throw new Exception('Parsing JSON failed: '.$this->getLastJsonErrorMessage(json_last_error()));
293
        }
294
        return $result;
295
    }
296
    
297
    /**
298
     * Return text error no json error
299
     * @param string $errorCode
300
     * @return string
301
     */
302
    protected function getLastJsonErrorMessage($errorCode) {
303
        if (!array_key_exists($errorCode, $this->errorReference)) {
304
            return self::JSON_UNKNOWN_ERROR;
305
        }
306
        return $this->errorReference[$errorCode];
307
    }
308
309
    public function standardQuery(string $urlType , string $filter, array $attributes)
310
    {
311
        /*
312
         *  curl -k -s -u  trapdirector:trapdirector -H 'X-HTTP-Method-Override: GET' -X POST 'https://localhost:5665/v1/objects/hosts' 
313
         *  -d '{"filter":"\"test_trap\" in host.groups","attrs": ["address" ,"address6"],"pretty": true}'
314
         
315
         {"results":[{"attrs":{"__name":"Icinga host","address":"127.0.0.1","display_name":"Icinga host","name":"Icinga host"},"joins":{},"meta":{},"name":"Icinga host","type":"Host"}]}
316
         */
317
        
318
        if (! isset($this->queryURL[$urlType] ))
319
        {
320
            throw new Exception("Unkown object type");
321
        }
322
        $url=$this->queryURL[$urlType];
323
        $body=array();
324
        if ($filter !== NULL)
325
        {
326
            $body['filter'] = $filter;
327
        }
328
        if (count($attributes) != 0)
329
        {
330
            $body['attrs'] = $attributes;
331
        }
332
333
        try
334
        {
335
            $result=$this->request('POST', $url, array('X-HTTP-Method-Override: GET'), $body);
336
        } catch (Exception $e)
337
        {
338
            throw new Exception($e->getMessage());
339
        }
340
        
341
        $this->checkResultStatus($result);
342
        
343
        $numHost=0;
344
        $hostArray=array();
345
        while (isset($result->results[$numHost]) && property_exists ($result->results[$numHost],'attrs'))
346
        {
347
            $hostArray[$numHost] = $result->results[$numHost]->attrs;
348
            $numHost++;
349
        }
350
        return $hostArray;
351
    }
352
    
353
}
354
355