Core: import basic api implementation
This commit is contained in:
parent
da3c68ee07
commit
68677e610f
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Director\Core;
|
||||
|
||||
use Icinga\Exception\IcingaException;
|
||||
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
|
||||
use Icinga\Module\Director\Objects\DirectorDeploymentLog;
|
||||
|
||||
class CoreApi
|
||||
{
|
||||
protected $client;
|
||||
|
||||
public function __construct(RestApiClient $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
public function getModules()
|
||||
{
|
||||
return $this->client->get('config/packages')->getResult('name');
|
||||
}
|
||||
|
||||
public function listModuleStages($name, $active = null)
|
||||
{
|
||||
$modules = $this->getModules();
|
||||
$found = array();
|
||||
|
||||
if (array_key_exists($name, $modules)) {
|
||||
$module = $modules[$name];
|
||||
$current = $module->{'active-stage'};
|
||||
foreach ($module->stages as $stage) {
|
||||
if ($active === null) {
|
||||
$found[] = $stage;
|
||||
} elseif ($active === true) {
|
||||
if ($current === $stage) {
|
||||
$found[] = $stage;
|
||||
}
|
||||
} elseif ($active === false) {
|
||||
if ($current !== $stage) {
|
||||
$found[] = $stage;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
public function wipeInactiveStages()
|
||||
{
|
||||
$moduleName = 'director';
|
||||
foreach ($this->listModuleStages($moduleName, false) as $stage) {
|
||||
$this->client->delete('config/stages/' . $moduleName . '/' . $stage);
|
||||
}
|
||||
}
|
||||
|
||||
public function listStageFiles($stage)
|
||||
{
|
||||
return array_keys(
|
||||
$this->client->get(
|
||||
'config/stages/director/' . $stage
|
||||
)->getResult('name', array('type' => 'file'))
|
||||
);
|
||||
}
|
||||
|
||||
public function getStagedFile($stage, $file)
|
||||
{
|
||||
return $this->client->getRaw(
|
||||
'config/files/director/' . $stage . '/' . urlencode($file)
|
||||
);
|
||||
}
|
||||
|
||||
public function hasModule($moduleName)
|
||||
{
|
||||
$modules = $this->getModules();
|
||||
return array_key_exists($moduleName, $modules);
|
||||
}
|
||||
|
||||
public function createModule($moduleName)
|
||||
{
|
||||
return $this->client->post('config/packages/' . $moduleName)->succeeded();
|
||||
}
|
||||
|
||||
public function deleteModule($moduleName)
|
||||
{
|
||||
return $this->client->delete('config/packages/' . $moduleName)->succeeded();
|
||||
}
|
||||
|
||||
public function assertModuleExists($moduleName)
|
||||
{
|
||||
if (! $this->hasModule($moduleName)) {
|
||||
if (! $this->createModule($moduleName)) {
|
||||
throw new IcingaException(
|
||||
'Failed to create the module "%s" through the REST API',
|
||||
$moduleName
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function deleteStage($moduleName, $stageName)
|
||||
{
|
||||
return $this->client->delete('config/stages', array(
|
||||
'module' => $moduleName,
|
||||
'stage' => $stageName
|
||||
))->succeeded();
|
||||
}
|
||||
|
||||
public function dumpConfig(IcingaConfig $config, $db, $moduleName = 'director')
|
||||
{
|
||||
$start = microtime(true);
|
||||
$data = $config->getFileContents();
|
||||
$deployment = DirectorDeploymentLog::create(array(
|
||||
// 'config_id' => $config->id,
|
||||
// 'peer_identity' => $endpoint->object_name,
|
||||
'peer_identity' => $this->client->getPeerIdentity(),
|
||||
'start_time' => date('Y-m-d H:i:s'),
|
||||
// 'triggered_by' => Util::getUsername(),
|
||||
/// 'username' => Util::getUsername(),
|
||||
// 'module_name' => $moduleName,
|
||||
));
|
||||
|
||||
$this->assertModuleExists($moduleName);
|
||||
|
||||
$response = $this->client->post(
|
||||
'config/stages/' . $moduleName,
|
||||
array(
|
||||
'files' => $config->getFileContents()
|
||||
)
|
||||
);
|
||||
|
||||
$duration = (int) ((microtime(true) - $start) * 1000);
|
||||
// $deployment->duration_ms = $duration;
|
||||
$deployment->duration_dump = $duration;
|
||||
|
||||
if ($response->succeeded()) {
|
||||
if ($stage = $response->getResult('stage', array('package' => $moduleName))) { // Status?
|
||||
$deployment->stage_name = key($stage);
|
||||
}
|
||||
$deployment->dump_succeeded = 'y';
|
||||
} else {
|
||||
$deployment->dump_succeeded = 'n';
|
||||
}
|
||||
|
||||
return $deployment->store($db);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Director\Core;
|
||||
|
||||
class RestApiClient
|
||||
{
|
||||
protected $version = 'v1';
|
||||
|
||||
protected $peer;
|
||||
|
||||
protected $port;
|
||||
|
||||
protected $user;
|
||||
|
||||
protected $pass;
|
||||
|
||||
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 getPeerIdentity()
|
||||
{
|
||||
return $this->peer;
|
||||
}
|
||||
|
||||
protected function url($url)
|
||||
{
|
||||
return sprintf('https://%s:%d/%s/%s', $this->peer, $this->port, $this->version, $url);
|
||||
}
|
||||
|
||||
protected function request($method, $url, $body = null, $raw = false)
|
||||
{
|
||||
$auth = base64_encode(sprintf('%s:%s', $this->user, $this->pass));
|
||||
$headers = array(
|
||||
'Host: ' . $this->getPeerIdentity(),
|
||||
'Authorization: Basic ' . $auth,
|
||||
'Connection: close'
|
||||
);
|
||||
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,
|
||||
'header' => $headers
|
||||
),
|
||||
'ssl' => array(
|
||||
'verify_peer' => false,
|
||||
// 'cafile' => $dir . 'cacert.pem',
|
||||
// 'verify_depth' => 5,
|
||||
// 'CN_match' => $peerName // != peer
|
||||
)
|
||||
);
|
||||
$context = stream_context_create($opts);
|
||||
|
||||
if ($raw) {
|
||||
return file_get_contents($this->url($url), false, $context);
|
||||
} else {
|
||||
return RestApiResponse::fromJsonResult(file_get_contents($this->url($url), false, $context));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Director\Core;
|
||||
|
||||
class RestApiResponse
|
||||
{
|
||||
protected $errorMessage;
|
||||
|
||||
protected $results;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public static function fromJsonResult($json)
|
||||
{
|
||||
$response = new static;
|
||||
return $response->parseJsonResult($json);
|
||||
}
|
||||
|
||||
public static function fromErrorMessage($error)
|
||||
{
|
||||
$response = new static;
|
||||
$response->errorMessage = $error;
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function getResult($desiredKey, $filter = array())
|
||||
{
|
||||
$response = array();
|
||||
foreach ($this->results as $result) {
|
||||
foreach ($filter as $key => $val) {
|
||||
if (! property_exists($result, $key)) {
|
||||
continue;
|
||||
}
|
||||
if ($result->$key !== $val) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (! property_exists($result, $desiredKey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$response[$result->$desiredKey] = $result;
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function getErrorMessage()
|
||||
{
|
||||
return $this->errorMessage;
|
||||
}
|
||||
|
||||
public function succeeded()
|
||||
{
|
||||
return $this->errorMessage === null;
|
||||
}
|
||||
|
||||
protected function parseJsonResult($json)
|
||||
{
|
||||
$result = @json_decode($json);
|
||||
if ($result === false) {
|
||||
return $this->setJsonError();
|
||||
}
|
||||
|
||||
$this->results = $result->results; // TODO: Check if set
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function setJsonError()
|
||||
{
|
||||
switch (json_last_error()) {
|
||||
default:
|
||||
$this->errorMessage = 'An unknown JSON decode error occured';
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue