Allow repositories to be bound to an AlmanacService
Summary:
Ref T2783. This is primarily exploratory and just figuring out what we're blocked on:
- Allow a Repository to be bound to a Service. The Service may eventually define multiple read/write nodes, etc.
- There's no UI to do this binding yet, you have to touch the database manually.
- If a repository is bound to a Service, effect Conduit calls via calls to the remote service instead of executing them in-process.
- These don't actually work yet since there's no authentication (see T5955).
Test Plan:
- Made a nice Service with a nice Binding to a nice Interface on a nice Device.
- Force-associated a repository with the service using a raw MySQL query.
- Saw Phabricator try to make a remote call to the service (on localhost) and fail because of missing auth stuff.
- Also ran `almanac.queryservices`.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T2783
Differential Revision: https://secure.phabricator.com/D10982
This commit is contained in:
2
resources/sql/autopatches/20141210.reposervice.sql
Normal file
2
resources/sql/autopatches/20141210.reposervice.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE {$NAMESPACE}_repository.repository
|
||||||
|
ADD almanacServicePHID VARBINARY(64);
|
||||||
@@ -31,7 +31,8 @@ final class AlmanacQueryServicesConduitAPIMethod
|
|||||||
$viewer = $request->getUser();
|
$viewer = $request->getUser();
|
||||||
|
|
||||||
$query = id(new AlmanacServiceQuery())
|
$query = id(new AlmanacServiceQuery())
|
||||||
->setViewer($viewer);
|
->setViewer($viewer)
|
||||||
|
->needBindings(true);
|
||||||
|
|
||||||
$ids = $request->getValue('ids');
|
$ids = $request->getValue('ids');
|
||||||
if ($ids !== null) {
|
if ($ids !== null) {
|
||||||
@@ -52,16 +53,6 @@ final class AlmanacQueryServicesConduitAPIMethod
|
|||||||
|
|
||||||
$services = $query->executeWithCursorPager($pager);
|
$services = $query->executeWithCursorPager($pager);
|
||||||
|
|
||||||
if ($services) {
|
|
||||||
$bindings = id(new AlmanacBindingQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withServicePHIDs(mpull($services, 'getPHID'))
|
|
||||||
->execute();
|
|
||||||
$bindings = mgroup($bindings, 'getServicePHID');
|
|
||||||
} else {
|
|
||||||
$bindings = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = array();
|
$data = array();
|
||||||
foreach ($services as $service) {
|
foreach ($services as $service) {
|
||||||
$phid = $service->getPHID();
|
$phid = $service->getPHID();
|
||||||
@@ -69,7 +60,7 @@ final class AlmanacQueryServicesConduitAPIMethod
|
|||||||
$properties = $service->getAlmanacProperties();
|
$properties = $service->getAlmanacProperties();
|
||||||
$properties = mpull($properties, 'getFieldValue', 'getFieldName');
|
$properties = mpull($properties, 'getFieldValue', 'getFieldName');
|
||||||
|
|
||||||
$service_bindings = idx($bindings, $phid, array());
|
$service_bindings = $service->getBindings();
|
||||||
$service_bindings = array_values($service_bindings);
|
$service_bindings = array_values($service_bindings);
|
||||||
foreach ($service_bindings as $key => $service_binding) {
|
foreach ($service_bindings as $key => $service_binding) {
|
||||||
$service_bindings[$key] = $this->getBindingDictionary($service_binding);
|
$service_bindings[$key] = $this->getBindingDictionary($service_binding);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ final class AlmanacServiceQuery
|
|||||||
private $ids;
|
private $ids;
|
||||||
private $phids;
|
private $phids;
|
||||||
private $names;
|
private $names;
|
||||||
|
private $needBindings;
|
||||||
|
|
||||||
public function withIDs(array $ids) {
|
public function withIDs(array $ids) {
|
||||||
$this->ids = $ids;
|
$this->ids = $ids;
|
||||||
@@ -22,6 +23,11 @@ final class AlmanacServiceQuery
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function needBindings($need_bindings) {
|
||||||
|
$this->needBindings = $need_bindings;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
protected function loadPage() {
|
protected function loadPage() {
|
||||||
$table = new AlmanacService();
|
$table = new AlmanacService();
|
||||||
$conn_r = $table->establishConnection('r');
|
$conn_r = $table->establishConnection('r');
|
||||||
@@ -71,4 +77,22 @@ final class AlmanacServiceQuery
|
|||||||
return $this->formatWhereClause($where);
|
return $this->formatWhereClause($where);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function didFilterPage(array $services) {
|
||||||
|
if ($this->needBindings) {
|
||||||
|
$service_phids = mpull($services, 'getPHID');
|
||||||
|
$bindings = id(new AlmanacBindingQuery())
|
||||||
|
->setViewer($this->getViewer())
|
||||||
|
->withServicePHIDs($service_phids)
|
||||||
|
->execute();
|
||||||
|
$bindings = mgroup($bindings, 'getServicePHID');
|
||||||
|
|
||||||
|
foreach ($services as $service) {
|
||||||
|
$service_bindings = idx($bindings, $service->getPHID(), array());
|
||||||
|
$service->attachBindings($service_bindings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::didFilterPage($services);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ final class AlmanacService
|
|||||||
|
|
||||||
private $customFields = self::ATTACHABLE;
|
private $customFields = self::ATTACHABLE;
|
||||||
private $almanacProperties = self::ATTACHABLE;
|
private $almanacProperties = self::ATTACHABLE;
|
||||||
|
private $bindings = self::ATTACHABLE;
|
||||||
|
|
||||||
public static function initializeNewService() {
|
public static function initializeNewService() {
|
||||||
return id(new AlmanacService())
|
return id(new AlmanacService())
|
||||||
@@ -65,6 +66,15 @@ final class AlmanacService
|
|||||||
return '/almanac/service/view/'.$this->getName().'/';
|
return '/almanac/service/view/'.$this->getName().'/';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getBindings() {
|
||||||
|
return $this->assertAttached($this->bindings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachBindings(array $bindings) {
|
||||||
|
$this->bindings = $bindings;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( AlmanacPropertyInterface )------------------------------------------- */
|
/* -( AlmanacPropertyInterface )------------------------------------------- */
|
||||||
|
|
||||||
|
|||||||
@@ -62,12 +62,61 @@ abstract class DiffusionQuery extends PhabricatorQuery {
|
|||||||
|
|
||||||
$params = $params + $core_params;
|
$params = $params + $core_params;
|
||||||
|
|
||||||
return id(new ConduitCall(
|
$service_phid = $repository->getAlmanacServicePHID();
|
||||||
$method,
|
if ($service_phid === null) {
|
||||||
$params
|
return id(new ConduitCall($method, $params))
|
||||||
))
|
->setUser($user)
|
||||||
->setUser($user)
|
->execute();
|
||||||
->execute();
|
}
|
||||||
|
|
||||||
|
$service = id(new AlmanacServiceQuery())
|
||||||
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
->withPHIDs(array($service_phid))
|
||||||
|
->needBindings(true)
|
||||||
|
->executeOne();
|
||||||
|
if (!$service) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'The Alamnac service for this repository is invalid or could not '.
|
||||||
|
'be loaded.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$bindings = $service->getBindings();
|
||||||
|
if (!$bindings) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'The Alamanc service for this repository is not bound to any '.
|
||||||
|
'interfaces.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$uris = array();
|
||||||
|
foreach ($bindings as $binding) {
|
||||||
|
$iface = $binding->getInterface();
|
||||||
|
|
||||||
|
$protocol = $binding->getAlmanacPropertyValue('protocol');
|
||||||
|
if ($protocol === 'http') {
|
||||||
|
$uris[] = 'http://'.$iface->renderDisplayAddress().'/';
|
||||||
|
} else if ($protocol === 'https' || $protocol === null) {
|
||||||
|
$uris[] = 'https://'.$iface->renderDisplayAddress().'/';
|
||||||
|
} else {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'The Almanac service for this repository has a binding to an '.
|
||||||
|
'invalid interface with an unknown protocol ("%s").',
|
||||||
|
$protocol));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shuffle($uris);
|
||||||
|
$uri = head($uris);
|
||||||
|
|
||||||
|
$domain = id(new PhutilURI(PhabricatorEnv::getURI('/')))->getDomain();
|
||||||
|
|
||||||
|
// TODO: This call needs authentication, which is blocked by T5955.
|
||||||
|
|
||||||
|
return id(new ConduitClient($uri))
|
||||||
|
->setHost($domain)
|
||||||
|
->callMethodSynchronous($method, $params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function execute() {
|
public function execute() {
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
|||||||
protected $versionControlSystem;
|
protected $versionControlSystem;
|
||||||
protected $details = array();
|
protected $details = array();
|
||||||
protected $credentialPHID;
|
protected $credentialPHID;
|
||||||
|
protected $almanacServicePHID;
|
||||||
|
|
||||||
private $commitCount = self::ATTACHABLE;
|
private $commitCount = self::ATTACHABLE;
|
||||||
private $mostRecentCommit = self::ATTACHABLE;
|
private $mostRecentCommit = self::ATTACHABLE;
|
||||||
@@ -86,6 +87,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
|||||||
'uuid' => 'text64?',
|
'uuid' => 'text64?',
|
||||||
'pushPolicy' => 'policy',
|
'pushPolicy' => 'policy',
|
||||||
'credentialPHID' => 'phid?',
|
'credentialPHID' => 'phid?',
|
||||||
|
'almanacServicePHID' => 'phid?',
|
||||||
),
|
),
|
||||||
self::CONFIG_KEY_SCHEMA => array(
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
'key_phid' => null,
|
'key_phid' => null,
|
||||||
|
|||||||
Reference in New Issue
Block a user