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);
 }
 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);
 }
 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;
 }
 protected function newLease(DrydockBlueprint $blueprint)
 {
     return DrydockLease::initializeNewLease()->setAuthorizingPHID($blueprint->getPHID());
 }
 /**
  * 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;
 }
 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;
 }
 private function reclaimResources(DrydockBlueprint $blueprint, DrydockLease $lease)
 {
     $viewer = $this->getViewer();
     $resources = id(new DrydockResourceQuery())->setViewer($viewer)->withBlueprintPHIDs(array($blueprint->getPHID()))->withStatuses(array(DrydockResourceStatus::STATUS_ACTIVE))->execute();
     // TODO: We could be much smarter about this and try to release long-unused
     // resources, resources with many similar copies, old resources, resources
     // that are cheap to rebuild, etc.
     shuffle($resources);
     foreach ($resources as $resource) {
         if ($this->canReclaimResource($resource)) {
             $this->reclaimResource($resource, $lease);
             return $resource;
         }
     }
     return null;
 }