IcingaObjectHandler: delegate REST API
This commit is contained in:
parent
a7b796466f
commit
93cb271554
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Director\RestApi;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Exception\IcingaException;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Module\Director\Core\CoreApi;
|
||||
use Icinga\Module\Director\Exception\DuplicateKeyException;
|
||||
use Icinga\Module\Director\Objects\IcingaObject;
|
||||
use Icinga\Module\Director\Util;
|
||||
|
||||
class IcingaObjectHandler extends RequestHandler
|
||||
{
|
||||
/** @var IcingaObject */
|
||||
protected $object;
|
||||
|
||||
/** @var CoreApi */
|
||||
protected $api;
|
||||
|
||||
public function setObject(IcingaObject $object)
|
||||
{
|
||||
$this->object = $object;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setApi(CoreApi $api)
|
||||
{
|
||||
$this->api = $api;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IcingaObject
|
||||
* @throws ProgrammingError
|
||||
*/
|
||||
protected function requireObject()
|
||||
{
|
||||
if ($this->object === null) {
|
||||
throw new ProgrammingError('Object is required');
|
||||
}
|
||||
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IcingaObject
|
||||
*/
|
||||
protected function eventuallyLoadObject()
|
||||
{
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
protected function requireJsonBody()
|
||||
{
|
||||
$data = json_decode($this->request->getRawBody());
|
||||
|
||||
if ($data === null) {
|
||||
$this->response->setHttpResponseCode(400);
|
||||
throw new IcingaException(
|
||||
'Invalid JSON: %s',
|
||||
$this->getLastJsonError()
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getType()
|
||||
{
|
||||
return $this->request->getControllerName();
|
||||
}
|
||||
|
||||
protected function handleApiRequest()
|
||||
{
|
||||
try {
|
||||
$this->processApiRequest();
|
||||
} catch (NotFoundError $e) {
|
||||
$this->sendJsonError($e, 404);
|
||||
return;
|
||||
} catch (DuplicateKeyException $e) {
|
||||
$this->sendJsonError($e, 422);
|
||||
return;
|
||||
} catch (Exception $e) {
|
||||
$this->sendJsonError($e);
|
||||
}
|
||||
|
||||
if ($this->request->getActionName() !== 'index') {
|
||||
throw new NotFoundError('Not found');
|
||||
}
|
||||
}
|
||||
|
||||
protected function processApiRequest()
|
||||
{
|
||||
$request = $this->request;
|
||||
$response = $this->response;
|
||||
$db = $this->db;
|
||||
|
||||
// TODO: I hate doing this:
|
||||
if ($this->request->getActionName() === 'ticket') {
|
||||
$host = $this->requireObject();
|
||||
|
||||
if ($host->getResolvedProperty('has_agent') !== 'y') {
|
||||
throw new NotFoundError('The host "%s" is not an agent', $host->getObjectName());
|
||||
}
|
||||
|
||||
$this->sendJson(
|
||||
Util::getIcingaTicket(
|
||||
$host->getObjectName(),
|
||||
$this->api->getTicketSalt()
|
||||
)
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch ($request->getMethod()) {
|
||||
case 'DELETE':
|
||||
$object = $this->requireObject();
|
||||
$object->delete();
|
||||
$this->sendJson($object->toPlainObject(false, true));
|
||||
break;
|
||||
|
||||
case 'POST':
|
||||
case 'PUT':
|
||||
$data = (array) $this->requireJsonBody();
|
||||
$type = $this->getType();
|
||||
if ($object = $this->eventuallyLoadObject()) {
|
||||
if ($request->getMethod() === 'POST') {
|
||||
$object->setProperties($data);
|
||||
} else {
|
||||
$data = array_merge([
|
||||
'object_type' => $object->get('object_type'),
|
||||
'object_name' => $object->getObjectName()
|
||||
], $data);
|
||||
$object->replaceWith(
|
||||
IcingaObject::createByType($type, $data, $db)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$object = IcingaObject::createByType($type, $data, $db);
|
||||
}
|
||||
|
||||
if ($object->hasBeenModified()) {
|
||||
$status = $object->hasBeenLoadedFromDb() ? 200 : 201;
|
||||
$object->store();
|
||||
$response->setHttpResponseCode($status);
|
||||
} else {
|
||||
$response->setHttpResponseCode(304);
|
||||
}
|
||||
|
||||
$this->sendJson($object->toPlainObject(false, true));
|
||||
break;
|
||||
|
||||
case 'GET':
|
||||
$params = $this->request->getUrl()->getParams();
|
||||
$this->requireObject();
|
||||
$properties = $params->shift('properties');
|
||||
if (strlen($properties)) {
|
||||
$properties = preg_split('/\s*,\s*/', $properties, -1, PREG_SPLIT_NO_EMPTY);
|
||||
} else {
|
||||
$properties = null;
|
||||
}
|
||||
|
||||
$this->sendJson(
|
||||
$this->requireObject()->toPlainObject(
|
||||
$params->shift('resolved'),
|
||||
! $params->shift('withNull'),
|
||||
$properties
|
||||
)
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
$request->getResponse()->setHttpResponseCode(400);
|
||||
throw new IcingaException('Unsupported method ' . $request->getMethod());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,8 +29,10 @@ abstract class ObjectController extends ActionController
|
|||
/** @var IcingaObject */
|
||||
protected $object;
|
||||
|
||||
/** @var bool This controller handles REST API requests */
|
||||
protected $isApified = true;
|
||||
|
||||
/** @var array Allowed object types we are allowed to edit anyways */
|
||||
protected $allowedExternals = array(
|
||||
'apiuser',
|
||||
'endpoint'
|
||||
|
@ -40,30 +42,24 @@ abstract class ObjectController extends ActionController
|
|||
{
|
||||
parent::init();
|
||||
|
||||
$this->eventuallyLoadObject();
|
||||
if ($this->getRequest()->isApiRequest()) {
|
||||
$this->handleApiRequest();
|
||||
} else {
|
||||
$type = strtolower($this->getType());
|
||||
if (null !== $this->params->get('name') || $this->params->get('id')) {
|
||||
$this->loadObject();
|
||||
$handler = new IcingaObjectHandler($this->getRequest(), $this->getResponse(), $this->db());
|
||||
$handler->setApi($this->api());
|
||||
if ($this->object) {
|
||||
$handler->setObject($this->object);
|
||||
}
|
||||
$this->tabs(new ObjectTabs($type, $this->getAuth(), $this->object));
|
||||
$handler->dispatch();
|
||||
} else {
|
||||
$this->tabs(new ObjectTabs($this->getType(), $this->getAuth(), $this->object));
|
||||
}
|
||||
}
|
||||
|
||||
public function indexAction()
|
||||
{
|
||||
if ($this->getRequest()->isApiRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->object
|
||||
&& $this->object->isExternal()
|
||||
&& ! in_array($this->object->getShortTableName(), $this->allowedExternals)
|
||||
) {
|
||||
$this->redirectNow(
|
||||
$this->getRequest()->getUrl()->setPath(sprintf('director/%s/render', $this->getType()))
|
||||
);
|
||||
if (! $this->getRequest()->isApiRequest()) {
|
||||
$this->redirectToPreviewForExternals()
|
||||
->editAction();
|
||||
}
|
||||
|
||||
$this->editAction();
|
||||
|
@ -266,10 +262,23 @@ abstract class ObjectController extends ActionController
|
|||
);
|
||||
}
|
||||
|
||||
protected function eventuallyLoadObject()
|
||||
{
|
||||
if (null !== $this->params->get('name') || $this->params->get('id')) {
|
||||
$this->loadObject();
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadObject()
|
||||
{
|
||||
if ($this->object === null) {
|
||||
if (null !== ($name = $this->params->get('name'))) {
|
||||
if ($id = $this->params->get('id')) {
|
||||
$this->object = IcingaObject::loadByType(
|
||||
$this->getType(),
|
||||
(int) $id,
|
||||
$this->db()
|
||||
);
|
||||
} elseif (null !== ($name = $this->params->get('name'))) {
|
||||
$this->object = IcingaObject::loadByType(
|
||||
$this->getType(),
|
||||
$name,
|
||||
|
@ -280,12 +289,6 @@ abstract class ObjectController extends ActionController
|
|||
$this->object = null;
|
||||
throw new NotFoundError('No such object available');
|
||||
}
|
||||
} elseif ($id = $this->params->get('id')) {
|
||||
$this->object = IcingaObject::loadByType(
|
||||
$this->getType(),
|
||||
(int) $id,
|
||||
$this->db()
|
||||
);
|
||||
} elseif ($this->getRequest()->isApiRequest()) {
|
||||
if ($this->getRequest()->isGet()) {
|
||||
$this->getResponse()->setHttpResponseCode(422);
|
||||
|
|
Loading…
Reference in New Issue