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 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; }
/** * Check that the resource a blueprint allocated is roughly the sort of * object we expect. * * @param DrydockBlueprint Blueprint which built the resource. * @param wild Thing which the blueprint claims is a valid resource. * @param DrydockLease Lease the resource was allocated for. * @return void * @task allocator */ private function validateAllocatedResource(DrydockBlueprint $blueprint, $resource, DrydockLease $lease) { if (!$resource instanceof DrydockResource) { throw new Exception(pht('Blueprint "%s" (of type "%s") is not properly implemented: %s must ' . 'return an object of type %s or throw, but returned something else.', $blueprint->getBlueprintName(), $blueprint->getClassName(), 'allocateResource()', 'DrydockResource')); } if (!$resource->isAllocatedResource()) { 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()')); } $resource_type = $resource->getType(); $lease_type = $lease->getResourceType(); if ($resource_type !== $lease_type) { throw new Exception(pht('Blueprint "%s" (of type "%s") is not properly implemented: it ' . 'built a resource of type "%s" to satisfy a lease requesting a ' . 'resource of type "%s".', $blueprint->getBlueprintName(), $blueprint->getClassName(), $resource_type, $lease_type)); } }
private function allocateLease(DrydockLease $lease) { $type = $lease->getResourceType(); $blueprints = $this->loadAllBlueprints(); // TODO: Policy stuff. $pool = id(new DrydockResource())->loadAllWhere('type = %s AND status = %s', $lease->getResourceType(), DrydockResourceStatus::STATUS_OPEN); $this->logToDrydock(pht('Found %d Open Resource(s)', count($pool))); $candidates = array(); foreach ($pool as $key => $candidate) { if (!isset($blueprints[$candidate->getBlueprintPHID()])) { unset($pool[$key]); continue; } $blueprint = $blueprints[$candidate->getBlueprintPHID()]; $implementation = $blueprint->getImplementation(); if ($implementation->filterResource($candidate, $lease)) { $candidates[] = $candidate; } } $this->logToDrydock(pht('%d Open Resource(s) Remain', count($candidates))); $resource = null; if ($candidates) { shuffle($candidates); foreach ($candidates as $candidate_resource) { $blueprint = $blueprints[$candidate_resource->getBlueprintPHID()]->getImplementation(); if ($blueprint->allocateLease($candidate_resource, $lease)) { $resource = $candidate_resource; break; } } } if (!$resource) { $blueprints = DrydockBlueprintImplementation::getAllBlueprintImplementationsForResource($type); $this->logToDrydock(pht('Found %d Blueprints', count($blueprints))); foreach ($blueprints as $key => $candidate_blueprint) { if (!$candidate_blueprint->isEnabled()) { unset($blueprints[$key]); continue; } } $this->logToDrydock(pht('%d Blueprints Enabled', count($blueprints))); foreach ($blueprints as $key => $candidate_blueprint) { if (!$candidate_blueprint->canAllocateMoreResources($pool)) { unset($blueprints[$key]); continue; } } $this->logToDrydock(pht('%d Blueprints Can Allocate', count($blueprints))); if (!$blueprints) { $lease->setStatus(DrydockLeaseStatus::STATUS_BROKEN); $lease->save(); $this->logToDrydock(pht("There are no resources of type '%s' available, and no " . "blueprints which can allocate new ones.", $type)); return; } // TODO: Rank intelligently. shuffle($blueprints); $blueprint = head($blueprints); $resource = $blueprint->allocateResource($lease); if (!$blueprint->allocateLease($resource, $lease)) { // TODO: This "should" happen only if we lost a race with another lease, // which happened to acquire this resource immediately after we // allocated it. In this case, the right behavior is to retry // immediately. However, other things like a blueprint allocating a // resource it can't actually allocate the lease on might be happening // too, in which case we'd just allocate infinite resources. Probably // what we should do is test for an active or allocated lease and retry // if we find one (although it might have already been released by now) // and fail really hard ("your configuration is a huge broken mess") // otherwise. But just throw for now since this stuff is all edge-casey. // Alternatively we could bring resources up in a "BESPOKE" status // and then switch them to "OPEN" only after the allocating lease gets // its grubby mitts on the resource. This might make more sense but // is a bit messy. throw new Exception(pht('Lost an allocation race?')); } } $blueprint = $resource->getBlueprint(); $blueprint->acquireLease($resource, $lease); }