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:
parent
1650874004
commit
9b0fa5747b
17 changed files with 192 additions and 86 deletions
|
@ -122,6 +122,7 @@ abstract class DrydockBlueprintImplementation {
|
|||
$resource->beginReadLocking();
|
||||
$resource->reload();
|
||||
|
||||
// TODO: Policy stuff.
|
||||
$other_leases = id(new DrydockLease())->loadAllWhere(
|
||||
'status IN (%Ld) AND resourceID = %d',
|
||||
array(
|
||||
|
@ -388,13 +389,13 @@ abstract class DrydockBlueprintImplementation {
|
|||
}
|
||||
|
||||
protected function newResourceTemplate($name) {
|
||||
$resource = new DrydockResource();
|
||||
$resource->setBlueprintPHID($this->getInstance()->getPHID());
|
||||
$resource->setBlueprintClass($this->getBlueprintClass());
|
||||
$resource->setType($this->getType());
|
||||
$resource->setStatus(DrydockResourceStatus::STATUS_PENDING);
|
||||
$resource->setName($name);
|
||||
$resource->save();
|
||||
$resource = id(new DrydockResource())
|
||||
->setBlueprintPHID($this->getInstance()->getPHID())
|
||||
->setBlueprintClass($this->getBlueprintClass())
|
||||
->setType($this->getType())
|
||||
->setStatus(DrydockResourceStatus::STATUS_PENDING)
|
||||
->setName($name)
|
||||
->save();
|
||||
|
||||
$this->activeResource = $resource;
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ final class DrydockWorkingCopyBlueprintImplementation
|
|||
throw new Exception("Unsupported VCS!");
|
||||
}
|
||||
|
||||
// TODO: Policy stuff here too.
|
||||
$host_lease = id(new DrydockLease())
|
||||
->setResourceType('host')
|
||||
->waitUntilActive();
|
||||
|
|
|
@ -16,12 +16,12 @@ final class DrydockBlueprintCreateController
|
|||
return $this->createDialog($implementations);
|
||||
}
|
||||
|
||||
$blueprint = new DrydockBlueprint();
|
||||
$blueprint->setClassName($class);
|
||||
$blueprint->setDetails(array());
|
||||
$blueprint->setViewPolicy(PhabricatorPolicies::POLICY_ADMIN);
|
||||
$blueprint->setEditPolicy(PhabricatorPolicies::POLICY_ADMIN);
|
||||
$blueprint->save();
|
||||
$blueprint = id(new DrydockBlueprint())
|
||||
->setClassName($class)
|
||||
->setDetails(array())
|
||||
->setViewPolicy(PhabricatorPolicies::POLICY_ADMIN)
|
||||
->setEditPolicy(PhabricatorPolicies::POLICY_ADMIN)
|
||||
->save();
|
||||
|
||||
$edit_uri = $this->getApplicationURI(
|
||||
"blueprint/edit/".$blueprint->getID()."/");
|
||||
|
|
|
@ -10,9 +10,12 @@ final class DrydockBlueprintViewController extends DrydockBlueprintController {
|
|||
|
||||
public function processRequest() {
|
||||
$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) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
@ -30,7 +33,7 @@ final class DrydockBlueprintViewController extends DrydockBlueprintController {
|
|||
|
||||
$resources = id(new DrydockResourceQuery())
|
||||
->withBlueprintPHIDs(array($blueprint->getPHID()))
|
||||
->setViewer($user)
|
||||
->setViewer($viewer)
|
||||
->execute();
|
||||
|
||||
$resource_list = $this->buildResourceListView($resources);
|
||||
|
|
|
@ -10,9 +10,12 @@ final class DrydockLeaseViewController extends DrydockLeaseController {
|
|||
|
||||
public function processRequest() {
|
||||
$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) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
@ -32,7 +35,7 @@ final class DrydockLeaseViewController extends DrydockLeaseController {
|
|||
$pager->setOffset($request->getInt('offset'));
|
||||
|
||||
$logs = id(new DrydockLogQuery())
|
||||
->setViewer($user)
|
||||
->setViewer($viewer)
|
||||
->withLeaseIDs(array($lease->getID()))
|
||||
->executeWithOffsetPager($pager);
|
||||
|
||||
|
|
|
@ -10,9 +10,12 @@ final class DrydockResourceCloseController extends DrydockResourceController {
|
|||
|
||||
public function processRequest() {
|
||||
$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) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
@ -22,7 +25,7 @@ final class DrydockResourceCloseController extends DrydockResourceController {
|
|||
|
||||
if ($resource->getStatus() != DrydockResourceStatus::STATUS_OPEN) {
|
||||
$dialog = id(new AphrontDialogView())
|
||||
->setUser($user)
|
||||
->setUser($viewer)
|
||||
->setTitle(pht('Resource Not Open'))
|
||||
->appendChild(phutil_tag('p', array(), pht(
|
||||
'You can only close "open" resources.')))
|
||||
|
@ -31,22 +34,22 @@ final class DrydockResourceCloseController extends DrydockResourceController {
|
|||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
}
|
||||
|
||||
if (!$request->isDialogFormPost()) {
|
||||
$dialog = id(new AphrontDialogView())
|
||||
->setUser($user)
|
||||
->setTitle(pht('Really close resource?'))
|
||||
->appendChild(phutil_tag('p', array(), pht(
|
||||
'Closing a resource releases all leases and destroys the '.
|
||||
'resource. It can not be undone. Continue?')))
|
||||
->addSubmitButton(pht('Close Resource'))
|
||||
->addCancelButton($resource_uri);
|
||||
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
if ($request->isFormPost()) {
|
||||
$resource->closeResource();
|
||||
return id(new AphrontReloadResponse())->setURI($resource_uri);
|
||||
}
|
||||
|
||||
$resource->closeResource();
|
||||
$dialog = id(new AphrontDialogView())
|
||||
->setUser($viewer)
|
||||
->setTitle(pht('Really close resource?'))
|
||||
->appendChild(
|
||||
pht(
|
||||
'Closing a resource releases all leases and destroys the '.
|
||||
'resource. It can not be undone. Continue?'))
|
||||
->addSubmitButton(pht('Close Resource'))
|
||||
->addCancelButton($resource_uri);
|
||||
|
||||
return id(new AphrontReloadResponse())->setURI($resource_uri);
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,9 +10,12 @@ final class DrydockResourceViewController extends DrydockResourceController {
|
|||
|
||||
public function processRequest() {
|
||||
$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) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
@ -29,7 +32,7 @@ final class DrydockResourceViewController extends DrydockResourceController {
|
|||
$resource_uri = $this->getApplicationURI($resource_uri);
|
||||
|
||||
$leases = id(new DrydockLeaseQuery())
|
||||
->setViewer($user)
|
||||
->setViewer($viewer)
|
||||
->withResourceIDs(array($resource->getID()))
|
||||
->execute();
|
||||
|
||||
|
@ -41,7 +44,7 @@ final class DrydockResourceViewController extends DrydockResourceController {
|
|||
$pager->setOffset($request->getInt('offset'));
|
||||
|
||||
$logs = id(new DrydockLogQuery())
|
||||
->setViewer($user)
|
||||
->setViewer($viewer)
|
||||
->withResourceIDs(array($resource->getID()))
|
||||
->executeWithOffsetPager($pager);
|
||||
|
||||
|
|
|
@ -25,8 +25,15 @@ final class DrydockManagementCloseWorkflow
|
|||
"Specify one or more resource IDs to close.");
|
||||
}
|
||||
|
||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||
|
||||
$resources = id(new DrydockResourceQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs($ids)
|
||||
->execute();
|
||||
|
||||
foreach ($ids as $id) {
|
||||
$resource = id(new DrydockResource())->load($id);
|
||||
$resource = idx($resources, $id);
|
||||
if (!$resource) {
|
||||
$console->writeErr("Resource %d does not exist!\n", $id);
|
||||
} else if ($resource->getStatus() != DrydockResourceStatus::STATUS_OPEN) {
|
||||
|
|
|
@ -49,17 +49,22 @@ final class DrydockManagementCreateResourceWorkflow
|
|||
$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) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
"Specified blueprint does not exist.");
|
||||
}
|
||||
|
||||
$resource = new DrydockResource();
|
||||
$resource->setBlueprintPHID($blueprint->getPHID());
|
||||
$resource->setType($blueprint->getImplementation()->getType());
|
||||
$resource->setName($resource_name);
|
||||
$resource->setStatus(DrydockResourceStatus::STATUS_OPEN);
|
||||
$resource = id(new DrydockResource())
|
||||
->setBlueprintPHID($blueprint->getPHID())
|
||||
->setType($blueprint->getImplementation()->getType())
|
||||
->setName($resource_name)
|
||||
->setStatus(DrydockResourceStatus::STATUS_OPEN);
|
||||
if ($attributes) {
|
||||
$resource->setAttributes($attributes);
|
||||
}
|
||||
|
|
|
@ -44,17 +44,25 @@ final class DrydockLeaseQuery
|
|||
}
|
||||
|
||||
public function willFilterPage(array $leases) {
|
||||
$resources = id(new DrydockResourceQuery())
|
||||
->setParentQuery($this)
|
||||
->setViewer($this->getViewer())
|
||||
->withIDs(mpull($leases, 'getResourceID'))
|
||||
->execute();
|
||||
$resource_ids = array_filter(mpull($leases, 'getResourceID'));
|
||||
if ($resource_ids) {
|
||||
$resources = id(new DrydockResourceQuery())
|
||||
->setParentQuery($this)
|
||||
->setViewer($this->getViewer())
|
||||
->withIDs($resource_ids)
|
||||
->execute();
|
||||
} else {
|
||||
$resources = array();
|
||||
}
|
||||
|
||||
foreach ($leases as $key => $lease) {
|
||||
$resource = idx($resources, $lease->getResourceID());
|
||||
if (!$resource) {
|
||||
unset($leases[$key]);
|
||||
continue;
|
||||
$resource = null;
|
||||
if ($lease->getResourceID()) {
|
||||
$resource = idx($resources, $lease->getResourceID());
|
||||
if (!$resource) {
|
||||
unset($leases[$key]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$lease->attachResource($resource);
|
||||
}
|
||||
|
|
|
@ -31,18 +31,60 @@ final class DrydockLogQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
}
|
||||
|
||||
public function willFilterPage(array $logs) {
|
||||
$resource_ids = mpull($logs, 'getResourceID');
|
||||
$resources = id(new DrydockResourceQuery())
|
||||
->setParentQuery($this)
|
||||
->setViewer($this->getViewer())
|
||||
->withIDs($resource_ids)
|
||||
->execute();
|
||||
$resource_ids = array_filter(mpull($logs, 'getResourceID'));
|
||||
if ($resource_ids) {
|
||||
$resources = id(new DrydockResourceQuery())
|
||||
->setParentQuery($this)
|
||||
->setViewer($this->getViewer())
|
||||
->withIDs($resource_ids)
|
||||
->execute();
|
||||
} else {
|
||||
$resources = array();
|
||||
}
|
||||
|
||||
foreach ($logs as $key => $log) {
|
||||
$resource = idx($resources, $log->getResourceID());
|
||||
$resource = null;
|
||||
if ($log->getResourceID()) {
|
||||
$resource = idx($resources, $log->getResourceID());
|
||||
if (!$resource) {
|
||||
unset($logs[$key]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$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;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ final class DrydockLease extends DrydockDAO
|
|||
return $this->assertAttached($this->resource);
|
||||
}
|
||||
|
||||
public function attachResource(DrydockResource $resource) {
|
||||
public function attachResource(DrydockResource $resource = null) {
|
||||
$this->resource = $resource;
|
||||
return $this;
|
||||
}
|
||||
|
@ -194,11 +194,17 @@ final class DrydockLease extends DrydockDAO
|
|||
}
|
||||
|
||||
public function getPolicy($capability) {
|
||||
return $this->getResource()->getPolicy($capability);
|
||||
if ($this->getResource()) {
|
||||
return $this->getResource()->getPolicy($capability);
|
||||
}
|
||||
return PhabricatorPolicies::getMostOpenPolicy();
|
||||
}
|
||||
|
||||
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||
return $this->getResource()->hasAutomaticCapability($capability, $viewer);
|
||||
if ($this->getResource()) {
|
||||
return $this->getResource()->hasAutomaticCapability($capability, $viewer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function describeAutomaticCapability($capability) {
|
||||
|
|
|
@ -9,6 +9,7 @@ final class DrydockLog extends DrydockDAO
|
|||
protected $message;
|
||||
|
||||
private $resource = self::ATTACHABLE;
|
||||
private $lease = self::ATTACHABLE;
|
||||
|
||||
public function getConfiguration() {
|
||||
return array(
|
||||
|
@ -25,6 +26,15 @@ final class DrydockLog extends DrydockDAO
|
|||
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 )----------------------------------------- */
|
||||
|
||||
|
@ -36,17 +46,17 @@ final class DrydockLog extends DrydockDAO
|
|||
}
|
||||
|
||||
public function getPolicy($capability) {
|
||||
if (!$this->getResource()) {
|
||||
return PhabricatorPolicies::getMostOpenPolicy();
|
||||
if ($this->getResource()) {
|
||||
return $this->getResource()->getPolicy($capability);
|
||||
}
|
||||
return $this->getResource()->getPolicy($capability);
|
||||
return $this->getLease()->getPolicy($capability);
|
||||
}
|
||||
|
||||
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||
if (!$this->getResource()) {
|
||||
return false;
|
||||
if ($this->getResource()) {
|
||||
return $this->getResource()->hasAutomaticCapability($capability, $viewer);
|
||||
}
|
||||
return $this->getResource()->hasAutomaticCapability($capability, $viewer);
|
||||
return $this->getLease()->hasAutomaticCapability($capability, $viewer);
|
||||
}
|
||||
|
||||
public function describeAutomaticCapability($capability) {
|
||||
|
|
|
@ -52,6 +52,7 @@ final class DrydockResource extends DrydockDAO
|
|||
}
|
||||
|
||||
public function getBlueprint() {
|
||||
// TODO: Policy stuff.
|
||||
if (empty($this->blueprint)) {
|
||||
$blueprint = id(new DrydockBlueprint())
|
||||
->loadOneWhere('phid = %s', $this->blueprintPHID);
|
||||
|
@ -62,13 +63,16 @@ final class DrydockResource extends DrydockDAO
|
|||
|
||||
public function closeResource() {
|
||||
$this->openTransaction();
|
||||
$leases = id(new DrydockLease())->loadAllWhere(
|
||||
'resourceID = %d AND status IN (%Ld)',
|
||||
$this->getID(),
|
||||
array(
|
||||
DrydockLeaseStatus::STATUS_PENDING,
|
||||
DrydockLeaseStatus::STATUS_ACTIVE,
|
||||
));
|
||||
$statuses = array(
|
||||
DrydockLeaseStatus::STATUS_PENDING,
|
||||
DrydockLeaseStatus::STATUS_ACTIVE,
|
||||
);
|
||||
|
||||
$leases = id(new DrydockLeaseQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withResourceIDs(array($this->getID()))
|
||||
->withStatuses($statuses)
|
||||
->execute();
|
||||
|
||||
foreach ($leases as $lease) {
|
||||
switch ($lease->getStatus()) {
|
||||
|
|
|
@ -13,10 +13,13 @@ final class DrydockAllocatorWorker extends PhabricatorWorker {
|
|||
|
||||
private function loadLease() {
|
||||
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) {
|
||||
throw new PhabricatorWorkerPermanentFailureException(
|
||||
"No such lease!");
|
||||
pht("No such lease %d!", $this->getTaskData()));
|
||||
}
|
||||
$this->lease = $lease;
|
||||
}
|
||||
|
@ -53,7 +56,10 @@ final class DrydockAllocatorWorker extends PhabricatorWorker {
|
|||
}
|
||||
|
||||
private function loadAllBlueprints() {
|
||||
$instances = id(new DrydockBlueprint())->loadAll();
|
||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||
$instances = id(new DrydockBlueprintQuery())
|
||||
->setViewer($viewer)
|
||||
->execute();
|
||||
$blueprints = array();
|
||||
foreach ($instances as $instance) {
|
||||
$blueprints[$instance->getPHID()] = $instance;
|
||||
|
@ -66,6 +72,7 @@ final class DrydockAllocatorWorker extends PhabricatorWorker {
|
|||
|
||||
$blueprints = $this->loadAllBlueprints();
|
||||
|
||||
// TODO: Policy stuff.
|
||||
$pool = id(new DrydockResource())->loadAllWhere(
|
||||
'type = %s AND status = %s',
|
||||
$lease->getResourceType(),
|
||||
|
|
|
@ -28,11 +28,13 @@ final class LeaseHostBuildStepImplementation
|
|||
$settings = $this->getSettings();
|
||||
|
||||
// Create the lease.
|
||||
$lease = new DrydockLease();
|
||||
$lease->setResourceType('host');
|
||||
$lease->setAttributes(
|
||||
array('platform' => $settings['platform']));
|
||||
$lease->queueForActivation();
|
||||
$lease = id(new DrydockLease())
|
||||
->setResourceType('host')
|
||||
->setAttributes(
|
||||
array(
|
||||
'platform' => $settings['platform'],
|
||||
))
|
||||
->queueForActivation();
|
||||
|
||||
// Wait until the lease is fulfilled.
|
||||
// TODO: This will throw an exception if the lease can't be fulfilled;
|
||||
|
|
|
@ -82,6 +82,7 @@ final class HarbormasterBuildArtifact extends HarbormasterDAO
|
|||
$data = $this->getArtifactData();
|
||||
|
||||
// FIXME: Is there a better way of doing this?
|
||||
// TODO: Policy stuff, etc.
|
||||
$lease = id(new DrydockLease())->load(
|
||||
$data['drydock-lease']);
|
||||
if ($lease === null) {
|
||||
|
|
Loading…
Reference in a new issue