Page MenuHomePhabricator

D16565.diff
No OneTemporary

D16565.diff

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

Mime Type
text/plain
Expires
Sat, May 11, 4:07 AM (3 w, 11 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6273122
Default Alt Text
D16565.diff (17 KB)

Event Timeline