diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -7,7 +7,7 @@ */ return array( 'names' => array( - 'core.pkg.css' => 'fe2446e9', + 'core.pkg.css' => '14b73308', 'core.pkg.js' => 'cbdbd552', 'darkconsole.pkg.js' => 'df001cab', 'differential.pkg.css' => '36884139', @@ -127,7 +127,7 @@ 'rsrc/css/phui/phui-document.css' => 'a5615198', 'rsrc/css/phui/phui-feed-story.css' => '55dc7732', 'rsrc/css/phui/phui-fontkit.css' => 'fff25cfa', - 'rsrc/css/phui/phui-form-view.css' => 'a2d72756', + 'rsrc/css/phui/phui-form-view.css' => '9365aa7c', 'rsrc/css/phui/phui-form.css' => 'b78ec020', 'rsrc/css/phui/phui-header-view.css' => '39594ac0', 'rsrc/css/phui/phui-icon.css' => 'b4963a4f', @@ -777,7 +777,7 @@ 'phui-font-icon-base-css' => 'eb84f033', 'phui-fontkit-css' => 'fff25cfa', 'phui-form-css' => 'b78ec020', - 'phui-form-view-css' => 'a2d72756', + 'phui-form-view-css' => '9365aa7c', 'phui-header-view-css' => '39594ac0', 'phui-icon-view-css' => 'b4963a4f', 'phui-image-mask-css' => '5a8b09c8', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -599,6 +599,7 @@ 'DrydockConstants' => 'applications/drydock/constants/DrydockConstants.php', 'DrydockController' => 'applications/drydock/controller/DrydockController.php', 'DrydockCreateBlueprintsCapability' => 'applications/drydock/capability/DrydockCreateBlueprintsCapability.php', + 'DrydockCustomAttributes' => 'applications/drydock/util/DrydockCustomAttributes.php', 'DrydockDAO' => 'applications/drydock/storage/DrydockDAO.php', 'DrydockDefaultEditCapability' => 'applications/drydock/capability/DrydockDefaultEditCapability.php', 'DrydockDefaultViewCapability' => 'applications/drydock/capability/DrydockDefaultViewCapability.php', @@ -2307,6 +2308,7 @@ 'PhabricatorStandardCustomFieldRemarkup' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php', 'PhabricatorStandardCustomFieldSelect' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldSelect.php', 'PhabricatorStandardCustomFieldText' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldText.php', + 'PhabricatorStandardCustomFieldTextarea' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldTextarea.php', 'PhabricatorStandardCustomFieldUsers' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldUsers.php', 'PhabricatorStandardPageView' => 'view/page/PhabricatorStandardPageView.php', 'PhabricatorStatusController' => 'applications/system/controller/PhabricatorStatusController.php', @@ -3443,6 +3445,7 @@ 'DrydockConsoleController' => 'DrydockController', 'DrydockController' => 'PhabricatorController', 'DrydockCreateBlueprintsCapability' => 'PhabricatorPolicyCapability', + 'DrydockCustomAttributes' => 'Phobject', 'DrydockDAO' => 'PhabricatorLiskDAO', 'DrydockDefaultEditCapability' => 'PhabricatorPolicyCapability', 'DrydockDefaultViewCapability' => 'PhabricatorPolicyCapability', @@ -5307,6 +5310,7 @@ 'PhabricatorStandardCustomFieldRemarkup' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldSelect' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldText' => 'PhabricatorStandardCustomField', + 'PhabricatorStandardCustomFieldTextarea' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldUsers' => 'PhabricatorStandardCustomFieldPHIDs', 'PhabricatorStandardPageView' => 'PhabricatorBarePageView', 'PhabricatorStatusController' => 'PhabricatorController', diff --git a/src/applications/drydock/blueprint/DrydockAmazonEC2HostBlueprintImplementation.php b/src/applications/drydock/blueprint/DrydockAmazonEC2HostBlueprintImplementation.php --- a/src/applications/drydock/blueprint/DrydockAmazonEC2HostBlueprintImplementation.php +++ b/src/applications/drydock/blueprint/DrydockAmazonEC2HostBlueprintImplementation.php @@ -33,15 +33,26 @@ } public function canAllocateResourceForLease(DrydockLease $lease) { - return + $platform_match = $lease->getAttribute('platform') === $this->getDetail('platform'); + $custom_match = DrydockCustomAttributes::hasRequirements( + $lease->getAttributes(), + $this->getDetail('attributes')); + + return $platform_match && $custom_match; } protected function canAllocateLease( DrydockResource $resource, DrydockLease $lease) { - return + + $platform_match = $lease->getAttribute('platform') === $resource->getAttribute('platform'); + $custom_match = DrydockCustomAttributes::hasRequirements( + $lease->getAttributes(), + $this->getDetail('attributes')); + + return $platform_match && $custom_match; } protected function executeAllocateResource( @@ -644,6 +655,18 @@ 'than the On Demand price for this instance type, or you could end '. 'up paying more than the non-spot instance price.'), ), + 'attr-header' => array( + 'name' => pht('Host Attributes'), + 'type' => 'header' + ), + 'attributes' => array( + 'name' => pht('Host Attributes'), + 'type' => 'textarea', + 'caption' => pht( + 'A newline separated list of host attributes. Each attribute '. + 'should be specified in a key=value format.'), + 'monospace' => true, + ), ) + parent::getFieldSpecifications(); } diff --git a/src/applications/drydock/storage/DrydockLease.php b/src/applications/drydock/storage/DrydockLease.php --- a/src/applications/drydock/storage/DrydockLease.php +++ b/src/applications/drydock/storage/DrydockLease.php @@ -69,6 +69,10 @@ return idx($this->attributes, $key, $default); } + public function getAttributes() { + return $this->attributes; + } + public function generatePHID() { return PhabricatorPHID::generateNewPHID(DrydockLeasePHIDType::TYPECONST); } diff --git a/src/applications/drydock/util/DrydockCustomAttributes.php b/src/applications/drydock/util/DrydockCustomAttributes.php new file mode 100644 --- /dev/null +++ b/src/applications/drydock/util/DrydockCustomAttributes.php @@ -0,0 +1,44 @@ + $value) { + // Only compare custom attributes. + if (substr($key, 0, 5) === 'attr_') { + if ($value === true) { + if (!array_key_exists($provided, $key)) { + return false; + } + } else { + if (idx($provided, $key) !== $value) { + return false; + } + } + } + } + + return true; + } + +} diff --git a/src/applications/harbormaster/step/HarbormasterLeaseHostBuildStepImplementation.php b/src/applications/harbormaster/step/HarbormasterLeaseHostBuildStepImplementation.php --- a/src/applications/harbormaster/step/HarbormasterLeaseHostBuildStepImplementation.php +++ b/src/applications/harbormaster/step/HarbormasterLeaseHostBuildStepImplementation.php @@ -17,13 +17,16 @@ $settings = $this->getSettings(); + $custom_attributes = DrydockCustomAttributes::parse( + $settings['attributes']); + // Create the lease. $lease = id(new DrydockLease()) ->setResourceType('host') ->setAttributes( array( 'platform' => $settings['platform'], - )) + ) + $custom_attributes) ->queueForActivation(); // Wait until the lease is fulfilled. @@ -63,6 +66,14 @@ 'type' => 'text', 'required' => true, ), + 'attributes' => array( + 'name' => pht('Required Attributes'), + 'type' => 'textarea', + 'caption' => pht( + 'A newline separated list of required host attributes. Each '. + 'attribute should be specified in a key=value format.'), + 'monospace' => true, + ), ); } diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldTextarea.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldTextarea.php new file mode 100644 --- /dev/null +++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldTextarea.php @@ -0,0 +1,74 @@ +getFieldConfigValue('monospace', false); + $custom_class = + $monospace ? 'aphront-form-control-textarea-monospace' : null; + + return id(new AphrontFormTextAreaControl()) + ->setLabel($this->getFieldName()) + ->setName($this->getFieldKey()) + ->setCaption($this->getCaption()) + ->setValue($this->getFieldValue()) + ->setCustomClass($custom_class); + } + + public function getStyleForPropertyView() { + return 'block'; + } + + public function getApplicationTransactionRemarkupBlocks( + PhabricatorApplicationTransaction $xaction) { + return array( + $xaction->getNewValue(), + ); + } + + public function renderPropertyViewValue(array $handles) { + $value = $this->getFieldValue(); + + if (!strlen($value)) { + return null; + } + + return phutil_tag( + 'pre', + array(), + $value); + } + + public function getApplicationTransactionTitle( + PhabricatorApplicationTransaction $xaction) { + $author_phid = $xaction->getAuthorPHID(); + + // TODO: Expose fancy transactions. + + return pht( + '%s edited %s.', + $xaction->renderHandleLink($author_phid), + $this->getFieldName()); + } + + public function shouldAppearInHerald() { + return true; + } + + public function getHeraldFieldConditions() { + return array( + HeraldAdapter::CONDITION_CONTAINS, + HeraldAdapter::CONDITION_NOT_CONTAINS, + HeraldAdapter::CONDITION_IS, + HeraldAdapter::CONDITION_IS_NOT, + HeraldAdapter::CONDITION_REGEXP, + ); + } + + +} diff --git a/webroot/rsrc/css/phui/phui-form-view.css b/webroot/rsrc/css/phui/phui-form-view.css --- a/webroot/rsrc/css/phui/phui-form-view.css +++ b/webroot/rsrc/css/phui/phui-form-view.css @@ -137,6 +137,10 @@ height: 24em; } +.aphront-form-control-textarea-monospace { + font-family: monospace; +} + .aphront-form-control-select .aphront-form-input { padding-top: 2px; }