Page MenuHomePhabricator

D15345.diff
No OneTemporary

D15345.diff

diff --git a/resources/sql/autopatches/20160225.almanac.1.disablebinding.sql b/resources/sql/autopatches/20160225.almanac.1.disablebinding.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20160225.almanac.1.disablebinding.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {$NAMESPACE}_almanac.almanac_binding
+ ADD isDisabled BOOL 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
@@ -11,6 +11,7 @@
'class' => array(
'AlmanacAddress' => 'applications/almanac/util/AlmanacAddress.php',
'AlmanacBinding' => 'applications/almanac/storage/AlmanacBinding.php',
+ 'AlmanacBindingDisableController' => 'applications/almanac/controller/AlmanacBindingDisableController.php',
'AlmanacBindingEditController' => 'applications/almanac/controller/AlmanacBindingEditController.php',
'AlmanacBindingEditor' => 'applications/almanac/editor/AlmanacBindingEditor.php',
'AlmanacBindingPHIDType' => 'applications/almanac/phid/AlmanacBindingPHIDType.php',
@@ -51,6 +52,7 @@
'AlmanacEditor' => 'applications/almanac/editor/AlmanacEditor.php',
'AlmanacInterface' => 'applications/almanac/storage/AlmanacInterface.php',
'AlmanacInterfaceDatasource' => 'applications/almanac/typeahead/AlmanacInterfaceDatasource.php',
+ 'AlmanacInterfaceDeleteController' => 'applications/almanac/controller/AlmanacInterfaceDeleteController.php',
'AlmanacInterfaceEditController' => 'applications/almanac/controller/AlmanacInterfaceEditController.php',
'AlmanacInterfacePHIDType' => 'applications/almanac/phid/AlmanacInterfacePHIDType.php',
'AlmanacInterfaceQuery' => 'applications/almanac/query/AlmanacInterfaceQuery.php',
@@ -3996,6 +3998,7 @@
'PhabricatorDestructibleInterface',
'PhabricatorExtendedPolicyInterface',
),
+ 'AlmanacBindingDisableController' => 'AlmanacServiceController',
'AlmanacBindingEditController' => 'AlmanacServiceController',
'AlmanacBindingEditor' => 'AlmanacEditor',
'AlmanacBindingPHIDType' => 'PhabricatorPHIDType',
@@ -4049,8 +4052,10 @@
'AlmanacDAO',
'PhabricatorPolicyInterface',
'PhabricatorDestructibleInterface',
+ 'PhabricatorExtendedPolicyInterface',
),
'AlmanacInterfaceDatasource' => 'PhabricatorTypeaheadDatasource',
+ 'AlmanacInterfaceDeleteController' => 'AlmanacDeviceController',
'AlmanacInterfaceEditController' => 'AlmanacDeviceController',
'AlmanacInterfacePHIDType' => 'PhabricatorPHIDType',
'AlmanacInterfaceQuery' => 'AlmanacQuery',
diff --git a/src/applications/almanac/application/PhabricatorAlmanacApplication.php b/src/applications/almanac/application/PhabricatorAlmanacApplication.php
--- a/src/applications/almanac/application/PhabricatorAlmanacApplication.php
+++ b/src/applications/almanac/application/PhabricatorAlmanacApplication.php
@@ -55,9 +55,11 @@
),
'interface/' => array(
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacInterfaceEditController',
+ 'delete/(?:(?P<id>\d+)/)?' => 'AlmanacInterfaceDeleteController',
),
'binding/' => array(
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacBindingEditController',
+ 'disable/(?:(?P<id>\d+)/)?' => 'AlmanacBindingDisableController',
'(?P<id>\d+)/' => 'AlmanacBindingViewController',
),
'network/' => array(
@@ -80,6 +82,17 @@
}
protected function getCustomCapabilities() {
+ $cluster_caption = pht(
+ 'This permission is very dangerous. %s',
+ phutil_tag(
+ 'a',
+ array(
+ 'href' => PhabricatorEnv::getDoclink(
+ 'User Guide: Phabricator Clusters'),
+ 'target' => '_blank',
+ ),
+ pht('Learn More')));
+
return array(
AlmanacCreateServicesCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
@@ -94,7 +107,8 @@
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
AlmanacManageClusterServicesCapability::CAPABILITY => array(
- 'default' => PhabricatorPolicies::POLICY_ADMIN,
+ 'default' => PhabricatorPolicies::POLICY_NOONE,
+ 'caption' => $cluster_caption,
),
);
}
diff --git a/src/applications/almanac/controller/AlmanacBindingDisableController.php b/src/applications/almanac/controller/AlmanacBindingDisableController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/controller/AlmanacBindingDisableController.php
@@ -0,0 +1,69 @@
+<?php
+
+final class AlmanacBindingDisableController
+ extends AlmanacServiceController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $request->getViewer();
+
+ $id = $request->getURIData('id');
+ $binding = id(new AlmanacBindingQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$binding) {
+ return new Aphront404Response();
+ }
+
+ $id = $binding->getID();
+ $is_disable = !$binding->getIsDisabled();
+ $done_uri = $binding->getURI();
+
+ if ($is_disable) {
+ $disable_title = pht('Disable Binding');
+ $disable_body = pht('Disable this binding?');
+ $disable_button = pht('Disable Binding');
+
+ $v_disable = 1;
+ } else {
+ $disable_title = pht('Enable Binding');
+ $disable_body = pht('Enable this binding?');
+ $disable_button = pht('Enable Binding');
+
+ $v_disable = 0;
+ }
+
+
+ if ($request->isFormPost()) {
+ $type_disable = AlmanacBindingTransaction::TYPE_DISABLE;
+
+ $xactions = array();
+
+ $xactions[] = id(new AlmanacBindingTransaction())
+ ->setTransactionType($type_disable)
+ ->setNewValue($v_disable);
+
+ $editor = id(new AlmanacBindingEditor())
+ ->setActor($viewer)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true);
+
+ $editor->applyTransactions($binding, $xactions);
+
+ return id(new AphrontRedirectResponse())->setURI($done_uri);
+ }
+
+ return $this->newDialog()
+ ->setTitle($disable_title)
+ ->appendParagraph($disable_body)
+ ->addSubmitButton($disable_button)
+ ->addCancelButton($done_uri);
+ }
+
+}
diff --git a/src/applications/almanac/controller/AlmanacBindingViewController.php b/src/applications/almanac/controller/AlmanacBindingViewController.php
--- a/src/applications/almanac/controller/AlmanacBindingViewController.php
+++ b/src/applications/almanac/controller/AlmanacBindingViewController.php
@@ -35,6 +35,10 @@
->setHeader($title)
->setPolicyObject($binding);
+ if ($binding->getIsDisabled()) {
+ $header->setStatus('fa-ban', 'red', pht('Disabled'));
+ }
+
$box = id(new PHUIObjectBoxView())
->setHeader($header)
->addPropertyList($property_list);
@@ -114,6 +118,24 @@
->setWorkflow(!$can_edit)
->setDisabled(!$can_edit));
+ if ($binding->getIsDisabled()) {
+ $disable_icon = 'fa-check';
+ $disable_text = pht('Enable Binding');
+ } else {
+ $disable_icon = 'fa-ban';
+ $disable_text = pht('Disable Binding');
+ }
+
+ $disable_href = $this->getApplicationURI("binding/disable/{$id}/");
+
+ $actions->addAction(
+ id(new PhabricatorActionView())
+ ->setIcon($disable_icon)
+ ->setName($disable_text)
+ ->setHref($disable_href)
+ ->setWorkflow(true)
+ ->setDisabled(!$can_edit));
+
return $actions;
}
diff --git a/src/applications/almanac/controller/AlmanacController.php b/src/applications/almanac/controller/AlmanacController.php
--- a/src/applications/almanac/controller/AlmanacController.php
+++ b/src/applications/almanac/controller/AlmanacController.php
@@ -177,7 +177,8 @@
$doc_link = phutil_tag(
'a',
array(
- 'href' => PhabricatorEnv::getDoclink('Almanac User Guide'),
+ 'href' => PhabricatorEnv::getDoclink(
+ 'User Guide: Phabricator Clusters'),
'target' => '_blank',
),
pht('Learn More'));
diff --git a/src/applications/almanac/controller/AlmanacInterfaceDeleteController.php b/src/applications/almanac/controller/AlmanacInterfaceDeleteController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/controller/AlmanacInterfaceDeleteController.php
@@ -0,0 +1,72 @@
+<?php
+
+final class AlmanacInterfaceDeleteController
+ extends AlmanacDeviceController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $request->getViewer();
+
+ $id = $request->getURIData('id');
+ $interface = id(new AlmanacInterfaceQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$interface) {
+ return new Aphront404Response();
+ }
+
+ $device = $interface->getDevice();
+ $device_uri = $device->getURI();
+
+ if ($interface->loadIsInUse()) {
+ return $this->newDialog()
+ ->setTitle(pht('Interface In Use'))
+ ->appendParagraph(
+ pht(
+ 'You can not delete this interface because it is currently in '.
+ 'use. One or more services are bound to it.'))
+ ->addCancelButton($device_uri);
+ }
+
+ if ($request->isFormPost()) {
+ $type_interface = AlmanacDeviceTransaction::TYPE_INTERFACE;
+
+ $xactions = array();
+
+ $v_old = array(
+ 'id' => $interface->getID(),
+ ) + $interface->toAddress()->toDictionary();
+
+ $xactions[] = id(new AlmanacDeviceTransaction())
+ ->setTransactionType($type_interface)
+ ->setOldValue($v_old)
+ ->setNewValue(null);
+
+ $editor = id(new AlmanacDeviceEditor())
+ ->setActor($viewer)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true);
+
+ $editor->applyTransactions($device, $xactions);
+
+ return id(new AphrontRedirectResponse())->setURI($device_uri);
+ }
+
+ return $this->newDialog()
+ ->setTitle(pht('Delete Interface'))
+ ->appendParagraph(
+ pht(
+ 'Remove interface %s on device %s?',
+ phutil_tag('strong', array(), $interface->renderDisplayAddress()),
+ phutil_tag('strong', array(), $device->getName())))
+ ->addCancelButton($device_uri)
+ ->addSubmitButton(pht('Delete Interface'));
+ }
+
+}
diff --git a/src/applications/almanac/controller/AlmanacServiceViewController.php b/src/applications/almanac/controller/AlmanacServiceViewController.php
--- a/src/applications/almanac/controller/AlmanacServiceViewController.php
+++ b/src/applications/almanac/controller/AlmanacServiceViewController.php
@@ -122,7 +122,8 @@
->setNoDataString(
pht('This service has not been bound to any device interfaces yet.'))
->setUser($viewer)
- ->setBindings($bindings);
+ ->setBindings($bindings)
+ ->setHideServiceColumn(true);
$header = id(new PHUIHeaderView())
->setHeader(pht('Service Bindings'))
diff --git a/src/applications/almanac/editor/AlmanacBindingEditor.php b/src/applications/almanac/editor/AlmanacBindingEditor.php
--- a/src/applications/almanac/editor/AlmanacBindingEditor.php
+++ b/src/applications/almanac/editor/AlmanacBindingEditor.php
@@ -13,6 +13,7 @@
$types = parent::getTransactionTypes();
$types[] = AlmanacBindingTransaction::TYPE_INTERFACE;
+ $types[] = AlmanacBindingTransaction::TYPE_DISABLE;
return $types;
}
@@ -23,6 +24,8 @@
switch ($xaction->getTransactionType()) {
case AlmanacBindingTransaction::TYPE_INTERFACE:
return $object->getInterfacePHID();
+ case AlmanacBindingTransaction::TYPE_DISABLE:
+ return $object->getIsDisabled();
}
return parent::getCustomTransactionOldValue($object, $xaction);
@@ -35,6 +38,8 @@
switch ($xaction->getTransactionType()) {
case AlmanacBindingTransaction::TYPE_INTERFACE:
return $xaction->getNewValue();
+ case AlmanacBindingTransaction::TYPE_DISABLE:
+ return (int)$xaction->getNewValue();
}
return parent::getCustomTransactionNewValue($object, $xaction);
@@ -53,6 +58,9 @@
$object->setDevicePHID($interface->getDevicePHID());
$object->setInterfacePHID($interface->getPHID());
return;
+ case AlmanacBindingTransaction::TYPE_DISABLE:
+ $object->setIsDisabled($xaction->getNewValue());
+ return;
}
return parent::applyCustomInternalTransaction($object, $xaction);
@@ -63,6 +71,8 @@
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
+ case AlmanacBindingTransaction::TYPE_DISABLE:
+ return;
case AlmanacBindingTransaction::TYPE_INTERFACE:
$interface_phids = array();
diff --git a/src/applications/almanac/editor/AlmanacDeviceEditor.php b/src/applications/almanac/editor/AlmanacDeviceEditor.php
--- a/src/applications/almanac/editor/AlmanacDeviceEditor.php
+++ b/src/applications/almanac/editor/AlmanacDeviceEditor.php
@@ -310,6 +310,19 @@
pht('You can not edit an invalid or restricted interface.'),
$xaction);
$errors[] = $error;
+ continue;
+ }
+
+ $new = $xaction->getNewValue();
+ if (!$new) {
+ if ($interface->loadIsInUse()) {
+ $error = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('In Use'),
+ pht('You can not delete an interface which is still in use.'),
+ $xaction);
+ $errors[] = $error;
+ }
}
}
}
diff --git a/src/applications/almanac/engineextension/AlmanacSearchEngineAttachment.php b/src/applications/almanac/engineextension/AlmanacSearchEngineAttachment.php
--- a/src/applications/almanac/engineextension/AlmanacSearchEngineAttachment.php
+++ b/src/applications/almanac/engineextension/AlmanacSearchEngineAttachment.php
@@ -28,6 +28,7 @@
'phid' => $binding->getPHID(),
'properties' => $this->getAlmanacPropertyList($binding),
'interface' => $this->getAlmanacInterfaceDictionary($interface),
+ 'disabled' => (bool)$binding->getIsDisabled(),
);
}
diff --git a/src/applications/almanac/storage/AlmanacBinding.php b/src/applications/almanac/storage/AlmanacBinding.php
--- a/src/applications/almanac/storage/AlmanacBinding.php
+++ b/src/applications/almanac/storage/AlmanacBinding.php
@@ -13,6 +13,7 @@
protected $devicePHID;
protected $interfacePHID;
protected $mailKey;
+ protected $isDisabled;
private $service = self::ATTACHABLE;
private $device = self::ATTACHABLE;
@@ -22,7 +23,8 @@
public static function initializeNewBinding(AlmanacService $service) {
return id(new AlmanacBinding())
->setServicePHID($service->getPHID())
- ->attachAlmanacProperties(array());
+ ->attachAlmanacProperties(array())
+ ->setIsDisabled(0);
}
protected function getConfiguration() {
@@ -30,6 +32,7 @@
self::CONFIG_AUX_PHID => true,
self::CONFIG_COLUMN_SCHEMA => array(
'mailKey' => 'bytes20',
+ 'isDisabled' => 'bool',
),
self::CONFIG_KEY_SCHEMA => array(
'key_service' => array(
diff --git a/src/applications/almanac/storage/AlmanacBindingTransaction.php b/src/applications/almanac/storage/AlmanacBindingTransaction.php
--- a/src/applications/almanac/storage/AlmanacBindingTransaction.php
+++ b/src/applications/almanac/storage/AlmanacBindingTransaction.php
@@ -4,6 +4,7 @@
extends AlmanacTransaction {
const TYPE_INTERFACE = 'almanac:binding:interface';
+ const TYPE_DISABLE = 'almanac:binding:disable';
public function getApplicationName() {
return 'almanac';
@@ -57,6 +58,17 @@
$this->renderHandleLink($new));
}
break;
+ case self::TYPE_DISABLE:
+ if ($new) {
+ return pht(
+ '%s disabled this binding.',
+ $this->renderHandleLink($author_phid));
+ } else {
+ return pht(
+ '%s enabled this binding.',
+ $this->renderHandleLink($author_phid));
+ }
+ break;
}
return parent::getTitle();
diff --git a/src/applications/almanac/storage/AlmanacDeviceTransaction.php b/src/applications/almanac/storage/AlmanacDeviceTransaction.php
--- a/src/applications/almanac/storage/AlmanacDeviceTransaction.php
+++ b/src/applications/almanac/storage/AlmanacDeviceTransaction.php
@@ -69,7 +69,7 @@
return pht(
'%s removed the interface %s from this device.',
$this->renderHandleLink($author_phid),
- $this->describeInterface($new));
+ $this->describeInterface($old));
} else if ($new) {
return pht(
'%s added the interface %s to this device.',
diff --git a/src/applications/almanac/storage/AlmanacInterface.php b/src/applications/almanac/storage/AlmanacInterface.php
--- a/src/applications/almanac/storage/AlmanacInterface.php
+++ b/src/applications/almanac/storage/AlmanacInterface.php
@@ -4,7 +4,8 @@
extends AlmanacDAO
implements
PhabricatorPolicyInterface,
- PhabricatorDestructibleInterface {
+ PhabricatorDestructibleInterface,
+ PhabricatorExtendedPolicyInterface {
protected $devicePHID;
protected $networkPHID;
@@ -74,6 +75,16 @@
return $this->getAddress().':'.$this->getPort();
}
+ public function loadIsInUse() {
+ $binding = id(new AlmanacBindingQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withInterfacePHIDs(array($this->getPHID()))
+ ->setLimit(1)
+ ->executeOne();
+
+ return (bool)$binding;
+ }
+
/* -( PhabricatorPolicyInterface )----------------------------------------- */
@@ -105,6 +116,27 @@
}
+/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */
+
+
+ public function getExtendedPolicy($capability, PhabricatorUser $viewer) {
+ switch ($capability) {
+ case PhabricatorPolicyCapability::CAN_EDIT:
+ if ($this->getDevice()->isClusterDevice()) {
+ return array(
+ array(
+ new PhabricatorAlmanacApplication(),
+ AlmanacManageClusterServicesCapability::CAPABILITY,
+ ),
+ );
+ }
+ break;
+ }
+
+ return array();
+ }
+
+
/* -( PhabricatorDestructibleInterface )----------------------------------- */
diff --git a/src/applications/almanac/view/AlmanacBindingTableView.php b/src/applications/almanac/view/AlmanacBindingTableView.php
--- a/src/applications/almanac/view/AlmanacBindingTableView.php
+++ b/src/applications/almanac/view/AlmanacBindingTableView.php
@@ -5,6 +5,8 @@
private $bindings;
private $noDataString;
+ private $hideServiceColumn;
+
public function setNoDataString($no_data_string) {
$this->noDataString = $no_data_string;
return $this;
@@ -23,6 +25,15 @@
return $this->bindings;
}
+ public function setHideServiceColumn($hide_service_column) {
+ $this->hideServiceColumn = $hide_service_column;
+ return $this;
+ }
+
+ public function getHideServiceColumn() {
+ return $this->hideServiceColumn;
+ }
+
public function render() {
$bindings = $this->getBindings();
$viewer = $this->getUser();
@@ -35,6 +46,22 @@
}
$handles = $viewer->loadHandles($phids);
+ $icon_disabled = id(new PHUIIconView())
+ ->setIcon('fa-ban')
+ ->addSigil('has-tooltip')
+ ->setMetadata(
+ array(
+ 'tip' => pht('Disabled'),
+ ));
+
+ $icon_active = id(new PHUIIconView())
+ ->setIcon('fa-check')
+ ->addSigil('has-tooltip')
+ ->setMetadata(
+ array(
+ 'tip' => pht('Active'),
+ ));
+
$rows = array();
foreach ($bindings as $binding) {
$addr = $binding->getInterface()->getAddress();
@@ -42,6 +69,7 @@
$rows[] = array(
$binding->getID(),
+ ($binding->getIsDisabled() ? $icon_disabled : $icon_active),
$handles->renderHandle($binding->getServicePHID()),
$handles->renderHandle($binding->getDevicePHID()),
$handles->renderHandle($binding->getInterface()->getNetworkPHID()),
@@ -61,6 +89,7 @@
->setHeaders(
array(
pht('ID'),
+ null,
pht('Service'),
pht('Device'),
pht('Network'),
@@ -70,11 +99,18 @@
->setColumnClasses(
array(
'',
+ 'icon',
'',
'',
'',
'wide',
'action',
+ ))
+ ->setColumnVisibility(
+ array(
+ true,
+ true,
+ !$this->getHideServiceColumn(),
));
return $table;
diff --git a/src/applications/almanac/view/AlmanacInterfaceTableView.php b/src/applications/almanac/view/AlmanacInterfaceTableView.php
--- a/src/applications/almanac/view/AlmanacInterfaceTableView.php
+++ b/src/applications/almanac/view/AlmanacInterfaceTableView.php
@@ -27,7 +27,9 @@
$interfaces = $this->getInterfaces();
$viewer = $this->getUser();
- if ($this->getCanEdit()) {
+ $can_edit = $this->getCanEdit();
+
+ if ($can_edit) {
$button_class = 'small grey button';
} else {
$button_class = 'small grey button disabled';
@@ -42,13 +44,22 @@
$handles->renderHandle($interface->getNetworkPHID()),
$interface->getAddress(),
$interface->getPort(),
- phutil_tag(
+ javelin_tag(
'a',
array(
'class' => $button_class,
'href' => '/almanac/interface/edit/'.$interface->getID().'/',
+ 'sigil' => ($can_edit ? null : 'workflow'),
),
pht('Edit')),
+ javelin_tag(
+ 'a',
+ array(
+ 'class' => $button_class,
+ 'href' => '/almanac/interface/delete/'.$interface->getID().'/',
+ 'sigil' => 'workflow',
+ ),
+ pht('Delete')),
);
}
@@ -60,6 +71,7 @@
pht('Address'),
pht('Port'),
null,
+ null,
))
->setColumnClasses(
array(
@@ -68,6 +80,7 @@
'',
'',
'action',
+ 'action',
));
return $table;
diff --git a/src/applications/drydock/blueprint/DrydockAlmanacServiceHostBlueprintImplementation.php b/src/applications/drydock/blueprint/DrydockAlmanacServiceHostBlueprintImplementation.php
--- a/src/applications/drydock/blueprint/DrydockAlmanacServiceHostBlueprintImplementation.php
+++ b/src/applications/drydock/blueprint/DrydockAlmanacServiceHostBlueprintImplementation.php
@@ -267,6 +267,11 @@
$free = array();
foreach ($bindings as $binding) {
+ // Don't consider disabled bindings to be available.
+ if ($binding->getIsDisabled()) {
+ continue;
+ }
+
if (empty($allocated_phids[$binding->getPHID()])) {
$free[] = $binding;
}
diff --git a/src/docs/user/configuration/cluster.diviner b/src/docs/user/configuration/cluster.diviner
--- a/src/docs/user/configuration/cluster.diviner
+++ b/src/docs/user/configuration/cluster.diviner
@@ -1,7 +1,7 @@
@title User Guide: Phabricator Clusters
@group config
-Guide on scaling Phabricator across multiple machines, for large installs.
+Guide on scaling Phabricator across multiple machines.
Overview
========
@@ -9,10 +9,42 @@
IMPORTANT: Phabricator clustering is in its infancy and does not work at all
yet. This document is mostly a placeholder.
-Locking Services
-================
-
-Very briefly, you can set "Can Manage Cluster Services" to "No One" to lock
-the cluster definition.
+IMPORTANT: DO NOT CONFIGURE CLUSTER SERVICES UNLESS YOU HAVE **TWENTY YEARS OF
+EXPERIENCE WITH PHABRICATOR** AND **A MINIMUM OF 17 PHABRICATOR PHDs**. YOU
+WILL BREAK YOUR INSTALL AND BE UNABLE TO REPAIR IT.
See also @{article:Almanac User Guide}.
+
+
+Managing Cluster Configuration
+==============================
+
+Cluster configuration is managed primarily from the **Almanac** application.
+
+To define cluster services and create or edit cluster configuration, you must
+have the **Can Manage Cluster Services** application permission in Almanac. If
+you do not have this permission, all cluster services and all connected devices
+will be locked and not editable.
+
+The **Can Manage Cluster Services** permission is stronger than service and
+device policies, and overrides them. You can never edit a cluster service if
+you don't have this permission, even if the **Can Edit** policy on the service
+itself is very permissive.
+
+
+Locking Cluster Configuration
+=============================
+
+IMPORTANT: Managing cluster services is **dangerous** and **fragile**.
+
+If you make a mistake, you can break your install. Because the install is
+broken, you will be unable to load the web interface in order to repair it.
+
+IMPORTANT: Currently, broken clusters must be repaired by manually fixing them
+in the database. There are no instructions available on how to do this, and no
+tools to help you. Do not configure cluster services.
+
+If an attacker gains access to an account with permission to manage cluster
+services, they can add devices they control as database servers. These servers
+will then receive sensitive data and traffic, and allow the attacker to
+escalate their access and completely compromise an install.

File Metadata

Mime Type
text/plain
Expires
Thu, Oct 24, 8:24 AM (3 w, 3 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6738715
Default Alt Text
D15345.diff (25 KB)

Event Timeline