Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/drydock/management/DrydockManagementReleaseLeaseWorkflow.php b/src/applications/drydock/management/DrydockManagementReleaseLeaseWorkflow.php
index 20af18ec21..0628f57b38 100644
--- a/src/applications/drydock/management/DrydockManagementReleaseLeaseWorkflow.php
+++ b/src/applications/drydock/management/DrydockManagementReleaseLeaseWorkflow.php
@@ -1,70 +1,118 @@
<?php
final class DrydockManagementReleaseLeaseWorkflow
extends DrydockManagementWorkflow {
protected function didConstruct() {
$this
->setName('release-lease')
->setSynopsis(pht('Release a lease.'))
->setArguments(
array(
array(
'name' => 'id',
'param' => 'id',
'repeat' => true,
'help' => pht('Lease ID to release.'),
),
+ array(
+ 'name' => 'all',
+ 'help' => pht('Release all leases. Dangerous!'),
+ ),
));
}
public function execute(PhutilArgumentParser $args) {
+ $is_all = $args->getArg('all');
$ids = $args->getArg('id');
- if (!$ids) {
+
+ if (!$ids && !$is_all) {
throw new PhutilArgumentUsageException(
pht(
- 'Specify one or more lease IDs to release with "%s".',
- '--id'));
+ 'Select which leases you want to release. See "--help" for '.
+ 'guidance.'));
}
$viewer = $this->getViewer();
- $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID();
- $leases = id(new DrydockLeaseQuery())
+ $statuses = $this->getReleaseableLeaseStatuses();
+
+ $query = id(new DrydockLeaseQuery())
->setViewer($viewer)
- ->withIDs($ids)
- ->execute();
+ ->withStatuses(mpull($statuses, 'getKey'));
- PhabricatorWorker::setRunAllTasksInProcess(true);
- foreach ($ids as $id) {
- $lease = idx($leases, $id);
- if (!$lease) {
- echo tsprintf(
- "%s\n",
- pht('Lease "%s" does not exist.', $id));
- continue;
+ if ($ids) {
+ $query->withIDs($ids);
+ }
+
+ $leases = $query->execute();
+
+ if ($ids) {
+ $id_map = mpull($leases, null, 'getID');
+
+ foreach ($ids as $id) {
+ $lease = idx($id_map, $id);
+ if (!$lease) {
+ throw new PhutilArgumentUsageException(
+ pht('Lease "%s" does not exist.', $id));
+ }
}
+ $leases = array_select_keys($id_map, $ids);
+ }
+
+ if (!$leases) {
+ echo tsprintf(
+ "%s\n",
+ pht('No leases selected for release.'));
+
+ return 0;
+ }
+
+ $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID();
+
+ PhabricatorWorker::setRunAllTasksInProcess(true);
+
+ foreach ($leases as $lease) {
if (!$lease->canRelease()) {
echo tsprintf(
"%s\n",
- pht('Lease "%s" is not releasable.', $id));
+ pht(
+ 'Lease "%s" is not releasable.',
+ $lease->getDisplayName()));
continue;
}
$command = DrydockCommand::initializeNewCommand($viewer)
->setTargetPHID($lease->getPHID())
->setAuthorPHID($drydock_phid)
->setCommand(DrydockCommand::COMMAND_RELEASE)
->save();
$lease->scheduleUpdate();
echo tsprintf(
"%s\n",
- pht('Scheduled release of lease "%s".', $id));
+ pht(
+ 'Scheduled release of lease "%s".',
+ $lease->getDisplayName()));
+ }
+
+ }
+
+ private function getReleaseableLeaseStatuses() {
+ $statuses = DrydockLeaseStatus::getAllStatuses();
+ foreach ($statuses as $key => $status) {
+ $statuses[$key] = DrydockLeaseStatus::newStatusObject($status);
+ }
+
+ foreach ($statuses as $key => $status) {
+ if (!$status->canRelease()) {
+ unset($statuses[$key]);
+ }
}
+ return $statuses;
}
}
diff --git a/src/applications/drydock/management/DrydockManagementReleaseResourceWorkflow.php b/src/applications/drydock/management/DrydockManagementReleaseResourceWorkflow.php
index 01060a5325..afd826cbc0 100644
--- a/src/applications/drydock/management/DrydockManagementReleaseResourceWorkflow.php
+++ b/src/applications/drydock/management/DrydockManagementReleaseResourceWorkflow.php
@@ -1,71 +1,117 @@
<?php
final class DrydockManagementReleaseResourceWorkflow
extends DrydockManagementWorkflow {
protected function didConstruct() {
$this
->setName('release-resource')
->setSynopsis(pht('Release a resource.'))
->setArguments(
array(
array(
'name' => 'id',
'param' => 'id',
'repeat' => true,
'help' => pht('Resource ID to release.'),
),
+ array(
+ 'name' => 'all',
+ 'help' => pht('Release all resources. Dangerous!'),
+ ),
));
}
public function execute(PhutilArgumentParser $args) {
+ $is_all = $args->getArg('all');
$ids = $args->getArg('id');
- if (!$ids) {
+ if (!$ids && !$is_all) {
throw new PhutilArgumentUsageException(
pht(
- 'Specify one or more resource IDs to release with "%s".',
- '--id'));
+ 'Specify which resources you want to release. See "--help" for '.
+ 'guidance.'));
}
$viewer = $this->getViewer();
- $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID();
+ $statuses = $this->getReleaseableResourceStatuses();
- $resources = id(new DrydockResourceQuery())
+ $query = id(new DrydockResourceQuery())
->setViewer($viewer)
- ->withIDs($ids)
- ->execute();
+ ->withStatuses(mpull($statuses, 'getKey'));
- PhabricatorWorker::setRunAllTasksInProcess(true);
- foreach ($ids as $id) {
- $resource = idx($resources, $id);
+ if ($ids) {
+ $query->withIDs($ids);
+ }
- if (!$resource) {
- echo tsprintf(
- "%s\n",
- pht('Resource "%s" does not exist.', $id));
- continue;
+ $resources = $query->execute();
+
+ if ($ids) {
+ $id_map = mpull($resources, null, 'getID');
+
+ foreach ($ids as $id) {
+ $resource = idx($resources, $id);
+
+ if (!$resource) {
+ throw new PhutilArgumentUsageException(
+ pht('Resource "%s" does not exist.', $id));
+ }
}
+ $resources = array_select_keys($id_map, $ids);
+ }
+
+ if (!$resources) {
+ echo tsprintf(
+ "%s\n",
+ pht('No resources selected for release.'));
+
+ return 0;
+ }
+
+ $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID();
+
+ PhabricatorWorker::setRunAllTasksInProcess(true);
+
+ foreach ($resources as $resource) {
if (!$resource->canRelease()) {
echo tsprintf(
"%s\n",
- pht('Resource "%s" is not releasable.', $id));
+ pht(
+ 'Resource "%s" is not releasable.',
+ $resource->getDisplayName()));
continue;
}
$command = DrydockCommand::initializeNewCommand($viewer)
->setTargetPHID($resource->getPHID())
->setAuthorPHID($drydock_phid)
->setCommand(DrydockCommand::COMMAND_RELEASE)
->save();
$resource->scheduleUpdate();
echo tsprintf(
"%s\n",
- pht('Scheduled release of resource "%s".', $id));
+ pht(
+ 'Scheduled release of resource "%s".',
+ $resource->getDisplayName()));
}
+ return 0;
}
+ private function getReleaseableResourceStatuses() {
+ $statuses = DrydockResourceStatus::getAllStatuses();
+ foreach ($statuses as $key => $status) {
+ $statuses[$key] = DrydockResourceStatus::newStatusObject($status);
+ }
+
+ foreach ($statuses as $key => $status) {
+ if (!$status->canRelease()) {
+ unset($statuses[$key]);
+ }
+ }
+
+ return $statuses;
+ }
}
diff --git a/src/applications/drydock/storage/DrydockLease.php b/src/applications/drydock/storage/DrydockLease.php
index 5243aa1498..ba16aaf493 100644
--- a/src/applications/drydock/storage/DrydockLease.php
+++ b/src/applications/drydock/storage/DrydockLease.php
@@ -1,608 +1,612 @@
<?php
final class DrydockLease extends DrydockDAO
implements
PhabricatorPolicyInterface,
PhabricatorConduitResultInterface {
protected $resourcePHID;
protected $resourceType;
protected $until;
protected $ownerPHID;
protected $authorizingPHID;
protected $attributes = array();
protected $status = DrydockLeaseStatus::STATUS_PENDING;
protected $acquiredEpoch;
protected $activatedEpoch;
private $resource = self::ATTACHABLE;
private $unconsumedCommands = self::ATTACHABLE;
private $releaseOnDestruction;
private $isAcquired = false;
private $isActivated = false;
private $activateWhenAcquired = false;
private $slotLocks = array();
public static function initializeNewLease() {
$lease = new DrydockLease();
// Pregenerate a PHID so that the caller can set something up to release
// this lease before queueing it for activation.
$lease->setPHID($lease->generatePHID());
return $lease;
}
/**
* Flag this lease to be released when its destructor is called. This is
* mostly useful if you have a script which acquires, uses, and then releases
* a lease, as you don't need to explicitly handle exceptions to properly
* release the lease.
*/
public function setReleaseOnDestruction($release) {
$this->releaseOnDestruction = $release;
return $this;
}
public function __destruct() {
if (!$this->releaseOnDestruction) {
return;
}
if (!$this->canRelease()) {
return;
}
$actor = PhabricatorUser::getOmnipotentUser();
$drydock_phid = id(new PhabricatorDrydockApplication())->getPHID();
$command = DrydockCommand::initializeNewCommand($actor)
->setTargetPHID($this->getPHID())
->setAuthorPHID($drydock_phid)
->setCommand(DrydockCommand::COMMAND_RELEASE)
->save();
$this->scheduleUpdate();
}
public function setStatus($status) {
if ($status == DrydockLeaseStatus::STATUS_ACQUIRED) {
if (!$this->getAcquiredEpoch()) {
$this->setAcquiredEpoch(PhabricatorTime::getNow());
}
}
if ($status == DrydockLeaseStatus::STATUS_ACTIVE) {
if (!$this->getActivatedEpoch()) {
$this->setActivatedEpoch(PhabricatorTime::getNow());
}
}
return parent::setStatus($status);
}
public function getLeaseName() {
return pht('Lease %d', $this->getID());
}
protected function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_SERIALIZATION => array(
'attributes' => self::SERIALIZATION_JSON,
),
self::CONFIG_COLUMN_SCHEMA => array(
'status' => 'text32',
'until' => 'epoch?',
'resourceType' => 'text128',
'ownerPHID' => 'phid?',
'resourcePHID' => 'phid?',
'acquiredEpoch' => 'epoch?',
'activatedEpoch' => 'epoch?',
),
self::CONFIG_KEY_SCHEMA => array(
'key_resource' => array(
'columns' => array('resourcePHID', 'status'),
),
'key_status' => array(
'columns' => array('status'),
),
'key_owner' => array(
'columns' => array('ownerPHID'),
),
'key_recent' => array(
'columns' => array('resourcePHID', 'dateModified'),
),
),
) + parent::getConfiguration();
}
public function setAttribute($key, $value) {
$this->attributes[$key] = $value;
return $this;
}
public function getAttribute($key, $default = null) {
return idx($this->attributes, $key, $default);
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(DrydockLeasePHIDType::TYPECONST);
}
public function getInterface($type) {
return $this->getResource()->getInterface($this, $type);
}
public function getResource() {
return $this->assertAttached($this->resource);
}
public function attachResource(DrydockResource $resource = null) {
$this->resource = $resource;
return $this;
}
public function hasAttachedResource() {
return ($this->resource !== null);
}
public function getUnconsumedCommands() {
return $this->assertAttached($this->unconsumedCommands);
}
public function attachUnconsumedCommands(array $commands) {
$this->unconsumedCommands = $commands;
return $this;
}
public function isReleasing() {
foreach ($this->getUnconsumedCommands() as $command) {
if ($command->getCommand() == DrydockCommand::COMMAND_RELEASE) {
return true;
}
}
return false;
}
public function queueForActivation() {
if ($this->getID()) {
throw new Exception(
pht('Only new leases may be queued for activation!'));
}
if (!$this->getAuthorizingPHID()) {
throw new Exception(
pht(
'Trying to queue a lease for activation without an authorizing '.
'object. Use "%s" to specify the PHID of the authorizing object. '.
'The authorizing object must be approved to use the allowed '.
'blueprints.',
'setAuthorizingPHID()'));
}
if (!$this->getAllowedBlueprintPHIDs()) {
throw new Exception(
pht(
'Trying to queue a lease for activation without any allowed '.
'Blueprints. Use "%s" to specify allowed blueprints. The '.
'authorizing object must be approved to use the allowed blueprints.',
'setAllowedBlueprintPHIDs()'));
}
$this
->setStatus(DrydockLeaseStatus::STATUS_PENDING)
->save();
$this->scheduleUpdate();
$this->logEvent(DrydockLeaseQueuedLogType::LOGCONST);
return $this;
}
public function setActivateWhenAcquired($activate) {
$this->activateWhenAcquired = true;
return $this;
}
public function needSlotLock($key) {
$this->slotLocks[] = $key;
return $this;
}
public function acquireOnResource(DrydockResource $resource) {
$expect_status = DrydockLeaseStatus::STATUS_PENDING;
$actual_status = $this->getStatus();
if ($actual_status != $expect_status) {
throw new Exception(
pht(
'Trying to acquire a lease on a resource which is in the wrong '.
'state: status must be "%s", actually "%s".',
$expect_status,
$actual_status));
}
if ($this->activateWhenAcquired) {
$new_status = DrydockLeaseStatus::STATUS_ACTIVE;
} else {
$new_status = DrydockLeaseStatus::STATUS_ACQUIRED;
}
if ($new_status == DrydockLeaseStatus::STATUS_ACTIVE) {
if ($resource->getStatus() == DrydockResourceStatus::STATUS_PENDING) {
throw new Exception(
pht(
'Trying to acquire an active lease on a pending resource. '.
'You can not immediately activate leases on resources which '.
'need time to start up.'));
}
}
// Before we associate the lease with the resource, we lock the resource
// and reload it to make sure it is still pending or active. If we don't
// do this, the resource may have just been reclaimed. (Once we acquire
// the resource that stops it from being released, so we're nearly safe.)
$resource_phid = $resource->getPHID();
$hash = PhabricatorHash::digestForIndex($resource_phid);
$lock_key = 'drydock.resource:'.$hash;
$lock = PhabricatorGlobalLock::newLock($lock_key);
try {
$lock->lock(15);
} catch (Exception $ex) {
throw new DrydockResourceLockException(
pht(
'Failed to acquire lock for resource ("%s") while trying to '.
'acquire lease ("%s").',
$resource->getPHID(),
$this->getPHID()));
}
$resource->reload();
if (($resource->getStatus() !== DrydockResourceStatus::STATUS_ACTIVE) &&
($resource->getStatus() !== DrydockResourceStatus::STATUS_PENDING)) {
throw new DrydockAcquiredBrokenResourceException(
pht(
'Trying to acquire lease ("%s") on a resource ("%s") in the '.
'wrong status ("%s").',
$this->getPHID(),
$resource->getPHID(),
$resource->getStatus()));
}
$caught = null;
try {
$this->openTransaction();
try {
DrydockSlotLock::acquireLocks($this->getPHID(), $this->slotLocks);
$this->slotLocks = array();
} catch (DrydockSlotLockException $ex) {
$this->killTransaction();
$this->logEvent(
DrydockSlotLockFailureLogType::LOGCONST,
array(
'locks' => $ex->getLockMap(),
));
throw $ex;
}
$this
->setResourcePHID($resource->getPHID())
->attachResource($resource)
->setStatus($new_status)
->save();
$this->saveTransaction();
} catch (Exception $ex) {
$caught = $ex;
}
$lock->unlock();
if ($caught) {
throw $caught;
}
$this->isAcquired = true;
$this->logEvent(DrydockLeaseAcquiredLogType::LOGCONST);
if ($new_status == DrydockLeaseStatus::STATUS_ACTIVE) {
$this->didActivate();
}
return $this;
}
public function isAcquiredLease() {
return $this->isAcquired;
}
public function activateOnResource(DrydockResource $resource) {
$expect_status = DrydockLeaseStatus::STATUS_ACQUIRED;
$actual_status = $this->getStatus();
if ($actual_status != $expect_status) {
throw new Exception(
pht(
'Trying to activate a lease which has the wrong status: status '.
'must be "%s", actually "%s".',
$expect_status,
$actual_status));
}
if ($resource->getStatus() == DrydockResourceStatus::STATUS_PENDING) {
// TODO: Be stricter about this?
throw new Exception(
pht(
'Trying to activate a lease on a pending resource.'));
}
$this->openTransaction();
try {
DrydockSlotLock::acquireLocks($this->getPHID(), $this->slotLocks);
$this->slotLocks = array();
} catch (DrydockSlotLockException $ex) {
$this->killTransaction();
$this->logEvent(
DrydockSlotLockFailureLogType::LOGCONST,
array(
'locks' => $ex->getLockMap(),
));
throw $ex;
}
$this
->setStatus(DrydockLeaseStatus::STATUS_ACTIVE)
->save();
$this->saveTransaction();
$this->isActivated = true;
$this->didActivate();
return $this;
}
public function isActivatedLease() {
return $this->isActivated;
}
public function scheduleUpdate($epoch = null) {
PhabricatorWorker::scheduleTask(
'DrydockLeaseUpdateWorker',
array(
'leasePHID' => $this->getPHID(),
'isExpireTask' => ($epoch !== null),
),
array(
'objectPHID' => $this->getPHID(),
'delayUntil' => ($epoch ? (int)$epoch : null),
));
}
public function setAwakenTaskIDs(array $ids) {
$this->setAttribute('internal.awakenTaskIDs', $ids);
return $this;
}
public function setAllowedBlueprintPHIDs(array $phids) {
$this->setAttribute('internal.blueprintPHIDs', $phids);
return $this;
}
public function getAllowedBlueprintPHIDs() {
return $this->getAttribute('internal.blueprintPHIDs', array());
}
private function didActivate() {
$viewer = PhabricatorUser::getOmnipotentUser();
$need_update = false;
$this->logEvent(DrydockLeaseActivatedLogType::LOGCONST);
$commands = id(new DrydockCommandQuery())
->setViewer($viewer)
->withTargetPHIDs(array($this->getPHID()))
->withConsumed(false)
->execute();
if ($commands) {
$need_update = true;
}
if ($need_update) {
$this->scheduleUpdate();
}
$expires = $this->getUntil();
if ($expires) {
$this->scheduleUpdate($expires);
}
$this->awakenTasks();
}
public function logEvent($type, array $data = array()) {
$log = id(new DrydockLog())
->setEpoch(PhabricatorTime::getNow())
->setType($type)
->setData($data);
$log->setLeasePHID($this->getPHID());
$resource_phid = $this->getResourcePHID();
if ($resource_phid) {
$resource = $this->getResource();
$log->setResourcePHID($resource->getPHID());
$log->setBlueprintPHID($resource->getBlueprintPHID());
}
return $log->save();
}
/**
* Awaken yielded tasks after a state change.
*
* @return this
*/
public function awakenTasks() {
$awaken_ids = $this->getAttribute('internal.awakenTaskIDs');
if (is_array($awaken_ids) && $awaken_ids) {
PhabricatorWorker::awakenTaskIDs($awaken_ids);
}
return $this;
}
public function getURI() {
$id = $this->getID();
return "/drydock/lease/{$id}/";
}
+ public function getDisplayName() {
+ return pht('Drydock Lease %d', $this->getID());
+ }
+
/* -( Status )------------------------------------------------------------- */
public function getStatusObject() {
return DrydockLeaseStatus::newStatusObject($this->getStatus());
}
public function getStatusIcon() {
return $this->getStatusObject()->getIcon();
}
public function getStatusColor() {
return $this->getStatusObject()->getColor();
}
public function getStatusDisplayName() {
return $this->getStatusObject()->getDisplayName();
}
public function isActivating() {
return $this->getStatusObject()->isActivating();
}
public function isActive() {
return $this->getStatusObject()->isActive();
}
public function canRelease() {
if (!$this->getID()) {
return false;
}
return $this->getStatusObject()->canRelease();
}
public function canReceiveCommands() {
return $this->getStatusObject()->canReceiveCommands();
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
public function getPolicy($capability) {
if ($this->getResource()) {
return $this->getResource()->getPolicy($capability);
}
// TODO: Implement reasonable policies.
return PhabricatorPolicies::getMostOpenPolicy();
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
if ($this->getResource()) {
return $this->getResource()->hasAutomaticCapability($capability, $viewer);
}
return false;
}
public function describeAutomaticCapability($capability) {
return pht('Leases inherit policies from the resources they lease.');
}
/* -( PhabricatorConduitResultInterface )---------------------------------- */
public function getFieldSpecificationsForConduit() {
return array(
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('resourcePHID')
->setType('phid?')
->setDescription(pht('PHID of the leased resource, if any.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('resourceType')
->setType('string')
->setDescription(pht('Type of resource being leased.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('until')
->setType('int?')
->setDescription(pht('Epoch at which this lease expires, if any.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('ownerPHID')
->setType('phid?')
->setDescription(pht('The PHID of the object that owns this lease.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('authorizingPHID')
->setType('phid')
->setDescription(pht(
'The PHID of the object that authorized this lease.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('status')
->setType('map<string, wild>')
->setDescription(pht(
"The string constant and name of this lease's status.")),
);
}
public function getFieldValuesForConduit() {
$status = $this->getStatus();
$until = $this->getUntil();
if ($until) {
$until = (int)$until;
} else {
$until = null;
}
return array(
'resourcePHID' => $this->getResourcePHID(),
'resourceType' => $this->getResourceType(),
'until' => $until,
'ownerPHID' => $this->getOwnerPHID(),
'authorizingPHID' => $this->getAuthorizingPHID(),
'status' => array(
'value' => $status,
'name' => DrydockLeaseStatus::getNameForStatus($status),
),
);
}
public function getConduitSearchAttachments() {
return array();
}
}
diff --git a/src/applications/drydock/storage/DrydockResource.php b/src/applications/drydock/storage/DrydockResource.php
index bc672dba3c..38e6660f7e 100644
--- a/src/applications/drydock/storage/DrydockResource.php
+++ b/src/applications/drydock/storage/DrydockResource.php
@@ -1,379 +1,383 @@
<?php
final class DrydockResource extends DrydockDAO
implements
PhabricatorPolicyInterface,
PhabricatorConduitResultInterface {
protected $id;
protected $phid;
protected $blueprintPHID;
protected $status;
protected $until;
protected $type;
protected $attributes = array();
protected $capabilities = array();
protected $ownerPHID;
private $blueprint = self::ATTACHABLE;
private $unconsumedCommands = self::ATTACHABLE;
private $isAllocated = false;
private $isActivated = false;
private $activateWhenAllocated = false;
private $slotLocks = array();
protected function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_SERIALIZATION => array(
'attributes' => self::SERIALIZATION_JSON,
'capabilities' => self::SERIALIZATION_JSON,
),
self::CONFIG_COLUMN_SCHEMA => array(
'ownerPHID' => 'phid?',
'status' => 'text32',
'type' => 'text64',
'until' => 'epoch?',
),
self::CONFIG_KEY_SCHEMA => array(
'key_type' => array(
'columns' => array('type', 'status'),
),
'key_blueprint' => array(
'columns' => array('blueprintPHID', 'status'),
),
),
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(DrydockResourcePHIDType::TYPECONST);
}
public function getResourceName() {
return $this->getBlueprint()->getResourceName($this);
}
public function getAttribute($key, $default = null) {
return idx($this->attributes, $key, $default);
}
public function getAttributesForTypeSpec(array $attribute_names) {
return array_select_keys($this->attributes, $attribute_names);
}
public function setAttribute($key, $value) {
$this->attributes[$key] = $value;
return $this;
}
public function getCapability($key, $default = null) {
return idx($this->capbilities, $key, $default);
}
public function getInterface(DrydockLease $lease, $type) {
return $this->getBlueprint()->getInterface($this, $lease, $type);
}
public function getBlueprint() {
return $this->assertAttached($this->blueprint);
}
public function attachBlueprint(DrydockBlueprint $blueprint) {
$this->blueprint = $blueprint;
return $this;
}
public function getUnconsumedCommands() {
return $this->assertAttached($this->unconsumedCommands);
}
public function attachUnconsumedCommands(array $commands) {
$this->unconsumedCommands = $commands;
return $this;
}
public function isReleasing() {
foreach ($this->getUnconsumedCommands() as $command) {
if ($command->getCommand() == DrydockCommand::COMMAND_RELEASE) {
return true;
}
}
return false;
}
public function setActivateWhenAllocated($activate) {
$this->activateWhenAllocated = $activate;
return $this;
}
public function needSlotLock($key) {
$this->slotLocks[] = $key;
return $this;
}
public function allocateResource() {
// We expect resources to have a pregenerated PHID, as they should have
// been created by a call to DrydockBlueprint->newResourceTemplate().
if (!$this->getPHID()) {
throw new Exception(
pht(
'Trying to allocate a resource with no generated PHID. Use "%s" to '.
'create new resource templates.',
'newResourceTemplate()'));
}
$expect_status = DrydockResourceStatus::STATUS_PENDING;
$actual_status = $this->getStatus();
if ($actual_status != $expect_status) {
throw new Exception(
pht(
'Trying to allocate a resource from the wrong status. Status must '.
'be "%s", actually "%s".',
$expect_status,
$actual_status));
}
if ($this->activateWhenAllocated) {
$new_status = DrydockResourceStatus::STATUS_ACTIVE;
} else {
$new_status = DrydockResourceStatus::STATUS_PENDING;
}
$this->openTransaction();
try {
DrydockSlotLock::acquireLocks($this->getPHID(), $this->slotLocks);
$this->slotLocks = array();
} catch (DrydockSlotLockException $ex) {
$this->killTransaction();
if ($this->getID()) {
$log_target = $this;
} else {
// If we don't have an ID, we have to log this on the blueprint, as the
// resource is not going to be saved so the PHID will vanish.
$log_target = $this->getBlueprint();
}
$log_target->logEvent(
DrydockSlotLockFailureLogType::LOGCONST,
array(
'locks' => $ex->getLockMap(),
));
throw $ex;
}
$this
->setStatus($new_status)
->save();
$this->saveTransaction();
$this->isAllocated = true;
if ($new_status == DrydockResourceStatus::STATUS_ACTIVE) {
$this->didActivate();
}
return $this;
}
public function isAllocatedResource() {
return $this->isAllocated;
}
public function activateResource() {
if (!$this->getID()) {
throw new Exception(
pht(
'Trying to activate a resource which has not yet been persisted.'));
}
$expect_status = DrydockResourceStatus::STATUS_PENDING;
$actual_status = $this->getStatus();
if ($actual_status != $expect_status) {
throw new Exception(
pht(
'Trying to activate a resource from the wrong status. Status must '.
'be "%s", actually "%s".',
$expect_status,
$actual_status));
}
$this->openTransaction();
try {
DrydockSlotLock::acquireLocks($this->getPHID(), $this->slotLocks);
$this->slotLocks = array();
} catch (DrydockSlotLockException $ex) {
$this->killTransaction();
$this->logEvent(
DrydockSlotLockFailureLogType::LOGCONST,
array(
'locks' => $ex->getLockMap(),
));
throw $ex;
}
$this
->setStatus(DrydockResourceStatus::STATUS_ACTIVE)
->save();
$this->saveTransaction();
$this->isActivated = true;
$this->didActivate();
return $this;
}
public function isActivatedResource() {
return $this->isActivated;
}
public function scheduleUpdate($epoch = null) {
PhabricatorWorker::scheduleTask(
'DrydockResourceUpdateWorker',
array(
'resourcePHID' => $this->getPHID(),
'isExpireTask' => ($epoch !== null),
),
array(
'objectPHID' => $this->getPHID(),
'delayUntil' => ($epoch ? (int)$epoch : null),
));
}
private function didActivate() {
$viewer = PhabricatorUser::getOmnipotentUser();
$need_update = false;
$commands = id(new DrydockCommandQuery())
->setViewer($viewer)
->withTargetPHIDs(array($this->getPHID()))
->withConsumed(false)
->execute();
if ($commands) {
$need_update = true;
}
if ($need_update) {
$this->scheduleUpdate();
}
$expires = $this->getUntil();
if ($expires) {
$this->scheduleUpdate($expires);
}
}
public function logEvent($type, array $data = array()) {
$log = id(new DrydockLog())
->setEpoch(PhabricatorTime::getNow())
->setType($type)
->setData($data);
$log->setResourcePHID($this->getPHID());
$log->setBlueprintPHID($this->getBlueprintPHID());
return $log->save();
}
+ public function getDisplayName() {
+ return pht('Drydock Resource %d', $this->getID());
+ }
+
/* -( Status )------------------------------------------------------------- */
public function getStatusObject() {
return DrydockResourceStatus::newStatusObject($this->getStatus());
}
public function getStatusIcon() {
return $this->getStatusObject()->getIcon();
}
public function getStatusColor() {
return $this->getStatusObject()->getColor();
}
public function getStatusDisplayName() {
return $this->getStatusObject()->getDisplayName();
}
public function canRelease() {
return $this->getStatusObject()->canRelease();
}
public function canReceiveCommands() {
return $this->getStatusObject()->canReceiveCommands();
}
public function isActive() {
return $this->getStatusObject()->isActive();
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
public function getPolicy($capability) {
return $this->getBlueprint()->getPolicy($capability);
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return $this->getBlueprint()->hasAutomaticCapability(
$capability,
$viewer);
}
public function describeAutomaticCapability($capability) {
return pht('Resources inherit the policies of their blueprints.');
}
/* -( PhabricatorConduitResultInterface )---------------------------------- */
public function getFieldSpecificationsForConduit() {
return array(
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('blueprintPHID')
->setType('phid')
->setDescription(pht('The blueprint which generated this resource.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('status')
->setType('map<string, wild>')
->setDescription(pht('Information about resource status.')),
);
}
public function getFieldValuesForConduit() {
$status = $this->getStatus();
return array(
'blueprintPHID' => $this->getBlueprintPHID(),
'status' => array(
'value' => $status,
'name' => DrydockResourceStatus::getNameForStatus($status),
),
);
}
public function getConduitSearchAttachments() {
return array();
}
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Mar 14, 5:37 PM (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
72066
Default Alt Text
(35 KB)

Event Timeline