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; }
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); }