public function processRequest()
 {
     $request = $this->getRequest();
     $viewer = $request->getUser();
     $this->requireApplicationCapability(DrydockCreateBlueprintsCapability::CAPABILITY);
     $implementations = DrydockBlueprintImplementation::getAllBlueprintImplementations();
     $errors = array();
     $e_blueprint = null;
     if ($request->isFormPost()) {
         $class = $request->getStr('blueprint-type');
         if (!isset($implementations[$class])) {
             $e_blueprint = pht('Required');
             $errors[] = pht('You must choose a blueprint type.');
         }
         if (!$errors) {
             $edit_uri = $this->getApplicationURI('blueprint/edit/?class=' . $class);
             return id(new AphrontRedirectResponse())->setURI($edit_uri);
         }
     }
     $control = id(new AphrontFormRadioButtonControl())->setName('blueprint-type')->setLabel(pht('Blueprint Type'))->setError($e_blueprint);
     foreach ($implementations as $implementation_name => $implementation) {
         $disabled = !$implementation->isEnabled();
         $control->addButton($implementation_name, $implementation->getBlueprintName(), array(pht('Provides: %s', $implementation->getType()), phutil_tag('br'), phutil_tag('br'), $implementation->getDescription()), $disabled ? 'disabled' : null, $disabled);
     }
     $title = pht('Create New Blueprint');
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb(pht('New Blueprint'));
     $form = id(new AphrontFormView())->setUser($viewer)->appendChild($control)->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($this->getApplicationURI('blueprint/'))->setValue(pht('Continue')));
     $box = id(new PHUIObjectBoxView())->setFormErrors($errors)->setHeaderText($title)->setForm($form);
     return $this->buildApplicationPage(array($crumbs, $box), array('title' => $title));
 }
 private function buildTypeSelectionResponse()
 {
     $request = $this->getRequest();
     $viewer = $this->getViewer();
     $implementations = DrydockBlueprintImplementation::getAllBlueprintImplementations();
     $errors = array();
     $e_blueprint = null;
     if ($request->isFormPost()) {
         $class = $request->getStr('blueprintType');
         if (!isset($implementations[$class])) {
             $e_blueprint = pht('Required');
             $errors[] = pht('You must choose a blueprint type.');
         }
     }
     $control = id(new AphrontFormRadioButtonControl())->setName('blueprintType')->setLabel(pht('Blueprint Type'))->setError($e_blueprint);
     foreach ($implementations as $implementation_name => $implementation) {
         $disabled = !$implementation->isEnabled();
         $impl_icon = $implementation->getBlueprintIcon();
         $impl_name = $implementation->getBlueprintName();
         $impl_icon = id(new PHUIIconView())->setIcon($impl_icon, 'lightgreytext');
         $control->addButton($implementation_name, array($impl_icon, ' ', $impl_name), array(pht('Provides: %s', $implementation->getType()), phutil_tag('br'), phutil_tag('br'), $implementation->getDescription()), $disabled ? 'disabled' : null, $disabled);
     }
     $title = pht('Create New Blueprint');
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb(pht('New Blueprint'));
     $form = id(new AphrontFormView())->setUser($viewer)->appendChild($control)->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($this->getApplicationURI('blueprint/'))->setValue(pht('Continue')));
     $box = id(new PHUIObjectBoxView())->setFormErrors($errors)->setHeaderText($title)->setForm($form);
     return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->appendChild($box);
 }
 public function getImplementation()
 {
     $class = $this->className;
     $implementations = DrydockBlueprintImplementation::getAllBlueprintImplementations();
     if (!isset($implementations[$class])) {
         throw new Exception(pht("Invalid class name for blueprint (got '%s')", $class));
     }
     return id(new $class())->attachInstance($this);
 }
 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;
 }
 protected function willFilterPage(array $blueprints)
 {
     $impls = DrydockBlueprintImplementation::getAllBlueprintImplementations();
     foreach ($blueprints as $key => $blueprint) {
         $impl = idx($impls, $blueprint->getClassName());
         if (!$impl) {
             $this->didRejectResult($blueprint);
             unset($blueprints[$key]);
             continue;
         }
         $impl = clone $impl;
         $blueprint->attachImplementation($impl);
     }
     return $blueprints;
 }
Example #6
0
 public function closeResource()
 {
     $this->openTransaction();
     $statuses = array(DrydockLeaseStatus::STATUS_PENDING, DrydockLeaseStatus::STATUS_ACTIVE);
     $leases = id(new DrydockLeaseQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withResourceIDs(array($this->getID()))->withStatuses($statuses)->execute();
     foreach ($leases as $lease) {
         switch ($lease->getStatus()) {
             case DrydockLeaseStatus::STATUS_PENDING:
                 $message = pht('Breaking pending lease (resource closing).');
                 $lease->setStatus(DrydockLeaseStatus::STATUS_BROKEN);
                 break;
             case DrydockLeaseStatus::STATUS_ACTIVE:
                 $message = pht('Releasing active lease (resource closing).');
                 $lease->setStatus(DrydockLeaseStatus::STATUS_RELEASED);
                 break;
         }
         DrydockBlueprintImplementation::writeLog($this, $lease, $message);
         $lease->save();
     }
     $this->setStatus(DrydockResourceStatus::STATUS_CLOSED);
     $this->save();
     $this->saveTransaction();
 }
 /**
  * Get all the @{class:DrydockBlueprintImplementation}s which can possibly
  * build a resource to satisfy a lease.
  *
  * This method returns blueprints which might, at some time, be able to
  * build a resource which can satisfy the lease. They may not be able to
  * build that resource right now.
  *
  * @param DrydockLease Requested lease.
  * @return list<DrydockBlueprintImplementation> List of qualifying blueprint
  *   implementations.
  * @task allocator
  */
 private function loadBlueprintImplementationsForAllocatingLease(DrydockLease $lease)
 {
     $impls = DrydockBlueprintImplementation::getAllBlueprintImplementations();
     $keep = array();
     foreach ($impls as $key => $impl) {
         // Don't use disabled blueprint types.
         if (!$impl->isEnabled()) {
             continue;
         }
         // Don't use blueprint types which can't allocate the correct kind of
         // resource.
         if ($impl->getType() != $lease->getResourceType()) {
             continue;
         }
         if (!$impl->canAnyBlueprintEverAllocateResourceForLease($lease)) {
             continue;
         }
         $keep[$key] = $impl;
     }
     return $keep;
 }
 public function getFieldSpecifications()
 {
     return array('almanacServicePHIDs' => array('name' => pht('Almanac Services'), 'type' => 'datasource', 'datasource.class' => 'AlmanacServiceDatasource', 'datasource.parameters' => array('serviceClasses' => $this->getAlmanacServiceClasses()), 'required' => true), 'credentialPHID' => array('name' => pht('Credentials'), 'type' => 'credential', 'credential.provides' => PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE, 'credential.type' => PassphraseSSHPrivateKeyTextCredentialType::CREDENTIAL_TYPE)) + parent::getFieldSpecifications();
 }
 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));
 }
 public function getFieldSpecifications()
 {
     return array('blueprintPHIDs' => array('name' => pht('Use Blueprints'), 'type' => 'blueprints', 'required' => true)) + parent::getFieldSpecifications();
 }
 public function testGetAllBlueprintImplementations()
 {
     DrydockBlueprintImplementation::getAllBlueprintImplementations();
     $this->assertTrue(true);
 }
 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);
 }