private function updateLease(DrydockLease $lease)
 {
     if ($lease->getStatus() != DrydockLeaseStatus::STATUS_ACTIVE) {
         return;
     }
     $viewer = $this->getViewer();
     $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID();
     // Check if the lease has expired. If it is, we're going to send it a
     // release command. This command will be handled immediately below, it
     // just generates a command log and improves consistency.
     $now = PhabricatorTime::getNow();
     $expires = $lease->getUntil();
     if ($expires && $expires <= $now) {
         $command = DrydockCommand::initializeNewCommand($viewer)->setTargetPHID($lease->getPHID())->setAuthorPHID($drydock_phid)->setCommand(DrydockCommand::COMMAND_RELEASE)->save();
     }
     $commands = $this->loadCommands($lease->getPHID());
     foreach ($commands as $command) {
         if ($lease->getStatus() != DrydockLeaseStatus::STATUS_ACTIVE) {
             // Leases can't receive commands before they activate or after they
             // release.
             break;
         }
         $this->processCommand($lease, $command);
         $command->setIsConsumed(true)->save();
     }
     // If this is the task which will eventually release the lease after it
     // expires but it is still active, reschedule the task to run after the
     // lease expires. This can happen if the lease's expiration was pushed
     // forward.
     if ($lease->getStatus() == DrydockLeaseStatus::STATUS_ACTIVE) {
         if ($this->getTaskDataValue('isExpireTask') && $expires) {
             throw new PhabricatorWorkerYieldException($expires - $now);
         }
     }
 }
 private function activateLease(DrydockLease $lease)
 {
     $actual_status = $lease->getStatus();
     if ($actual_status != DrydockLeaseStatus::STATUS_ACQUIRED) {
         throw new PhabricatorWorkerPermanentFailureException(pht('Trying to activate lease from wrong status ("%s").', $actual_status));
     }
     $resource = $lease->getResource();
     if (!$resource) {
         throw new PhabricatorWorkerPermanentFailureException(pht('Trying to activate lease with no resource.'));
     }
     $resource_status = $resource->getStatus();
     if ($resource_status == DrydockResourceStatus::STATUS_PENDING) {
         // TODO: This is explicitly a temporary failure -- we are waiting for
         // the resource to come up.
         throw new Exception(pht('Resource still activating.'));
     }
     if ($resource_status != DrydockResourceStatus::STATUS_ACTIVE) {
         throw new PhabricatorWorkerPermanentFailureException(pht('Trying to activate lease on a dead resource (in status "%s").', $resource_status));
     }
     // NOTE: We can race resource destruction here. Between the time we
     // performed the read above and now, the resource might have closed, so
     // we may activate leases on dead resources. At least for now, this seems
     // fine: a resource dying right before we activate a lease on it should not
     // be distinguisahble from a resource dying right after we activate a lease
     // on it. We end up with an active lease on a dead resource either way, and
     // can not prevent resources dying from lightning strikes.
     $blueprint = $resource->getBlueprint();
     $blueprint->activateLease($resource, $lease);
     $this->validateActivatedLease($blueprint, $resource, $lease);
 }
 private function buildPropertyListView(DrydockLease $lease, PhabricatorActionListView $actions)
 {
     $viewer = $this->getViewer();
     $view = new PHUIPropertyListView();
     $view->setActionList($actions);
     $view->addProperty(pht('Status'), DrydockLeaseStatus::getNameForStatus($lease->getStatus()));
     $view->addProperty(pht('Resource Type'), $lease->getResourceType());
     $resource_phid = $lease->getResourcePHID();
     if ($resource_phid) {
         $resource_display = $viewer->renderHandle($resource_phid);
     } else {
         $resource_display = phutil_tag('em', array(), pht('No Resource'));
     }
     $view->addProperty(pht('Resource'), $resource_display);
     $until = $lease->getUntil();
     if ($until) {
         $until_display = phabricator_datetime($until, $viewer);
     } else {
         $until_display = phutil_tag('em', array(), pht('Never'));
     }
     $view->addProperty(pht('Expires'), $until_display);
     $attributes = $lease->getAttributes();
     if ($attributes) {
         $view->addSectionHeader(pht('Attributes'), 'fa-list-ul');
         foreach ($attributes as $key => $value) {
             $view->addProperty($key, $value);
         }
     }
     return $view;
 }
 private function destroyLease(DrydockLease $lease)
 {
     $status = $lease->getStatus();
     switch ($status) {
         case DrydockLeaseStatus::STATUS_RELEASED:
         case DrydockLeaseStatus::STATUS_BROKEN:
             break;
         default:
             throw new PhabricatorWorkerPermanentFailureException(pht('Unable to destroy lease ("%s"), lease has the wrong ' . 'status ("%s").', $lease->getPHID(), $status));
     }
     $resource = $lease->getResource();
     $blueprint = $resource->getBlueprint();
     $blueprint->destroyLease($resource, $lease);
     $lease->setStatus(DrydockLeaseStatus::STATUS_DESTROYED)->save();
 }
 private function buildPropertyListView(DrydockLease $lease, PhabricatorActionListView $actions)
 {
     $view = new PHUIPropertyListView();
     $view->setActionList($actions);
     switch ($lease->getStatus()) {
         case DrydockLeaseStatus::STATUS_ACTIVE:
             $status = pht('Active');
             break;
         case DrydockLeaseStatus::STATUS_RELEASED:
             $status = pht('Released');
             break;
         case DrydockLeaseStatus::STATUS_EXPIRED:
             $status = pht('Expired');
             break;
         case DrydockLeaseStatus::STATUS_PENDING:
             $status = pht('Pending');
             break;
         case DrydockLeaseStatus::STATUS_BROKEN:
             $status = pht('Broken');
             break;
         default:
             $status = pht('Unknown');
             break;
     }
     $view->addProperty(pht('Status'), $status);
     $view->addProperty(pht('Resource Type'), $lease->getResourceType());
     $view->addProperty(pht('Resource'), $lease->getResourceID());
     $attributes = $lease->getAttributes();
     if ($attributes) {
         $view->addSectionHeader(pht('Attributes'));
         foreach ($attributes as $key => $value) {
             $view->addProperty($key, $value);
         }
     }
     return $view;
 }
 /**
  * @task break
  */
 protected function breakLease(DrydockLease $lease, Exception $ex)
 {
     switch ($lease->getStatus()) {
         case DrydockLeaseStatus::STATUS_BROKEN:
         case DrydockLeaseStatus::STATUS_RELEASED:
         case DrydockLeaseStatus::STATUS_DESTROYED:
             throw new PhutilProxyException(pht('Unexpected failure while destroying lease ("%s").', $lease->getPHID()), $ex);
     }
     $lease->setStatus(DrydockLeaseStatus::STATUS_BROKEN)->save();
     $lease->logEvent(DrydockLeaseActivationFailureLogType::LOGCONST, array('class' => get_class($ex), 'message' => $ex->getMessage()));
     $lease->awakenTasks();
     $this->queueTask(__CLASS__, array('leasePHID' => $lease->getPHID()), array('objectPHID' => $lease->getPHID()));
     throw new PhabricatorWorkerPermanentFailureException(pht('Permanent failure while activating lease ("%s"): %s', $lease->getPHID(), $ex->getMessage()));
 }
 protected function requireActiveLease(DrydockLease $lease)
 {
     $lease_status = $lease->getStatus();
     switch ($lease_status) {
         case DrydockLeaseStatus::STATUS_PENDING:
         case DrydockLeaseStatus::STATUS_ACQUIRED:
             throw new PhabricatorWorkerYieldException(15);
         case DrydockLeaseStatus::STATUS_ACTIVE:
             return;
         default:
             throw new Exception(pht('Lease ("%s") is in bad state ("%s"), expected "%s".', $lease->getPHID(), $lease_status, DrydockLeaseStatus::STATUS_ACTIVE));
     }
 }
 protected function requireActiveLease(DrydockLease $lease)
 {
     $lease_status = $lease->getStatus();
     switch ($lease_status) {
         case DrydockLeaseStatus::STATUS_ACQUIRED:
             // TODO: Temporary failure.
             throw new Exception(pht('Lease still activating.'));
         case DrydockLeaseStatus::STATUS_ACTIVE:
             return;
         default:
             // TODO: Permanent failure.
             throw new Exception(pht('Lease in bad state.'));
     }
 }