mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-29 10:12:41 +01:00
Restructure Drydock so that blueprints are instances in the DB
Summary: //(this diff used to be about applying policies to blueprints)// This restructures Drydock so that blueprints are instances in the DB, with an associated implementation class. Thus resources now have a `blueprintPHID` instead of `blueprintClass` and DrydockBlueprint becomes a DAO. The old DrydockBlueprint is renamed to DrydockBlueprintImplementation, and the DrydockBlueprint DAO has a `blueprintClass` column on it. This now just implements CAN_VIEW and CAN_EDIT policies for blueprints, although they are probably not enforced in all of the places they could be. Test Plan: Used the `create-resource` and `lease` commands. Closed resources and leases in the UI. Clicked around the new and old lists to make sure everything is still working. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley CC: Korvin, epriestley, aran Maniphest Tasks: T4111, T2015 Differential Revision: https://secure.phabricator.com/D7638
This commit is contained in:
parent
f93c6985ad
commit
ba16df0fed
25 changed files with 729 additions and 41 deletions
11
resources/sql/patches/20131123.drydockblueprintpolicy.sql
Normal file
11
resources/sql/patches/20131123.drydockblueprintpolicy.sql
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_drydock.drydock_blueprint (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
phid VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||||
|
className VARCHAR(255) NOT NULL COLLATE utf8_bin,
|
||||||
|
viewPolicy VARCHAR(64) NOT NULL,
|
||||||
|
editPolicy VARCHAR(64) NOT NULL,
|
||||||
|
details LONGTEXT CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
UNIQUE KEY `key_phid` (phid)
|
||||||
|
) ENGINE=InnoDB, COLLATE utf8_general_ci;
|
|
@ -0,0 +1,5 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_drydock.drydock_resource
|
||||||
|
ADD COLUMN blueprintPHID VARCHAR(64) NOT NULL COLLATE utf8_bin;
|
||||||
|
|
||||||
|
ALTER TABLE {$NAMESPACE}_drydock.drydock_resource
|
||||||
|
DROP COLUMN blueprintClass;
|
|
@ -626,8 +626,14 @@ phutil_register_library_map(array(
|
||||||
'DoorkeeperTagsController' => 'applications/doorkeeper/controller/DoorkeeperTagsController.php',
|
'DoorkeeperTagsController' => 'applications/doorkeeper/controller/DoorkeeperTagsController.php',
|
||||||
'DrydockAllocatorWorker' => 'applications/drydock/worker/DrydockAllocatorWorker.php',
|
'DrydockAllocatorWorker' => 'applications/drydock/worker/DrydockAllocatorWorker.php',
|
||||||
'DrydockApacheWebrootInterface' => 'applications/drydock/interface/webroot/DrydockApacheWebrootInterface.php',
|
'DrydockApacheWebrootInterface' => 'applications/drydock/interface/webroot/DrydockApacheWebrootInterface.php',
|
||||||
'DrydockBlueprint' => 'applications/drydock/blueprint/DrydockBlueprint.php',
|
'DrydockBlueprint' => 'applications/drydock/storage/DrydockBlueprint.php',
|
||||||
|
'DrydockBlueprintCreateController' => 'applications/drydock/controller/DrydockBlueprintCreateController.php',
|
||||||
|
'DrydockBlueprintEditController' => 'applications/drydock/controller/DrydockBlueprintEditController.php',
|
||||||
|
'DrydockBlueprintImplementation' => 'applications/drydock/blueprint/DrydockBlueprintImplementation.php',
|
||||||
|
'DrydockBlueprintListController' => 'applications/drydock/controller/DrydockBlueprintListController.php',
|
||||||
|
'DrydockBlueprintQuery' => 'applications/drydock/query/DrydockBlueprintQuery.php',
|
||||||
'DrydockBlueprintScopeGuard' => 'applications/drydock/util/DrydockBlueprintScopeGuard.php',
|
'DrydockBlueprintScopeGuard' => 'applications/drydock/util/DrydockBlueprintScopeGuard.php',
|
||||||
|
'DrydockBlueprintViewController' => 'applications/drydock/controller/DrydockBlueprintViewController.php',
|
||||||
'DrydockCommandInterface' => 'applications/drydock/interface/command/DrydockCommandInterface.php',
|
'DrydockCommandInterface' => 'applications/drydock/interface/command/DrydockCommandInterface.php',
|
||||||
'DrydockConstants' => 'applications/drydock/constants/DrydockConstants.php',
|
'DrydockConstants' => 'applications/drydock/constants/DrydockConstants.php',
|
||||||
'DrydockController' => 'applications/drydock/controller/DrydockController.php',
|
'DrydockController' => 'applications/drydock/controller/DrydockController.php',
|
||||||
|
@ -640,7 +646,7 @@ phutil_register_library_map(array(
|
||||||
'DrydockLeaseStatus' => 'applications/drydock/constants/DrydockLeaseStatus.php',
|
'DrydockLeaseStatus' => 'applications/drydock/constants/DrydockLeaseStatus.php',
|
||||||
'DrydockLeaseViewController' => 'applications/drydock/controller/DrydockLeaseViewController.php',
|
'DrydockLeaseViewController' => 'applications/drydock/controller/DrydockLeaseViewController.php',
|
||||||
'DrydockLocalCommandInterface' => 'applications/drydock/interface/command/DrydockLocalCommandInterface.php',
|
'DrydockLocalCommandInterface' => 'applications/drydock/interface/command/DrydockLocalCommandInterface.php',
|
||||||
'DrydockLocalHostBlueprint' => 'applications/drydock/blueprint/DrydockLocalHostBlueprint.php',
|
'DrydockLocalHostBlueprintImplementation' => 'applications/drydock/blueprint/DrydockLocalHostBlueprintImplementation.php',
|
||||||
'DrydockLog' => 'applications/drydock/storage/DrydockLog.php',
|
'DrydockLog' => 'applications/drydock/storage/DrydockLog.php',
|
||||||
'DrydockLogController' => 'applications/drydock/controller/DrydockLogController.php',
|
'DrydockLogController' => 'applications/drydock/controller/DrydockLogController.php',
|
||||||
'DrydockLogQuery' => 'applications/drydock/query/DrydockLogQuery.php',
|
'DrydockLogQuery' => 'applications/drydock/query/DrydockLogQuery.php',
|
||||||
|
@ -650,7 +656,8 @@ phutil_register_library_map(array(
|
||||||
'DrydockManagementReleaseWorkflow' => 'applications/drydock/management/DrydockManagementReleaseWorkflow.php',
|
'DrydockManagementReleaseWorkflow' => 'applications/drydock/management/DrydockManagementReleaseWorkflow.php',
|
||||||
'DrydockManagementWaitForLeaseWorkflow' => 'applications/drydock/management/DrydockManagementWaitForLeaseWorkflow.php',
|
'DrydockManagementWaitForLeaseWorkflow' => 'applications/drydock/management/DrydockManagementWaitForLeaseWorkflow.php',
|
||||||
'DrydockManagementWorkflow' => 'applications/drydock/management/DrydockManagementWorkflow.php',
|
'DrydockManagementWorkflow' => 'applications/drydock/management/DrydockManagementWorkflow.php',
|
||||||
'DrydockPreallocatedHostBlueprint' => 'applications/drydock/blueprint/DrydockPreallocatedHostBlueprint.php',
|
'DrydockPHIDTypeBlueprint' => 'applications/drydock/phid/DrydockPHIDTypeBlueprint.php',
|
||||||
|
'DrydockPreallocatedHostBlueprintImplementation' => 'applications/drydock/blueprint/DrydockPreallocatedHostBlueprintImplementation.php',
|
||||||
'DrydockResource' => 'applications/drydock/storage/DrydockResource.php',
|
'DrydockResource' => 'applications/drydock/storage/DrydockResource.php',
|
||||||
'DrydockResourceCloseController' => 'applications/drydock/controller/DrydockResourceCloseController.php',
|
'DrydockResourceCloseController' => 'applications/drydock/controller/DrydockResourceCloseController.php',
|
||||||
'DrydockResourceListController' => 'applications/drydock/controller/DrydockResourceListController.php',
|
'DrydockResourceListController' => 'applications/drydock/controller/DrydockResourceListController.php',
|
||||||
|
@ -659,7 +666,7 @@ phutil_register_library_map(array(
|
||||||
'DrydockResourceViewController' => 'applications/drydock/controller/DrydockResourceViewController.php',
|
'DrydockResourceViewController' => 'applications/drydock/controller/DrydockResourceViewController.php',
|
||||||
'DrydockSSHCommandInterface' => 'applications/drydock/interface/command/DrydockSSHCommandInterface.php',
|
'DrydockSSHCommandInterface' => 'applications/drydock/interface/command/DrydockSSHCommandInterface.php',
|
||||||
'DrydockWebrootInterface' => 'applications/drydock/interface/webroot/DrydockWebrootInterface.php',
|
'DrydockWebrootInterface' => 'applications/drydock/interface/webroot/DrydockWebrootInterface.php',
|
||||||
'DrydockWorkingCopyBlueprint' => 'applications/drydock/blueprint/DrydockWorkingCopyBlueprint.php',
|
'DrydockWorkingCopyBlueprintImplementation' => 'applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php',
|
||||||
'FeedPublisherHTTPWorker' => 'applications/feed/worker/FeedPublisherHTTPWorker.php',
|
'FeedPublisherHTTPWorker' => 'applications/feed/worker/FeedPublisherHTTPWorker.php',
|
||||||
'FeedPublisherWorker' => 'applications/feed/worker/FeedPublisherWorker.php',
|
'FeedPublisherWorker' => 'applications/feed/worker/FeedPublisherWorker.php',
|
||||||
'FeedPushWorker' => 'applications/feed/worker/FeedPushWorker.php',
|
'FeedPushWorker' => 'applications/feed/worker/FeedPushWorker.php',
|
||||||
|
@ -2951,6 +2958,16 @@ phutil_register_library_map(array(
|
||||||
'DoorkeeperTagsController' => 'PhabricatorController',
|
'DoorkeeperTagsController' => 'PhabricatorController',
|
||||||
'DrydockAllocatorWorker' => 'PhabricatorWorker',
|
'DrydockAllocatorWorker' => 'PhabricatorWorker',
|
||||||
'DrydockApacheWebrootInterface' => 'DrydockWebrootInterface',
|
'DrydockApacheWebrootInterface' => 'DrydockWebrootInterface',
|
||||||
|
'DrydockBlueprint' =>
|
||||||
|
array(
|
||||||
|
0 => 'DrydockDAO',
|
||||||
|
1 => 'PhabricatorPolicyInterface',
|
||||||
|
),
|
||||||
|
'DrydockBlueprintCreateController' => 'DrydockController',
|
||||||
|
'DrydockBlueprintEditController' => 'DrydockController',
|
||||||
|
'DrydockBlueprintListController' => 'DrydockController',
|
||||||
|
'DrydockBlueprintQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'DrydockBlueprintViewController' => 'DrydockController',
|
||||||
'DrydockCommandInterface' => 'DrydockInterface',
|
'DrydockCommandInterface' => 'DrydockInterface',
|
||||||
'DrydockController' => 'PhabricatorController',
|
'DrydockController' => 'PhabricatorController',
|
||||||
'DrydockDAO' => 'PhabricatorLiskDAO',
|
'DrydockDAO' => 'PhabricatorLiskDAO',
|
||||||
|
@ -2961,7 +2978,7 @@ phutil_register_library_map(array(
|
||||||
'DrydockLeaseStatus' => 'DrydockConstants',
|
'DrydockLeaseStatus' => 'DrydockConstants',
|
||||||
'DrydockLeaseViewController' => 'DrydockController',
|
'DrydockLeaseViewController' => 'DrydockController',
|
||||||
'DrydockLocalCommandInterface' => 'DrydockCommandInterface',
|
'DrydockLocalCommandInterface' => 'DrydockCommandInterface',
|
||||||
'DrydockLocalHostBlueprint' => 'DrydockBlueprint',
|
'DrydockLocalHostBlueprintImplementation' => 'DrydockBlueprintImplementation',
|
||||||
'DrydockLog' => 'DrydockDAO',
|
'DrydockLog' => 'DrydockDAO',
|
||||||
'DrydockLogController' => 'DrydockController',
|
'DrydockLogController' => 'DrydockController',
|
||||||
'DrydockLogQuery' => 'PhabricatorOffsetPagedQuery',
|
'DrydockLogQuery' => 'PhabricatorOffsetPagedQuery',
|
||||||
|
@ -2971,7 +2988,8 @@ phutil_register_library_map(array(
|
||||||
'DrydockManagementReleaseWorkflow' => 'DrydockManagementWorkflow',
|
'DrydockManagementReleaseWorkflow' => 'DrydockManagementWorkflow',
|
||||||
'DrydockManagementWaitForLeaseWorkflow' => 'DrydockManagementWorkflow',
|
'DrydockManagementWaitForLeaseWorkflow' => 'DrydockManagementWorkflow',
|
||||||
'DrydockManagementWorkflow' => 'PhutilArgumentWorkflow',
|
'DrydockManagementWorkflow' => 'PhutilArgumentWorkflow',
|
||||||
'DrydockPreallocatedHostBlueprint' => 'DrydockBlueprint',
|
'DrydockPHIDTypeBlueprint' => 'PhabricatorPHIDType',
|
||||||
|
'DrydockPreallocatedHostBlueprintImplementation' => 'DrydockBlueprintImplementation',
|
||||||
'DrydockResource' =>
|
'DrydockResource' =>
|
||||||
array(
|
array(
|
||||||
0 => 'DrydockDAO',
|
0 => 'DrydockDAO',
|
||||||
|
@ -2984,7 +3002,7 @@ phutil_register_library_map(array(
|
||||||
'DrydockResourceViewController' => 'DrydockController',
|
'DrydockResourceViewController' => 'DrydockController',
|
||||||
'DrydockSSHCommandInterface' => 'DrydockCommandInterface',
|
'DrydockSSHCommandInterface' => 'DrydockCommandInterface',
|
||||||
'DrydockWebrootInterface' => 'DrydockInterface',
|
'DrydockWebrootInterface' => 'DrydockInterface',
|
||||||
'DrydockWorkingCopyBlueprint' => 'DrydockBlueprint',
|
'DrydockWorkingCopyBlueprintImplementation' => 'DrydockBlueprintImplementation',
|
||||||
'FeedPublisherHTTPWorker' => 'FeedPushWorker',
|
'FeedPublisherHTTPWorker' => 'FeedPushWorker',
|
||||||
'FeedPublisherWorker' => 'FeedPushWorker',
|
'FeedPublisherWorker' => 'FeedPushWorker',
|
||||||
'FeedPushWorker' => 'PhabricatorWorker',
|
'FeedPushWorker' => 'PhabricatorWorker',
|
||||||
|
|
|
@ -34,6 +34,12 @@ final class PhabricatorApplicationDrydock extends PhabricatorApplication {
|
||||||
return array(
|
return array(
|
||||||
'/drydock/' => array(
|
'/drydock/' => array(
|
||||||
'' => 'DrydockResourceListController',
|
'' => 'DrydockResourceListController',
|
||||||
|
'blueprint/' => array(
|
||||||
|
'' => 'DrydockBlueprintListController',
|
||||||
|
'(?P<id>[1-9]\d*)/' => 'DrydockBlueprintViewController',
|
||||||
|
'create/' => 'DrydockBlueprintCreateController',
|
||||||
|
'edit/(?P<id>[1-9]\d*)/' => 'DrydockBlueprintEditController',
|
||||||
|
),
|
||||||
'resource/' => array(
|
'resource/' => array(
|
||||||
'' => 'DrydockResourceListController',
|
'' => 'DrydockResourceListController',
|
||||||
'(?P<id>[1-9]\d*)/' => 'DrydockResourceViewController',
|
'(?P<id>[1-9]\d*)/' => 'DrydockResourceViewController',
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
* @task resource Resource Allocation
|
* @task resource Resource Allocation
|
||||||
* @task log Logging
|
* @task log Logging
|
||||||
*/
|
*/
|
||||||
abstract class DrydockBlueprint {
|
abstract class DrydockBlueprintImplementation {
|
||||||
|
|
||||||
private $activeResource;
|
private $activeResource;
|
||||||
private $activeLease;
|
private $activeLease;
|
||||||
|
private $instance;
|
||||||
|
|
||||||
abstract public function getType();
|
abstract public function getType();
|
||||||
abstract public function getInterface(
|
abstract public function getInterface(
|
||||||
|
@ -18,6 +19,8 @@ abstract class DrydockBlueprint {
|
||||||
|
|
||||||
abstract public function isEnabled();
|
abstract public function isEnabled();
|
||||||
|
|
||||||
|
abstract public function getDescription();
|
||||||
|
|
||||||
public function getBlueprintClass() {
|
public function getBlueprintClass() {
|
||||||
return get_class($this);
|
return get_class($this);
|
||||||
}
|
}
|
||||||
|
@ -37,6 +40,20 @@ abstract class DrydockBlueprint {
|
||||||
return $lease;
|
return $lease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getInstance() {
|
||||||
|
if (!$this->instance) {
|
||||||
|
throw new Exception(
|
||||||
|
"Attach the blueprint instance to the implementation.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachInstance(DrydockBlueprint $instance) {
|
||||||
|
$this->instance = $instance;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( Lease Acquisition )-------------------------------------------------- */
|
/* -( Lease Acquisition )-------------------------------------------------- */
|
||||||
|
|
||||||
|
@ -343,13 +360,13 @@ abstract class DrydockBlueprint {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function getAllBlueprints() {
|
public static function getAllBlueprintImplementations() {
|
||||||
static $list = null;
|
static $list = null;
|
||||||
|
|
||||||
if ($list === null) {
|
if ($list === null) {
|
||||||
$blueprints = id(new PhutilSymbolLoader())
|
$blueprints = id(new PhutilSymbolLoader())
|
||||||
->setType('class')
|
->setType('class')
|
||||||
->setAncestorClass('DrydockBlueprint')
|
->setAncestorClass('DrydockBlueprintImplementation')
|
||||||
->setConcreteOnly(true)
|
->setConcreteOnly(true)
|
||||||
->selectAndLoadSymbols();
|
->selectAndLoadSymbols();
|
||||||
$list = ipull($blueprints, 'name', 'name');
|
$list = ipull($blueprints, 'name', 'name');
|
||||||
|
@ -361,16 +378,17 @@ abstract class DrydockBlueprint {
|
||||||
return $list;
|
return $list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getAllBlueprintsForResource($type) {
|
public static function getAllBlueprintImplementationsForResource($type) {
|
||||||
static $groups = null;
|
static $groups = null;
|
||||||
if ($groups === null) {
|
if ($groups === null) {
|
||||||
$groups = mgroup(self::getAllBlueprints(), 'getType');
|
$groups = mgroup(self::getAllBlueprintImplementations(), 'getType');
|
||||||
}
|
}
|
||||||
return idx($groups, $type, array());
|
return idx($groups, $type, array());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newResourceTemplate($name) {
|
protected function newResourceTemplate($name) {
|
||||||
$resource = new DrydockResource();
|
$resource = new DrydockResource();
|
||||||
|
$resource->setBlueprintPHID($this->getInstance()->getPHID());
|
||||||
$resource->setBlueprintClass($this->getBlueprintClass());
|
$resource->setBlueprintClass($this->getBlueprintClass());
|
||||||
$resource->setType($this->getType());
|
$resource->setType($this->getType());
|
||||||
$resource->setStatus(DrydockResourceStatus::STATUS_PENDING);
|
$resource->setStatus(DrydockResourceStatus::STATUS_PENDING);
|
|
@ -1,11 +1,16 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class DrydockLocalHostBlueprint extends DrydockBlueprint {
|
final class DrydockLocalHostBlueprintImplementation
|
||||||
|
extends DrydockBlueprintImplementation {
|
||||||
|
|
||||||
public function isEnabled() {
|
public function isEnabled() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDescription() {
|
||||||
|
return pht('Allocates storage on the local host.');
|
||||||
|
}
|
||||||
|
|
||||||
public function canAllocateMoreResources(array $pool) {
|
public function canAllocateMoreResources(array $pool) {
|
||||||
assert_instances_of($pool, 'DrydockResource');
|
assert_instances_of($pool, 'DrydockResource');
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class DrydockPreallocatedHostBlueprint extends DrydockBlueprint {
|
final class DrydockPreallocatedHostBlueprintImplementation
|
||||||
|
extends DrydockBlueprintImplementation {
|
||||||
|
|
||||||
public function isEnabled() {
|
public function isEnabled() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDescription() {
|
||||||
|
return pht('Leases out preallocated, remote hosts.');
|
||||||
|
}
|
||||||
|
|
||||||
public function canAllocateMoreResources(array $pool) {
|
public function canAllocateMoreResources(array $pool) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
|
@ -1,11 +1,16 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class DrydockWorkingCopyBlueprint extends DrydockBlueprint {
|
final class DrydockWorkingCopyBlueprintImplementation
|
||||||
|
extends DrydockBlueprintImplementation {
|
||||||
|
|
||||||
public function isEnabled() {
|
public function isEnabled() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDescription() {
|
||||||
|
return pht('Allocates out working copies of repositories.');
|
||||||
|
}
|
||||||
|
|
||||||
protected function canAllocateLease(
|
protected function canAllocateLease(
|
||||||
DrydockResource $resource,
|
DrydockResource $resource,
|
||||||
DrydockLease $lease) {
|
DrydockLease $lease) {
|
|
@ -0,0 +1,68 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DrydockBlueprintCreateController
|
||||||
|
extends DrydockController {
|
||||||
|
|
||||||
|
public function willProcessRequest(array $data) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processRequest() {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$viewer = $request->getUser();
|
||||||
|
|
||||||
|
$implementations =
|
||||||
|
DrydockBlueprintImplementation::getAllBlueprintImplementations();
|
||||||
|
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
$class = $request->getStr('blueprint-type');
|
||||||
|
if (!isset($implementations[$class])) {
|
||||||
|
return $this->createDialog($implementations);
|
||||||
|
}
|
||||||
|
|
||||||
|
$blueprint = new DrydockBlueprint();
|
||||||
|
$blueprint->setClassName($class);
|
||||||
|
$blueprint->setDetails(array());
|
||||||
|
$blueprint->setViewPolicy(PhabricatorPolicies::POLICY_ADMIN);
|
||||||
|
$blueprint->setEditPolicy(PhabricatorPolicies::POLICY_ADMIN);
|
||||||
|
$blueprint->save();
|
||||||
|
|
||||||
|
$edit_uri = $this->getApplicationURI(
|
||||||
|
"blueprint/edit/".$blueprint->getID()."/");
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($edit_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->createDialog($implementations);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDialog(array $implementations) {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$viewer = $request->getUser();
|
||||||
|
|
||||||
|
$control = id(new AphrontFormRadioButtonControl())
|
||||||
|
->setName('blueprint-type');
|
||||||
|
|
||||||
|
foreach ($implementations as $implementation_name => $implementation) {
|
||||||
|
$control
|
||||||
|
->addButton(
|
||||||
|
$implementation_name,
|
||||||
|
$implementation->getBlueprintClass(),
|
||||||
|
$implementation->getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
$dialog = new AphrontDialogView();
|
||||||
|
$dialog->setTitle(pht('Create New Blueprint'))
|
||||||
|
->setUser($viewer)
|
||||||
|
->addSubmitButton(pht('Create Blueprint'))
|
||||||
|
->addCancelButton($this->getApplicationURI('blueprint/'));
|
||||||
|
$dialog->appendChild(
|
||||||
|
phutil_tag(
|
||||||
|
'p',
|
||||||
|
array(),
|
||||||
|
pht(
|
||||||
|
'Select what type of blueprint you want to create: ')));
|
||||||
|
$dialog->appendChild($control);
|
||||||
|
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DrydockBlueprintEditController extends DrydockController {
|
||||||
|
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
public function willProcessRequest(array $data) {
|
||||||
|
$this->id = idx($data, 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processRequest() {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$viewer = $request->getUser();
|
||||||
|
|
||||||
|
if ($this->id) {
|
||||||
|
$blueprint = id(new DrydockBlueprintQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($this->id))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
|
->executeOne();
|
||||||
|
if (!$blueprint) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$blueprint = new DrydockBlueprint();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
$v_view_policy = $request->getStr('viewPolicy');
|
||||||
|
$v_edit_policy = $request->getStr('editPolicy');
|
||||||
|
|
||||||
|
// TODO: Should we use transactions here?
|
||||||
|
$blueprint->setViewPolicy($v_view_policy);
|
||||||
|
$blueprint->setEditPolicy($v_edit_policy);
|
||||||
|
|
||||||
|
$blueprint->save();
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())
|
||||||
|
->setURI('/drydock/blueprint/');
|
||||||
|
}
|
||||||
|
|
||||||
|
$policies = id(new PhabricatorPolicyQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setObject($blueprint)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
if ($request->isAjax()) {
|
||||||
|
$form = id(new PHUIFormLayoutView())
|
||||||
|
->setUser($viewer);
|
||||||
|
} else {
|
||||||
|
$form = id(new AphrontFormView())
|
||||||
|
->setUser($viewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
$form
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setName('className')
|
||||||
|
->setLabel(pht('Implementation'))
|
||||||
|
->setValue($blueprint->getClassName())
|
||||||
|
->setDisabled(true))
|
||||||
|
->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));
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
|
|
||||||
|
$title = pht('Edit Blueprint');
|
||||||
|
$header = pht('Edit Blueprint %d', $blueprint->getID());
|
||||||
|
$crumbs->addCrumb(
|
||||||
|
id(new PhabricatorCrumbView())
|
||||||
|
->setName(pht('Blueprint %d', $blueprint->getID())));
|
||||||
|
$crumbs->addCrumb(
|
||||||
|
id(new PhabricatorCrumbView())
|
||||||
|
->setName(pht('Edit')));
|
||||||
|
|
||||||
|
if ($request->isAjax()) {
|
||||||
|
$dialog = id(new AphrontDialogView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setWidth(AphrontDialogView::WIDTH_FORM)
|
||||||
|
->setTitle($title)
|
||||||
|
->appendChild($form)
|
||||||
|
->addSubmitButton(pht('Edit Blueprint'))
|
||||||
|
->addCancelButton($this->getApplicationURI());
|
||||||
|
|
||||||
|
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
$form->appendChild(
|
||||||
|
id(new AphrontFormSubmitControl())
|
||||||
|
->setValue(pht('Save'))
|
||||||
|
->addCancelButton($this->getApplicationURI()));
|
||||||
|
|
||||||
|
$box = id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText($header)
|
||||||
|
->setForm($form);
|
||||||
|
|
||||||
|
return $this->buildApplicationPage(
|
||||||
|
array(
|
||||||
|
$crumbs,
|
||||||
|
$box,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'title' => $title,
|
||||||
|
'device' => true,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DrydockBlueprintListController extends DrydockController {
|
||||||
|
|
||||||
|
public function processRequest() {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$user = $request->getUser();
|
||||||
|
|
||||||
|
$title = pht('Blueprints');
|
||||||
|
|
||||||
|
$blueprint_header = id(new PHUIHeaderView())
|
||||||
|
->setHeader($title);
|
||||||
|
|
||||||
|
$blueprints = id(new DrydockBlueprintQuery())
|
||||||
|
->setViewer($user)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$blueprint_list = $this->buildBlueprintListView($blueprints);
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
|
$crumbs->addCrumb(
|
||||||
|
id(new PhabricatorCrumbView())
|
||||||
|
->setName($title)
|
||||||
|
->setHref($request->getRequestURI()));
|
||||||
|
|
||||||
|
$crumbs->addAction(
|
||||||
|
id(new PHUIListItemView())
|
||||||
|
->setName(pht('New Blueprint'))
|
||||||
|
->setHref($this->getApplicationURI('blueprint/create/'))
|
||||||
|
->setIcon('create'));
|
||||||
|
|
||||||
|
$nav = $this->buildSideNav('blueprint');
|
||||||
|
$nav->setCrumbs($crumbs);
|
||||||
|
$nav->appendChild(
|
||||||
|
array(
|
||||||
|
$blueprint_header,
|
||||||
|
$blueprint_list
|
||||||
|
));
|
||||||
|
|
||||||
|
return $this->buildApplicationPage(
|
||||||
|
$nav,
|
||||||
|
array(
|
||||||
|
'title' => $title,
|
||||||
|
'device' => true,
|
||||||
|
));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildBlueprintListView(array $blueprints) {
|
||||||
|
assert_instances_of($blueprints, 'DrydockBlueprint');
|
||||||
|
|
||||||
|
$user = $this->getRequest()->getUser();
|
||||||
|
$view = new PHUIObjectItemListView();
|
||||||
|
|
||||||
|
foreach ($blueprints as $blueprint) {
|
||||||
|
$item = id(new PHUIObjectItemView())
|
||||||
|
->setHeader($blueprint->getClassName())
|
||||||
|
->setHref($this->getApplicationURI('/blueprint/'.$blueprint->getID()))
|
||||||
|
->setObjectName(pht('Blueprint %d', $blueprint->getID()));
|
||||||
|
|
||||||
|
if ($blueprint->getImplementation()->isEnabled()) {
|
||||||
|
$item->addAttribute(pht('Enabled'));
|
||||||
|
$item->setBarColor('green');
|
||||||
|
} else {
|
||||||
|
$item->addAttribute(pht('Disabled'));
|
||||||
|
$item->setBarColor('red');
|
||||||
|
}
|
||||||
|
|
||||||
|
$item->addAttribute($blueprint->getImplementation()->getDescription());
|
||||||
|
|
||||||
|
$view->addItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DrydockBlueprintViewController extends DrydockController {
|
||||||
|
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
public function willProcessRequest(array $data) {
|
||||||
|
$this->id = $data['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processRequest() {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$user = $request->getUser();
|
||||||
|
|
||||||
|
$blueprint = id(new DrydockBlueprint())->load($this->id);
|
||||||
|
if (!$blueprint) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$title = 'Blueprint '.$blueprint->getID().' '.$blueprint->getClassName();
|
||||||
|
|
||||||
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setHeader($title);
|
||||||
|
|
||||||
|
$actions = $this->buildActionListView($blueprint);
|
||||||
|
$properties = $this->buildPropertyListView($blueprint, $actions);
|
||||||
|
|
||||||
|
$blueprint_uri = 'blueprint/'.$blueprint->getID().'/';
|
||||||
|
$blueprint_uri = $this->getApplicationURI($blueprint_uri);
|
||||||
|
|
||||||
|
$resources = id(new DrydockResourceQuery())
|
||||||
|
->withBlueprintPHIDs(array($blueprint->getPHID()))
|
||||||
|
->setViewer($user)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$resource_list = $this->buildResourceListView($resources);
|
||||||
|
$resource_list->setNoDataString(pht('This blueprint has no resources.'));
|
||||||
|
|
||||||
|
$pager = new AphrontPagerView();
|
||||||
|
$pager->setURI(new PhutilURI($blueprint_uri), 'offset');
|
||||||
|
$pager->setOffset($request->getInt('offset'));
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
|
$crumbs->setActionList($actions);
|
||||||
|
$crumbs->addCrumb(
|
||||||
|
id(new PhabricatorCrumbView())
|
||||||
|
->setName(pht('Blueprint %d', $blueprint->getID())));
|
||||||
|
|
||||||
|
$object_box = id(new PHUIObjectBoxView())
|
||||||
|
->setHeader($header)
|
||||||
|
->addPropertyList($properties);
|
||||||
|
|
||||||
|
return $this->buildApplicationPage(
|
||||||
|
array(
|
||||||
|
$crumbs,
|
||||||
|
$object_box,
|
||||||
|
$resource_list
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'device' => true,
|
||||||
|
'title' => $title,
|
||||||
|
));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildActionListView(DrydockBlueprint $blueprint) {
|
||||||
|
$view = id(new PhabricatorActionListView())
|
||||||
|
->setUser($this->getRequest()->getUser())
|
||||||
|
->setObjectURI($this->getRequest()->getRequestURI())
|
||||||
|
->setObject($blueprint);
|
||||||
|
|
||||||
|
$uri = '/blueprint/edit/'.$blueprint->getID().'/';
|
||||||
|
$uri = $this->getApplicationURI($uri);
|
||||||
|
|
||||||
|
$view->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setHref($uri)
|
||||||
|
->setName(pht('Edit Blueprint Policies'))
|
||||||
|
->setIcon('edit')
|
||||||
|
->setWorkflow(true)
|
||||||
|
->setDisabled(false));
|
||||||
|
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildPropertyListView(
|
||||||
|
DrydockBlueprint $blueprint,
|
||||||
|
PhabricatorActionListView $actions) {
|
||||||
|
|
||||||
|
$view = new PHUIPropertyListView();
|
||||||
|
$view->setActionList($actions);
|
||||||
|
|
||||||
|
$view->addProperty(
|
||||||
|
pht('Implementation'),
|
||||||
|
$blueprint->getClassName());
|
||||||
|
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,9 +5,10 @@ abstract class DrydockController extends PhabricatorController {
|
||||||
final protected function buildSideNav($selected) {
|
final protected function buildSideNav($selected) {
|
||||||
$nav = new AphrontSideNavFilterView();
|
$nav = new AphrontSideNavFilterView();
|
||||||
$nav->setBaseURI(new PhutilURI('/drydock/'));
|
$nav->setBaseURI(new PhutilURI('/drydock/'));
|
||||||
$nav->addFilter('resource', 'Resources');
|
$nav->addFilter('blueprint', 'Blueprints');
|
||||||
$nav->addFilter('lease', 'Leases');
|
$nav->addFilter('resource', 'Resources');
|
||||||
$nav->addFilter('log', 'Logs');
|
$nav->addFilter('lease', 'Leases');
|
||||||
|
$nav->addFilter('log', 'Logs');
|
||||||
|
|
||||||
$nav->selectFilter($selected, 'resource');
|
$nav->selectFilter($selected, 'resource');
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,6 @@ final class DrydockResourceViewController extends DrydockController {
|
||||||
->needResources(true)
|
->needResources(true)
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
$lease_header = id(new PHUIHeaderView())
|
|
||||||
->setHeader(pht('Leases'));
|
|
||||||
|
|
||||||
$lease_list = $this->buildLeaseListView($leases);
|
$lease_list = $this->buildLeaseListView($leases);
|
||||||
$lease_list->setNoDataString(pht('This resource has no leases.'));
|
$lease_list->setNoDataString(pht('This resource has no leases.'));
|
||||||
|
|
||||||
|
@ -64,7 +61,6 @@ final class DrydockResourceViewController extends DrydockController {
|
||||||
array(
|
array(
|
||||||
$crumbs,
|
$crumbs,
|
||||||
$object_box,
|
$object_box,
|
||||||
$lease_header,
|
|
||||||
$lease_list,
|
$lease_list,
|
||||||
$log_table,
|
$log_table,
|
||||||
),
|
),
|
||||||
|
@ -114,6 +110,11 @@ final class DrydockResourceViewController extends DrydockController {
|
||||||
pht('Resource Type'),
|
pht('Resource Type'),
|
||||||
$resource->getType());
|
$resource->getType());
|
||||||
|
|
||||||
|
// TODO: Load handle.
|
||||||
|
$view->addProperty(
|
||||||
|
pht('Blueprint'),
|
||||||
|
$resource->getBlueprintPHID());
|
||||||
|
|
||||||
$attributes = $resource->getAttributes();
|
$attributes = $resource->getAttributes();
|
||||||
if ($attributes) {
|
if ($attributes) {
|
||||||
$view->addSectionHeader(pht('Attributes'));
|
$view->addSectionHeader(pht('Attributes'));
|
||||||
|
|
|
@ -16,8 +16,8 @@ final class DrydockManagementCreateResourceWorkflow
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'name' => 'blueprint',
|
'name' => 'blueprint',
|
||||||
'param' => 'blueprint_type',
|
'param' => 'blueprint_id',
|
||||||
'help' => 'Blueprint type.',
|
'help' => 'Blueprint ID.',
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'name' => 'attributes',
|
'name' => 'attributes',
|
||||||
|
@ -36,10 +36,10 @@ final class DrydockManagementCreateResourceWorkflow
|
||||||
"Specify a resource name with `--name`.");
|
"Specify a resource name with `--name`.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$blueprint_type = $args->getArg('blueprint');
|
$blueprint_id = $args->getArg('blueprint');
|
||||||
if (!$blueprint_type) {
|
if (!$blueprint_id) {
|
||||||
throw new PhutilArgumentUsageException(
|
throw new PhutilArgumentUsageException(
|
||||||
"Specify a blueprint type with `--blueprint`.");
|
"Specify a blueprint ID with `--blueprint`.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$attributes = $args->getArg('attributes');
|
$attributes = $args->getArg('attributes');
|
||||||
|
@ -49,9 +49,15 @@ final class DrydockManagementCreateResourceWorkflow
|
||||||
$attributes = $options->parse($attributes);
|
$attributes = $options->parse($attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$blueprint = id(new DrydockBlueprint())->load((int)$blueprint_id);
|
||||||
|
if (!$blueprint) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
"Specified blueprint does not exist.");
|
||||||
|
}
|
||||||
|
|
||||||
$resource = new DrydockResource();
|
$resource = new DrydockResource();
|
||||||
$resource->setBlueprintClass($blueprint_type);
|
$resource->setBlueprintPHID($blueprint->getPHID());
|
||||||
$resource->setType(id(new $blueprint_type())->getType());
|
$resource->setType($blueprint->getImplementation()->getType());
|
||||||
$resource->setName($resource_name);
|
$resource->setName($resource_name);
|
||||||
$resource->setStatus(DrydockResourceStatus::STATUS_OPEN);
|
$resource->setStatus(DrydockResourceStatus::STATUS_OPEN);
|
||||||
if ($attributes) {
|
if ($attributes) {
|
||||||
|
|
34
src/applications/drydock/phid/DrydockPHIDTypeBlueprint.php
Normal file
34
src/applications/drydock/phid/DrydockPHIDTypeBlueprint.php
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DrydockPHIDTypeBlueprint extends PhabricatorPHIDType {
|
||||||
|
|
||||||
|
const TYPECONST = 'DRYB';
|
||||||
|
|
||||||
|
public function getTypeConstant() {
|
||||||
|
return self::TYPECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTypeName() {
|
||||||
|
return pht('Blueprint');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newObject() {
|
||||||
|
return new DrydockBlueprint();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildQueryForObjects(
|
||||||
|
PhabricatorObjectQuery $query,
|
||||||
|
array $phids) {
|
||||||
|
|
||||||
|
return id(new DrydockBlueprintQuery())
|
||||||
|
->withPHIDs($phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHandles(
|
||||||
|
PhabricatorHandleQuery $query,
|
||||||
|
array $handles,
|
||||||
|
array $objects) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
70
src/applications/drydock/query/DrydockBlueprintQuery.php
Normal file
70
src/applications/drydock/query/DrydockBlueprintQuery.php
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DrydockBlueprintQuery
|
||||||
|
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
|
|
||||||
|
private $ids;
|
||||||
|
private $phids;
|
||||||
|
|
||||||
|
public function withIDs(array $ids) {
|
||||||
|
$this->ids = $ids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withPHIDs(array $phids) {
|
||||||
|
$this->phids = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public 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($implementations, $blueprint->getClassName())) {
|
||||||
|
$blueprint->attachImplementation(
|
||||||
|
$implementations[$blueprint->getClassName()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $blueprints;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
||||||
|
$where = array();
|
||||||
|
|
||||||
|
if ($this->ids) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'id IN (%Ld)',
|
||||||
|
$this->ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->phids) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'phid IN (%Ld)',
|
||||||
|
$this->phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->formatWhereClause($where);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryApplicationClass() {
|
||||||
|
return 'PhabricatorApplicationDrydock';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -40,12 +40,16 @@ final class DrydockLeaseQuery extends PhabricatorOffsetPagedQuery {
|
||||||
'id IN (%Ld)',
|
'id IN (%Ld)',
|
||||||
mpull($leases, 'getResourceID'));
|
mpull($leases, 'getResourceID'));
|
||||||
|
|
||||||
foreach ($leases as $lease) {
|
foreach ($leases as $key => $lease) {
|
||||||
if ($lease->getResourceID()) {
|
if ($lease->getResourceID()) {
|
||||||
$resource = idx($resources, $lease->getResourceID());
|
$resource = idx($resources, $lease->getResourceID());
|
||||||
if ($resource) {
|
if ($resource) {
|
||||||
$lease->attachResource($resource);
|
$lease->attachResource($resource);
|
||||||
|
} else {
|
||||||
|
unset($leases[$key]);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
unset($leases[$key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ final class DrydockResourceQuery
|
||||||
private $ids;
|
private $ids;
|
||||||
private $statuses;
|
private $statuses;
|
||||||
private $types;
|
private $types;
|
||||||
|
private $blueprintPHIDs;
|
||||||
|
|
||||||
public function withIDs(array $ids) {
|
public function withIDs(array $ids) {
|
||||||
$this->ids = $ids;
|
$this->ids = $ids;
|
||||||
|
@ -22,6 +23,11 @@ final class DrydockResourceQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withBlueprintPHIDs(array $blueprint_phids) {
|
||||||
|
$this->blueprintPHIDs = $blueprint_phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function loadPage() {
|
public function loadPage() {
|
||||||
$table = new DrydockResource();
|
$table = new DrydockResource();
|
||||||
$conn_r = $table->establishConnection('r');
|
$conn_r = $table->establishConnection('r');
|
||||||
|
@ -63,6 +69,13 @@ final class DrydockResourceQuery
|
||||||
$this->statuses);
|
$this->statuses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->blueprintPHIDs) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'blueprintPHID IN (%Ls)',
|
||||||
|
$this->blueprintPHIDs);
|
||||||
|
}
|
||||||
|
|
||||||
$where[] = $this->buildPagingClause($conn_r);
|
$where[] = $this->buildPagingClause($conn_r);
|
||||||
|
|
||||||
return $this->formatWhereClause($where);
|
return $this->formatWhereClause($where);
|
||||||
|
|
72
src/applications/drydock/storage/DrydockBlueprint.php
Normal file
72
src/applications/drydock/storage/DrydockBlueprint.php
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DrydockBlueprint extends DrydockDAO
|
||||||
|
implements PhabricatorPolicyInterface {
|
||||||
|
|
||||||
|
protected $phid;
|
||||||
|
protected $className;
|
||||||
|
protected $viewPolicy;
|
||||||
|
protected $editPolicy;
|
||||||
|
protected $details;
|
||||||
|
|
||||||
|
public function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_AUX_PHID => true,
|
||||||
|
self::CONFIG_SERIALIZATION => array(
|
||||||
|
'details' => self::SERIALIZATION_JSON,
|
||||||
|
)
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generatePHID() {
|
||||||
|
return PhabricatorPHID::generateNewPHID(
|
||||||
|
DrydockPHIDTypeBlueprint::TYPECONST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getImplementation() {
|
||||||
|
$class = $this->className;
|
||||||
|
$implementations =
|
||||||
|
DrydockBlueprintImplementation::getAllBlueprintImplementations();
|
||||||
|
if (!isset($implementations[$class])) {
|
||||||
|
throw new Exception(
|
||||||
|
"Invalid class name for blueprint (got '".$class."')");
|
||||||
|
}
|
||||||
|
return id(new $class())->attachInstance($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getCapabilities() {
|
||||||
|
return array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPolicy($capability) {
|
||||||
|
switch ($capability) {
|
||||||
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||||
|
return $this->getViewPolicy();
|
||||||
|
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||||
|
return $this->getEditPolicy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||||
|
switch ($capability) {
|
||||||
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||||
|
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||||
|
return $viewer->getIsAdmin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeAutomaticCapability($capability) {
|
||||||
|
switch ($capability) {
|
||||||
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||||
|
return pht('Administrators can always view blueprints.');
|
||||||
|
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||||
|
return pht('Administrators can always edit blueprints.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ final class DrydockResource extends DrydockDAO
|
||||||
|
|
||||||
protected $id;
|
protected $id;
|
||||||
protected $phid;
|
protected $phid;
|
||||||
protected $blueprintClass;
|
protected $blueprintPHID;
|
||||||
protected $status;
|
protected $status;
|
||||||
|
|
||||||
protected $type;
|
protected $type;
|
||||||
|
@ -50,7 +50,9 @@ final class DrydockResource extends DrydockDAO
|
||||||
|
|
||||||
public function getBlueprint() {
|
public function getBlueprint() {
|
||||||
if (empty($this->blueprint)) {
|
if (empty($this->blueprint)) {
|
||||||
$this->blueprint = newv($this->blueprintClass, array());
|
$blueprint = id(new DrydockBlueprint())
|
||||||
|
->loadOneWhere('phid = %s', $this->blueprintPHID);
|
||||||
|
$this->blueprint = $blueprint->getImplementation();
|
||||||
}
|
}
|
||||||
return $this->blueprint;
|
return $this->blueprint;
|
||||||
}
|
}
|
||||||
|
@ -76,7 +78,7 @@ final class DrydockResource extends DrydockDAO
|
||||||
$lease->setStatus(DrydockLeaseStatus::STATUS_RELEASED);
|
$lease->setStatus(DrydockLeaseStatus::STATUS_RELEASED);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
DrydockBlueprint::writeLog($this, $lease, $message);
|
DrydockBlueprintImplementation::writeLog($this, $lease, $message);
|
||||||
$lease->save();
|
$lease->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
final class DrydockBlueprintScopeGuard {
|
final class DrydockBlueprintScopeGuard {
|
||||||
|
|
||||||
public function __construct(DrydockBlueprint $blueprint) {
|
public function __construct(DrydockBlueprintImplementation $blueprint) {
|
||||||
$this->blueprint = $blueprint;
|
$this->blueprint = $blueprint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ final class DrydockAllocatorWorker extends PhabricatorWorker {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function logToDrydock($message) {
|
private function logToDrydock($message) {
|
||||||
DrydockBlueprint::writeLog(
|
DrydockBlueprintImplementation::writeLog(
|
||||||
null,
|
null,
|
||||||
$this->loadLease(),
|
$this->loadLease(),
|
||||||
$message);
|
$message);
|
||||||
|
@ -52,9 +52,20 @@ final class DrydockAllocatorWorker extends PhabricatorWorker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function loadAllBlueprints() {
|
||||||
|
$instances = id(new DrydockBlueprint())->loadAll();
|
||||||
|
$blueprints = array();
|
||||||
|
foreach ($instances as $instance) {
|
||||||
|
$blueprints[$instance->getPHID()] = $instance;
|
||||||
|
}
|
||||||
|
return $blueprints;
|
||||||
|
}
|
||||||
|
|
||||||
private function allocateLease(DrydockLease $lease) {
|
private function allocateLease(DrydockLease $lease) {
|
||||||
$type = $lease->getResourceType();
|
$type = $lease->getResourceType();
|
||||||
|
|
||||||
|
$blueprints = $this->loadAllBlueprints();
|
||||||
|
|
||||||
$pool = id(new DrydockResource())->loadAllWhere(
|
$pool = id(new DrydockResource())->loadAllWhere(
|
||||||
'type = %s AND status = %s',
|
'type = %s AND status = %s',
|
||||||
$lease->getResourceType(),
|
$lease->getResourceType(),
|
||||||
|
@ -65,14 +76,15 @@ final class DrydockAllocatorWorker extends PhabricatorWorker {
|
||||||
|
|
||||||
$candidates = array();
|
$candidates = array();
|
||||||
foreach ($pool as $key => $candidate) {
|
foreach ($pool as $key => $candidate) {
|
||||||
try {
|
if (!isset($blueprints[$candidate->getBlueprintPHID()])) {
|
||||||
$blueprint = $candidate->getBlueprint();
|
|
||||||
} catch (Exception $ex) {
|
|
||||||
unset($pool[$key]);
|
unset($pool[$key]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($blueprint->filterResource($candidate, $lease)) {
|
$blueprint = $blueprints[$candidate->getBlueprintPHID()];
|
||||||
|
$implementation = $blueprint->getImplementation();
|
||||||
|
|
||||||
|
if ($implementation->filterResource($candidate, $lease)) {
|
||||||
$candidates[] = $candidate;
|
$candidates[] = $candidate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +95,8 @@ final class DrydockAllocatorWorker extends PhabricatorWorker {
|
||||||
if ($candidates) {
|
if ($candidates) {
|
||||||
shuffle($candidates);
|
shuffle($candidates);
|
||||||
foreach ($candidates as $candidate_resource) {
|
foreach ($candidates as $candidate_resource) {
|
||||||
$blueprint = $candidate_resource->getBlueprint();
|
$blueprint = $blueprints[$candidate_resource->getBlueprintPHID()]
|
||||||
|
->getImplementation();
|
||||||
if ($blueprint->allocateLease($candidate_resource, $lease)) {
|
if ($blueprint->allocateLease($candidate_resource, $lease)) {
|
||||||
$resource = $candidate_resource;
|
$resource = $candidate_resource;
|
||||||
break;
|
break;
|
||||||
|
@ -92,7 +105,8 @@ final class DrydockAllocatorWorker extends PhabricatorWorker {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$resource) {
|
if (!$resource) {
|
||||||
$blueprints = DrydockBlueprint::getAllBlueprintsForResource($type);
|
$blueprints = DrydockBlueprintImplementation
|
||||||
|
::getAllBlueprintImplementationsForResource($type);
|
||||||
|
|
||||||
$this->logToDrydock(
|
$this->logToDrydock(
|
||||||
pht('Found %d Blueprints', count($blueprints)));
|
pht('Found %d Blueprints', count($blueprints)));
|
||||||
|
|
|
@ -1788,6 +1788,14 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
||||||
'type' => 'sql',
|
'type' => 'sql',
|
||||||
'name' => $this->getPatchPath('20131122.repomirror.sql'),
|
'name' => $this->getPatchPath('20131122.repomirror.sql'),
|
||||||
),
|
),
|
||||||
|
'20131123.drydockblueprintpolicy.sql' => array(
|
||||||
|
'type' => 'sql',
|
||||||
|
'name' => $this->getPatchPath('20131123.drydockblueprintpolicy.sql'),
|
||||||
|
),
|
||||||
|
'20131129.drydockresourceblueprint.sql' => array(
|
||||||
|
'type' => 'sql',
|
||||||
|
'name' => $this->getPatchPath('20131129.drydockresourceblueprint.sql'),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,29 @@ final class PHUIFormLayoutView extends AphrontView {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function appendInstructions($text) {
|
||||||
|
return $this->appendChild(
|
||||||
|
phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'aphront-form-instructions',
|
||||||
|
),
|
||||||
|
$text));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function appendRemarkupInstructions($remarkup) {
|
||||||
|
if ($this->getUser() === null) {
|
||||||
|
throw new Exception(
|
||||||
|
"Call `setUser` before appending Remarkup to PHUIFormLayoutView.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->appendInstructions(
|
||||||
|
PhabricatorMarkupEngine::renderOneObject(
|
||||||
|
id(new PhabricatorMarkupOneOff())->setContent($remarkup),
|
||||||
|
'default',
|
||||||
|
$this->getUser()));
|
||||||
|
}
|
||||||
|
|
||||||
public function render() {
|
public function render() {
|
||||||
$classes = array('phui-form-view');
|
$classes = array('phui-form-view');
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue