Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F92400
D7638.diff
All Users
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
41 KB
Referenced Files
None
Subscribers
None
D7638.diff
View Options
diff --git a/resources/sql/patches/20131123.drydockblueprintpolicy.sql b/resources/sql/patches/20131123.drydockblueprintpolicy.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/patches/20131123.drydockblueprintpolicy.sql
@@ -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;
diff --git a/resources/sql/patches/20131129.drydockresourceblueprint.sql b/resources/sql/patches/20131129.drydockresourceblueprint.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/patches/20131129.drydockresourceblueprint.sql
@@ -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;
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
@@ -626,8 +626,14 @@
'DoorkeeperTagsController' => 'applications/doorkeeper/controller/DoorkeeperTagsController.php',
'DrydockAllocatorWorker' => 'applications/drydock/worker/DrydockAllocatorWorker.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',
+ 'DrydockBlueprintViewController' => 'applications/drydock/controller/DrydockBlueprintViewController.php',
'DrydockCommandInterface' => 'applications/drydock/interface/command/DrydockCommandInterface.php',
'DrydockConstants' => 'applications/drydock/constants/DrydockConstants.php',
'DrydockController' => 'applications/drydock/controller/DrydockController.php',
@@ -640,7 +646,7 @@
'DrydockLeaseStatus' => 'applications/drydock/constants/DrydockLeaseStatus.php',
'DrydockLeaseViewController' => 'applications/drydock/controller/DrydockLeaseViewController.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',
'DrydockLogController' => 'applications/drydock/controller/DrydockLogController.php',
'DrydockLogQuery' => 'applications/drydock/query/DrydockLogQuery.php',
@@ -650,16 +656,17 @@
'DrydockManagementReleaseWorkflow' => 'applications/drydock/management/DrydockManagementReleaseWorkflow.php',
'DrydockManagementWaitForLeaseWorkflow' => 'applications/drydock/management/DrydockManagementWaitForLeaseWorkflow.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',
'DrydockResourceCloseController' => 'applications/drydock/controller/DrydockResourceCloseController.php',
'DrydockResourceListController' => 'applications/drydock/controller/DrydockResourceListController.php',
'DrydockResourceQuery' => 'applications/drydock/query/DrydockResourceQuery.php',
'DrydockResourceStatus' => 'applications/drydock/constants/DrydockResourceStatus.php',
'DrydockResourceViewController' => 'applications/drydock/controller/DrydockResourceViewController.php',
'DrydockSSHCommandInterface' => 'applications/drydock/interface/command/DrydockSSHCommandInterface.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',
'FeedPublisherWorker' => 'applications/feed/worker/FeedPublisherWorker.php',
'FeedPushWorker' => 'applications/feed/worker/FeedPushWorker.php',
@@ -2951,6 +2958,16 @@
'DoorkeeperTagsController' => 'PhabricatorController',
'DrydockAllocatorWorker' => 'PhabricatorWorker',
'DrydockApacheWebrootInterface' => 'DrydockWebrootInterface',
+ 'DrydockBlueprint' =>
+ array(
+ 0 => 'DrydockDAO',
+ 1 => 'PhabricatorPolicyInterface',
+ ),
+ 'DrydockBlueprintCreateController' => 'DrydockController',
+ 'DrydockBlueprintEditController' => 'DrydockController',
+ 'DrydockBlueprintListController' => 'DrydockController',
+ 'DrydockBlueprintQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'DrydockBlueprintViewController' => 'DrydockController',
'DrydockCommandInterface' => 'DrydockInterface',
'DrydockController' => 'PhabricatorController',
'DrydockDAO' => 'PhabricatorLiskDAO',
@@ -2961,7 +2978,7 @@
'DrydockLeaseStatus' => 'DrydockConstants',
'DrydockLeaseViewController' => 'DrydockController',
'DrydockLocalCommandInterface' => 'DrydockCommandInterface',
- 'DrydockLocalHostBlueprint' => 'DrydockBlueprint',
+ 'DrydockLocalHostBlueprintImplementation' => 'DrydockBlueprintImplementation',
'DrydockLog' => 'DrydockDAO',
'DrydockLogController' => 'DrydockController',
'DrydockLogQuery' => 'PhabricatorOffsetPagedQuery',
@@ -2971,7 +2988,8 @@
'DrydockManagementReleaseWorkflow' => 'DrydockManagementWorkflow',
'DrydockManagementWaitForLeaseWorkflow' => 'DrydockManagementWorkflow',
'DrydockManagementWorkflow' => 'PhutilArgumentWorkflow',
- 'DrydockPreallocatedHostBlueprint' => 'DrydockBlueprint',
+ 'DrydockPHIDTypeBlueprint' => 'PhabricatorPHIDType',
+ 'DrydockPreallocatedHostBlueprintImplementation' => 'DrydockBlueprintImplementation',
'DrydockResource' =>
array(
0 => 'DrydockDAO',
@@ -2984,7 +3002,7 @@
'DrydockResourceViewController' => 'DrydockController',
'DrydockSSHCommandInterface' => 'DrydockCommandInterface',
'DrydockWebrootInterface' => 'DrydockInterface',
- 'DrydockWorkingCopyBlueprint' => 'DrydockBlueprint',
+ 'DrydockWorkingCopyBlueprintImplementation' => 'DrydockBlueprintImplementation',
'FeedPublisherHTTPWorker' => 'FeedPushWorker',
'FeedPublisherWorker' => 'FeedPushWorker',
'FeedPushWorker' => 'PhabricatorWorker',
diff --git a/src/applications/drydock/application/PhabricatorApplicationDrydock.php b/src/applications/drydock/application/PhabricatorApplicationDrydock.php
--- a/src/applications/drydock/application/PhabricatorApplicationDrydock.php
+++ b/src/applications/drydock/application/PhabricatorApplicationDrydock.php
@@ -34,6 +34,12 @@
return array(
'/drydock/' => array(
'' => 'DrydockResourceListController',
+ 'blueprint/' => array(
+ '' => 'DrydockBlueprintListController',
+ '(?P<id>[1-9]\d*)/' => 'DrydockBlueprintViewController',
+ 'create/' => 'DrydockBlueprintCreateController',
+ 'edit/(?P<id>[1-9]\d*)/' => 'DrydockBlueprintEditController',
+ ),
'resource/' => array(
'' => 'DrydockResourceListController',
'(?P<id>[1-9]\d*)/' => 'DrydockResourceViewController',
diff --git a/src/applications/drydock/blueprint/DrydockBlueprint.php b/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php
rename from src/applications/drydock/blueprint/DrydockBlueprint.php
rename to src/applications/drydock/blueprint/DrydockBlueprintImplementation.php
--- a/src/applications/drydock/blueprint/DrydockBlueprint.php
+++ b/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php
@@ -5,10 +5,11 @@
* @task resource Resource Allocation
* @task log Logging
*/
-abstract class DrydockBlueprint {
+abstract class DrydockBlueprintImplementation {
private $activeResource;
private $activeLease;
+ private $instance;
abstract public function getType();
abstract public function getInterface(
@@ -18,6 +19,8 @@
abstract public function isEnabled();
+ abstract public function getDescription();
+
public function getBlueprintClass() {
return get_class($this);
}
@@ -37,6 +40,20 @@
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 )-------------------------------------------------- */
@@ -343,13 +360,13 @@
}
- public static function getAllBlueprints() {
+ public static function getAllBlueprintImplementations() {
static $list = null;
if ($list === null) {
$blueprints = id(new PhutilSymbolLoader())
->setType('class')
- ->setAncestorClass('DrydockBlueprint')
+ ->setAncestorClass('DrydockBlueprintImplementation')
->setConcreteOnly(true)
->selectAndLoadSymbols();
$list = ipull($blueprints, 'name', 'name');
@@ -361,16 +378,17 @@
return $list;
}
- public static function getAllBlueprintsForResource($type) {
+ public static function getAllBlueprintImplementationsForResource($type) {
static $groups = null;
if ($groups === null) {
- $groups = mgroup(self::getAllBlueprints(), 'getType');
+ $groups = mgroup(self::getAllBlueprintImplementations(), 'getType');
}
return idx($groups, $type, array());
}
protected function newResourceTemplate($name) {
$resource = new DrydockResource();
+ $resource->setBlueprintPHID($this->getInstance()->getPHID());
$resource->setBlueprintClass($this->getBlueprintClass());
$resource->setType($this->getType());
$resource->setStatus(DrydockResourceStatus::STATUS_PENDING);
diff --git a/src/applications/drydock/blueprint/DrydockLocalHostBlueprint.php b/src/applications/drydock/blueprint/DrydockLocalHostBlueprintImplementation.php
rename from src/applications/drydock/blueprint/DrydockLocalHostBlueprint.php
rename to src/applications/drydock/blueprint/DrydockLocalHostBlueprintImplementation.php
--- a/src/applications/drydock/blueprint/DrydockLocalHostBlueprint.php
+++ b/src/applications/drydock/blueprint/DrydockLocalHostBlueprintImplementation.php
@@ -1,11 +1,16 @@
<?php
-final class DrydockLocalHostBlueprint extends DrydockBlueprint {
+final class DrydockLocalHostBlueprintImplementation
+ extends DrydockBlueprintImplementation {
public function isEnabled() {
return false;
}
+ public function getDescription() {
+ return pht('Allocates storage on the local host.');
+ }
+
public function canAllocateMoreResources(array $pool) {
assert_instances_of($pool, 'DrydockResource');
diff --git a/src/applications/drydock/blueprint/DrydockPreallocatedHostBlueprint.php b/src/applications/drydock/blueprint/DrydockPreallocatedHostBlueprintImplementation.php
rename from src/applications/drydock/blueprint/DrydockPreallocatedHostBlueprint.php
rename to src/applications/drydock/blueprint/DrydockPreallocatedHostBlueprintImplementation.php
--- a/src/applications/drydock/blueprint/DrydockPreallocatedHostBlueprint.php
+++ b/src/applications/drydock/blueprint/DrydockPreallocatedHostBlueprintImplementation.php
@@ -1,11 +1,16 @@
<?php
-final class DrydockPreallocatedHostBlueprint extends DrydockBlueprint {
+final class DrydockPreallocatedHostBlueprintImplementation
+ extends DrydockBlueprintImplementation {
public function isEnabled() {
return true;
}
+ public function getDescription() {
+ return pht('Leases out preallocated, remote hosts.');
+ }
+
public function canAllocateMoreResources(array $pool) {
return false;
}
diff --git a/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprint.php b/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php
rename from src/applications/drydock/blueprint/DrydockWorkingCopyBlueprint.php
rename to src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php
--- a/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprint.php
+++ b/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php
@@ -1,11 +1,16 @@
<?php
-final class DrydockWorkingCopyBlueprint extends DrydockBlueprint {
+final class DrydockWorkingCopyBlueprintImplementation
+ extends DrydockBlueprintImplementation {
public function isEnabled() {
return true;
}
+ public function getDescription() {
+ return pht('Allocates out working copies of repositories.');
+ }
+
protected function canAllocateLease(
DrydockResource $resource,
DrydockLease $lease) {
diff --git a/src/applications/drydock/controller/DrydockBlueprintCreateController.php b/src/applications/drydock/controller/DrydockBlueprintCreateController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/controller/DrydockBlueprintCreateController.php
@@ -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);
+ }
+
+}
diff --git a/src/applications/drydock/controller/DrydockBlueprintEditController.php b/src/applications/drydock/controller/DrydockBlueprintEditController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/controller/DrydockBlueprintEditController.php
@@ -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,
+ ));
+ }
+
+}
diff --git a/src/applications/drydock/controller/DrydockBlueprintListController.php b/src/applications/drydock/controller/DrydockBlueprintListController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/controller/DrydockBlueprintListController.php
@@ -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;
+ }
+
+}
diff --git a/src/applications/drydock/controller/DrydockBlueprintViewController.php b/src/applications/drydock/controller/DrydockBlueprintViewController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/controller/DrydockBlueprintViewController.php
@@ -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;
+ }
+
+}
diff --git a/src/applications/drydock/controller/DrydockController.php b/src/applications/drydock/controller/DrydockController.php
--- a/src/applications/drydock/controller/DrydockController.php
+++ b/src/applications/drydock/controller/DrydockController.php
@@ -5,9 +5,10 @@
final protected function buildSideNav($selected) {
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI('/drydock/'));
- $nav->addFilter('resource', 'Resources');
- $nav->addFilter('lease', 'Leases');
- $nav->addFilter('log', 'Logs');
+ $nav->addFilter('blueprint', 'Blueprints');
+ $nav->addFilter('resource', 'Resources');
+ $nav->addFilter('lease', 'Leases');
+ $nav->addFilter('log', 'Logs');
$nav->selectFilter($selected, 'resource');
diff --git a/src/applications/drydock/controller/DrydockResourceViewController.php b/src/applications/drydock/controller/DrydockResourceViewController.php
--- a/src/applications/drydock/controller/DrydockResourceViewController.php
+++ b/src/applications/drydock/controller/DrydockResourceViewController.php
@@ -33,9 +33,6 @@
->needResources(true)
->execute();
- $lease_header = id(new PHUIHeaderView())
- ->setHeader(pht('Leases'));
-
$lease_list = $this->buildLeaseListView($leases);
$lease_list->setNoDataString(pht('This resource has no leases.'));
@@ -64,7 +61,6 @@
array(
$crumbs,
$object_box,
- $lease_header,
$lease_list,
$log_table,
),
@@ -114,6 +110,11 @@
pht('Resource Type'),
$resource->getType());
+ // TODO: Load handle.
+ $view->addProperty(
+ pht('Blueprint'),
+ $resource->getBlueprintPHID());
+
$attributes = $resource->getAttributes();
if ($attributes) {
$view->addSectionHeader(pht('Attributes'));
diff --git a/src/applications/drydock/management/DrydockManagementCreateResourceWorkflow.php b/src/applications/drydock/management/DrydockManagementCreateResourceWorkflow.php
--- a/src/applications/drydock/management/DrydockManagementCreateResourceWorkflow.php
+++ b/src/applications/drydock/management/DrydockManagementCreateResourceWorkflow.php
@@ -16,8 +16,8 @@
),
array(
'name' => 'blueprint',
- 'param' => 'blueprint_type',
- 'help' => 'Blueprint type.',
+ 'param' => 'blueprint_id',
+ 'help' => 'Blueprint ID.',
),
array(
'name' => 'attributes',
@@ -36,10 +36,10 @@
"Specify a resource name with `--name`.");
}
- $blueprint_type = $args->getArg('blueprint');
- if (!$blueprint_type) {
+ $blueprint_id = $args->getArg('blueprint');
+ if (!$blueprint_id) {
throw new PhutilArgumentUsageException(
- "Specify a blueprint type with `--blueprint`.");
+ "Specify a blueprint ID with `--blueprint`.");
}
$attributes = $args->getArg('attributes');
@@ -49,9 +49,15 @@
$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->setBlueprintClass($blueprint_type);
- $resource->setType(id(new $blueprint_type())->getType());
+ $resource->setBlueprintPHID($blueprint->getPHID());
+ $resource->setType($blueprint->getImplementation()->getType());
$resource->setName($resource_name);
$resource->setStatus(DrydockResourceStatus::STATUS_OPEN);
if ($attributes) {
diff --git a/src/applications/drydock/phid/DrydockPHIDTypeBlueprint.php b/src/applications/drydock/phid/DrydockPHIDTypeBlueprint.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/phid/DrydockPHIDTypeBlueprint.php
@@ -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) {
+
+ }
+
+}
diff --git a/src/applications/drydock/query/DrydockResourceQuery.php b/src/applications/drydock/query/DrydockBlueprintQuery.php
copy from src/applications/drydock/query/DrydockResourceQuery.php
copy to src/applications/drydock/query/DrydockBlueprintQuery.php
--- a/src/applications/drydock/query/DrydockResourceQuery.php
+++ b/src/applications/drydock/query/DrydockBlueprintQuery.php
@@ -1,42 +1,46 @@
<?php
-final class DrydockResourceQuery
+final class DrydockBlueprintQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
- private $statuses;
- private $types;
+ private $phids;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
- public function withTypes(array $types) {
- $this->types = $types;
- return $this;
- }
-
- public function withStatuses(array $statuses) {
- $this->statuses = $statuses;
+ public function withPHIDs(array $phids) {
+ $this->phids = $phids;
return $this;
}
public function loadPage() {
- $table = new DrydockResource();
+ $table = new DrydockBlueprint();
$conn_r = $table->establishConnection('r');
$data = queryfx_all(
$conn_r,
- 'SELECT resource.* FROM %T resource %Q %Q %Q',
+ 'SELECT blueprint.* FROM %T blueprint %Q %Q %Q',
$table->getTableName(),
$this->buildWhereClause($conn_r),
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
- $resources = $table->loadAllFromArray($data);
+ $blueprints = $table->loadAllFromArray($data);
+
+ $implementations =
+ DrydockBlueprintImplementation::getAllBlueprintImplementations();
+
+ foreach ($blueprints as $blueprint) {
+ if (array_key_exists($implementations, $blueprint->getClassName())) {
+ $blueprint->attachImplementation(
+ $implementations[$blueprint->getClassName()]);
+ }
+ }
- return $resources;
+ return $blueprints;
}
private function buildWhereClause(AphrontDatabaseConnection $conn_r) {
@@ -49,22 +53,13 @@
$this->ids);
}
- if ($this->types) {
+ if ($this->phids) {
$where[] = qsprintf(
$conn_r,
- 'type IN (%Ls)',
- $this->types);
+ 'phid IN (%Ld)',
+ $this->phids);
}
- if ($this->statuses) {
- $where[] = qsprintf(
- $conn_r,
- 'status IN (%Ls)',
- $this->statuses);
- }
-
- $where[] = $this->buildPagingClause($conn_r);
-
return $this->formatWhereClause($where);
}
diff --git a/src/applications/drydock/query/DrydockLeaseQuery.php b/src/applications/drydock/query/DrydockLeaseQuery.php
--- a/src/applications/drydock/query/DrydockLeaseQuery.php
+++ b/src/applications/drydock/query/DrydockLeaseQuery.php
@@ -40,12 +40,16 @@
'id IN (%Ld)',
mpull($leases, 'getResourceID'));
- foreach ($leases as $lease) {
+ foreach ($leases as $key => $lease) {
if ($lease->getResourceID()) {
$resource = idx($resources, $lease->getResourceID());
if ($resource) {
$lease->attachResource($resource);
+ } else {
+ unset($leases[$key]);
}
+ } else {
+ unset($leases[$key]);
}
}
}
diff --git a/src/applications/drydock/query/DrydockResourceQuery.php b/src/applications/drydock/query/DrydockResourceQuery.php
--- a/src/applications/drydock/query/DrydockResourceQuery.php
+++ b/src/applications/drydock/query/DrydockResourceQuery.php
@@ -6,6 +6,7 @@
private $ids;
private $statuses;
private $types;
+ private $blueprintPHIDs;
public function withIDs(array $ids) {
$this->ids = $ids;
@@ -22,6 +23,11 @@
return $this;
}
+ public function withBlueprintPHIDs(array $blueprint_phids) {
+ $this->blueprintPHIDs = $blueprint_phids;
+ return $this;
+ }
+
public function loadPage() {
$table = new DrydockResource();
$conn_r = $table->establishConnection('r');
@@ -63,6 +69,13 @@
$this->statuses);
}
+ if ($this->blueprintPHIDs) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'blueprintPHID IN (%Ls)',
+ $this->blueprintPHIDs);
+ }
+
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);
diff --git a/src/applications/drydock/storage/DrydockBlueprint.php b/src/applications/drydock/storage/DrydockBlueprint.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/storage/DrydockBlueprint.php
@@ -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.');
+ }
+ }
+}
diff --git a/src/applications/drydock/storage/DrydockResource.php b/src/applications/drydock/storage/DrydockResource.php
--- a/src/applications/drydock/storage/DrydockResource.php
+++ b/src/applications/drydock/storage/DrydockResource.php
@@ -5,7 +5,7 @@
protected $id;
protected $phid;
- protected $blueprintClass;
+ protected $blueprintPHID;
protected $status;
protected $type;
@@ -50,7 +50,9 @@
public function getBlueprint() {
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;
}
@@ -76,7 +78,7 @@
$lease->setStatus(DrydockLeaseStatus::STATUS_RELEASED);
break;
}
- DrydockBlueprint::writeLog($this, $lease, $message);
+ DrydockBlueprintImplementation::writeLog($this, $lease, $message);
$lease->save();
}
diff --git a/src/applications/drydock/util/DrydockBlueprintScopeGuard.php b/src/applications/drydock/util/DrydockBlueprintScopeGuard.php
--- a/src/applications/drydock/util/DrydockBlueprintScopeGuard.php
+++ b/src/applications/drydock/util/DrydockBlueprintScopeGuard.php
@@ -2,7 +2,7 @@
final class DrydockBlueprintScopeGuard {
- public function __construct(DrydockBlueprint $blueprint) {
+ public function __construct(DrydockBlueprintImplementation $blueprint) {
$this->blueprint = $blueprint;
}
diff --git a/src/applications/drydock/worker/DrydockAllocatorWorker.php b/src/applications/drydock/worker/DrydockAllocatorWorker.php
--- a/src/applications/drydock/worker/DrydockAllocatorWorker.php
+++ b/src/applications/drydock/worker/DrydockAllocatorWorker.php
@@ -24,7 +24,7 @@
}
private function logToDrydock($message) {
- DrydockBlueprint::writeLog(
+ DrydockBlueprintImplementation::writeLog(
null,
$this->loadLease(),
$message);
@@ -52,9 +52,20 @@
}
}
+ 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) {
$type = $lease->getResourceType();
+ $blueprints = $this->loadAllBlueprints();
+
$pool = id(new DrydockResource())->loadAllWhere(
'type = %s AND status = %s',
$lease->getResourceType(),
@@ -65,14 +76,15 @@
$candidates = array();
foreach ($pool as $key => $candidate) {
- try {
- $blueprint = $candidate->getBlueprint();
- } catch (Exception $ex) {
+ if (!isset($blueprints[$candidate->getBlueprintPHID()])) {
unset($pool[$key]);
continue;
}
- if ($blueprint->filterResource($candidate, $lease)) {
+ $blueprint = $blueprints[$candidate->getBlueprintPHID()];
+ $implementation = $blueprint->getImplementation();
+
+ if ($implementation->filterResource($candidate, $lease)) {
$candidates[] = $candidate;
}
}
@@ -83,16 +95,18 @@
if ($candidates) {
shuffle($candidates);
foreach ($candidates as $candidate_resource) {
- $blueprint = $candidate_resource->getBlueprint();
+ $blueprint = $blueprints[$candidate_resource->getBlueprintPHID()]
+ ->getImplementation();
if ($blueprint->allocateLease($candidate_resource, $lease)) {
$resource = $candidate_resource;
break;
}
}
}
if (!$resource) {
- $blueprints = DrydockBlueprint::getAllBlueprintsForResource($type);
+ $blueprints = DrydockBlueprintImplementation
+ ::getAllBlueprintImplementationsForResource($type);
$this->logToDrydock(
pht('Found %d Blueprints', count($blueprints)));
diff --git a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
--- a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
+++ b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
@@ -1788,6 +1788,14 @@
'type' => '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'),
+ ),
);
}
}
diff --git a/src/view/form/PHUIFormLayoutView.php b/src/view/form/PHUIFormLayoutView.php
--- a/src/view/form/PHUIFormLayoutView.php
+++ b/src/view/form/PHUIFormLayoutView.php
@@ -14,6 +14,29 @@
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() {
$classes = array('phui-form-view');
File Metadata
Details
Attached
Mime Type
text/x-diff
Storage Engine
amazon-s3
Storage Format
Raw Data
Storage Handle
phabricator/bw/u6/ynqhnl3zbydbazae
Default Alt Text
D7638.diff (41 KB)
Attached To
Mode
D7638: Restructure Drydock so that blueprints are instances in the DB
Attached
Detach File
Event Timeline
Log In to Comment