Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15379316
D16565.id39942.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
17 KB
Referenced Files
None
Subscribers
None
D16565.id39942.diff
View Options
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
@@ -945,13 +945,16 @@
'DrydockCommandError' => 'applications/drydock/exception/DrydockCommandError.php',
'DrydockCommandInterface' => 'applications/drydock/interface/command/DrydockCommandInterface.php',
'DrydockCommandQuery' => 'applications/drydock/query/DrydockCommandQuery.php',
+ 'DrydockConduitAPIMethod' => 'applications/drydock/conduit/DrydockConduitAPIMethod.php',
'DrydockConsoleController' => 'applications/drydock/controller/DrydockConsoleController.php',
'DrydockConstants' => 'applications/drydock/constants/DrydockConstants.php',
'DrydockController' => 'applications/drydock/controller/DrydockController.php',
'DrydockCreateBlueprintsCapability' => 'applications/drydock/capability/DrydockCreateBlueprintsCapability.php',
+ 'DrydockCreateLeaseConduitAPIMethod' => 'applications/drydock/conduit/DrydockCreateLeaseConduitAPIMethod.php',
'DrydockDAO' => 'applications/drydock/storage/DrydockDAO.php',
'DrydockDefaultEditCapability' => 'applications/drydock/capability/DrydockDefaultEditCapability.php',
'DrydockDefaultViewCapability' => 'applications/drydock/capability/DrydockDefaultViewCapability.php',
+ 'DrydockDestroyLeaseConduitAPIMethod' => 'applications/drydock/conduit/DrydockDestroyLeaseConduitAPIMethod.php',
'DrydockFilesystemInterface' => 'applications/drydock/interface/filesystem/DrydockFilesystemInterface.php',
'DrydockInterface' => 'applications/drydock/interface/DrydockInterface.php',
'DrydockLandRepositoryOperation' => 'applications/drydock/operation/DrydockLandRepositoryOperation.php',
@@ -1008,6 +1011,7 @@
'DrydockRepositoryOperationType' => 'applications/drydock/operation/DrydockRepositoryOperationType.php',
'DrydockRepositoryOperationUpdateWorker' => 'applications/drydock/worker/DrydockRepositoryOperationUpdateWorker.php',
'DrydockRepositoryOperationViewController' => 'applications/drydock/controller/DrydockRepositoryOperationViewController.php',
+ 'DrydockRequestAuthorizationConduitAPIMethod' => 'applications/drydock/conduit/DrydockRequestAuthorizationConduitAPIMethod.php',
'DrydockResource' => 'applications/drydock/storage/DrydockResource.php',
'DrydockResourceActivationFailureLogType' => 'applications/drydock/logtype/DrydockResourceActivationFailureLogType.php',
'DrydockResourceActivationYieldLogType' => 'applications/drydock/logtype/DrydockResourceActivationYieldLogType.php',
@@ -5489,13 +5493,16 @@
'DrydockCommandError' => 'Phobject',
'DrydockCommandInterface' => 'DrydockInterface',
'DrydockCommandQuery' => 'DrydockQuery',
+ 'DrydockConduitAPIMethod' => 'ConduitAPIMethod',
'DrydockConsoleController' => 'DrydockController',
'DrydockConstants' => 'Phobject',
'DrydockController' => 'PhabricatorController',
'DrydockCreateBlueprintsCapability' => 'PhabricatorPolicyCapability',
+ 'DrydockCreateLeaseConduitAPIMethod' => 'DrydockConduitAPIMethod',
'DrydockDAO' => 'PhabricatorLiskDAO',
'DrydockDefaultEditCapability' => 'PhabricatorPolicyCapability',
'DrydockDefaultViewCapability' => 'PhabricatorPolicyCapability',
+ 'DrydockDestroyLeaseConduitAPIMethod' => 'DrydockConduitAPIMethod',
'DrydockFilesystemInterface' => 'DrydockInterface',
'DrydockInterface' => 'Phobject',
'DrydockLandRepositoryOperation' => 'DrydockRepositoryOperationType',
@@ -5561,6 +5568,7 @@
'DrydockRepositoryOperationType' => 'Phobject',
'DrydockRepositoryOperationUpdateWorker' => 'DrydockWorker',
'DrydockRepositoryOperationViewController' => 'DrydockRepositoryOperationController',
+ 'DrydockRequestAuthorizationConduitAPIMethod' => 'DrydockConduitAPIMethod',
'DrydockResource' => array(
'DrydockDAO',
'PhabricatorPolicyInterface',
diff --git a/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php b/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php
--- a/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php
+++ b/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php
@@ -15,6 +15,27 @@
abstract public function getBlueprintName();
abstract public function getDescription();
+ public function getSummary() {
+ return $this->getDescription();
+ }
+
+ public function getLeaseAttributesSpecification() {
+ return null;
+ }
+
+ public function getLeaseAttributesDescriptions() {
+ throw new PhutilMethodNotImplementedException();
+ }
+
+ public function validateLeaseAttributes(array $lease_attributes) {
+ $attribute_spec = $this->getLeaseAttributesSpecification();
+ PhutilTypeSpec::checkMap($lease_attributes, $attribute_spec);
+ }
+
+ public function getLeaseAttributesDataExample() {
+ return null;
+ }
+
public function getBlueprintIcon() {
return 'fa-map-o';
}
diff --git a/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php b/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php
--- a/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php
+++ b/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php
@@ -23,6 +23,37 @@
return pht('Allows Drydock to check out working copies of repositories.');
}
+ public function getLeaseAttributesSpecification() {
+ return array(
+ 'repositories.map' => 'map<string, map<string, wild>>',
+ 'repositories.strict' => 'optional bool',
+ );
+ }
+
+ public function getLeaseAttributesDescriptions() {
+ return array(
+ 'repositories.map' => pht(
+ 'Maps clone folder names to information about what repositories they '.
+ 'should contain and what state those repositories should be in.'),
+ 'repositories.strict' => pht(
+ 'Set to true in order to force the working copy to contain only '.
+ 'the repositories specified.'),
+ );
+ }
+
+ public function getLeaseAttributesDataExample() {
+ return array(
+ 'repositories.map' => array(
+ 'janitorial-services' => array(
+ 'phid' => 'PHID-REPO-gb3x27pjw4wffij3od44',
+ 'default' => true,
+ 'commit' => '3a66dac400a50632f442aed6cb8cf65c80e5ae70',
+ ),
+ ),
+ 'repositories.strict' => true,
+ );
+ }
+
public function canAnyBlueprintEverAllocateResourceForLease(
DrydockLease $lease) {
return true;
diff --git a/src/applications/drydock/conduit/DrydockConduitAPIMethod.php b/src/applications/drydock/conduit/DrydockConduitAPIMethod.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/conduit/DrydockConduitAPIMethod.php
@@ -0,0 +1,18 @@
+<?php
+
+abstract class DrydockConduitAPIMethod extends ConduitAPIMethod {
+
+ final public function getApplication() {
+ return PhabricatorApplication::getByClass(
+ 'PhabricatorDrydockApplication');
+ }
+
+ public function getMethodStatus() {
+ return self::METHOD_STATUS_UNSTABLE;
+ }
+
+ public function getMethodStatusDescription() {
+ return pht('All Drydock APIs are new and subject to change.');
+ }
+
+}
diff --git a/src/applications/drydock/conduit/DrydockCreateLeaseConduitAPIMethod.php b/src/applications/drydock/conduit/DrydockCreateLeaseConduitAPIMethod.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/conduit/DrydockCreateLeaseConduitAPIMethod.php
@@ -0,0 +1,171 @@
+<?php
+
+final class DrydockCreateLeaseConduitAPIMethod
+ extends DrydockConduitAPIMethod {
+
+ public function getAPIMethodName() {
+ return 'drydock.createlease';
+ }
+
+ public function getMethodSummary() {
+ return pht('Lease a Drydock resource.');
+ }
+
+ public function getMethodDescription() {
+ $implementations =
+ DrydockBlueprintImplementation::getAllBlueprintImplementations();
+ $implementations = mfilter($implementations, 'isEnabled');
+
+ $head_class = pht('Class');
+ $head_type = pht('Type');
+ $head_name = pht('Name');
+ $head_desc = pht('Summary');
+
+ $out = array();
+ $out[] = pht(
+ 'This method leases a Drydock resource using an existing Drydock '.
+ 'blueprint. Before using a blueprint here, you must obtain '.
+ 'authorization for its use. You can request authorizations by calling '.
+ '`drydock.requestauthorization`.');
+ $out[] = null;
+ $out[] = pht(
+ 'When leasing a resource via a blueprint, the implementation class for '.
+ 'that blueprint determines what type of resource is leased. The '.
+ 'following blueprint implementation classes are supported:');
+
+ $out[] = "| {$head_class} | {$head_type} | {$head_name} | {$head_desc} |";
+ $out[] = '|---------------|--------------|--------------|--------------|';
+ foreach ($implementations as $class => $implementation) {
+ $type = $implementation->getType();
+ $name = $implementation->getBlueprintName();
+ $desc = $implementation->getSummary();
+ $out[] = "| `{$class}` | `{$type}` | **{$name}** | {$desc} |";
+ }
+
+ $out[] = null;
+ $out[] = pht(
+ 'Some blueprint implementations also define attributes which should '.
+ 'be provided when leasing resources. You should provide these '.
+ 'attributes using the `leaseAttributes` parameter when calling '.
+ 'this method. The attributes you provide depend on the implementation '.
+ 'class for the blueprint you are using.');
+
+ $head_key = pht('Key');
+
+ foreach ($implementations as $class => $implementation) {
+ $type = $implementation->getType();
+ $name = $implementation->getBlueprintName();
+
+ $out[] = "== {$name} ==";
+ $out[] = null;
+ $out[] = $implementation->getDescription();
+ $out[] = null;
+ $out[] = pht(
+ 'Blueprints with implementations of class `%s` will lease '.
+ 'resources of the `%s` type.',
+ $class,
+ $type);
+ $out[] = null;
+
+ $spec = $implementation->getLeaseAttributesSpecification();
+ if (!$spec) {
+ $out[] = pht(
+ '//(This implementation does not specify any lease attributes)//');
+ $out[] = null;
+ continue;
+ }
+
+ $desc = $implementation->getLeaseAttributesDescriptions();
+ $out[] = "| {$head_key} | {$head_type} | {$head_desc} |";
+ $out[] = '|-------------|--------------|--------------|';
+ foreach ($spec as $key => $key_type) {
+ $key_desc = idx($desc, $key);
+ $out[] = "| `{$key}` | //{$key_type}// | {$key_desc} |";
+ }
+
+ $example = $implementation->getLeaseAttributesDataExample();
+ if ($example !== null) {
+ $json = new PhutilJSON();
+ $rendered = $json->encodeFormatted($example);
+
+ $out[] = pht('For example:');
+ $out[] = '```lang=json';
+ $out[] = $rendered;
+ $out[] = '```';
+ }
+ }
+
+ return implode("\n", $out);
+ }
+
+ protected function defineParamTypes() {
+ return array(
+ 'blueprintPHID' => 'required phid',
+ 'leaseAttributes' => 'optional map<string, wild>',
+ );
+ }
+
+ protected function defineErrorTypes() {
+ return array(
+ 'ERR_NO_BLUEPRINT' => pht(
+ 'No active blueprint exists with the specified PHID.'),
+ 'ERR_NOT_AUTHORIZED' => pht(
+ 'You are not authorized to use this blueprint.'),
+ );
+ }
+
+ protected function defineReturnType() {
+ return 'wild';
+ }
+
+ protected function execute(ConduitAPIRequest $request) {
+ $viewer = $request->getUser();
+ $blueprint_phid = $request->getValue('blueprintPHID');
+ $blueprint = id(new DrydockBlueprintQuery())
+ ->setViewer($viewer)
+ ->withDisabled(false)
+ ->withPHIDs(array($blueprint_phid))
+ ->executeOne();
+ if (!$blueprint) {
+ throw new ConduitException('ERR_NO_BLUEPRINT');
+ }
+
+ $authorization = id(new DrydockAuthorizationQuery())
+ ->setViewer($viewer)
+ ->withBlueprintPHIDs(array($blueprint_phid))
+ ->withObjectPHIDs(array($viewer->getPHID()))
+ ->withBlueprintStates(array(
+ DrydockAuthorization::BLUEPRINTAUTH_AUTHORIZED,
+ ))
+ ->withObjectStates(array(DrydockAuthorization::OBJECTAUTH_ACTIVE))
+ ->executeOne();
+ if (!$authorization) {
+ throw new ConduitException('ERR_NOT_AUTHORIZED');
+ }
+
+ $implementation = $blueprint->getImplementation();
+ $lease = id(new DrydockLease())
+ ->setOwnerPHID($viewer->getPHID())
+ ->setResourceType($implementation->getType())
+ ->setAuthorizingPHID($viewer->getPHID())
+ ->setAllowedBlueprintPHIDs(array($blueprint_phid));
+
+ $lease_attributes = $request->getValue('leaseAttributes', array());
+ $implementation->validateLeaseAttributes($lease_attributes);
+ foreach ($lease_attributes as $key => $value) {
+ $lease->setAttribute($key, $value);
+ }
+
+ $lease->queueForActivation();
+
+ $search = id(new ConduitCall('drydock.lease.search', array(
+ 'constraints' => array(
+ 'phids' => array($lease->getPHID()),
+ ),
+ )))
+ ->setUser($viewer)
+ ->execute();
+ return idxv($search, array('data', 0));
+ }
+
+}
diff --git a/src/applications/drydock/conduit/DrydockDestroyLeaseConduitAPIMethod.php b/src/applications/drydock/conduit/DrydockDestroyLeaseConduitAPIMethod.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/conduit/DrydockDestroyLeaseConduitAPIMethod.php
@@ -0,0 +1,63 @@
+<?php
+
+final class DrydockDestroyLeaseConduitAPIMethod
+ extends DrydockConduitAPIMethod {
+
+ public function getAPIMethodName() {
+ return 'drydock.destroylease';
+ }
+
+ public function getMethodDescription() {
+ return pht('Destroy a Drydock lease.');
+ }
+
+ protected function defineParamTypes() {
+ return array(
+ 'leasePHID' => 'required phid',
+ );
+ }
+
+ protected function defineErrorTypes() {
+ return array(
+ 'ERR_NO_LEASE' => pht('No active lease exists with this ID.'),
+ 'ERR_NOT_AUTHORIZED' => pht(
+ 'You are not authorized to destroy this lease.'),
+ );
+ }
+
+ protected function defineReturnType() {
+ return 'map<string, wild>';
+ }
+
+ protected function execute(ConduitAPIRequest $request) {
+ $viewer = $request->getUser();
+ $lease = id(new DrydockLeaseQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($request->getValue('leasePHID')))
+ ->executeOne();
+ if (!$lease) {
+ throw new ConduitException('ERR_NO_LEASE');
+ }
+
+ if ($lease->getOwnerPHID() !== $viewer->getPHID()) {
+ throw new ConduitException('ERR_NOT_AUTHORIZED');
+ }
+
+ $command = DrydockCommand::initializeNewCommand($viewer)
+ ->setTargetPHID($lease->getPHID())
+ ->setCommand(DrydockCommand::COMMAND_RELEASE)
+ ->save();
+
+ $lease->scheduleUpdate();
+
+ $search = id(new ConduitCall('drydock.lease.search', array(
+ 'constraints' => array(
+ 'phids' => array($lease->getPHID()),
+ ),
+ )))
+ ->setUser($viewer)
+ ->execute();
+ return idxv($search, array('data', 0));
+ }
+
+}
diff --git a/src/applications/drydock/conduit/DrydockRequestAuthorizationConduitAPIMethod.php b/src/applications/drydock/conduit/DrydockRequestAuthorizationConduitAPIMethod.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/conduit/DrydockRequestAuthorizationConduitAPIMethod.php
@@ -0,0 +1,73 @@
+<?php
+
+final class DrydockRequestAuthorizationConduitAPIMethod
+ extends DrydockConduitAPIMethod {
+
+ public function getAPIMethodName() {
+ return 'drydock.requestauthorization';
+ }
+
+ public function getMethodDescription() {
+ return pht('Request permission to use a Drydock blueprint.');
+ }
+
+ protected function defineParamTypes() {
+ return array(
+ 'blueprintPHID' => 'required phid',
+ );
+ }
+
+ protected function defineErrorTypes() {
+ return array(
+ 'ERR_NO_BLUEPRINT' => pht(
+ 'No active blueprint exists with the specified PHID.'),
+ );
+ }
+
+ protected function defineReturnType() {
+ return 'map<string, wild>';
+ }
+
+ protected function execute(ConduitAPIRequest $request) {
+ $viewer = $request->getUser();
+ $blueprint_phid = $request->getValue('blueprintPHID');
+ $blueprint = id(new DrydockBlueprintQuery())
+ ->setViewer($viewer)
+ ->withDisabled(false)
+ ->withPHIDs(array($blueprint_phid))
+ ->executeOne();
+ if (!$blueprint) {
+ throw new ConduitException('ERR_NO_BLUEPRINT');
+ }
+
+ $authorizations = id(new DrydockAuthorizationQuery())
+ ->setViewer($viewer)
+ ->withObjectPHIDs(array($viewer->getPHID()))
+ ->withBlueprintStates(array(
+ DrydockAuthorization::BLUEPRINTAUTH_AUTHORIZED,
+ ))
+ ->withObjectStates(array(DrydockAuthorization::OBJECTAUTH_ACTIVE))
+ ->execute();
+ $authorizations = mpull($authorizations, null, 'getBlueprintPHID');
+ $old = array_keys($authorizations);
+ if (!in_array($blueprint_phid, $old)) {
+ $new = array_mergev(array($old, array($blueprint_phid)));
+ DrydockAuthorization::applyAuthorizationChanges(
+ $viewer,
+ $viewer->getPHID(),
+ $old,
+ $new);
+ }
+
+ $search = id(new ConduitCall('drydock.authorization.search', array(
+ 'constraints' => array(
+ 'objectPHIDs' => array($viewer->getPHID()),
+ 'blueprintPHIDs' => array($blueprint_phid),
+ ),
+ )))
+ ->setUser($viewer)
+ ->execute();
+ return idxv($search, array('data', 0));
+ }
+
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Mar 14, 8:11 PM (2 w, 3 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7317028
Default Alt Text
D16565.id39942.diff (17 KB)
Attached To
Mode
D16565: Expose Drydock lease management from conduit
Attached
Detach File
Event Timeline
Log In to Comment