icingaweb2-module-director/library/Director/Core/RestApiClient.php

279 lines
7.5 KiB
PHP
Raw Normal View History

2015-09-14 16:23:43 +02:00
<?php
namespace Icinga\Module\Director\Core;
2015-11-09 18:31:26 +01:00
use Icinga\Application\Benchmark;
use Icinga\Exception\ConfigurationError;
2015-09-29 19:01:25 +02:00
use Exception;
2015-09-14 16:23:43 +02:00
class RestApiClient
{
protected $version = 'v1';
protected $peer;
protected $port;
protected $user;
protected $pass;
2015-12-23 17:12:53 +01:00
protected $curl;
2016-01-19 18:01:21 +01:00
protected $readBuffer = '';
protected $onEvent;
2015-09-14 16:23:43 +02:00
public function __construct($peer, $port = 5665, $cn = null)
{
$this->peer = $peer;
$this->port = $port;
}
// TODO: replace with Web2 CA trust resource plus cert and get rid
// of user/pass or at least strongly advise against using it
public function setCredentials($user, $pass)
{
$this->user = $user;
$this->pass = $pass;
return $this;
}
public function onEvent($callback)
{
$this->onEvent = $callback;
return $this;
}
2015-09-14 16:23:43 +02:00
public function getPeerIdentity()
{
return $this->peer;
}
protected function url($url)
{
return sprintf('https://%s:%d/%s/%s', $this->peer, $this->port, $this->version, $url);
}
2016-01-19 18:01:21 +01:00
// protected function request($method, $url, $body = null, $raw = false)
public function request($method, $url, $body = null, $raw = false, $stream = false)
2015-12-23 17:12:53 +01:00
{
if (function_exists('curl_version')) {
2016-01-19 18:01:21 +01:00
return $this->curlRequest($method, $url, $body, $raw, $stream);
/*
// Completely disabled fallback method, caused too many issues
// with hanging connections on specific PHP versions
2015-12-23 17:12:53 +01:00
} elseif (version_compare(PHP_VERSION, '5.4.0') >= 0) {
2016-01-19 18:01:21 +01:00
// TODO: fail if stream
2015-12-23 17:12:53 +01:00
return $this->phpRequest($method, $url, $body, $raw);
*/
2015-12-23 17:12:53 +01:00
} else {
throw new Exception(
'No CURL extension detected, it must be installed and enabled'
);
2015-12-23 17:12:53 +01:00
}
}
protected function phpRequest($method, $url, $body = null, $raw = false)
2015-09-14 16:23:43 +02:00
{
$auth = base64_encode(sprintf('%s:%s', $this->user, $this->pass));
$headers = array(
'Host: ' . $this->getPeerIdentity(),
'Authorization: Basic ' . $auth,
'Connection: close'
);
if (! $raw) {
$headers[] = 'Accept: application/json';
}
2015-09-14 16:23:43 +02:00
if ($body !== null) {
$body = json_encode($body);
$headers[] = 'Content-Type: application/json';
}
$opts = array(
'http' => array(
'protocol_version' => '1.1',
'user_agent' => 'Icinga Web 2.0 - Director',
'method' => strtoupper($method),
'content' => $body,
2015-09-29 19:01:25 +02:00
'header' => $headers,
'ignore_errors' => true
2015-09-14 16:23:43 +02:00
),
'ssl' => array(
2015-12-23 17:12:53 +01:00
// TODO: Fix this!
2015-09-14 16:23:43 +02:00
'verify_peer' => false,
// 'cafile' => $dir . 'cacert.pem',
// 'verify_depth' => 5,
// 'CN_match' => $peerName // != peer
)
);
$context = stream_context_create($opts);
2015-11-09 18:31:26 +01:00
Benchmark::measure('Rest Api, sending ' . $url);
2015-09-29 19:01:25 +02:00
$res = file_get_contents($this->url($url), false, $context);
if (substr(array_shift($http_response_header), 0, 10) !== 'HTTP/1.1 2') {
throw new Exception($res);
}
2015-11-09 18:31:26 +01:00
Benchmark::measure('Rest Api, got response');
2015-09-14 16:23:43 +02:00
if ($raw) {
2015-09-29 19:01:25 +02:00
return $res;
2015-09-14 16:23:43 +02:00
} else {
2015-09-29 19:01:25 +02:00
return RestApiResponse::fromJsonResult($res);
2015-09-14 16:23:43 +02:00
}
}
2016-01-19 18:01:21 +01:00
protected function curlRequest($method, $url, $body = null, $raw = false, $stream = false)
2015-12-23 17:12:53 +01:00
{
$auth = sprintf('%s:%s', $this->user, $this->pass);
$headers = array(
'Host: ' . $this->getPeerIdentity(),
2016-01-19 18:01:21 +01:00
// 'Connection: close'
2015-12-23 17:12:53 +01:00
);
if (! $raw) {
$headers[] = 'Accept: application/json';
}
if ($body !== null) {
$body = json_encode($body);
$headers[] = 'Content-Type: application/json';
}
$curl = $this->curl();
$opts = array(
CURLOPT_URL => $this->url($url),
CURLOPT_HTTPHEADER => $headers,
CURLOPT_USERPWD => $auth,
2015-12-23 17:12:53 +01:00
CURLOPT_CUSTOMREQUEST => strtoupper($method),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 3,
2015-12-23 17:12:53 +01:00
// TODO: Fix this!
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_SSL_VERIFYPEER => false,
);
if ($body !== null) {
$opts[CURLOPT_POSTFIELDS] = $body;
}
2016-01-19 18:01:21 +01:00
if ($stream) {
$opts[CURLOPT_WRITEFUNCTION] = array($this, 'readPart');
}
2015-12-23 17:12:53 +01:00
curl_setopt_array($curl, $opts);
2016-02-26 11:58:37 +01:00
// TODO: request headers, validate status code
2015-12-23 17:12:53 +01:00
Benchmark::measure('Rest Api, sending ' . $url);
$res = curl_exec($curl);
if ($res === false) {
throw new Exception('CURL ERROR: ' . curl_error($curl));
}
$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($statusCode === 401) {
throw new ConfigurationError(
'Unable to authenticate, please check your API credentials'
);
}
2015-12-23 17:12:53 +01:00
Benchmark::measure('Rest Api, got response');
2016-01-19 18:01:21 +01:00
if ($stream) {
return $this;
}
2015-12-23 17:12:53 +01:00
if ($raw) {
return $res;
} else {
return RestApiResponse::fromJsonResult($res);
}
}
2015-09-14 16:23:43 +02:00
public function get($url, $body = null)
{
return $this->request('get', $url, $body);
}
public function getRaw($url, $body = null)
{
return $this->request('get', $url, $body, true);
}
public function post($url, $body = null)
{
return $this->request('post', $url, $body);
}
public function put($url, $body = null)
{
return $this->request('put', $url, $body);
}
public function delete($url, $body = null)
{
return $this->request('delete', $url, $body);
}
2015-12-23 17:12:53 +01:00
2016-11-01 18:28:36 +01:00
/**
* @throws Exception
*
* @return resource
*/
2015-12-23 17:12:53 +01:00
protected function curl()
{
if ($this->curl === null) {
$this->curl = curl_init(sprintf('https://%s:%d', $this->peer, $this->port));
if (! $this->curl) {
throw new Exception('CURL INIT ERROR: ' . curl_error($this->curl));
}
}
2016-01-19 18:01:21 +01:00
2016-11-01 18:28:36 +01:00
return $this->curl;
2016-01-19 18:01:21 +01:00
}
protected function processEvents()
2016-01-19 18:01:21 +01:00
{
$offset = 0;
while (false !== ($pos = strpos($this->readBuffer, "\n", $offset))) {
if ($pos === $offset) {
echo "Got empty line $offset / $pos\n";
$offset = $pos + 1;
continue;
}
$str = substr($this->readBuffer, $offset, $pos);
$decoded = json_decode($str);
if ($decoded === false) {
2016-02-26 11:58:37 +01:00
throw new Exception('Got invalid JSON: ' . $str);
}
// printf("Processing %s bytes\n", strlen($str));
// print_r($decoded);
if ($this->onEvent !== null) {
$func = $this->onEvent;
$func($decoded);
}
2016-01-19 18:01:21 +01:00
$offset = $pos + 1;
}
if ($offset > 0) {
$this->readBuffer = substr($this->readBuffer, $offset + 1);
}
// echo "REMAINING: " . strlen($this->readBuffer) . "\n";
2016-01-19 18:01:21 +01:00
}
public function __destruct()
{
if ($this->curl !== null && is_resource($this->curl)) {
curl_close($this->curl);
}
}
2015-09-14 16:23:43 +02:00
}