Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14415042
D15757.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
9 KB
Referenced Files
None
Subscribers
None
D15757.id.diff
View Options
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
@@ -132,7 +132,7 @@
->setHideServiceColumn(true);
$header = id(new PHUIHeaderView())
- ->setHeader(pht('SERVICE BINDINGS'))
+ ->setHeader(pht('Service Bindings'))
->addActionLink(
id(new PHUIButtonView())
->setTag('a')
diff --git a/src/applications/diffusion/ssh/DiffusionGitUploadPackSSHWorkflow.php b/src/applications/diffusion/ssh/DiffusionGitUploadPackSSHWorkflow.php
--- a/src/applications/diffusion/ssh/DiffusionGitUploadPackSSHWorkflow.php
+++ b/src/applications/diffusion/ssh/DiffusionGitUploadPackSSHWorkflow.php
@@ -16,11 +16,15 @@
protected function executeRepositoryOperations() {
$repository = $this->getRepository();
+ $skip_sync = $this->shouldSkipReadSynchronization();
+
if ($this->shouldProxy()) {
$command = $this->getProxyCommand();
} else {
$command = csprintf('git-upload-pack -- %s', $repository->getLocalPath());
- $repository->synchronizeWorkingCopyBeforeRead();
+ if (!$skip_sync) {
+ $repository->synchronizeWorkingCopyBeforeRead();
+ }
}
$command = PhabricatorDaemon::sudoCommandAsDaemonUser($command);
diff --git a/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php b/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php
--- a/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php
+++ b/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php
@@ -201,6 +201,14 @@
$repository = $this->getRepository();
$viewer = $this->getUser();
+ if ($viewer->isOmnipotent()) {
+ throw new Exception(
+ pht(
+ 'This request is authenticated as a cluster device, but is '.
+ 'performing a write. Writes must be performed with a real '.
+ 'user account.'));
+ }
+
switch ($repository->getServeOverSSH()) {
case PhabricatorRepository::SERVE_READONLY:
if ($protocol_command !== null) {
@@ -236,4 +244,18 @@
return $this->hasWriteAccess;
}
+ protected function shouldSkipReadSynchronization() {
+ $viewer = $this->getUser();
+
+ // Currently, the only case where devices interact over SSH without
+ // assuming user credentials is when synchronizing before a read. These
+ // synchronizing reads do not themselves need to be synchronized.
+ if ($viewer->isOmnipotent()) {
+ return true;
+ }
+
+ return false;
+ }
+
+
}
diff --git a/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php b/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php
--- a/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php
+++ b/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php
@@ -96,6 +96,8 @@
}
if ($repository->isHosted()) {
+ $repository->synchronizeWorkingCopyBeforeRead();
+
if ($is_git) {
$this->installGitHook();
} else if ($is_svn) {
diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php
--- a/src/applications/repository/storage/PhabricatorRepository.php
+++ b/src/applications/repository/storage/PhabricatorRepository.php
@@ -1349,7 +1349,7 @@
}
$ssh_user = AlmanacKeys::getClusterSSHUser();
- if ($ssh_user !== null) {
+ if (strlen($ssh_user)) {
$uri->setUser($ssh_user);
}
@@ -1927,31 +1927,9 @@
$never_proxy,
array $protocols) {
- $service_phid = $this->getAlmanacServicePHID();
- if (!$service_phid) {
- // No service, so this is a local repository.
- return null;
- }
-
- $service = id(new AlmanacServiceQuery())
- ->setViewer(PhabricatorUser::getOmnipotentUser())
- ->withPHIDs(array($service_phid))
- ->needBindings(true)
- ->needProperties(true)
- ->executeOne();
+ $service = $this->loadAlmanacService();
if (!$service) {
- throw new Exception(
- pht(
- 'The Almanac service for this repository is invalid or could not '.
- 'be loaded.'));
- }
-
- $service_type = $service->getServiceImplementation();
- if (!($service_type instanceof AlmanacClusterRepositoryServiceType)) {
- throw new Exception(
- pht(
- 'The Almanac service for this repository does not have the correct '.
- 'service type.'));
+ return null;
}
$bindings = $service->getBindings();
@@ -1990,16 +1968,14 @@
}
}
- $protocol = $binding->getAlmanacPropertyValue('protocol');
- if ($protocol === null) {
- $protocol = 'https';
- }
+ $uri = $this->getClusterRepositoryURIFromBinding($binding);
+ $protocol = $uri->getProtocol();
if (empty($protocol_map[$protocol])) {
continue;
}
- $uris[] = $protocol.'://'.$iface->renderDisplayAddress().'/';
+ $uris[] = $uri;
}
if (!$uris) {
@@ -2226,6 +2202,16 @@
return false;
}
+ $service_phid = $this->getAlmanacServicePHID();
+ if (!$service_phid) {
+ return false;
+ }
+
+ // TODO: For now, this is only supported for Git.
+ if (!$this->isGit()) {
+ return false;
+ }
+
return true;
}
@@ -2275,8 +2261,7 @@
}
}
- // TODO: Actualy fetch the newer version from one of the nodes which has
- // it.
+ $this->synchronizeWorkingCopyFromDevices($fetchable);
PhabricatorRepositoryWorkingCopyVersion::updateVersion(
$repository_phid,
@@ -2393,6 +2378,137 @@
}
+ /**
+ * @task sync
+ */
+ private function synchronizeWorkingCopyFromDevices(array $device_phids) {
+ $service = $this->loadAlmanacService();
+ if (!$service) {
+ throw new Exception(pht('Failed to load repository cluster service.'));
+ }
+
+ $device_map = array_fuse($device_phids);
+ $bindings = $service->getBindings();
+
+ $fetchable = array();
+ foreach ($bindings as $binding) {
+ // We can't fetch from disabled nodes.
+ if ($binding->getIsDisabled()) {
+ continue;
+ }
+
+ // We can't fetch from nodes which don't have the newest version.
+ $device_phid = $binding->getDevicePHID();
+ if (empty($device_map[$device_phid])) {
+ continue;
+ }
+
+ // TODO: For now, only fetch over SSH. We could support fetching over
+ // HTTP eventually.
+ if ($binding->getAlmanacPropertyValue('protocol') != 'ssh') {
+ continue;
+ }
+
+ $fetchable[] = $binding;
+ }
+
+ if (!$fetchable) {
+ throw new Exception(
+ pht(
+ 'Leader lost: no up-to-date nodes in repository cluster are '.
+ 'fetchable.'));
+ }
+
+ $caught = null;
+ foreach ($fetchable as $binding) {
+ try {
+ $this->synchronizeWorkingCopyFromBinding($binding);
+ $caught = null;
+ break;
+ } catch (Exception $ex) {
+ $caught = $ex;
+ }
+ }
+
+ if ($caught) {
+ throw $caught;
+ }
+ }
+
+ private function synchronizeWorkingCopyFromBinding($binding) {
+ $fetch_uri = $this->getClusterRepositoryURIFromBinding($binding);
+
+ if ($this->isGit()) {
+ $argv = array(
+ 'fetch --prune -- %s %s',
+ $fetch_uri,
+ '+refs/*:refs/*',
+ );
+ } else {
+ throw new Exception(pht('Binding sync only supported for git!'));
+ }
+
+ $future = DiffusionCommandEngine::newCommandEngine($this)
+ ->setArgv($argv)
+ ->setConnectAsDevice(true)
+ ->setProtocol($fetch_uri->getProtocol())
+ ->newFuture();
+
+ $future->setCWD($this->getLocalPath());
+
+ $future->resolvex();
+ }
+
+ private function getClusterRepositoryURIFromBinding(
+ AlmanacBinding $binding) {
+ $protocol = $binding->getAlmanacPropertyValue('protocol');
+ if ($protocol === null) {
+ $protocol = 'https';
+ }
+
+ $iface = $binding->getInterface();
+ $address = $iface->renderDisplayAddress();
+
+ $path = $this->getURI();
+
+ return id(new PhutilURI("{$protocol}://{$address}"))
+ ->setPath($path);
+ }
+
+ private function loadAlmanacService() {
+ $service_phid = $this->getAlmanacServicePHID();
+ if (!$service_phid) {
+ // No service, so this is a local repository.
+ return null;
+ }
+
+ $service = id(new AlmanacServiceQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withPHIDs(array($service_phid))
+ ->needBindings(true)
+ ->needProperties(true)
+ ->executeOne();
+ if (!$service) {
+ throw new Exception(
+ pht(
+ 'The Almanac service for this repository is invalid or could not '.
+ 'be loaded.'));
+ }
+
+ $service_type = $service->getServiceImplementation();
+ if (!($service_type instanceof AlmanacClusterRepositoryServiceType)) {
+ throw new Exception(
+ pht(
+ 'The Almanac service for this repository does not have the correct '.
+ 'service type.'));
+ }
+
+ return $service;
+ }
+
+
+
+
/* -( Symbols )-------------------------------------------------------------*/
public function getSymbolSources() {
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Dec 25, 4:48 PM (1 h, 5 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6924437
Default Alt Text
D15757.id.diff (9 KB)
Attached To
Mode
D15757: Synchronize (hosted, git, clustered, SSH) repositories prior to reads
Attached
Detach File
Event Timeline
Log In to Comment