1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-20 20:40:56 +01:00

Make Drydock more broadly aware of policies

Summary:
Ref T2015. Moves a bunch of raw object loads into modern policy-aware queries.

Also straightens out the Log and Lease policies a little bit: there are legitimate states where these objects are not attached to a resource (particularly, while a lease is being acquired). Handle these more gracefully.

Test Plan: Lint / browsed stuff.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T2015

Differential Revision: https://secure.phabricator.com/D7836
This commit is contained in:
epriestley 2013-12-27 13:15:19 -08:00
parent 1650874004
commit 9b0fa5747b
17 changed files with 192 additions and 86 deletions

View file

@ -122,6 +122,7 @@ abstract class DrydockBlueprintImplementation {
$resource->beginReadLocking(); $resource->beginReadLocking();
$resource->reload(); $resource->reload();
// TODO: Policy stuff.
$other_leases = id(new DrydockLease())->loadAllWhere( $other_leases = id(new DrydockLease())->loadAllWhere(
'status IN (%Ld) AND resourceID = %d', 'status IN (%Ld) AND resourceID = %d',
array( array(
@ -388,13 +389,13 @@ abstract class DrydockBlueprintImplementation {
} }
protected function newResourceTemplate($name) { protected function newResourceTemplate($name) {
$resource = new DrydockResource(); $resource = id(new DrydockResource())
$resource->setBlueprintPHID($this->getInstance()->getPHID()); ->setBlueprintPHID($this->getInstance()->getPHID())
$resource->setBlueprintClass($this->getBlueprintClass()); ->setBlueprintClass($this->getBlueprintClass())
$resource->setType($this->getType()); ->setType($this->getType())
$resource->setStatus(DrydockResourceStatus::STATUS_PENDING); ->setStatus(DrydockResourceStatus::STATUS_PENDING)
$resource->setName($name); ->setName($name)
$resource->save(); ->save();
$this->activeResource = $resource; $this->activeResource = $resource;

View file

@ -52,6 +52,7 @@ final class DrydockWorkingCopyBlueprintImplementation
throw new Exception("Unsupported VCS!"); throw new Exception("Unsupported VCS!");
} }
// TODO: Policy stuff here too.
$host_lease = id(new DrydockLease()) $host_lease = id(new DrydockLease())
->setResourceType('host') ->setResourceType('host')
->waitUntilActive(); ->waitUntilActive();

View file

@ -16,12 +16,12 @@ final class DrydockBlueprintCreateController
return $this->createDialog($implementations); return $this->createDialog($implementations);
} }
$blueprint = new DrydockBlueprint(); $blueprint = id(new DrydockBlueprint())
$blueprint->setClassName($class); ->setClassName($class)
$blueprint->setDetails(array()); ->setDetails(array())
$blueprint->setViewPolicy(PhabricatorPolicies::POLICY_ADMIN); ->setViewPolicy(PhabricatorPolicies::POLICY_ADMIN)
$blueprint->setEditPolicy(PhabricatorPolicies::POLICY_ADMIN); ->setEditPolicy(PhabricatorPolicies::POLICY_ADMIN)
$blueprint->save(); ->save();
$edit_uri = $this->getApplicationURI( $edit_uri = $this->getApplicationURI(
"blueprint/edit/".$blueprint->getID()."/"); "blueprint/edit/".$blueprint->getID()."/");

View file

@ -10,9 +10,12 @@ final class DrydockBlueprintViewController extends DrydockBlueprintController {
public function processRequest() { public function processRequest() {
$request = $this->getRequest(); $request = $this->getRequest();
$user = $request->getUser(); $viewer = $request->getUser();
$blueprint = id(new DrydockBlueprint())->load($this->id); $blueprint = id(new DrydockBlueprintQuery())
->setViewer($viewer)
->withIDs(array($this->id))
->executeOne();
if (!$blueprint) { if (!$blueprint) {
return new Aphront404Response(); return new Aphront404Response();
} }
@ -30,7 +33,7 @@ final class DrydockBlueprintViewController extends DrydockBlueprintController {
$resources = id(new DrydockResourceQuery()) $resources = id(new DrydockResourceQuery())
->withBlueprintPHIDs(array($blueprint->getPHID())) ->withBlueprintPHIDs(array($blueprint->getPHID()))
->setViewer($user) ->setViewer($viewer)
->execute(); ->execute();
$resource_list = $this->buildResourceListView($resources); $resource_list = $this->buildResourceListView($resources);

View file

@ -10,9 +10,12 @@ final class DrydockLeaseViewController extends DrydockLeaseController {
public function processRequest() { public function processRequest() {
$request = $this->getRequest(); $request = $this->getRequest();
$user = $request->getUser(); $viewer = $request->getUser();
$lease = id(new DrydockLease())->load($this->id); $lease = id(new DrydockLeaseQuery())
->setViewer($viewer)
->withIDs(array($this->id))
->executeOne();
if (!$lease) { if (!$lease) {
return new Aphront404Response(); return new Aphront404Response();
} }
@ -32,7 +35,7 @@ final class DrydockLeaseViewController extends DrydockLeaseController {
$pager->setOffset($request->getInt('offset')); $pager->setOffset($request->getInt('offset'));
$logs = id(new DrydockLogQuery()) $logs = id(new DrydockLogQuery())
->setViewer($user) ->setViewer($viewer)
->withLeaseIDs(array($lease->getID())) ->withLeaseIDs(array($lease->getID()))
->executeWithOffsetPager($pager); ->executeWithOffsetPager($pager);

View file

@ -10,9 +10,12 @@ final class DrydockResourceCloseController extends DrydockResourceController {
public function processRequest() { public function processRequest() {
$request = $this->getRequest(); $request = $this->getRequest();
$user = $request->getUser(); $viewer = $request->getUser();
$resource = id(new DrydockResource())->load($this->id); $resource = id(new DrydockResourceQuery())
->setViewer($viewer)
->withIDs(array($this->id))
->executeOne();
if (!$resource) { if (!$resource) {
return new Aphront404Response(); return new Aphront404Response();
} }
@ -22,7 +25,7 @@ final class DrydockResourceCloseController extends DrydockResourceController {
if ($resource->getStatus() != DrydockResourceStatus::STATUS_OPEN) { if ($resource->getStatus() != DrydockResourceStatus::STATUS_OPEN) {
$dialog = id(new AphrontDialogView()) $dialog = id(new AphrontDialogView())
->setUser($user) ->setUser($viewer)
->setTitle(pht('Resource Not Open')) ->setTitle(pht('Resource Not Open'))
->appendChild(phutil_tag('p', array(), pht( ->appendChild(phutil_tag('p', array(), pht(
'You can only close "open" resources.'))) 'You can only close "open" resources.')))
@ -31,22 +34,22 @@ final class DrydockResourceCloseController extends DrydockResourceController {
return id(new AphrontDialogResponse())->setDialog($dialog); return id(new AphrontDialogResponse())->setDialog($dialog);
} }
if (!$request->isDialogFormPost()) { if ($request->isFormPost()) {
$resource->closeResource();
return id(new AphrontReloadResponse())->setURI($resource_uri);
}
$dialog = id(new AphrontDialogView()) $dialog = id(new AphrontDialogView())
->setUser($user) ->setUser($viewer)
->setTitle(pht('Really close resource?')) ->setTitle(pht('Really close resource?'))
->appendChild(phutil_tag('p', array(), pht( ->appendChild(
pht(
'Closing a resource releases all leases and destroys the '. 'Closing a resource releases all leases and destroys the '.
'resource. It can not be undone. Continue?'))) 'resource. It can not be undone. Continue?'))
->addSubmitButton(pht('Close Resource')) ->addSubmitButton(pht('Close Resource'))
->addCancelButton($resource_uri); ->addCancelButton($resource_uri);
return id(new AphrontDialogResponse())->setDialog($dialog); return id(new AphrontDialogResponse())->setDialog($dialog);
} }
$resource->closeResource();
return id(new AphrontReloadResponse())->setURI($resource_uri);
}
} }

View file

@ -10,9 +10,12 @@ final class DrydockResourceViewController extends DrydockResourceController {
public function processRequest() { public function processRequest() {
$request = $this->getRequest(); $request = $this->getRequest();
$user = $request->getUser(); $viewer = $request->getUser();
$resource = id(new DrydockResource())->load($this->id); $resource = id(new DrydockResourceQuery())
->setViewer($viewer)
->withIDs(array($this->id))
->executeOne();
if (!$resource) { if (!$resource) {
return new Aphront404Response(); return new Aphront404Response();
} }
@ -29,7 +32,7 @@ final class DrydockResourceViewController extends DrydockResourceController {
$resource_uri = $this->getApplicationURI($resource_uri); $resource_uri = $this->getApplicationURI($resource_uri);
$leases = id(new DrydockLeaseQuery()) $leases = id(new DrydockLeaseQuery())
->setViewer($user) ->setViewer($viewer)
->withResourceIDs(array($resource->getID())) ->withResourceIDs(array($resource->getID()))
->execute(); ->execute();
@ -41,7 +44,7 @@ final class DrydockResourceViewController extends DrydockResourceController {
$pager->setOffset($request->getInt('offset')); $pager->setOffset($request->getInt('offset'));
$logs = id(new DrydockLogQuery()) $logs = id(new DrydockLogQuery())
->setViewer($user) ->setViewer($viewer)
->withResourceIDs(array($resource->getID())) ->withResourceIDs(array($resource->getID()))
->executeWithOffsetPager($pager); ->executeWithOffsetPager($pager);

View file

@ -25,8 +25,15 @@ final class DrydockManagementCloseWorkflow
"Specify one or more resource IDs to close."); "Specify one or more resource IDs to close.");
} }
$viewer = PhabricatorUser::getOmnipotentUser();
$resources = id(new DrydockResourceQuery())
->setViewer($viewer)
->withIDs($ids)
->execute();
foreach ($ids as $id) { foreach ($ids as $id) {
$resource = id(new DrydockResource())->load($id); $resource = idx($resources, $id);
if (!$resource) { if (!$resource) {
$console->writeErr("Resource %d does not exist!\n", $id); $console->writeErr("Resource %d does not exist!\n", $id);
} else if ($resource->getStatus() != DrydockResourceStatus::STATUS_OPEN) { } else if ($resource->getStatus() != DrydockResourceStatus::STATUS_OPEN) {

View file

@ -49,17 +49,22 @@ final class DrydockManagementCreateResourceWorkflow
$attributes = $options->parse($attributes); $attributes = $options->parse($attributes);
} }
$blueprint = id(new DrydockBlueprint())->load((int)$blueprint_id); $viewer = PhabricatorUser::getOmnipotentUser();
$blueprint = id(new DrydockBlueprintQuery())
->setViewer($viewer)
->withIDs(array($blueprint_id))
->executeOne();
if (!$blueprint) { if (!$blueprint) {
throw new PhutilArgumentUsageException( throw new PhutilArgumentUsageException(
"Specified blueprint does not exist."); "Specified blueprint does not exist.");
} }
$resource = new DrydockResource(); $resource = id(new DrydockResource())
$resource->setBlueprintPHID($blueprint->getPHID()); ->setBlueprintPHID($blueprint->getPHID())
$resource->setType($blueprint->getImplementation()->getType()); ->setType($blueprint->getImplementation()->getType())
$resource->setName($resource_name); ->setName($resource_name)
$resource->setStatus(DrydockResourceStatus::STATUS_OPEN); ->setStatus(DrydockResourceStatus::STATUS_OPEN);
if ($attributes) { if ($attributes) {
$resource->setAttributes($attributes); $resource->setAttributes($attributes);
} }

View file

@ -44,18 +44,26 @@ final class DrydockLeaseQuery
} }
public function willFilterPage(array $leases) { public function willFilterPage(array $leases) {
$resource_ids = array_filter(mpull($leases, 'getResourceID'));
if ($resource_ids) {
$resources = id(new DrydockResourceQuery()) $resources = id(new DrydockResourceQuery())
->setParentQuery($this) ->setParentQuery($this)
->setViewer($this->getViewer()) ->setViewer($this->getViewer())
->withIDs(mpull($leases, 'getResourceID')) ->withIDs($resource_ids)
->execute(); ->execute();
} else {
$resources = array();
}
foreach ($leases as $key => $lease) { foreach ($leases as $key => $lease) {
$resource = null;
if ($lease->getResourceID()) {
$resource = idx($resources, $lease->getResourceID()); $resource = idx($resources, $lease->getResourceID());
if (!$resource) { if (!$resource) {
unset($leases[$key]); unset($leases[$key]);
continue; continue;
} }
}
$lease->attachResource($resource); $lease->attachResource($resource);
} }

View file

@ -31,18 +31,60 @@ final class DrydockLogQuery extends PhabricatorCursorPagedPolicyAwareQuery {
} }
public function willFilterPage(array $logs) { public function willFilterPage(array $logs) {
$resource_ids = mpull($logs, 'getResourceID'); $resource_ids = array_filter(mpull($logs, 'getResourceID'));
if ($resource_ids) {
$resources = id(new DrydockResourceQuery()) $resources = id(new DrydockResourceQuery())
->setParentQuery($this) ->setParentQuery($this)
->setViewer($this->getViewer()) ->setViewer($this->getViewer())
->withIDs($resource_ids) ->withIDs($resource_ids)
->execute(); ->execute();
} else {
$resources = array();
}
foreach ($logs as $key => $log) { foreach ($logs as $key => $log) {
$resource = null;
if ($log->getResourceID()) {
$resource = idx($resources, $log->getResourceID()); $resource = idx($resources, $log->getResourceID());
if (!$resource) {
unset($logs[$key]);
continue;
}
}
$log->attachResource($resource); $log->attachResource($resource);
} }
$lease_ids = array_filter(mpull($logs, 'getLeaseID'));
if ($lease_ids) {
$leases = id(new DrydockLeaseQuery())
->setParentQuery($this)
->setViewer($this->getViewer())
->withIDs($lease_ids)
->execute();
} else {
$leases = array();
}
foreach ($logs as $key => $log) {
$lease = null;
if ($log->getLeaseID()) {
$lease = idx($leases, $log->getLeaseID());
if (!$lease) {
unset($logs[$key]);
continue;
}
}
$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; return $logs;
} }

View file

@ -67,7 +67,7 @@ final class DrydockLease extends DrydockDAO
return $this->assertAttached($this->resource); return $this->assertAttached($this->resource);
} }
public function attachResource(DrydockResource $resource) { public function attachResource(DrydockResource $resource = null) {
$this->resource = $resource; $this->resource = $resource;
return $this; return $this;
} }
@ -194,12 +194,18 @@ final class DrydockLease extends DrydockDAO
} }
public function getPolicy($capability) { public function getPolicy($capability) {
if ($this->getResource()) {
return $this->getResource()->getPolicy($capability); return $this->getResource()->getPolicy($capability);
} }
return PhabricatorPolicies::getMostOpenPolicy();
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
if ($this->getResource()) {
return $this->getResource()->hasAutomaticCapability($capability, $viewer); return $this->getResource()->hasAutomaticCapability($capability, $viewer);
} }
return false;
}
public function describeAutomaticCapability($capability) { public function describeAutomaticCapability($capability) {
return pht('Leases inherit policies from the resources they lease.'); return pht('Leases inherit policies from the resources they lease.');

View file

@ -9,6 +9,7 @@ final class DrydockLog extends DrydockDAO
protected $message; protected $message;
private $resource = self::ATTACHABLE; private $resource = self::ATTACHABLE;
private $lease = self::ATTACHABLE;
public function getConfiguration() { public function getConfiguration() {
return array( return array(
@ -25,6 +26,15 @@ final class DrydockLog extends DrydockDAO
return $this->assertAttached($this->resource); return $this->assertAttached($this->resource);
} }
public function attachLease(DrydockLease $lease = null) {
$this->lease = $lease;
return $this;
}
public function getLease() {
return $this->assertAttached($this->lease);
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */ /* -( PhabricatorPolicyInterface )----------------------------------------- */
@ -36,18 +46,18 @@ final class DrydockLog extends DrydockDAO
} }
public function getPolicy($capability) { public function getPolicy($capability) {
if (!$this->getResource()) { if ($this->getResource()) {
return PhabricatorPolicies::getMostOpenPolicy();
}
return $this->getResource()->getPolicy($capability); return $this->getResource()->getPolicy($capability);
} }
return $this->getLease()->getPolicy($capability);
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
if (!$this->getResource()) { if ($this->getResource()) {
return false;
}
return $this->getResource()->hasAutomaticCapability($capability, $viewer); return $this->getResource()->hasAutomaticCapability($capability, $viewer);
} }
return $this->getLease()->hasAutomaticCapability($capability, $viewer);
}
public function describeAutomaticCapability($capability) { public function describeAutomaticCapability($capability) {
return pht('Logs inherit the policy of their resources.'); return pht('Logs inherit the policy of their resources.');

View file

@ -52,6 +52,7 @@ final class DrydockResource extends DrydockDAO
} }
public function getBlueprint() { public function getBlueprint() {
// TODO: Policy stuff.
if (empty($this->blueprint)) { if (empty($this->blueprint)) {
$blueprint = id(new DrydockBlueprint()) $blueprint = id(new DrydockBlueprint())
->loadOneWhere('phid = %s', $this->blueprintPHID); ->loadOneWhere('phid = %s', $this->blueprintPHID);
@ -62,13 +63,16 @@ final class DrydockResource extends DrydockDAO
public function closeResource() { public function closeResource() {
$this->openTransaction(); $this->openTransaction();
$leases = id(new DrydockLease())->loadAllWhere( $statuses = array(
'resourceID = %d AND status IN (%Ld)',
$this->getID(),
array(
DrydockLeaseStatus::STATUS_PENDING, DrydockLeaseStatus::STATUS_PENDING,
DrydockLeaseStatus::STATUS_ACTIVE, DrydockLeaseStatus::STATUS_ACTIVE,
)); );
$leases = id(new DrydockLeaseQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withResourceIDs(array($this->getID()))
->withStatuses($statuses)
->execute();
foreach ($leases as $lease) { foreach ($leases as $lease) {
switch ($lease->getStatus()) { switch ($lease->getStatus()) {

View file

@ -13,10 +13,13 @@ final class DrydockAllocatorWorker extends PhabricatorWorker {
private function loadLease() { private function loadLease() {
if (empty($this->lease)) { if (empty($this->lease)) {
$lease = id(new DrydockLease())->load($this->getTaskData()); $lease = id(new DrydockLeaseQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withIDs(array($this->getTaskData()))
->executeOne();
if (!$lease) { if (!$lease) {
throw new PhabricatorWorkerPermanentFailureException( throw new PhabricatorWorkerPermanentFailureException(
"No such lease!"); pht("No such lease %d!", $this->getTaskData()));
} }
$this->lease = $lease; $this->lease = $lease;
} }
@ -53,7 +56,10 @@ final class DrydockAllocatorWorker extends PhabricatorWorker {
} }
private function loadAllBlueprints() { private function loadAllBlueprints() {
$instances = id(new DrydockBlueprint())->loadAll(); $viewer = PhabricatorUser::getOmnipotentUser();
$instances = id(new DrydockBlueprintQuery())
->setViewer($viewer)
->execute();
$blueprints = array(); $blueprints = array();
foreach ($instances as $instance) { foreach ($instances as $instance) {
$blueprints[$instance->getPHID()] = $instance; $blueprints[$instance->getPHID()] = $instance;
@ -66,6 +72,7 @@ final class DrydockAllocatorWorker extends PhabricatorWorker {
$blueprints = $this->loadAllBlueprints(); $blueprints = $this->loadAllBlueprints();
// TODO: Policy stuff.
$pool = id(new DrydockResource())->loadAllWhere( $pool = id(new DrydockResource())->loadAllWhere(
'type = %s AND status = %s', 'type = %s AND status = %s',
$lease->getResourceType(), $lease->getResourceType(),

View file

@ -28,11 +28,13 @@ final class LeaseHostBuildStepImplementation
$settings = $this->getSettings(); $settings = $this->getSettings();
// Create the lease. // Create the lease.
$lease = new DrydockLease(); $lease = id(new DrydockLease())
$lease->setResourceType('host'); ->setResourceType('host')
$lease->setAttributes( ->setAttributes(
array('platform' => $settings['platform'])); array(
$lease->queueForActivation(); 'platform' => $settings['platform'],
))
->queueForActivation();
// Wait until the lease is fulfilled. // Wait until the lease is fulfilled.
// TODO: This will throw an exception if the lease can't be fulfilled; // TODO: This will throw an exception if the lease can't be fulfilled;

View file

@ -82,6 +82,7 @@ final class HarbormasterBuildArtifact extends HarbormasterDAO
$data = $this->getArtifactData(); $data = $this->getArtifactData();
// FIXME: Is there a better way of doing this? // FIXME: Is there a better way of doing this?
// TODO: Policy stuff, etc.
$lease = id(new DrydockLease())->load( $lease = id(new DrydockLease())->load(
$data['drydock-lease']); $data['drydock-lease']);
if ($lease === null) { if ($lease === null) {