Skip to content

Commit db50d0f

Browse files
author
epriestley
committedFeb 22, 2016
Rough-in Almanac namespaces
Summary: Ref T6741. Ref T10246. Root problem: to provide Drydock in the cluster, we need to expose Almanac, and doing so would let users accidentally or intentionally create a bunch of `repo006.phacility.net` devices/services which could conflict with the real ones we manage. There's currently no way to say "you can't create anything named `*.blah.net`". This adds "namespaces", which let you do that (well, not yet, but they will after the next diff). After the next diff, if you try to create `repo003.phacility.net`, but the namespace `phacility.net` already exists and you don't have permission to edit it, you'll be asked to choose a different name. Also various modernizations and some new docs. Test Plan: - Created cool namespaces like `this.computer`. - Almanac namespaces don't actually enforce policies yet. Reviewers: chad Reviewed By: chad Maniphest Tasks: T6741, T10246 Differential Revision: https://secure.phabricator.com/D15324
1 parent 50debec commit db50d0f

29 files changed

+1195
-40
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CREATE TABLE {$NAMESPACE}_almanac.almanac_namespacename_ngrams (
2+
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
3+
objectID INT UNSIGNED NOT NULL,
4+
ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT},
5+
KEY `key_object` (objectID),
6+
KEY `key_ngram` (ngram, objectID)
7+
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CREATE TABLE {$NAMESPACE}_almanac.almanac_namespace (
2+
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
3+
phid VARBINARY(64) NOT NULL,
4+
name VARCHAR(128) NOT NULL COLLATE {$COLLATE_TEXT},
5+
nameIndex BINARY(12) NOT NULL,
6+
mailKey BINARY(20) NOT NULL,
7+
viewPolicy VARBINARY(64) NOT NULL,
8+
editPolicy VARBINARY(64) NOT NULL,
9+
dateCreated INT UNSIGNED NOT NULL,
10+
dateModified INT UNSIGNED NOT NULL,
11+
UNIQUE KEY `key_phid` (phid),
12+
UNIQUE KEY `key_nameindex` (nameIndex),
13+
KEY `key_name` (name)
14+
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
CREATE TABLE {$NAMESPACE}_almanac.almanac_namespacetransaction (
2+
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
3+
phid VARBINARY(64) NOT NULL,
4+
authorPHID VARBINARY(64) NOT NULL,
5+
objectPHID VARBINARY(64) NOT NULL,
6+
viewPolicy VARBINARY(64) NOT NULL,
7+
editPolicy VARBINARY(64) NOT NULL,
8+
commentPHID VARBINARY(64) DEFAULT NULL,
9+
commentVersion INT UNSIGNED NOT NULL,
10+
transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL,
11+
oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
12+
newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
13+
contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
14+
metadata LONGTEXT COLLATE {$COLLATE_TEXT} 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 {$COLLATE_TEXT};

‎src/__phutil_library_map__.php

+37
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
'AlmanacCoreCustomField' => 'applications/almanac/customfield/AlmanacCoreCustomField.php',
2929
'AlmanacCreateClusterServicesCapability' => 'applications/almanac/capability/AlmanacCreateClusterServicesCapability.php',
3030
'AlmanacCreateDevicesCapability' => 'applications/almanac/capability/AlmanacCreateDevicesCapability.php',
31+
'AlmanacCreateNamespacesCapability' => 'applications/almanac/capability/AlmanacCreateNamespacesCapability.php',
3132
'AlmanacCreateNetworksCapability' => 'applications/almanac/capability/AlmanacCreateNetworksCapability.php',
3233
'AlmanacCreateServicesCapability' => 'applications/almanac/capability/AlmanacCreateServicesCapability.php',
3334
'AlmanacCustomField' => 'applications/almanac/customfield/AlmanacCustomField.php',
@@ -61,6 +62,19 @@
6162
'AlmanacManagementWorkflow' => 'applications/almanac/management/AlmanacManagementWorkflow.php',
6263
'AlmanacNames' => 'applications/almanac/util/AlmanacNames.php',
6364
'AlmanacNamesTestCase' => 'applications/almanac/util/__tests__/AlmanacNamesTestCase.php',
65+
'AlmanacNamespace' => 'applications/almanac/storage/AlmanacNamespace.php',
66+
'AlmanacNamespaceController' => 'applications/almanac/controller/AlmanacNamespaceController.php',
67+
'AlmanacNamespaceEditController' => 'applications/almanac/controller/AlmanacNamespaceEditController.php',
68+
'AlmanacNamespaceEditEngine' => 'applications/almanac/editor/AlmanacNamespaceEditEngine.php',
69+
'AlmanacNamespaceEditor' => 'applications/almanac/editor/AlmanacNamespaceEditor.php',
70+
'AlmanacNamespaceListController' => 'applications/almanac/controller/AlmanacNamespaceListController.php',
71+
'AlmanacNamespaceNameNgrams' => 'applications/almanac/storage/AlmanacNamespaceNameNgrams.php',
72+
'AlmanacNamespacePHIDType' => 'applications/almanac/phid/AlmanacNamespacePHIDType.php',
73+
'AlmanacNamespaceQuery' => 'applications/almanac/query/AlmanacNamespaceQuery.php',
74+
'AlmanacNamespaceSearchEngine' => 'applications/almanac/query/AlmanacNamespaceSearchEngine.php',
75+
'AlmanacNamespaceTransaction' => 'applications/almanac/storage/AlmanacNamespaceTransaction.php',
76+
'AlmanacNamespaceTransactionQuery' => 'applications/almanac/query/AlmanacNamespaceTransactionQuery.php',
77+
'AlmanacNamespaceViewController' => 'applications/almanac/controller/AlmanacNamespaceViewController.php',
6478
'AlmanacNetwork' => 'applications/almanac/storage/AlmanacNetwork.php',
6579
'AlmanacNetworkController' => 'applications/almanac/controller/AlmanacNetworkController.php',
6680
'AlmanacNetworkEditController' => 'applications/almanac/controller/AlmanacNetworkEditController.php',
@@ -4000,6 +4014,7 @@
40004014
),
40014015
'AlmanacCreateClusterServicesCapability' => 'PhabricatorPolicyCapability',
40024016
'AlmanacCreateDevicesCapability' => 'PhabricatorPolicyCapability',
4017+
'AlmanacCreateNamespacesCapability' => 'PhabricatorPolicyCapability',
40034018
'AlmanacCreateNetworksCapability' => 'PhabricatorPolicyCapability',
40044019
'AlmanacCreateServicesCapability' => 'PhabricatorPolicyCapability',
40054020
'AlmanacCustomField' => 'PhabricatorCustomField',
@@ -4047,6 +4062,28 @@
40474062
'AlmanacManagementWorkflow' => 'PhabricatorManagementWorkflow',
40484063
'AlmanacNames' => 'Phobject',
40494064
'AlmanacNamesTestCase' => 'PhabricatorTestCase',
4065+
'AlmanacNamespace' => array(
4066+
'AlmanacDAO',
4067+
'PhabricatorPolicyInterface',
4068+
'PhabricatorCustomFieldInterface',
4069+
'PhabricatorApplicationTransactionInterface',
4070+
'PhabricatorProjectInterface',
4071+
'AlmanacPropertyInterface',
4072+
'PhabricatorDestructibleInterface',
4073+
'PhabricatorNgramsInterface',
4074+
),
4075+
'AlmanacNamespaceController' => 'AlmanacController',
4076+
'AlmanacNamespaceEditController' => 'AlmanacController',
4077+
'AlmanacNamespaceEditEngine' => 'PhabricatorEditEngine',
4078+
'AlmanacNamespaceEditor' => 'PhabricatorApplicationTransactionEditor',
4079+
'AlmanacNamespaceListController' => 'AlmanacNamespaceController',
4080+
'AlmanacNamespaceNameNgrams' => 'PhabricatorSearchNgrams',
4081+
'AlmanacNamespacePHIDType' => 'PhabricatorPHIDType',
4082+
'AlmanacNamespaceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
4083+
'AlmanacNamespaceSearchEngine' => 'PhabricatorApplicationSearchEngine',
4084+
'AlmanacNamespaceTransaction' => 'PhabricatorApplicationTransaction',
4085+
'AlmanacNamespaceTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
4086+
'AlmanacNamespaceViewController' => 'AlmanacNamespaceController',
40504087
'AlmanacNetwork' => array(
40514088
'AlmanacDAO',
40524089
'PhabricatorApplicationTransactionInterface',

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

+13-4
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public function getApplicationGroup() {
2929
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
3030
return array(
3131
array(
32-
'name' => pht('Alamanac User Guide'),
32+
'name' => pht('Almanac User Guide'),
3333
'href' => PhabricatorEnv::getDoclink('Almanac User Guide'),
3434
),
3535
);
@@ -44,12 +44,12 @@ public function getRoutes() {
4444
'/almanac/' => array(
4545
'' => 'AlmanacConsoleController',
4646
'service/' => array(
47-
'(?:query/(?P<queryKey>[^/]+)/)?' => 'AlmanacServiceListController',
47+
$this->getQueryRoutePattern() => 'AlmanacServiceListController',
4848
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacServiceEditController',
4949
'view/(?P<name>[^/]+)/' => 'AlmanacServiceViewController',
5050
),
5151
'device/' => array(
52-
'(?:query/(?P<queryKey>[^/]+)/)?' => 'AlmanacDeviceListController',
52+
$this->getQueryRoutePattern() => 'AlmanacDeviceListController',
5353
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacDeviceEditController',
5454
'view/(?P<name>[^/]+)/' => 'AlmanacDeviceViewController',
5555
),
@@ -61,14 +61,20 @@ public function getRoutes() {
6161
'(?P<id>\d+)/' => 'AlmanacBindingViewController',
6262
),
6363
'network/' => array(
64-
'(?:query/(?P<queryKey>[^/]+)/)?' => 'AlmanacNetworkListController',
64+
$this->getQueryRoutePattern() => 'AlmanacNetworkListController',
6565
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacNetworkEditController',
6666
'(?P<id>\d+)/' => 'AlmanacNetworkViewController',
6767
),
6868
'property/' => array(
6969
'edit/' => 'AlmanacPropertyEditController',
7070
'delete/' => 'AlmanacPropertyDeleteController',
7171
),
72+
'namespace/' => array(
73+
$this->getQueryRoutePattern() => 'AlmanacNamespaceListController',
74+
$this->getEditRoutePattern('edit/')
75+
=> 'AlmanacNamespaceEditController',
76+
'(?P<id>\d+)/' => 'AlmanacNamespaceViewController',
77+
),
7278
),
7379
);
7480
}
@@ -84,6 +90,9 @@ protected function getCustomCapabilities() {
8490
AlmanacCreateNetworksCapability::CAPABILITY => array(
8591
'default' => PhabricatorPolicies::POLICY_ADMIN,
8692
),
93+
AlmanacCreateNamespacesCapability::CAPABILITY => array(
94+
'default' => PhabricatorPolicies::POLICY_ADMIN,
95+
),
8796
AlmanacCreateClusterServicesCapability::CAPABILITY => array(
8897
'default' => PhabricatorPolicies::POLICY_ADMIN,
8998
),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
final class AlmanacCreateNamespacesCapability
4+
extends PhabricatorPolicyCapability {
5+
6+
const CAPABILITY = 'almanac.namespaces';
7+
8+
public function getCapabilityName() {
9+
return pht('Can Create Namespaces');
10+
}
11+
12+
public function describeCapabilityRejection() {
13+
return pht('You do not have permission to create Almanac namespaces.');
14+
}
15+
16+
}

‎src/applications/almanac/controller/AlmanacConsoleController.php

+35-9
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,52 @@ public function handleRequest(AphrontRequest $request) {
1212
$menu = id(new PHUIObjectItemListView())
1313
->setUser($viewer);
1414

15-
$menu->addItem(
16-
id(new PHUIObjectItemView())
17-
->setHeader(pht('Services'))
18-
->setHref($this->getApplicationURI('service/'))
19-
->setIcon('fa-plug')
20-
->addAttribute(pht('Manage Almanac services.')));
21-
2215
$menu->addItem(
2316
id(new PHUIObjectItemView())
2417
->setHeader(pht('Devices'))
2518
->setHref($this->getApplicationURI('device/'))
2619
->setIcon('fa-server')
27-
->addAttribute(pht('Manage Almanac devices.')));
20+
->addAttribute(
21+
pht(
22+
'Create an inventory of physical and virtual hosts and '.
23+
'devices.')));
24+
25+
$menu->addItem(
26+
id(new PHUIObjectItemView())
27+
->setHeader(pht('Services'))
28+
->setHref($this->getApplicationURI('service/'))
29+
->setIcon('fa-plug')
30+
->addAttribute(
31+
pht(
32+
'Create and update services, and map them to interfaces on '.
33+
'devices.')));
2834

2935
$menu->addItem(
3036
id(new PHUIObjectItemView())
3137
->setHeader(pht('Networks'))
3238
->setHref($this->getApplicationURI('network/'))
3339
->setIcon('fa-globe')
34-
->addAttribute(pht('Manage Almanac networks.')));
40+
->addAttribute(
41+
pht(
42+
'Manage public and private networks.')));
43+
44+
$menu->addItem(
45+
id(new PHUIObjectItemView())
46+
->setHeader(pht('Namespaces'))
47+
->setHref($this->getApplicationURI('namespace/'))
48+
->setIcon('fa-asterisk')
49+
->addAttribute(
50+
pht('Control who can create new named services and devices.')));
51+
52+
$docs_uri = PhabricatorEnv::getDoclink(
53+
'Almanac User Guide');
54+
55+
$menu->addItem(
56+
id(new PHUIObjectItemView())
57+
->setHeader(pht('Documentation'))
58+
->setHref($docs_uri)
59+
->setIcon('fa-book')
60+
->addAttribute(pht('Browse documentation for Almanac.')));
3561

3662
$crumbs = $this->buildApplicationCrumbs();
3763
$crumbs->addTextCrumb(pht('Console'));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
abstract class AlmanacNamespaceController extends AlmanacController {
4+
5+
protected function buildApplicationCrumbs() {
6+
$crumbs = parent::buildApplicationCrumbs();
7+
8+
$list_uri = $this->getApplicationURI('namespace/');
9+
$crumbs->addTextCrumb(pht('Namespaces'), $list_uri);
10+
11+
return $crumbs;
12+
}
13+
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
final class AlmanacNamespaceEditController extends AlmanacController {
4+
5+
public function handleRequest(AphrontRequest $request) {
6+
return id(new AlmanacNamespaceEditEngine())
7+
->setController($this)
8+
->buildResponse();
9+
}
10+
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
final class AlmanacNamespaceListController
4+
extends AlmanacNamespaceController {
5+
6+
public function shouldAllowPublic() {
7+
return true;
8+
}
9+
10+
public function handleRequest(AphrontRequest $request) {
11+
return id(new AlmanacNamespaceSearchEngine())
12+
->setController($this)
13+
->buildResponse();
14+
}
15+
16+
protected function buildApplicationCrumbs() {
17+
$crumbs = parent::buildApplicationCrumbs();
18+
19+
id(new AlmanacNamespaceEditEngine())
20+
->setViewer($this->getViewer())
21+
->addActionToCrumbs($crumbs);
22+
23+
return $crumbs;
24+
}
25+
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
final class AlmanacNamespaceViewController
4+
extends AlmanacNamespaceController {
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+
$namespace = id(new AlmanacNamespaceQuery())
15+
->setViewer($viewer)
16+
->withIDs(array($id))
17+
->executeOne();
18+
if (!$namespace) {
19+
return new Aphront404Response();
20+
}
21+
22+
$title = pht('Namespace %s', $namespace->getName());
23+
24+
$property_list = $this->buildPropertyList($namespace);
25+
$action_list = $this->buildActionList($namespace);
26+
$property_list->setActionList($action_list);
27+
28+
$header = id(new PHUIHeaderView())
29+
->setUser($viewer)
30+
->setHeader($namespace->getName())
31+
->setPolicyObject($namespace);
32+
33+
$box = id(new PHUIObjectBoxView())
34+
->setHeader($header)
35+
->addPropertyList($property_list);
36+
37+
$crumbs = $this->buildApplicationCrumbs();
38+
$crumbs->addTextCrumb($namespace->getName());
39+
40+
$timeline = $this->buildTransactionTimeline(
41+
$namespace,
42+
new AlmanacNamespaceTransactionQuery());
43+
$timeline->setShouldTerminate(true);
44+
45+
return $this->newPage()
46+
->setTitle($title)
47+
->setCrumbs($crumbs)
48+
->appendChild(
49+
array(
50+
$box,
51+
$timeline,
52+
));
53+
}
54+
55+
private function buildPropertyList(AlmanacNamespace $namespace) {
56+
$viewer = $this->getViewer();
57+
58+
$properties = id(new PHUIPropertyListView())
59+
->setUser($viewer);
60+
61+
return $properties;
62+
}
63+
64+
private function buildActionList(AlmanacNamespace $namespace) {
65+
$viewer = $this->getViewer();
66+
$id = $namespace->getID();
67+
68+
$can_edit = PhabricatorPolicyFilter::hasCapability(
69+
$viewer,
70+
$namespace,
71+
PhabricatorPolicyCapability::CAN_EDIT);
72+
73+
$actions = id(new PhabricatorActionListView())
74+
->setUser($viewer);
75+
76+
$actions->addAction(
77+
id(new PhabricatorActionView())
78+
->setIcon('fa-pencil')
79+
->setName(pht('Edit Namespace'))
80+
->setHref($this->getApplicationURI("namespace/edit/{$id}/"))
81+
->setWorkflow(!$can_edit)
82+
->setDisabled(!$can_edit));
83+
84+
return $actions;
85+
}
86+
87+
}

0 commit comments

Comments
 (0)
Failed to load comments.