1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-09-19 16:58:48 +02:00

Move Drydock logs to PHIDs and increased structure

Summary:
Ref T9252. Several general changes here:

  - Moves logs to use PHIDs instead of IDs. This generally improves flexibility (for example, it's a lot easier to render handles).
  - Adds `blueprintPHID` to logs. Although you can usually figure this out from the leasePHID or resourcePHID, it lets us query relevant logs on Blueprint views.
  - Instead of making logs a top-level object, make them strictly a sub-object of Blueprints, Resources and Leases. So you go Drydock > Lease > Logs, etc., to get to logs.
    - I might restore the "everything" view eventually, but it doesn't interact well with policies and I'm not sure it's very useful. A policy-violating `bin/drydock log` might be cleaner.
  - Policy-wise, we always show you that logs exist, we just don't show you log content if it's about something you can't see. This is similar to seeing restricted handles in other applications.
  - Instead of just having a message, give logs "type" + "data". This will let logs be more structured and translatable. This is similar to recent changes to Herald which seem to have worked well.

Test Plan:
Added some placeholder log writes, viewed those logs in the UI.

{F855199}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9252

Differential Revision: https://secure.phabricator.com/D14196
This commit is contained in:
epriestley 2015-10-01 08:06:23 -07:00
parent 98006f2cf3
commit 2ef5b5321d
14 changed files with 488 additions and 252 deletions

View file

@ -0,0 +1,25 @@
TRUNCATE {$NAMESPACE}_drydock.drydock_log;
ALTER TABLE {$NAMESPACE}_drydock.drydock_log
DROP resourceID;
ALTER TABLE {$NAMESPACE}_drydock.drydock_log
DROP leaseID;
ALTER TABLE {$NAMESPACE}_drydock.drydock_log
DROP message;
ALTER TABLE {$NAMESPACE}_drydock.drydock_log
ADD blueprintPHID VARBINARY(64);
ALTER TABLE {$NAMESPACE}_drydock.drydock_log
ADD resourcePHID VARBINARY(64);
ALTER TABLE {$NAMESPACE}_drydock.drydock_log
ADD leasePHID VARBINARY(64);
ALTER TABLE {$NAMESPACE}_drydock.drydock_log
ADD type VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT};
ALTER TABLE {$NAMESPACE}_drydock.drydock_log
ADD data LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT};

View file

@ -47,7 +47,7 @@ final class PhabricatorDrydockApplication extends PhabricatorApplication {
return array(
'/drydock/' => array(
'' => 'DrydockConsoleController',
'blueprint/' => array(
'(?P<type>blueprint)/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'DrydockBlueprintListController',
'(?P<id>[1-9]\d*)/' => array(
'' => 'DrydockBlueprintViewController',
@ -55,29 +55,32 @@ final class PhabricatorDrydockApplication extends PhabricatorApplication {
'DrydockBlueprintDisableController',
'resources/(?:query/(?P<queryKey>[^/]+)/)?' =>
'DrydockResourceListController',
'logs/(?:query/(?P<queryKey>[^/]+)/)?' =>
'DrydockLogListController',
),
'create/' => 'DrydockBlueprintCreateController',
'edit/(?:(?P<id>[1-9]\d*)/)?' => 'DrydockBlueprintEditController',
),
'resource/' => array(
'(?P<type>resource)/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'DrydockResourceListController',
'(?P<id>[1-9]\d*)/' => array(
'' => 'DrydockResourceViewController',
'release/' => 'DrydockResourceReleaseController',
'leases/(?:query/(?P<queryKey>[^/]+)/)?' =>
'DrydockLeaseListController',
'logs/(?:query/(?P<queryKey>[^/]+)/)?' =>
'DrydockLogListController',
),
),
'lease/' => array(
'(?P<type>lease)/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'DrydockLeaseListController',
'(?P<id>[1-9]\d*)/' => array(
'' => 'DrydockLeaseViewController',
'release/' => 'DrydockLeaseReleaseController',
'logs/(?:query/(?P<queryKey>[^/]+)/)?' =>
'DrydockLogListController',
),
),
'log/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'DrydockLogListController',
),
),
);
}

View file

@ -250,46 +250,6 @@ abstract class DrydockBlueprintImplementation extends Phobject {
/* -( Logging )------------------------------------------------------------ */
/**
* @task log
*/
protected function logException(Exception $ex) {
$this->log($ex->getMessage());
}
/**
* @task log
*/
protected function log($message) {
self::writeLog(null, null, $message);
}
/**
* @task log
*/
public static function writeLog(
DrydockResource $resource = null,
DrydockLease $lease = null,
$message = null) {
$log = id(new DrydockLog())
->setEpoch(time())
->setMessage($message);
if ($resource) {
$log->setResourceID($resource->getID());
}
if ($lease) {
$log->setLeaseID($lease->getID());
}
$log->save();
}
public static function getAllBlueprintImplementations() {
return id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__)

View file

@ -56,11 +56,19 @@ final class DrydockBlueprintViewController extends DrydockBlueprintController {
new DrydockBlueprintTransactionQuery());
$timeline->setShouldTerminate(true);
$log_query = id(new DrydockLogQuery())
->withBlueprintPHIDs(array($blueprint->getPHID()));
$log_box = $this->buildLogBox(
$log_query,
$this->getApplicationURI("blueprint/{$id}/logs/query/all/"));
return $this->buildApplicationPage(
array(
$crumbs,
$object_box,
$resource_box,
$log_box,
$timeline,
),
array(

View file

@ -85,4 +85,31 @@ abstract class DrydockController extends PhabricatorController {
->addRawContent($table);
}
protected function buildLogBox(DrydockLogQuery $query, $all_uri) {
$viewer = $this->getViewer();
$logs = $query
->setViewer($viewer)
->setLimit(100)
->execute();
$log_table = id(new DrydockLogListView())
->setUser($viewer)
->setLogs($logs)
->render();
$log_header = id(new PHUIHeaderView())
->setHeader(pht('Logs'))
->addActionLink(
id(new PHUIButtonView())
->setTag('a')
->setHref($all_uri)
->setIconFont('fa-search')
->setText(pht('View All Logs')));
return id(new PHUIObjectBoxView())
->setHeader($log_header)
->setTable($log_table);
}
}

View file

@ -15,7 +15,8 @@ final class DrydockLeaseViewController extends DrydockLeaseController {
return new Aphront404Response();
}
$lease_uri = $this->getApplicationURI('lease/'.$lease->getID().'/');
$id = $lease->getID();
$lease_uri = $this->getApplicationURI("lease/{$id}/");
$title = pht('Lease %d', $lease->getID());
@ -29,20 +30,12 @@ final class DrydockLeaseViewController extends DrydockLeaseController {
$actions = $this->buildActionListView($lease);
$properties = $this->buildPropertyListView($lease, $actions);
$pager = new PHUIPagerView();
$pager->setURI(new PhutilURI($lease_uri), 'offset');
$pager->setOffset($request->getInt('offset'));
$log_query = id(new DrydockLogQuery())
->withLeasePHIDs(array($lease->getPHID()));
$logs = id(new DrydockLogQuery())
->setViewer($viewer)
->withLeaseIDs(array($lease->getID()))
->executeWithOffsetPager($pager);
$log_table = id(new DrydockLogListView())
->setUser($viewer)
->setLogs($logs)
->render();
$log_table->appendChild($pager);
$log_box = $this->buildLogBox(
$log_query,
$this->getApplicationURI("lease/{$id}/logs/query/all/"));
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($title, $lease_uri);
@ -56,10 +49,6 @@ final class DrydockLeaseViewController extends DrydockLeaseController {
->addPropertyList($locks, pht('Slot Locks'))
->addPropertyList($commands, pht('Commands'));
$log_box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Lease Logs'))
->setTable($log_table);
return $this->buildApplicationPage(
array(
$crumbs,

View file

@ -3,13 +3,60 @@
abstract class DrydockLogController
extends DrydockController {
private $blueprint;
private $resource;
private $lease;
public function setBlueprint(DrydockBlueprint $blueprint) {
$this->blueprint = $blueprint;
return $this;
}
public function getBlueprint() {
return $this->blueprint;
}
public function setResource(DrydockResource $resource) {
$this->resource = $resource;
return $this;
}
public function getResource() {
return $this->resource;
}
public function setLease(DrydockLease $lease) {
$this->lease = $lease;
return $this;
}
public function getLease() {
return $this->lease;
}
public function buildSideNavView() {
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
id(new DrydockLogSearchEngine())
->setViewer($this->getRequest()->getUser())
->addNavigationItems($nav->getMenu());
$engine = id(new DrydockLogSearchEngine())
->setViewer($this->getRequest()->getUser());
$blueprint = $this->getBlueprint();
if ($blueprint) {
$engine->setBlueprint($blueprint);
}
$resource = $this->getResource();
if ($resource) {
$engine->setResource($resource);
}
$lease = $this->getLease();
if ($lease) {
$engine->setLease($lease);
}
$engine->addNavigationItems($nav->getMenu());
$nav->selectFilter(null);
@ -18,9 +65,54 @@ abstract class DrydockLogController
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
$crumbs->addTextCrumb(
pht('Logs'),
$this->getApplicationURI('log/'));
$blueprint = $this->getBlueprint();
$resource = $this->getResource();
$lease = $this->getLease();
if ($blueprint) {
$id = $blueprint->getID();
$crumbs->addTextCrumb(
pht('Blueprints'),
$this->getApplicationURI('blueprint/'));
$crumbs->addTextCrumb(
$blueprint->getBlueprintName(),
$this->getApplicationURI("blueprint/{$id}/"));
$crumbs->addTextCrumb(
pht('Logs'),
$this->getApplicationURI("blueprint/{$id}/logs/"));
} else if ($resource) {
$id = $resource->getID();
$crumbs->addTextCrumb(
pht('Resources'),
$this->getApplicationURI('resource/'));
$crumbs->addTextCrumb(
$resource->getName(),
$this->getApplicationURI("resource/{$id}/"));
$crumbs->addTextCrumb(
pht('Logs'),
$this->getApplicationURI("resource/{$id}/logs/"));
} else if ($lease) {
$id = $lease->getID();
$crumbs->addTextCrumb(
pht('Leases'),
$this->getApplicationURI('lease/'));
$crumbs->addTextCrumb(
$lease->getLeaseName(),
$this->getApplicationURI("lease/{$id}/"));
$crumbs->addTextCrumb(
pht('Logs'),
$this->getApplicationURI("lease/{$id}/logs/"));
}
return $crumbs;
}

View file

@ -8,11 +8,53 @@ final class DrydockLogListController extends DrydockLogController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$querykey = $request->getURIData('queryKey');
$engine = new DrydockLogSearchEngine();
$id = $request->getURIData('id');
$type = $request->getURIData('type');
switch ($type) {
case 'blueprint':
$blueprint = id(new DrydockBlueprintQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
if (!$blueprint) {
return new Aphront404Response();
}
$engine->setBlueprint($blueprint);
$this->setBlueprint($blueprint);
break;
case 'resource':
$resource = id(new DrydockResourceQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
if (!$resource) {
return new Aphront404Response();
}
$engine->setResource($resource);
$this->setResource($resource);
break;
case 'lease':
$lease = id(new DrydockLeaseQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
if (!$lease) {
return new Aphront404Response();
}
$engine->setLease($lease);
$this->setLease($lease);
break;
default:
return new Aphront404Response();
}
$query_key = $request->getURIData('queryKey');
$controller = id(new PhabricatorApplicationSearchController())
->setQueryKey($querykey)
->setSearchEngine(new DrydockLogSearchEngine())
->setQueryKey($query_key)
->setSearchEngine($engine)
->setNavigation($this->buildSideNavView());
return $this->delegateToController($controller);

View file

@ -29,23 +29,15 @@ final class DrydockResourceViewController extends DrydockResourceController {
$actions = $this->buildActionListView($resource);
$properties = $this->buildPropertyListView($resource, $actions);
$resource_uri = 'resource/'.$resource->getID().'/';
$resource_uri = $this->getApplicationURI($resource_uri);
$id = $resource->getID();
$resource_uri = $this->getApplicationURI("resource/{$id}/");
$pager = new PHUIPagerView();
$pager->setURI(new PhutilURI($resource_uri), 'offset');
$pager->setOffset($request->getInt('offset'));
$log_query = id(new DrydockLogQuery())
->withResourcePHIDs(array($resource->getPHID()));
$logs = id(new DrydockLogQuery())
->setViewer($viewer)
->withResourceIDs(array($resource->getID()))
->executeWithOffsetPager($pager);
$log_table = id(new DrydockLogListView())
->setUser($viewer)
->setLogs($logs)
->render();
$log_table->appendChild($pager);
$log_box = $this->buildLogBox(
$log_query,
$this->getApplicationURI("resource/{$id}/logs/query/all/"));
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Resource %d', $resource->getID()));
@ -61,10 +53,6 @@ final class DrydockResourceViewController extends DrydockResourceController {
$lease_box = $this->buildLeaseBox($resource);
$log_box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Resource Logs'))
->setTable($log_table);
return $this->buildApplicationPage(
array(
$crumbs,

View file

@ -2,112 +2,125 @@
final class DrydockLogQuery extends DrydockQuery {
private $resourceIDs;
private $leaseIDs;
private $blueprintPHIDs;
private $resourcePHIDs;
private $leasePHIDs;
public function withResourceIDs(array $ids) {
$this->resourceIDs = $ids;
public function withBlueprintPHIDs(array $phids) {
$this->blueprintPHIDs = $phids;
return $this;
}
public function withLeaseIDs(array $ids) {
$this->leaseIDs = $ids;
public function withResourcePHIDs(array $phids) {
$this->resourcePHIDs = $phids;
return $this;
}
public function withLeasePHIDs(array $phids) {
$this->leasePHIDs = $phids;
return $this;
}
public function newResultObject() {
return new DrydockLog();
}
protected function loadPage() {
$table = new DrydockLog();
$conn_r = $table->establishConnection('r');
$data = queryfx_all(
$conn_r,
'SELECT log.* FROM %T log %Q %Q %Q',
$table->getTableName(),
$this->buildWhereClause($conn_r),
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
return $table->loadAllFromArray($data);
return $this->loadStandardPage($this->newResultObject());
}
protected function willFilterPage(array $logs) {
$resource_ids = array_filter(mpull($logs, 'getResourceID'));
if ($resource_ids) {
protected function didFilterPage(array $logs) {
$blueprint_phids = array_filter(mpull($logs, 'getBlueprintPHID'));
if ($blueprint_phids) {
$blueprints = id(new DrydockBlueprintQuery())
->setParentQuery($this)
->setViewer($this->getViewer())
->withPHIDs($blueprint_phids)
->execute();
$blueprints = mpull($blueprints, null, 'getPHID');
} else {
$blueprints = array();
}
foreach ($logs as $key => $log) {
$blueprint = null;
$blueprint_phid = $log->getBlueprintPHID();
if ($blueprint_phid) {
$blueprint = idx($blueprints, $blueprint_phid);
}
$log->attachBlueprint($blueprint);
}
$resource_phids = array_filter(mpull($logs, 'getResourcePHID'));
if ($resource_phids) {
$resources = id(new DrydockResourceQuery())
->setParentQuery($this)
->setViewer($this->getViewer())
->withIDs(array_unique($resource_ids))
->withPHIDs($resource_phids)
->execute();
$resources = mpull($resources, null, 'getPHID');
} else {
$resources = array();
}
foreach ($logs as $key => $log) {
$resource = null;
if ($log->getResourceID()) {
$resource = idx($resources, $log->getResourceID());
if (!$resource) {
unset($logs[$key]);
continue;
}
$resource_phid = $log->getResourcePHID();
if ($resource_phid) {
$resource = idx($resources, $resource_phid);
}
$log->attachResource($resource);
}
$lease_ids = array_filter(mpull($logs, 'getLeaseID'));
if ($lease_ids) {
$lease_phids = array_filter(mpull($logs, 'getLeasePHID'));
if ($lease_phids) {
$leases = id(new DrydockLeaseQuery())
->setParentQuery($this)
->setViewer($this->getViewer())
->withIDs(array_unique($lease_ids))
->withPHIDs($lease_phids)
->execute();
$leases = mpull($leases, null, 'getPHID');
} else {
$leases = array();
}
foreach ($logs as $key => $log) {
$lease = null;
if ($log->getLeaseID()) {
$lease = idx($leases, $log->getLeaseID());
if (!$lease) {
unset($logs[$key]);
continue;
}
$lease_phid = $log->getLeasePHID();
if ($lease_phid) {
$lease = idx($leases, $lease_phid);
}
$log->attachLease($lease);
}
// These logs are meaningless and their policies aren't computable. They
// shouldn't exist, but throw them away if they do.
foreach ($logs as $key => $log) {
if (!$log->getResource() && !$log->getLease()) {
unset($logs[$key]);
}
}
return $logs;
}
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
$where = array();
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->resourceIDs !== null) {
if ($this->blueprintPHIDs !== null) {
$where[] = qsprintf(
$conn_r,
'resourceID IN (%Ld)',
$this->resourceIDs);
$conn,
'blueprintPHID IN (%Ls)',
$this->blueprintPHIDs);
}
if ($this->leaseIDs !== null) {
if ($this->resourcePHIDs !== null) {
$where[] = qsprintf(
$conn_r,
'leaseID IN (%Ld)',
$this->leaseIDs);
$conn,
'resourcePHID IN (%Ls)',
$this->resourcePHIDs);
}
$where[] = $this->buildPagingClause($conn_r);
if ($this->leasePHIDs !== null) {
$where[] = qsprintf(
$conn,
'leasePHID IN (%Ls)',
$this->leasePHIDs);
}
return $this->formatWhereClause($where);
return $where;
}
}

View file

@ -2,6 +2,43 @@
final class DrydockLogSearchEngine extends PhabricatorApplicationSearchEngine {
private $blueprint;
private $resource;
private $lease;
public function setBlueprint(DrydockBlueprint $blueprint) {
$this->blueprint = $blueprint;
return $this;
}
public function getBlueprint() {
return $this->blueprint;
}
public function setResource(DrydockResource $resource) {
$this->resource = $resource;
return $this;
}
public function getResource() {
return $this->resource;
}
public function setLease(DrydockLease $lease) {
$this->lease = $lease;
return $this;
}
public function getLease() {
return $this->lease;
}
public function canUseInPanelContext() {
// Prevent use on Dashboard panels since all log queries currently need a
// parent object and these don't seem particularly useful in any case.
return false;
}
public function getResultTypeDescription() {
return pht('Drydock Logs');
}
@ -10,75 +47,59 @@ final class DrydockLogSearchEngine extends PhabricatorApplicationSearchEngine {
return 'PhabricatorDrydockApplication';
}
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$query = new PhabricatorSavedQuery();
$query->setParameter(
'resourcePHIDs',
$this->readListFromRequest($request, 'resources'));
$query->setParameter(
'leasePHIDs',
$this->readListFromRequest($request, 'leases'));
return $query;
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$resource_phids = $saved->getParameter('resourcePHIDs', array());
$lease_phids = $saved->getParameter('leasePHIDs', array());
// TODO: Change logs to use PHIDs instead of IDs.
$resource_ids = array();
$lease_ids = array();
if ($resource_phids) {
$resource_ids = id(new DrydockResourceQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs($resource_phids)
->execute();
$resource_ids = mpull($resource_ids, 'getID');
}
if ($lease_phids) {
$lease_ids = id(new DrydockLeaseQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs($lease_phids)
->execute();
$lease_ids = mpull($lease_ids, 'getID');
}
public function newQuery() {
$query = new DrydockLogQuery();
if ($resource_ids) {
$query->withResourceIDs($resource_ids);
$blueprint = $this->getBlueprint();
if ($blueprint) {
$query->withBlueprintPHIDs(array($blueprint->getPHID()));
}
if ($lease_ids) {
$query->withLeaseIDs($lease_ids);
$resource = $this->getResource();
if ($resource) {
$query->withResourcePHIDs(array($resource->getPHID()));
}
$lease = $this->getLease();
if ($lease) {
$query->withLeasePHIDs(array($lease->getPHID()));
}
return $query;
}
public function buildSearchForm(
AphrontFormView $form,
PhabricatorSavedQuery $saved) {
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
$form
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new DrydockResourceDatasource())
->setName('resources')
->setLabel(pht('Resources'))
->setValue($saved->getParameter('resourcePHIDs', array())))
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new DrydockLeaseDatasource())
->setName('leases')
->setLabel(pht('Leases'))
->setValue($saved->getParameter('leasePHIDs', array())));
return $query;
}
protected function buildCustomSearchFields() {
return array();
}
protected function getURI($path) {
return '/drydock/log/'.$path;
$blueprint = $this->getBlueprint();
if ($blueprint) {
$id = $blueprint->getID();
return "/drydock/blueprint/{$id}/logs/{$path}";
}
$resource = $this->getResource();
if ($resource) {
$id = $resource->getID();
return "/drydock/resource/{$id}/logs/{$path}";
}
$lease = $this->getLease();
if ($lease) {
$id = $lease->getID();
return "/drydock/lease/{$id}/logs/{$path}";
}
throw new Exception(
pht(
'Search engine has no blueprint, resource, or lease.'));
}
protected function getBuiltinQueryNames() {

View file

@ -347,6 +347,9 @@ final class DrydockLease extends DrydockDAO
$viewer = PhabricatorUser::getOmnipotentUser();
$need_update = false;
// TODO: This is just a placeholder to get some data in the table.
$this->logEvent('activated');
$commands = id(new DrydockCommandQuery())
->setViewer($viewer)
->withTargetPHIDs(array($this->getPHID()))
@ -371,6 +374,24 @@ final class DrydockLease extends DrydockDAO
}
}
public function logEvent($type, array $data = array()) {
$log = id(new DrydockLog())
->setEpoch(PhabricatorTime::getNow())
->setType($type)
->setData($data);
$log->setLeasePHID($this->getPHID());
$resource = $this->getResource();
if ($resource) {
$log->setResourcePHID($resource->getPHID());
$log->setBlueprintPHID($resource->getBlueprintPHID());
}
return $log->save();
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */

View file

@ -3,28 +3,38 @@
final class DrydockLog extends DrydockDAO
implements PhabricatorPolicyInterface {
protected $resourceID;
protected $leaseID;
protected $blueprintPHID;
protected $resourcePHID;
protected $leasePHID;
protected $epoch;
protected $message;
protected $type;
protected $data = array();
private $blueprint = self::ATTACHABLE;
private $resource = self::ATTACHABLE;
private $lease = self::ATTACHABLE;
protected function getConfiguration() {
return array(
self::CONFIG_TIMESTAMPS => false,
self::CONFIG_SERIALIZATION => array(
'data' => self::SERIALIZATION_JSON,
),
self::CONFIG_COLUMN_SCHEMA => array(
'resourceID' => 'id?',
'leaseID' => 'id?',
'message' => 'text',
'blueprintPHID' => 'phid?',
'resourcePHID' => 'phid?',
'leasePHID' => 'phid?',
'type' => 'text64',
),
self::CONFIG_KEY_SCHEMA => array(
'resourceID' => array(
'columns' => array('resourceID', 'epoch'),
'key_blueprint' => array(
'columns' => array('blueprintPHID', 'type'),
),
'leaseID' => array(
'columns' => array('leaseID', 'epoch'),
'key_resource' => array(
'columns' => array('resourcePHID', 'type'),
),
'key_lease' => array(
'columns' => array('leasePHID', 'type'),
),
'epoch' => array(
'columns' => array('epoch'),
@ -33,6 +43,15 @@ final class DrydockLog extends DrydockDAO
) + parent::getConfiguration();
}
public function attachBlueprint(DrydockBlueprint $blueprint = null) {
$this->blueprint = $blueprint;
return $this;
}
public function getBlueprint() {
return $this->assertAttached($this->blueprint);
}
public function attachResource(DrydockResource $resource = null) {
$this->resource = $resource;
return $this;
@ -51,6 +70,22 @@ final class DrydockLog extends DrydockDAO
return $this->assertAttached($this->lease);
}
public function isComplete() {
if ($this->getBlueprintPHID() && !$this->getBlueprint()) {
return false;
}
if ($this->getResourcePHID() && !$this->getResource()) {
return false;
}
if ($this->getLeasePHID() && !$this->getLease()) {
return false;
}
return true;
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
@ -62,21 +97,19 @@ final class DrydockLog extends DrydockDAO
}
public function getPolicy($capability) {
if ($this->getResource()) {
return $this->getResource()->getPolicy($capability);
}
return $this->getLease()->getPolicy($capability);
// NOTE: We let you see that logs exist no matter what, but don't actually
// show you log content unless you can see all of the associated objects.
return PhabricatorPolicies::getMostOpenPolicy();
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
if ($this->getResource()) {
return $this->getResource()->hasAutomaticCapability($capability, $viewer);
}
return $this->getLease()->hasAutomaticCapability($capability, $viewer);
return false;
}
public function describeAutomaticCapability($capability) {
return pht('Logs inherit the policy of their resources.');
return pht(
'To view log details, you must be able to view the associated '.
'blueprint, resource and lease.');
}
}

View file

@ -18,28 +18,45 @@ final class DrydockLogListView extends AphrontView {
$rows = array();
foreach ($logs as $log) {
$resource_uri = '/drydock/resource/'.$log->getResourceID().'/';
$lease_uri = '/drydock/lease/'.$log->getLeaseID().'/';
$blueprint_phid = $log->getBlueprintPHID();
if ($blueprint_phid) {
$blueprint = $viewer->renderHandle($blueprint_phid);
} else {
$blueprint = null;
}
$resource_name = $log->getResourceID();
if ($log->getResourceID() !== null) {
$resource_name = $log->getResource()->getName();
$resource_phid = $log->getResourcePHID();
if ($resource_phid) {
$resource = $viewer->renderHandle($resource_phid);
} else {
$resource = null;
}
$lease_phid = $log->getLeasePHID();
if ($lease_phid) {
$lease = $viewer->renderHandle($lease_phid);
} else {
$lease = null;
}
if ($log->isComplete()) {
// TODO: This is a placeholder.
$type = $log->getType();
$data = print_r($log->getData(), true);
} else {
$type = phutil_tag('em', array(), pht('Restricted'));
$data = phutil_tag(
'em',
array(),
pht('You do not have permission to view this log event.'));
}
$rows[] = array(
phutil_tag(
'a',
array(
'href' => $resource_uri,
),
$resource_name),
phutil_tag(
'a',
array(
'href' => $lease_uri,
),
$log->getLeaseID()),
$log->getMessage(),
$blueprint,
$resource,
$lease,
$type,
$data,
phabricator_datetime($log->getEpoch(), $viewer),
);
}
@ -48,20 +65,17 @@ final class DrydockLogListView extends AphrontView {
$table->setDeviceReadyTable(true);
$table->setHeaders(
array(
pht('Blueprint'),
pht('Resource'),
pht('Lease'),
pht('Message'),
pht('Type'),
pht('Data'),
pht('Date'),
));
$table->setShortHeaders(
array(
pht('R'),
pht('L'),
pht('Message'),
'',
));
$table->setColumnClasses(
array(
'',
'',
'',
'',
'wide',