示例#1
0
 protected function yieldIfExpiringResource(DrydockResource $resource)
 {
     if (!$resource->canReceiveCommands()) {
         return;
     }
     $this->yieldIfExpiring($resource->getUntil());
 }
 public function getInterface(DrydockResource $resource, DrydockLease $lease, $type)
 {
     switch ($type) {
         case 'command':
             return $this->loadLease($resource->getAttribute('lease.host'))->getInterface($type);
     }
     throw new Exception("No interface of type '{$type}'.");
 }
 protected function loadPage()
 {
     $table = new DrydockResource();
     $conn_r = $table->establishConnection('r');
     $data = queryfx_all($conn_r, 'SELECT resource.* FROM %T resource %Q %Q %Q', $table->getTableName(), $this->buildWhereClause($conn_r), $this->buildOrderClause($conn_r), $this->buildLimitClause($conn_r));
     $resources = $table->loadAllFromArray($data);
     return $resources;
 }
 private function buildLeaseBox(DrydockResource $resource)
 {
     $viewer = $this->getViewer();
     $leases = id(new DrydockLeaseQuery())->setViewer($viewer)->withResourcePHIDs(array($resource->getPHID()))->withStatuses(array(DrydockLeaseStatus::STATUS_PENDING, DrydockLeaseStatus::STATUS_ACQUIRED, DrydockLeaseStatus::STATUS_ACTIVE))->setLimit(100)->execute();
     $id = $resource->getID();
     $leases_uri = "resource/{$id}/leases/query/all/";
     $leases_uri = $this->getApplicationURI($leases_uri);
     $lease_header = id(new PHUIHeaderView())->setHeader(pht('Active Leases'))->addActionLink(id(new PHUIButtonView())->setTag('a')->setHref($leases_uri)->setIconFont('fa-search')->setText(pht('View All Leases')));
     $lease_list = id(new DrydockLeaseListView())->setUser($viewer)->setLeases($leases)->render()->setNoDataString(pht('This resource has no active leases.'));
     return id(new PHUIObjectBoxView())->setHeader($lease_header)->setObjectList($lease_list);
 }
 private function destroyResource(DrydockResource $resource)
 {
     $status = $resource->getStatus();
     switch ($status) {
         case DrydockResourceStatus::STATUS_RELEASED:
         case DrydockResourceStatus::STATUS_BROKEN:
             break;
         default:
             throw new PhabricatorWorkerPermanentFailureException(pht('Unable to destroy resource ("%s"), resource has the wrong ' . 'status ("%s").', $resource->getPHID(), $status));
     }
     $blueprint = $resource->getBlueprint();
     $blueprint->destroyResource($resource);
     $resource->setStatus(DrydockResourceStatus::STATUS_DESTROYED)->save();
 }
 public function getInterface(DrydockResource $resource, DrydockLease $lease, $type)
 {
     switch ($type) {
         case 'command':
             return id(new DrydockSSHCommandInterface())->setConfiguration(array('host' => $resource->getAttribute('host'), 'port' => $resource->getAttribute('port'), 'credential' => $resource->getAttribute('credential'), 'platform' => $resource->getAttribute('platform')))->setWorkingDirectory($lease->getAttribute('path'));
         case 'filesystem':
             return id(new DrydockSFTPFilesystemInterface())->setConfiguration(array('host' => $resource->getAttribute('host'), 'port' => $resource->getAttribute('port'), 'credential' => $resource->getAttribute('credential')));
     }
     throw new Exception(pht("No interface of type '%s'.", $type));
 }
 private function buildPropertyListView(DrydockResource $resource, PhabricatorActionListView $actions)
 {
     $viewer = $this->getViewer();
     $view = id(new PHUIPropertyListView())->setActionList($actions);
     $status = $resource->getStatus();
     $status = DrydockResourceStatus::getNameForStatus($status);
     $view->addProperty(pht('Status'), $status);
     $view->addProperty(pht('Resource Type'), $resource->getType());
     $view->addProperty(pht('Blueprint'), $viewer->renderHandle($resource->getBlueprintPHID()));
     $attributes = $resource->getAttributes();
     if ($attributes) {
         $view->addSectionHeader(pht('Attributes'), 'fa-list-ul');
         foreach ($attributes as $key => $value) {
             $view->addProperty($key, $value);
         }
     }
     return $view;
 }
 public function getInterface(DrydockResource $resource, DrydockLease $lease, $type)
 {
     switch ($type) {
         case 'webroot':
             $iface = new DrydockApacheWebrootInterface();
             $iface->setConfiguration(array('uri' => $lease->getAttribute('uri')));
             return $iface;
         case 'command':
             $host_lease_id = $resource->getAttribute('lease.host');
             $host_lease = id(new DrydockLease())->load($host_lease_id);
             $host_lease->attachResource($host_lease->loadResource());
             return $host_lease->getInterface($type);
     }
     throw new Exception("No interface of type '{$type}'.");
 }
 public function getInterface(DrydockBlueprint $blueprint, DrydockResource $resource, DrydockLease $lease, $type)
 {
     $viewer = PhabricatorUser::getOmnipotentUser();
     switch ($type) {
         case DrydockCommandInterface::INTERFACE_TYPE:
             $credential_phid = $blueprint->getFieldValue('credentialPHID');
             $binding_phid = $resource->getAttribute('almanacBindingPHID');
             $binding = id(new AlmanacBindingQuery())->setViewer($viewer)->withPHIDs(array($binding_phid))->executeOne();
             if (!$binding) {
                 // TODO: This is probably a permanent failure, destroy this resource?
                 throw new Exception(pht('Unable to load binding "%s" to create command interface.', $binding_phid));
             }
             $interface = $binding->getInterface();
             return id(new DrydockSSHCommandInterface())->setConfig('credentialPHID', $credential_phid)->setConfig('host', $interface->getAddress())->setConfig('port', $interface->getPort());
     }
 }
 private function releaseResource(DrydockResource $resource)
 {
     if ($resource->getStatus() != DrydockResourceStatus::STATUS_ACTIVE) {
         // If we had multiple release commands
         // This command is only meaningful to resources in the "Open" state.
         return;
     }
     $viewer = $this->getViewer();
     $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID();
     $resource->openTransaction();
     $resource->setStatus(DrydockResourceStatus::STATUS_RELEASED)->save();
     // TODO: Hold slot locks until destruction?
     DrydockSlotLock::releaseLocks($resource->getPHID());
     $resource->saveTransaction();
     $statuses = array(DrydockLeaseStatus::STATUS_PENDING, DrydockLeaseStatus::STATUS_ACQUIRED, DrydockLeaseStatus::STATUS_ACTIVE);
     $leases = id(new DrydockLeaseQuery())->setViewer($viewer)->withResourcePHIDs(array($resource->getPHID()))->withStatuses($statuses)->execute();
     foreach ($leases as $lease) {
         $command = DrydockCommand::initializeNewCommand($viewer)->setTargetPHID($lease->getPHID())->setAuthorPHID($drydock_phid)->setCommand(DrydockCommand::COMMAND_RELEASE)->save();
         $lease->scheduleUpdate();
     }
     PhabricatorWorker::scheduleTask('DrydockResourceDestroyWorker', array('resourcePHID' => $resource->getPHID()), array('objectPHID' => $resource->getPHID()));
 }
 private function loadHostLease(DrydockResource $resource)
 {
     $viewer = PhabricatorUser::getOmnipotentUser();
     $lease_phid = $resource->getAttribute('host.leasePHID');
     $lease = id(new DrydockLeaseQuery())->setViewer($viewer)->withPHIDs(array($lease_phid))->executeOne();
     if (!$lease) {
         throw new Exception(pht('Unable to load lease ("%s").', $lease_phid));
     }
     return $lease;
 }
 /**
  * @task destroy
  */
 private function destroyResource(DrydockResource $resource)
 {
     $blueprint = $resource->getBlueprint();
     $blueprint->destroyResource($resource);
     DrydockSlotLock::releaseLocks($resource->getPHID());
     $resource->setStatus(DrydockResourceStatus::STATUS_DESTROYED)->save();
 }
 /**
  * Apply standard limits on resource allocation rate.
  *
  * @param DrydockBlueprint The blueprint requesting an allocation.
  * @return bool True if further allocations should be limited.
  */
 protected function shouldLimitAllocatingPoolSize(DrydockBlueprint $blueprint)
 {
     // TODO: If this mechanism sticks around, these values should be
     // configurable by the blueprint implementation.
     // Limit on total number of active resources.
     $total_limit = $this->getConcurrentResourceLimit($blueprint);
     // Always allow at least this many allocations to be in flight at once.
     $min_allowed = 1;
     // Allow this fraction of allocating resources as a fraction of active
     // resources.
     $growth_factor = 0.25;
     $resource = new DrydockResource();
     $conn_r = $resource->establishConnection('r');
     $counts = queryfx_all($conn_r, 'SELECT status, COUNT(*) N FROM %T
     WHERE blueprintPHID = %s AND status != %s
     GROUP BY status', $resource->getTableName(), $blueprint->getPHID(), DrydockResourceStatus::STATUS_DESTROYED);
     $counts = ipull($counts, 'N', 'status');
     $n_alloc = idx($counts, DrydockResourceStatus::STATUS_PENDING, 0);
     $n_active = idx($counts, DrydockResourceStatus::STATUS_ACTIVE, 0);
     $n_broken = idx($counts, DrydockResourceStatus::STATUS_BROKEN, 0);
     $n_released = idx($counts, DrydockResourceStatus::STATUS_RELEASED, 0);
     // If we're at the limit on total active resources, limit additional
     // allocations.
     if ($total_limit !== null) {
         $n_total = $n_alloc + $n_active + $n_broken + $n_released;
         if ($n_total >= $total_limit) {
             return true;
         }
     }
     // If the number of in-flight allocations is fewer than the minimum number
     // of allowed allocations, don't impose a limit.
     if ($n_alloc < $min_allowed) {
         return false;
     }
     $allowed_alloc = (int) ceil($n_active * $growth_factor);
     // If the number of in-flight allocation is fewer than the number of
     // allowed allocations according to the pool growth factor, don't impose
     // a limit.
     if ($n_alloc < $allowed_alloc) {
         return false;
     }
     return true;
 }
示例#14
0
 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();
     $this->setStatus(DrydockLeaseStatus::STATUS_ACTIVE)->save();
     DrydockSlotLock::acquireLocks($this->getPHID(), $this->slotLocks);
     $this->slotLocks = array();
     $this->saveTransaction();
     $this->isActivated = true;
     $this->didActivate();
     return $this;
 }
 private function validateActivatedResource(DrydockBlueprint $blueprint, DrydockResource $resource)
 {
     if (!$resource->isActivatedResource()) {
         throw new Exception(pht('Blueprint "%s" (of type "%s") is not properly implemented: %s ' . 'must actually allocate the resource it returns.', $blueprint->getBlueprintName(), $blueprint->getClassName(), 'allocateResource()'));
     }
 }
示例#16
0
 protected function newResourceTemplate($name)
 {
     $resource = new DrydockResource();
     $resource->setBlueprintClass(get_class($this));
     $resource->setType($this->getType());
     $resource->setStatus(DrydockResourceStatus::STATUS_PENDING);
     $resource->setName($name);
     $resource->save();
     $this->activeResource = $resource;
     $this->log('New Template');
     return $resource;
 }
 /**
  * @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();
 }
示例#18
0
 protected function reclaimResource(DrydockResource $resource, DrydockLease $lease)
 {
     $viewer = $this->getViewer();
     $command = DrydockCommand::initializeNewCommand($viewer)->setTargetPHID($resource->getPHID())->setAuthorPHID($lease->getPHID())->setCommand(DrydockCommand::COMMAND_RECLAIM)->save();
     $resource->scheduleUpdate();
     return $this;
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $resource = new DrydockResource();
     $json = new PhutilJSON();
     $err_attributes = true;
     $err_capabilities = true;
     $json_attributes = $json->encodeFormatted($resource->getAttributes());
     $json_capabilities = $json->encodeFormatted($resource->getCapabilities());
     $errors = array();
     if ($request->isFormPost()) {
         $raw_attributes = $request->getStr('attributes');
         $attributes = json_decode($raw_attributes, true);
         if (!is_array($attributes)) {
             $err_attributes = 'Invalid';
             $errors[] = 'Enter attributes as a valid JSON object.';
             $json_attributes = $raw_attributes;
         } else {
             $resource->setAttributes($attributes);
             $json_attributes = $json->encodeFormatted($attributes);
             $err_attributes = null;
         }
         $raw_capabilities = $request->getStr('capabilities');
         $capabilities = json_decode($raw_capabilities, true);
         if (!is_array($capabilities)) {
             $err_capabilities = 'Invalid';
             $errors[] = 'Enter capabilities as a valid JSON object.';
             $json_capabilities = $raw_capabilities;
         } else {
             $resource->setCapabilities($capabilities);
             $json_capabilities = $json->encodeFormatted($capabilities);
             $err_capabilities = null;
         }
         $resource->setBlueprintClass($request->getStr('blueprint'));
         $resource->setType($resource->getBlueprint()->getType());
         $resource->setOwnerPHID($user->getPHID());
         $resource->setName($request->getStr('name'));
         if (!$errors) {
             $resource->save();
             return id(new AphrontRedirectResponse())->setURI('/drydock/resource/');
         }
     }
     $error_view = null;
     if ($errors) {
         $error_view = new AphrontErrorView();
         $error_view->setTitle('Form Errors');
         $error_view->setErrors($errors);
     }
     $blueprints = id(new PhutilSymbolLoader())->setType('class')->setAncestorClass('DrydockBlueprint')->selectAndLoadSymbols();
     $blueprints = ipull($blueprints, 'name', 'name');
     $panel = new AphrontPanelView();
     $panel->setWidth(AphrontPanelView::WIDTH_FORM);
     $panel->setHeader('Allocate Drydock Resource');
     $form = id(new AphrontFormView())->setUser($request->getUser())->appendChild(id(new AphrontFormTextControl())->setLabel('Name')->setName('name')->setValue($resource->getName()))->appendChild(id(new AphrontFormSelectControl())->setLabel('Blueprint')->setOptions($blueprints)->setName('blueprint')->setValue($resource->getBlueprintClass()))->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Attributes')->setName('attributes')->setValue($json_attributes)->setError($err_attributes)->setCaption('Specify attributes in JSON.'))->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Capabilities')->setName('capabilities')->setValue($json_capabilities)->setError($err_capabilities)->setCaption('Specify capabilities in JSON.'))->appendChild(id(new AphrontFormSubmitControl())->setValue('Allocate Resource'));
     $panel->appendChild($form);
     return $this->buildStandardPageResponse(array($error_view, $panel), array('title' => 'Allocate Resource'));
 }
 /**
  * Make sure that a lease was really acquired properly.
  *
  * @param DrydockBlueprint Blueprint which created the resource.
  * @param DrydockResource Resource which was acquired.
  * @param DrydockLease The lease which was supposedly acquired.
  * @return void
  * @task acquire
  */
 private function validateAcquiredLease(DrydockBlueprint $blueprint, DrydockResource $resource, DrydockLease $lease)
 {
     if (!$lease->isAcquiredLease()) {
         throw new Exception(pht('Blueprint "%s" (of type "%s") is not properly implemented: it ' . 'returned from "%s" without acquiring a lease.', $blueprint->getBlueprintName(), $blueprint->getClassName(), 'acquireLease()'));
     }
     $lease_phid = $lease->getResourcePHID();
     $resource_phid = $resource->getPHID();
     if ($lease_phid !== $resource_phid) {
         throw new Exception(pht('Blueprint "%s" (of type "%s") is not properly implemented: it ' . 'returned from "%s" with a lease acquired on the wrong resource.', $blueprint->getBlueprintName(), $blueprint->getClassName(), 'acquireLease()'));
     }
 }
 public function getInterface(DrydockResource $resource, DrydockLease $lease, $type)
 {
     switch ($type) {
         case 'command':
             $ssh = new DrydockSSHCommandInterface();
             $ssh->setConfiguration(array('host' => $resource->getAttribute('host'), 'user' => $resource->getAttribute('user'), 'ssh-keyfile' => $resource->getAttribute('ssh-keyfile')));
             return $ssh;
     }
     throw new Exception("No interface of type '{$type}'.");
 }