Skip to content

Commit d5b70e2

Browse files
author
epriestley
committedOct 27, 2014
Add AlmanacBinding, to bind a service to an interface
Summary: Ref T5833. Allows you to bind a service (like `db.example.com`) to one or more interfaces (for example, to specify a pool with one read/write host and two read-only hosts). You can't configure which hosts have which properties yet, but you can add all the relevant interfaces to the service. Next diff will start supporting service, binding, and device properties like "is writable", "is active", etc., so that Almanac will be able to express operations like "change which database is writable", "disable writes", "bring a device down", etc. Test Plan: See screenshots. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T5833 Differential Revision: https://secure.phabricator.com/D10745
1 parent de40bc0 commit d5b70e2

21 files changed

+1039
-3
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CREATE TABLE {$NAMESPACE}_almanac.almanac_binding (
2+
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
3+
phid VARBINARY(64) NOT NULL,
4+
servicePHID VARBINARY(64) NOT NULL,
5+
devicePHID VARBINARY(64) NOT NULL,
6+
interfacePHID VARBINARY(64) NOT NULL,
7+
mailKey BINARY(20) NOT NULL,
8+
dateCreated INT UNSIGNED NOT NULL,
9+
dateModified INT UNSIGNED NOT NULL,
10+
UNIQUE KEY `key_phid` (phid),
11+
UNIQUE KEY `key_service` (servicePHID, interfacePHID),
12+
KEY `key_device` (devicePHID),
13+
KEY `key_interface` (interfacePHID)
14+
) ENGINE=InnoDB, COLLATE utf8_general_ci;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
CREATE TABLE {$NAMESPACE}_almanac.almanac_bindingtransaction (
2+
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
3+
phid VARCHAR(64) COLLATE utf8_bin NOT NULL,
4+
authorPHID VARCHAR(64) COLLATE utf8_bin NOT NULL,
5+
objectPHID VARCHAR(64) COLLATE utf8_bin NOT NULL,
6+
viewPolicy VARCHAR(64) COLLATE utf8_bin NOT NULL,
7+
editPolicy VARCHAR(64) COLLATE utf8_bin NOT NULL,
8+
commentPHID VARCHAR(64) COLLATE utf8_bin DEFAULT NULL,
9+
commentVersion INT UNSIGNED NOT NULL,
10+
transactionType VARCHAR(32) COLLATE utf8_bin NOT NULL,
11+
oldValue LONGTEXT COLLATE utf8_bin NOT NULL,
12+
newValue LONGTEXT COLLATE utf8_bin NOT NULL,
13+
contentSource LONGTEXT COLLATE utf8_bin NOT NULL,
14+
metadata LONGTEXT COLLATE utf8_bin NOT NULL,
15+
dateCreated INT UNSIGNED NOT NULL,
16+
dateModified INT UNSIGNED NOT NULL,
17+
UNIQUE KEY `key_phid` (`phid`),
18+
KEY `key_object` (`objectPHID`)
19+
) ENGINE=InnoDB, COLLATE utf8_general_ci;

‎src/__phutil_library_map__.php

+23
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@
1010
'__library_version__' => 2,
1111
'class' => array(
1212
'AlmanacAddress' => 'applications/almanac/util/AlmanacAddress.php',
13+
'AlmanacBinding' => 'applications/almanac/storage/AlmanacBinding.php',
14+
'AlmanacBindingEditController' => 'applications/almanac/controller/AlmanacBindingEditController.php',
15+
'AlmanacBindingEditor' => 'applications/almanac/editor/AlmanacBindingEditor.php',
16+
'AlmanacBindingPHIDType' => 'applications/almanac/phid/AlmanacBindingPHIDType.php',
17+
'AlmanacBindingQuery' => 'applications/almanac/query/AlmanacBindingQuery.php',
18+
'AlmanacBindingTableView' => 'applications/almanac/view/AlmanacBindingTableView.php',
19+
'AlmanacBindingTransaction' => 'applications/almanac/storage/AlmanacBindingTransaction.php',
20+
'AlmanacBindingTransactionQuery' => 'applications/almanac/query/AlmanacBindingTransactionQuery.php',
21+
'AlmanacBindingViewController' => 'applications/almanac/controller/AlmanacBindingViewController.php',
1322
'AlmanacConduitUtil' => 'applications/almanac/util/AlmanacConduitUtil.php',
1423
'AlmanacConsoleController' => 'applications/almanac/controller/AlmanacConsoleController.php',
1524
'AlmanacController' => 'applications/almanac/controller/AlmanacController.php',
@@ -30,6 +39,7 @@
3039
'AlmanacDeviceTransactionQuery' => 'applications/almanac/query/AlmanacDeviceTransactionQuery.php',
3140
'AlmanacDeviceViewController' => 'applications/almanac/controller/AlmanacDeviceViewController.php',
3241
'AlmanacInterface' => 'applications/almanac/storage/AlmanacInterface.php',
42+
'AlmanacInterfaceDatasource' => 'applications/almanac/typeahead/AlmanacInterfaceDatasource.php',
3343
'AlmanacInterfaceEditController' => 'applications/almanac/controller/AlmanacInterfaceEditController.php',
3444
'AlmanacInterfacePHIDType' => 'applications/almanac/phid/AlmanacInterfacePHIDType.php',
3545
'AlmanacInterfaceQuery' => 'applications/almanac/query/AlmanacInterfaceQuery.php',
@@ -2947,6 +2957,18 @@
29472957
),
29482958
'xmap' => array(
29492959
'AlmanacAddress' => 'Phobject',
2960+
'AlmanacBinding' => array(
2961+
'AlmanacDAO',
2962+
'PhabricatorPolicyInterface',
2963+
),
2964+
'AlmanacBindingEditController' => 'AlmanacServiceController',
2965+
'AlmanacBindingEditor' => 'PhabricatorApplicationTransactionEditor',
2966+
'AlmanacBindingPHIDType' => 'PhabricatorPHIDType',
2967+
'AlmanacBindingQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
2968+
'AlmanacBindingTableView' => 'AphrontView',
2969+
'AlmanacBindingTransaction' => 'PhabricatorApplicationTransaction',
2970+
'AlmanacBindingTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
2971+
'AlmanacBindingViewController' => 'AlmanacServiceController',
29502972
'AlmanacConduitUtil' => 'Phobject',
29512973
'AlmanacConsoleController' => 'AlmanacController',
29522974
'AlmanacController' => 'PhabricatorController',
@@ -2973,6 +2995,7 @@
29732995
'AlmanacDAO',
29742996
'PhabricatorPolicyInterface',
29752997
),
2998+
'AlmanacInterfaceDatasource' => 'PhabricatorTypeaheadDatasource',
29762999
'AlmanacInterfaceEditController' => 'AlmanacDeviceController',
29773000
'AlmanacInterfacePHIDType' => 'PhabricatorPHIDType',
29783001
'AlmanacInterfaceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',

‎src/applications/almanac/application/PhabricatorAlmanacApplication.php

+4
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ public function getRoutes() {
4747
'interface/' => array(
4848
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacInterfaceEditController',
4949
),
50+
'binding/' => array(
51+
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacBindingEditController',
52+
'(?P<id>\d+)/' => 'AlmanacBindingViewController',
53+
),
5054
'network/' => array(
5155
'(?:query/(?P<queryKey>[^/]+)/)?' => 'AlmanacNetworkListController',
5256
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacNetworkEditController',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<?php
2+
3+
final class AlmanacBindingEditController
4+
extends AlmanacServiceController {
5+
6+
public function handleRequest(AphrontRequest $request) {
7+
$viewer = $request->getViewer();
8+
9+
$id = $request->getURIData('id');
10+
if ($id) {
11+
$binding = id(new AlmanacBindingQuery())
12+
->setViewer($viewer)
13+
->withIDs(array($id))
14+
->requireCapabilities(
15+
array(
16+
PhabricatorPolicyCapability::CAN_VIEW,
17+
PhabricatorPolicyCapability::CAN_EDIT,
18+
))
19+
->executeOne();
20+
if (!$binding) {
21+
return new Aphront404Response();
22+
}
23+
24+
$service = $binding->getService();
25+
$is_new = false;
26+
27+
$service_uri = $service->getURI();
28+
$cancel_uri = $binding->getURI();
29+
$title = pht('Edit Binding');
30+
$save_button = pht('Save Changes');
31+
} else {
32+
$service = id(new AlmanacServiceQuery())
33+
->setViewer($viewer)
34+
->withIDs(array($request->getStr('serviceID')))
35+
->requireCapabilities(
36+
array(
37+
PhabricatorPolicyCapability::CAN_VIEW,
38+
PhabricatorPolicyCapability::CAN_EDIT,
39+
))
40+
->executeOne();
41+
42+
$binding = AlmanacBinding::initializeNewBinding($service);
43+
$is_new = true;
44+
45+
$service_uri = $service->getURI();
46+
$cancel_uri = $service_uri;
47+
$title = pht('Create Binding');
48+
$save_button = pht('Create Binding');
49+
}
50+
51+
$v_interface = array();
52+
if ($binding->getInterfacePHID()) {
53+
$v_interface = array($binding->getInterfacePHID());
54+
}
55+
$e_interface = true;
56+
57+
$validation_exception = null;
58+
if ($request->isFormPost()) {
59+
$v_interface = $request->getArr('interfacePHIDs');
60+
61+
$type_interface = AlmanacBindingTransaction::TYPE_INTERFACE;
62+
63+
$xactions = array();
64+
65+
$xactions[] = id(new AlmanacBindingTransaction())
66+
->setTransactionType($type_interface)
67+
->setNewValue(head($v_interface));
68+
69+
$editor = id(new AlmanacBindingEditor())
70+
->setActor($viewer)
71+
->setContentSourceFromRequest($request)
72+
->setContinueOnNoEffect(true);
73+
74+
try {
75+
$editor->applyTransactions($binding, $xactions);
76+
77+
$binding_uri = $binding->getURI();
78+
return id(new AphrontRedirectResponse())->setURI($binding_uri);
79+
} catch (PhabricatorApplicationTransactionValidationException $ex) {
80+
$validation_exception = $ex;
81+
$e_interface = $ex->getShortMessage($type_interface);
82+
}
83+
}
84+
85+
$interface_handles = array();
86+
if ($v_interface) {
87+
$interface_handles = $this->loadViewerHandles($v_interface);
88+
}
89+
90+
$form = id(new AphrontFormView())
91+
->setUser($viewer)
92+
->appendChild(
93+
id(new AphrontFormTokenizerControl())
94+
->setName('interfacePHIDs')
95+
->setLabel('Interface')
96+
->setLimit(1)
97+
->setDatasource(new AlmanacInterfaceDatasource())
98+
->setValue($interface_handles)
99+
->setError($e_interface))
100+
->appendChild(
101+
id(new AphrontFormSubmitControl())
102+
->addCancelButton($cancel_uri)
103+
->setValue($save_button));
104+
105+
$box = id(new PHUIObjectBoxView())
106+
->setValidationException($validation_exception)
107+
->setHeaderText($title)
108+
->appendChild($form);
109+
110+
$crumbs = $this->buildApplicationCrumbs();
111+
$crumbs->addTextCrumb($service->getName(), $service_uri);
112+
if ($is_new) {
113+
$crumbs->addTextCrumb(pht('Create Binding'));
114+
} else {
115+
$crumbs->addTextCrumb(pht('Edit Binding'));
116+
}
117+
118+
return $this->buildApplicationPage(
119+
array(
120+
$crumbs,
121+
$box,
122+
),
123+
array(
124+
'title' => $title,
125+
));
126+
}
127+
128+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?php
2+
3+
final class AlmanacBindingViewController
4+
extends AlmanacServiceController {
5+
6+
public function shouldAllowPublic() {
7+
return true;
8+
}
9+
10+
public function handleRequest(AphrontRequest $request) {
11+
$viewer = $request->getViewer();
12+
13+
$id = $request->getURIData('id');
14+
15+
$binding = id(new AlmanacBindingQuery())
16+
->setViewer($viewer)
17+
->withIDs(array($id))
18+
->executeOne();
19+
if (!$binding) {
20+
return new Aphront404Response();
21+
}
22+
23+
$service = $binding->getService();
24+
$service_uri = $service->getURI();
25+
26+
$title = pht('Binding %s', $binding->getID());
27+
28+
$property_list = $this->buildPropertyList($binding);
29+
$action_list = $this->buildActionList($binding);
30+
$property_list->setActionList($action_list);
31+
32+
$header = id(new PHUIHeaderView())
33+
->setUser($viewer)
34+
->setHeader($title)
35+
->setPolicyObject($binding);
36+
37+
$box = id(new PHUIObjectBoxView())
38+
->setHeader($header)
39+
->addPropertyList($property_list);
40+
41+
$crumbs = $this->buildApplicationCrumbs();
42+
$crumbs->addTextCrumb($service->getName(), $service_uri);
43+
$crumbs->addTextCrumb($title);
44+
45+
$xactions = id(new AlmanacBindingTransactionQuery())
46+
->setViewer($viewer)
47+
->withObjectPHIDs(array($binding->getPHID()))
48+
->execute();
49+
50+
$xaction_view = id(new PhabricatorApplicationTransactionView())
51+
->setUser($viewer)
52+
->setObjectPHID($binding->getPHID())
53+
->setTransactions($xactions)
54+
->setShouldTerminate(true);
55+
56+
return $this->buildApplicationPage(
57+
array(
58+
$crumbs,
59+
$box,
60+
$xaction_view,
61+
),
62+
array(
63+
'title' => $title,
64+
));
65+
}
66+
67+
private function buildPropertyList(AlmanacBinding $binding) {
68+
$viewer = $this->getViewer();
69+
70+
$properties = id(new PHUIPropertyListView())
71+
->setUser($viewer);
72+
73+
$handles = $this->loadViewerHandles(
74+
array(
75+
$binding->getServicePHID(),
76+
$binding->getDevicePHID(),
77+
$binding->getInterface()->getNetworkPHID(),
78+
));
79+
80+
$properties->addProperty(
81+
pht('Service'),
82+
$handles[$binding->getServicePHID()]->renderLink());
83+
84+
$properties->addProperty(
85+
pht('Device'),
86+
$handles[$binding->getDevicePHID()]->renderLink());
87+
88+
$properties->addProperty(
89+
pht('Network'),
90+
$handles[$binding->getInterface()->getNetworkPHID()]->renderLink());
91+
92+
$properties->addProperty(
93+
pht('Interface'),
94+
$binding->getInterface()->renderDisplayAddress());
95+
96+
return $properties;
97+
}
98+
99+
private function buildActionList(AlmanacBinding $binding) {
100+
$viewer = $this->getViewer();
101+
$id = $binding->getID();
102+
103+
$can_edit = PhabricatorPolicyFilter::hasCapability(
104+
$viewer,
105+
$binding,
106+
PhabricatorPolicyCapability::CAN_EDIT);
107+
108+
$actions = id(new PhabricatorActionListView())
109+
->setUser($viewer);
110+
111+
$actions->addAction(
112+
id(new PhabricatorActionView())
113+
->setIcon('fa-pencil')
114+
->setName(pht('Edit Binding'))
115+
->setHref($this->getApplicationURI("binding/edit/{$id}/"))
116+
->setWorkflow(!$can_edit)
117+
->setDisabled(!$can_edit));
118+
119+
return $actions;
120+
}
121+
122+
}

0 commit comments

Comments
 (0)
Failed to load comments.