Page MenuHomePhabricator

D14254.id34416.diff
No OneTemporary

D14254.id34416.diff

diff --git a/resources/sql/autopatches/20151010.drydock.auth.2.sql b/resources/sql/autopatches/20151010.drydock.auth.2.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20151010.drydock.auth.2.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {$NAMESPACE}_drydock.drydock_lease
+ ADD authorizingPHID VARBINARY(64) NOT NULL;
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
@@ -847,6 +847,8 @@
'DrydockLeaseDestroyedLogType' => 'applications/drydock/logtype/DrydockLeaseDestroyedLogType.php',
'DrydockLeaseListController' => 'applications/drydock/controller/DrydockLeaseListController.php',
'DrydockLeaseListView' => 'applications/drydock/view/DrydockLeaseListView.php',
+ 'DrydockLeaseNoAuthorizationsLogType' => 'applications/drydock/logtype/DrydockLeaseNoAuthorizationsLogType.php',
+ 'DrydockLeaseNoBlueprintsLogType' => 'applications/drydock/logtype/DrydockLeaseNoBlueprintsLogType.php',
'DrydockLeasePHIDType' => 'applications/drydock/phid/DrydockLeasePHIDType.php',
'DrydockLeaseQuery' => 'applications/drydock/query/DrydockLeaseQuery.php',
'DrydockLeaseQueuedLogType' => 'applications/drydock/logtype/DrydockLeaseQueuedLogType.php',
@@ -4611,6 +4613,8 @@
'DrydockLeaseDestroyedLogType' => 'DrydockLogType',
'DrydockLeaseListController' => 'DrydockLeaseController',
'DrydockLeaseListView' => 'AphrontView',
+ 'DrydockLeaseNoAuthorizationsLogType' => 'DrydockLogType',
+ 'DrydockLeaseNoBlueprintsLogType' => 'DrydockLogType',
'DrydockLeasePHIDType' => 'PhabricatorPHIDType',
'DrydockLeaseQuery' => 'DrydockQuery',
'DrydockLeaseQueuedLogType' => 'DrydockLogType',
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
@@ -292,7 +292,8 @@
}
protected function newLease(DrydockBlueprint $blueprint) {
- return DrydockLease::initializeNewLease();
+ return DrydockLease::initializeNewLease()
+ ->setAuthorizingPHID($blueprint->getPHID());
}
protected function requireActiveLease(DrydockLease $lease) {
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
@@ -118,10 +118,13 @@
$resource_phid = $resource->getPHID();
+ $blueprint_phids = $blueprint->getFieldValue('blueprintPHIDs');
+
$host_lease = $this->newLease($blueprint)
->setResourceType('host')
->setOwnerPHID($resource_phid)
- ->setAttribute('workingcopy.resourcePHID', $resource_phid);
+ ->setAttribute('workingcopy.resourcePHID', $resource_phid)
+ ->setAllowedBlueprintPHIDs($blueprint_phids);
$resource
->setAttribute('host.leasePHID', $host_lease->getPHID())
diff --git a/src/applications/drydock/controller/DrydockLeaseViewController.php b/src/applications/drydock/controller/DrydockLeaseViewController.php
--- a/src/applications/drydock/controller/DrydockLeaseViewController.php
+++ b/src/applications/drydock/controller/DrydockLeaseViewController.php
@@ -116,6 +116,14 @@
}
$view->addProperty(pht('Owner'), $owner_display);
+ $authorizing_phid = $lease->getAuthorizingPHID();
+ if ($authorizing_phid) {
+ $authorizing_display = $viewer->renderHandle($authorizing_phid);
+ } else {
+ $authorizing_display = phutil_tag('em', array(), pht('None'));
+ }
+ $view->addProperty(pht('Authorized By'), $authorizing_display);
+
$resource_phid = $lease->getResourcePHID();
if ($resource_phid) {
$resource_display = $viewer->renderHandle($resource_phid);
diff --git a/src/applications/drydock/logtype/DrydockLeaseNoAuthorizationsLogType.php b/src/applications/drydock/logtype/DrydockLeaseNoAuthorizationsLogType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/logtype/DrydockLeaseNoAuthorizationsLogType.php
@@ -0,0 +1,26 @@
+<?php
+
+final class DrydockLeaseNoAuthorizationsLogType extends DrydockLogType {
+
+ const LOGCONST = 'core.lease.no-authorizations';
+
+ public function getLogTypeName() {
+ return pht('No Authorizations');
+ }
+
+ public function getLogTypeIcon(array $data) {
+ return 'fa-map-o red';
+ }
+
+ public function renderLog(array $data) {
+ $viewer = $this->getViewer();
+ $authorizing_phid = idx($data, 'authorizingPHID');
+
+ return pht(
+ 'The object which authorized this lease (%s) is not authorized to use '.
+ 'any of the blueprints the lease lists. Approve the authorizations '.
+ 'before using the lease.',
+ $viewer->renderHandle($authorizing_phid)->render());
+ }
+
+}
diff --git a/src/applications/drydock/logtype/DrydockLeaseNoBlueprintsLogType.php b/src/applications/drydock/logtype/DrydockLeaseNoBlueprintsLogType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/logtype/DrydockLeaseNoBlueprintsLogType.php
@@ -0,0 +1,19 @@
+<?php
+
+final class DrydockLeaseNoBlueprintsLogType extends DrydockLogType {
+
+ const LOGCONST = 'core.lease.no-blueprints';
+
+ public function getLogTypeName() {
+ return pht('No Blueprints');
+ }
+
+ public function getLogTypeIcon(array $data) {
+ return 'fa-map-o red';
+ }
+
+ public function renderLog(array $data) {
+ return pht('This lease does not list any usable blueprints.');
+ }
+
+}
diff --git a/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php b/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php
--- a/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php
+++ b/src/applications/drydock/management/DrydockManagementLeaseWorkflow.php
@@ -28,7 +28,7 @@
}
public function execute(PhutilArgumentParser $args) {
- $console = PhutilConsole::getConsole();
+ $viewer = $this->getViewer();
$resource_type = $args->getArg('type');
if (!$resource_type) {
@@ -59,6 +59,23 @@
$lease = id(new DrydockLease())
->setResourceType($resource_type);
+ $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID();
+ $lease->setAuthorizingPHID($drydock_phid);
+
+ // TODO: This is not hugely scalable, although this is a debugging workflow
+ // so maybe it's fine. Do we even need `bin/drydock lease` in the long run?
+ $all_blueprints = id(new DrydockBlueprintQuery())
+ ->setViewer($viewer)
+ ->execute();
+ $allowed_phids = mpull($all_blueprints, 'getPHID');
+ if (!$allowed_phids) {
+ throw new Exception(
+ pht(
+ 'No blueprints exist which can plausibly allocate resources to '.
+ 'satisfy the requested lease.'));
+ }
+ $lease->setAllowedBlueprintPHIDs($allowed_phids);
+
if ($attributes) {
$lease->setAttributes($attributes);
}
diff --git a/src/applications/drydock/phid/DrydockBlueprintPHIDType.php b/src/applications/drydock/phid/DrydockBlueprintPHIDType.php
--- a/src/applications/drydock/phid/DrydockBlueprintPHIDType.php
+++ b/src/applications/drydock/phid/DrydockBlueprintPHIDType.php
@@ -8,6 +8,14 @@
return pht('Blueprint');
}
+ public function getPHIDTypeApplicationClass() {
+ return 'PhabricatorDrydockApplication';
+ }
+
+ public function getTypeIcon() {
+ return 'fa-map-o';
+ }
+
public function newObject() {
return new DrydockBlueprint();
}
diff --git a/src/applications/drydock/phid/DrydockLeasePHIDType.php b/src/applications/drydock/phid/DrydockLeasePHIDType.php
--- a/src/applications/drydock/phid/DrydockLeasePHIDType.php
+++ b/src/applications/drydock/phid/DrydockLeasePHIDType.php
@@ -8,6 +8,14 @@
return pht('Drydock Lease');
}
+ public function getPHIDTypeApplicationClass() {
+ return 'PhabricatorDrydockApplication';
+ }
+
+ public function getTypeIcon() {
+ return 'fa-link';
+ }
+
public function newObject() {
return new DrydockLease();
}
diff --git a/src/applications/drydock/phid/DrydockResourcePHIDType.php b/src/applications/drydock/phid/DrydockResourcePHIDType.php
--- a/src/applications/drydock/phid/DrydockResourcePHIDType.php
+++ b/src/applications/drydock/phid/DrydockResourcePHIDType.php
@@ -8,6 +8,14 @@
return pht('Drydock Resource');
}
+ public function getPHIDTypeApplicationClass() {
+ return 'PhabricatorDrydockApplication';
+ }
+
+ public function getTypeIcon() {
+ return 'fa-map';
+ }
+
public function newObject() {
return new DrydockResource();
}
diff --git a/src/applications/drydock/query/DrydockBlueprintQuery.php b/src/applications/drydock/query/DrydockBlueprintQuery.php
--- a/src/applications/drydock/query/DrydockBlueprintQuery.php
+++ b/src/applications/drydock/query/DrydockBlueprintQuery.php
@@ -7,6 +7,7 @@
private $blueprintClasses;
private $datasourceQuery;
private $disabled;
+ private $authorizedPHIDs;
public function withIDs(array $ids) {
$this->ids = $ids;
@@ -33,10 +34,19 @@
return $this;
}
+ public function withAuthorizedPHIDs(array $phids) {
+ $this->authorizedPHIDs = $phids;
+ return $this;
+ }
+
public function newResultObject() {
return new DrydockBlueprint();
}
+ protected function getPrimaryTableAlias() {
+ return 'blueprint';
+ }
+
protected function loadPage() {
return $this->loadStandardPage($this->newResultObject());
}
@@ -63,39 +73,66 @@
if ($this->ids !== null) {
$where[] = qsprintf(
$conn,
- 'id IN (%Ld)',
+ 'blueprint.id IN (%Ld)',
$this->ids);
}
if ($this->phids !== null) {
$where[] = qsprintf(
$conn,
- 'phid IN (%Ls)',
+ 'blueprint.phid IN (%Ls)',
$this->phids);
}
if ($this->datasourceQuery !== null) {
$where[] = qsprintf(
$conn,
- 'blueprintName LIKE %>',
+ 'blueprint.blueprintName LIKE %>',
$this->datasourceQuery);
}
if ($this->blueprintClasses !== null) {
$where[] = qsprintf(
$conn,
- 'className IN (%Ls)',
+ 'blueprint.className IN (%Ls)',
$this->blueprintClasses);
}
if ($this->disabled !== null) {
$where[] = qsprintf(
$conn,
- 'isDisabled = %d',
+ 'blueprint.isDisabled = %d',
(int)$this->disabled);
}
return $where;
}
+ protected function shouldGroupQueryResultRows() {
+ if ($this->authorizedPHIDs !== null) {
+ return true;
+ }
+ return parent::shouldGroupQueryResultRows();
+ }
+
+ protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
+ $joins = parent::buildJoinClauseParts($conn);
+
+ if ($this->authorizedPHIDs !== null) {
+ $joins[] = qsprintf(
+ $conn,
+ 'JOIN %T authorization
+ ON authorization.blueprintPHID = blueprint.phid
+ AND authorization.objectPHID IN (%Ls)
+ AND authorization.objectAuthorizationState = %s
+ AND authorization.blueprintAuthorizationState = %s',
+ id(new DrydockAuthorization())->getTableName(),
+ $this->authorizedPHIDs,
+ DrydockAuthorization::OBJECTAUTH_ACTIVE,
+ DrydockAuthorization::BLUEPRINTAUTH_AUTHORIZED);
+ }
+
+ return $joins;
+ }
+
}
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
@@ -7,6 +7,7 @@
protected $resourceType;
protected $until;
protected $ownerPHID;
+ protected $authorizingPHID;
protected $attributes = array();
protected $status = DrydockLeaseStatus::STATUS_PENDING;
@@ -141,6 +142,25 @@
pht('Only new leases may be queued for activation!'));
}
+ if (!$this->getAuthorizingPHID()) {
+ throw new Exception(
+ pht(
+ 'Trying to queue a lease for activation without an authorizing '.
+ 'object. Use "%s" to specify the PHID of the authorizing object. '.
+ 'The authorizing object must be approved to use the allowed '.
+ 'blueprints.',
+ 'setAuthorizingPHID()'));
+ }
+
+ if (!$this->getAllowedBlueprintPHIDs()) {
+ throw new Exception(
+ pht(
+ 'Trying to queue a lease for activation without any allowed '.
+ 'Blueprints. Use "%s" to specify allowed blueprints. The '.
+ 'authorizing object must be approved to use the allowed blueprints.',
+ 'setAllowedBlueprintPHIDs()'));
+ }
+
$this
->setStatus(DrydockLeaseStatus::STATUS_PENDING)
->save();
@@ -376,6 +396,15 @@
return $this;
}
+ public function setAllowedBlueprintPHIDs(array $phids) {
+ $this->setAttribute('internal.blueprintPHIDs', $phids);
+ return $this;
+ }
+
+ public function getAllowedBlueprintPHIDs() {
+ return $this->getAttribute('internal.blueprintPHIDs', array());
+ }
+
private function didActivate() {
$viewer = PhabricatorUser::getOmnipotentUser();
$need_update = false;
diff --git a/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php b/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php
--- a/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php
+++ b/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php
@@ -300,11 +300,46 @@
return array();
}
- $blueprints = id(new DrydockBlueprintQuery())
+ $query = id(new DrydockBlueprintQuery())
->setViewer($viewer)
->withBlueprintClasses(array_keys($impls))
- ->withDisabled(false)
- ->execute();
+ ->withDisabled(false);
+
+ $blueprint_phids = $lease->getAllowedBlueprintPHIDs();
+ if (!$blueprint_phids) {
+ $lease->logEvent(DrydockLeaseNoBlueprintsLogType::LOGCONST);
+ return array();
+ }
+
+ // The Drydock application itself is allowed to authorize anything. This
+ // is primarily used for leases generated by CLI administrative tools.
+ $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID();
+
+ $authorizing_phid = $lease->getAuthorizingPHID();
+ if ($authorizing_phid != $drydock_phid) {
+ $blueprints = id(clone $query)
+ ->withAuthorizedPHIDs(array($authorizing_phid))
+ ->execute();
+ if (!$blueprints) {
+ // If we didn't hit any blueprints, check if this is an authorization
+ // problem: re-execute the query without the authorization constraint.
+ // If the second query hits blueprints, the overall configuration is
+ // fine but this is an authorization problem. If the second query also
+ // comes up blank, this is some other kind of configuration issue so
+ // we fall through to the default pathway.
+ $all_blueprints = $query->execute();
+ if ($all_blueprints) {
+ $lease->logEvent(
+ DrydockLeaseNoAuthorizationsLogType::LOGCONST,
+ array(
+ 'authorizingPHID' => $authorizing_phid,
+ ));
+ return array();
+ }
+ }
+ } else {
+ $blueprints = $query->execute();
+ }
$keep = array();
foreach ($blueprints as $key => $blueprint) {
diff --git a/src/applications/harbormaster/customfield/HarbormasterBuildStepCoreCustomField.php b/src/applications/harbormaster/customfield/HarbormasterBuildStepCoreCustomField.php
--- a/src/applications/harbormaster/customfield/HarbormasterBuildStepCoreCustomField.php
+++ b/src/applications/harbormaster/customfield/HarbormasterBuildStepCoreCustomField.php
@@ -67,11 +67,6 @@
$object->setDetail($key, $value);
}
- public function applyApplicationTransactionExternalEffects(
- PhabricatorApplicationTransaction $xaction) {
- return;
- }
-
public function getBuildTargetFieldValue() {
return $this->getProxy()->getFieldValue();
}
diff --git a/src/applications/harbormaster/phid/HarbormasterBuildStepPHIDType.php b/src/applications/harbormaster/phid/HarbormasterBuildStepPHIDType.php
--- a/src/applications/harbormaster/phid/HarbormasterBuildStepPHIDType.php
+++ b/src/applications/harbormaster/phid/HarbormasterBuildStepPHIDType.php
@@ -28,9 +28,13 @@
foreach ($handles as $phid => $handle) {
$build_step = $objects[$phid];
+ $id = $build_step->getID();
$name = $build_step->getName();
- $handle->setName($name);
+ $handle
+ ->setName($name)
+ ->setFullName(pht('Build Step %d: %s', $id, $name))
+ ->setURI("/harbormaster/step/{$id}/edit/");
}
}
diff --git a/src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php b/src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php
--- a/src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php
+++ b/src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php
@@ -41,9 +41,14 @@
$working_copy_type = id(new DrydockWorkingCopyBlueprintImplementation())
->getType();
+ $allowed_phids = $build_target->getFieldValue('repositoryPHIDs');
+ $authorizing_phid = $build_target->getBuildStep()->getPHID();
+
$lease = DrydockLease::initializeNewLease()
->setResourceType($working_copy_type)
- ->setOwnerPHID($build_target->getPHID());
+ ->setOwnerPHID($build_target->getPHID())
+ ->setAuthorizingPHID($authorizing_phid)
+ ->setAllowedBlueprintPHIDs($allowed_phids);
$map = $this->buildRepositoryMap($build_target);
@@ -104,6 +109,11 @@
'type' => 'text',
'required' => true,
),
+ 'blueprintPHIDs' => array(
+ 'name' => pht('Use Blueprints'),
+ 'type' => 'blueprints',
+ 'required' => true,
+ ),
'repositoryPHIDs' => array(
'name' => pht('Also Clone'),
'type' => 'datasource',

File Metadata

Mime Type
text/plain
Expires
Fri, May 10, 1:28 PM (3 w, 3 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6283272
Default Alt Text
D14254.id34416.diff (17 KB)

Event Timeline