private function buildPropertyListView(DrydockBlueprint $blueprint, PhabricatorActionListView $actions)
 {
     $view = new PHUIPropertyListView();
     $view->setActionList($actions);
     $view->addProperty(pht('Type'), $blueprint->getImplementation()->getBlueprintName());
     return $view;
 }
 private function buildResourceBox(DrydockBlueprint $blueprint)
 {
     $viewer = $this->getViewer();
     $resources = id(new DrydockResourceQuery())->setViewer($viewer)->withBlueprintPHIDs(array($blueprint->getPHID()))->withStatuses(array(DrydockResourceStatus::STATUS_PENDING, DrydockResourceStatus::STATUS_ACTIVE))->setLimit(100)->execute();
     $resource_list = id(new DrydockResourceListView())->setUser($viewer)->setResources($resources)->render()->setNoDataString(pht('This blueprint has no active resources.'));
     $id = $blueprint->getID();
     $resources_uri = "blueprint/{$id}/resources/query/all/";
     $resources_uri = $this->getApplicationURI($resources_uri);
     $resource_header = id(new PHUIHeaderView())->setHeader(pht('Active Resources'))->addActionLink(id(new PHUIButtonView())->setTag('a')->setHref($resources_uri)->setIconFont('fa-search')->setText(pht('View All Resources')));
     return id(new PHUIObjectBoxView())->setHeader($resource_header)->setObjectList($resource_list);
 }
 protected function loadPage()
 {
     $table = new DrydockBlueprint();
     $conn_r = $table->establishConnection('r');
     $data = queryfx_all($conn_r, 'SELECT blueprint.* FROM %T blueprint %Q %Q %Q', $table->getTableName(), $this->buildWhereClause($conn_r), $this->buildOrderClause($conn_r), $this->buildLimitClause($conn_r));
     $blueprints = $table->loadAllFromArray($data);
     $implementations = DrydockBlueprintImplementation::getAllBlueprintImplementations();
     foreach ($blueprints as $blueprint) {
         if (array_key_exists($blueprint->getClassName(), $implementations)) {
             $blueprint->attachImplementation($implementations[$blueprint->getClassName()]);
         }
     }
     return $blueprints;
 }
 private function buildAuthorizationsBox(DrydockBlueprint $blueprint)
 {
     $viewer = $this->getViewer();
     $limit = 25;
     // If there are pending authorizations against this blueprint, make sure
     // we show them first.
     $pending_authorizations = id(new DrydockAuthorizationQuery())->setViewer($viewer)->withBlueprintPHIDs(array($blueprint->getPHID()))->withObjectStates(array(DrydockAuthorization::OBJECTAUTH_ACTIVE))->withBlueprintStates(array(DrydockAuthorization::BLUEPRINTAUTH_REQUESTED))->setLimit($limit)->execute();
     $all_authorizations = id(new DrydockAuthorizationQuery())->setViewer($viewer)->withBlueprintPHIDs(array($blueprint->getPHID()))->withObjectStates(array(DrydockAuthorization::OBJECTAUTH_ACTIVE))->withBlueprintStates(array(DrydockAuthorization::BLUEPRINTAUTH_REQUESTED, DrydockAuthorization::BLUEPRINTAUTH_AUTHORIZED))->setLimit($limit)->execute();
     $authorizations = mpull($pending_authorizations, null, 'getPHID') + mpull($all_authorizations, null, 'getPHID');
     $authorization_list = id(new DrydockAuthorizationListView())->setUser($viewer)->setAuthorizations($authorizations)->setNoDataString(pht('No objects have active authorizations to use this blueprint.'));
     $id = $blueprint->getID();
     $authorizations_uri = "blueprint/{$id}/authorizations/query/all/";
     $authorizations_uri = $this->getApplicationURI($authorizations_uri);
     $authorizations_header = id(new PHUIHeaderView())->setHeader(pht('Active Authorizations'))->addActionLink(id(new PHUIButtonView())->setTag('a')->setHref($authorizations_uri)->setIconFont('fa-search')->setText(pht('View All')));
     return id(new PHUIObjectBoxView())->setHeader($authorizations_header)->setObjectList($authorization_list);
 }
 protected function newEditableObject()
 {
     $viewer = $this->getViewer();
     $blueprint = DrydockBlueprint::initializeNewBlueprint($viewer);
     $impl = $this->getBlueprintImplementation();
     if ($impl) {
         $blueprint->setClassName(get_class($impl))->attachImplementation(clone $impl);
     }
     return $blueprint;
 }
 protected function doWork()
 {
     $data = $this->getTaskData();
     $lease = id(new DrydockLease())->loadOneWhere('id = %d', $data['lease']);
     if (!$lease) {
         return;
     }
     $type = $data['type'];
     $candidates = id(new DrydockResource())->loadAllWhere('type = %s AND status = %s', $type, DrydockResourceStatus::STATUS_OPEN);
     if ($candidates) {
         shuffle($candidates);
         $resource = head($candidates);
     } else {
         $blueprints = DrydockBlueprint::getAllBlueprintsForResource($type);
         foreach ($blueprints as $key => $blueprint) {
             if (!$blueprint->canAllocateResources()) {
                 unset($blueprints[$key]);
                 continue;
             }
         }
         if (!$blueprints) {
             $lease->setStatus(DrydockLeaseStatus::STATUS_BROKEN);
             $lease->save();
             DrydockBlueprint::writeLog(null, $lease, "There are no resources of type '{$type}' available, and no " . "blueprints which can allocate new ones.");
             return;
         }
         // TODO: Rank intelligently.
         shuffle($blueprints);
         $blueprint = head($blueprints);
         if (isset($data['synchronous'])) {
             $blueprint->makeSynchronous();
         }
         $resource = $blueprint->allocateResource();
     }
     $blueprint = $resource->getBlueprint();
     $blueprint->acquireLease($resource, $lease);
 }
 /**
  * @task activate
  */
 private function validateActivatedLease(DrydockBlueprint $blueprint, DrydockResource $resource, DrydockLease $lease)
 {
     if (!$lease->isActivatedLease()) {
         throw new Exception(pht('Blueprint "%s" (of type "%s") is not properly implemented: it ' . 'returned from "%s" without activating a lease.', $blueprint->getBlueprintName(), $blueprint->getClassName(), 'acquireLease()'));
     }
 }
 private function loadFreeBindings(DrydockBlueprint $blueprint)
 {
     if ($this->freeBindings === null) {
         $viewer = PhabricatorUser::getOmnipotentUser();
         $pool = id(new DrydockResourceQuery())->setViewer($viewer)->withBlueprintPHIDs(array($blueprint->getPHID()))->withStatuses(array(DrydockResourceStatus::STATUS_PENDING, DrydockResourceStatus::STATUS_OPEN, DrydockResourceStatus::STATUS_CLOSED))->execute();
         $allocated_phids = array();
         foreach ($pool as $resource) {
             $allocated_phids[] = $resource->getAttribute('almanacDevicePHID');
         }
         $allocated_phids = array_fuse($allocated_phids);
         $services = $this->loadServices($blueprint);
         $bindings = $this->loadAllBindings($services);
         $free = array();
         foreach ($bindings as $binding) {
             if (empty($allocated_phids[$binding->getPHID()])) {
                 $free[] = $binding;
             }
         }
         $this->freeBindings = $free;
     }
     return $this->freeBindings;
 }
 /**
  * @task activate
  */
 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()'));
     }
 }
 /**
  * Get the effective concurrent resource limit for this blueprint.
  *
  * @param DrydockBlueprint Blueprint to get the limit for.
  * @return int|null Limit, or `null` for no limit.
  */
 protected function getConcurrentResourceLimit(DrydockBlueprint $blueprint)
 {
     if ($this->shouldUseConcurrentResourceLimit()) {
         $limit = $blueprint->getFieldValue('allocator.limit');
         $limit = (int) $limit;
         if ($limit > 0) {
             return $limit;
         } else {
             return null;
         }
     }
     return null;
 }
 /**
  * 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 lease
  */
 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) {
         // TODO: Destroy the lease?
         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()'));
     }
 }
<?php

echo pht('Adding names to Drydock blueprints.') . "\n";
$table = new DrydockBlueprint();
$conn_w = $table->establishConnection('w');
$iterator = new LiskMigrationIterator($table);
foreach ($iterator as $blueprint) {
    $id = $blueprint->getID();
    echo pht('Populating blueprint %d...', $id) . "\n";
    if (!strlen($blueprint->getBlueprintName())) {
        queryfx($conn_w, 'UPDATE %T SET blueprintName = %s WHERE id = %d', $table->getTableName(), pht('Blueprint %s', $id), $id);
    }
}
echo pht('Done.') . "\n";
 /**
  * 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 = 1;
     // 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.
     $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;
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $request->getViewer();
     $id = $request->getURIData('id');
     if ($id) {
         $blueprint = id(new DrydockBlueprintQuery())->setViewer($viewer)->withIDs(array($id))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
         if (!$blueprint) {
             return new Aphront404Response();
         }
         $impl = $blueprint->getImplementation();
         $cancel_uri = $this->getApplicationURI('blueprint/' . $id . '/');
     } else {
         $this->requireApplicationCapability(DrydockCreateBlueprintsCapability::CAPABILITY);
         $class = $request->getStr('class');
         $impl = DrydockBlueprintImplementation::getNamedImplementation($class);
         if (!$impl || !$impl->isEnabled()) {
             return new Aphront400Response();
         }
         $blueprint = DrydockBlueprint::initializeNewBlueprint($viewer);
         $blueprint->setClassName($class);
         $cancel_uri = $this->getApplicationURI('blueprint/');
     }
     $field_list = PhabricatorCustomField::getObjectFields($blueprint, PhabricatorCustomField::ROLE_EDIT);
     $field_list->setViewer($viewer)->readFieldsFromStorage($blueprint);
     $v_name = $blueprint->getBlueprintName();
     $e_name = true;
     $errors = array();
     $validation_exception = null;
     if ($request->isFormPost()) {
         $v_view_policy = $request->getStr('viewPolicy');
         $v_edit_policy = $request->getStr('editPolicy');
         $v_name = $request->getStr('name');
         if (!strlen($v_name)) {
             $e_name = pht('Required');
             $errors[] = pht('You must name this blueprint.');
         }
         if (!$errors) {
             $xactions = array();
             $xactions = $field_list->buildFieldTransactionsFromRequest(new DrydockBlueprintTransaction(), $request);
             $xactions[] = id(new DrydockBlueprintTransaction())->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)->setNewValue($v_view_policy);
             $xactions[] = id(new DrydockBlueprintTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)->setNewValue($v_edit_policy);
             $xactions[] = id(new DrydockBlueprintTransaction())->setTransactionType(DrydockBlueprintTransaction::TYPE_NAME)->setNewValue($v_name);
             $editor = id(new DrydockBlueprintEditor())->setActor($viewer)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true);
             try {
                 $editor->applyTransactions($blueprint, $xactions);
                 $id = $blueprint->getID();
                 $save_uri = $this->getApplicationURI("blueprint/{$id}/");
                 return id(new AphrontRedirectResponse())->setURI($save_uri);
             } catch (PhabricatorApplicationTransactionValidationException $ex) {
                 $validation_exception = $ex;
             }
         }
     }
     $policies = id(new PhabricatorPolicyQuery())->setViewer($viewer)->setObject($blueprint)->execute();
     $form = id(new AphrontFormView())->setUser($viewer)->addHiddenInput('class', $request->getStr('class'))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Name'))->setName('name')->setValue($v_name)->setError($e_name))->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('Blueprint Type'))->setValue($impl->getBlueprintName()))->appendChild(id(new AphrontFormPolicyControl())->setName('viewPolicy')->setPolicyObject($blueprint)->setCapability(PhabricatorPolicyCapability::CAN_VIEW)->setPolicies($policies))->appendChild(id(new AphrontFormPolicyControl())->setName('editPolicy')->setPolicyObject($blueprint)->setCapability(PhabricatorPolicyCapability::CAN_EDIT)->setPolicies($policies));
     $field_list->appendFieldsToForm($form);
     $crumbs = $this->buildApplicationCrumbs();
     if ($blueprint->getID()) {
         $title = pht('Edit Blueprint');
         $header = pht('Edit Blueprint %d', $blueprint->getID());
         $crumbs->addTextCrumb(pht('Blueprint %d', $blueprint->getID()));
         $crumbs->addTextCrumb(pht('Edit'));
         $submit = pht('Save Blueprint');
     } else {
         $title = pht('New Blueprint');
         $header = pht('New Blueprint');
         $crumbs->addTextCrumb(pht('New Blueprint'));
         $submit = pht('Create Blueprint');
     }
     $form->appendChild(id(new AphrontFormSubmitControl())->setValue($submit)->addCancelButton($cancel_uri));
     $box = id(new PHUIObjectBoxView())->setHeaderText($header)->setValidationException($validation_exception)->setFormErrors($errors)->setForm($form);
     return $this->buildApplicationPage(array($crumbs, $box), array('title' => $title));
 }
 private function loadFreeBindings(DrydockBlueprint $blueprint)
 {
     if ($this->freeBindings === null) {
         $viewer = PhabricatorUser::getOmnipotentUser();
         $pool = id(new DrydockResourceQuery())->setViewer($viewer)->withBlueprintPHIDs(array($blueprint->getPHID()))->withStatuses(array(DrydockResourceStatus::STATUS_PENDING, DrydockResourceStatus::STATUS_ACTIVE, DrydockResourceStatus::STATUS_BROKEN, DrydockResourceStatus::STATUS_RELEASED))->execute();
         $allocated_phids = array();
         foreach ($pool as $resource) {
             $allocated_phids[] = $resource->getAttribute('almanacBindingPHID');
         }
         $allocated_phids = array_fuse($allocated_phids);
         $services = $this->loadServices($blueprint);
         $bindings = $this->loadAllBindings($services);
         $free = array();
         foreach ($bindings as $binding) {
             // Don't consider disabled bindings to be available.
             if ($binding->getIsDisabled()) {
                 continue;
             }
             if (empty($allocated_phids[$binding->getPHID()])) {
                 $free[] = $binding;
             }
         }
         $this->freeBindings = $free;
     }
     return $this->freeBindings;
 }