@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add `bin/repository clusterize` and document setup and migration for clusters

Summary: Ref T4292. This provides at least some sort of hint about how to set up cluster repositories.

Test Plan:
- Read documentation.
- Ran `bin/repository clusterize` to add + remove clusters.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T4292

Differential Revision: https://secure.phabricator.com/D15798

+286 -24
+2
src/__phutil_library_map__.php
··· 3174 3174 'PhabricatorRepositoryGraphCache' => 'applications/repository/graphcache/PhabricatorRepositoryGraphCache.php', 3175 3175 'PhabricatorRepositoryGraphStream' => 'applications/repository/daemon/PhabricatorRepositoryGraphStream.php', 3176 3176 'PhabricatorRepositoryManagementCacheWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementCacheWorkflow.php', 3177 + 'PhabricatorRepositoryManagementClusterizeWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementClusterizeWorkflow.php', 3177 3178 'PhabricatorRepositoryManagementDiscoverWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php', 3178 3179 'PhabricatorRepositoryManagementEditWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementEditWorkflow.php', 3179 3180 'PhabricatorRepositoryManagementImportingWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php', ··· 7832 7833 'PhabricatorRepositoryGraphCache' => 'Phobject', 7833 7834 'PhabricatorRepositoryGraphStream' => 'Phobject', 7834 7835 'PhabricatorRepositoryManagementCacheWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 7836 + 'PhabricatorRepositoryManagementClusterizeWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 7835 7837 'PhabricatorRepositoryManagementDiscoverWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 7836 7838 'PhabricatorRepositoryManagementEditWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 7837 7839 'PhabricatorRepositoryManagementImportingWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
+117
src/applications/repository/management/PhabricatorRepositoryManagementClusterizeWorkflow.php
··· 1 + <?php 2 + 3 + final class PhabricatorRepositoryManagementClusterizeWorkflow 4 + extends PhabricatorRepositoryManagementWorkflow { 5 + 6 + protected function didConstruct() { 7 + $this 8 + ->setName('clusterize') 9 + ->setExamples('**clusterize** [options] __repository__ ...') 10 + ->setSynopsis( 11 + pht('Convert existing repositories into cluster repositories.')) 12 + ->setArguments( 13 + array( 14 + array( 15 + 'name' => 'service', 16 + 'param' => 'service', 17 + 'help' => pht( 18 + 'Cluster repository service in Almanac to move repositories '. 19 + 'into.'), 20 + ), 21 + array( 22 + 'name' => 'remove-service', 23 + 'help' => pht('Take repositories out of a cluster.'), 24 + ), 25 + array( 26 + 'name' => 'repositories', 27 + 'wildcard' => true, 28 + ), 29 + )); 30 + } 31 + 32 + public function execute(PhutilArgumentParser $args) { 33 + $viewer = $this->getViewer(); 34 + 35 + $repositories = $this->loadRepositories($args, 'repositories'); 36 + if (!$repositories) { 37 + throw new PhutilArgumentUsageException( 38 + pht('Specify one or more repositories to clusterize.')); 39 + } 40 + 41 + $service_name = $args->getArg('service'); 42 + $remove_service = $args->getArg('remove-service'); 43 + 44 + if ($remove_service && $service_name) { 45 + throw new PhutilArgumentUsageException( 46 + pht('Specify --service or --remove-service, but not both.')); 47 + } 48 + 49 + if (!$service_name && !$remove_service) { 50 + throw new PhutilArgumentUsageException( 51 + pht('Specify --service or --remove-service.')); 52 + } 53 + 54 + if ($remove_service) { 55 + $service = null; 56 + } else { 57 + $service = id(new AlmanacServiceQuery()) 58 + ->setViewer($viewer) 59 + ->withNames(array($service_name)) 60 + ->withServiceTypes( 61 + array( 62 + AlmanacClusterRepositoryServiceType::SERVICETYPE, 63 + )) 64 + ->executeOne(); 65 + if (!$service) { 66 + throw new PhutilArgumentUsageException( 67 + pht( 68 + 'No repository service "%s" exists.', 69 + $service_name)); 70 + } 71 + } 72 + 73 + 74 + if ($service) { 75 + $service_phid = $service->getPHID(); 76 + } else { 77 + $service_phid = null; 78 + } 79 + 80 + $content_source = $this->newContentSource(); 81 + $diffusion_phid = id(new PhabricatorDiffusionApplication())->getPHID(); 82 + 83 + foreach ($repositories as $repository) { 84 + $xactions = array(); 85 + 86 + $xactions[] = id(new PhabricatorRepositoryTransaction()) 87 + ->setTransactionType(PhabricatorRepositoryTransaction::TYPE_SERVICE) 88 + ->setNewValue($service_phid); 89 + 90 + id(new PhabricatorRepositoryEditor()) 91 + ->setActor($viewer) 92 + ->setActingAsPHID($diffusion_phid) 93 + ->setContentSource($content_source) 94 + ->setContinueOnNoEffect(true) 95 + ->setContinueOnMissingFields(true) 96 + ->applyTransactions($repository, $xactions); 97 + 98 + if ($service) { 99 + echo tsprintf( 100 + "%s\n", 101 + pht( 102 + 'Moved repository "%s" to cluster service "%s".', 103 + $repository->getDisplayName(), 104 + $service->getName())); 105 + } else { 106 + echo tsprintf( 107 + "%s\n", 108 + pht( 109 + 'Removed repository "%s" from cluster service.', 110 + $repository->getDisplayName())); 111 + } 112 + } 113 + 114 + return 0; 115 + } 116 + 117 + }
+8 -3
src/docs/user/cluster/cluster_devices.diviner
··· 93 93 94 94 Add **interfaces** to each device record so Phabricator can tell how to 95 95 connect to these hosts. Normally, you'll add one HTTP interface (usually on 96 - port 80) and one SSH interface (often on port 22) to each device: 96 + port 80) and one SSH interface (by default, on port 2222) to each device: 97 97 98 98 For example, if you are building a two-host repository cluster, you may end 99 99 up with records that look like these: 100 100 101 101 - Device: `repo001.mycompany.net` 102 - - Interface: `123.0.0.1:22` 102 + - Interface: `123.0.0.1:2222` 103 103 - Interface: `123.0.0.1:80` 104 104 - Device: `repo002.mycopmany.net` 105 - - Interface: `123.0.0.2:22` 105 + - Interface: `123.0.0.2:2222` 106 106 - Interface: `123.0.0.2:80` 107 107 108 108 Note that these hosts will normally run two `sshd` ports: the standard `sshd` ··· 229 229 230 230 Note that a copy of the active private key is stored in the `conf/keys/` 231 231 directory permanently. 232 + 233 + When converting a host into a cluster host, you may need to revisit 234 + @{article:Diffusion User Guide: Repository Hosting} and double check the `sudo` 235 + permission for the host. In particular, cluster hosts need to be able to run 236 + `ssh` via `sudo` so they can read the device private key. 232 237 233 238 234 239 Next Steps
+159 -21
src/docs/user/cluster/cluster_repositories.diviner
··· 9 9 WARNING: This feature is a very early prototype; the features this document 10 10 describes are mostly speculative fantasy. 11 11 12 - If you use Git or Mercurial, you can deploy Phabricator with multiple 13 - repository hosts, configured so that each host is readable and writable. The 14 - advantages of doing this are: 12 + If you use Git, you can deploy Phabricator with multiple repository hosts, 13 + configured so that each host is readable and writable. The advantages of doing 14 + this are: 15 15 16 16 - you can completely survive the loss of repository hosts; 17 17 - reads and writes can scale across multiple machines; and ··· 20 20 This configuration is complex, and many installs do not need to pursue it. 21 21 22 22 This configuration is not currently supported with Subversion or Mercurial. 23 - 24 - 25 - Repository Hosts 26 - ================ 27 - 28 - Repository hosts must run a complete, fully configured copy of Phabricator, 29 - including a webserver. They must also run a properly configured `sshd`. 30 - 31 - Generally, these hosts will run the same set of services and configuration that 32 - web hosts run. If you prefer, you can overlay these services and put web and 33 - repository services on the same hosts. See @{article:Clustering Introduction} 34 - for some guidance on overlaying services. 35 - 36 - When a user requests information about a repository that can only be satisfied 37 - by examining a repository working copy, the webserver receiving the request 38 - will make an HTTP service call to a repository server which hosts the 39 - repository to retrieve the data it needs. It will use the result of this query 40 - to respond to the user. 41 23 42 24 43 25 How Reads and Writes Work ··· 93 75 94 76 Other mitigations are possible, but securing a network against the NSA and 95 77 similar agents of other rogue nations is beyond the scope of this document. 78 + 79 + 80 + Repository Hosts 81 + ================ 82 + 83 + Repository hosts must run a complete, fully configured copy of Phabricator, 84 + including a webserver. They must also run a properly configured `sshd`. 85 + 86 + If you are converting existing hosts into cluster hosts, you may need to 87 + revisit @{article:Diffusion User Guide: Repository Hosting} and make sure 88 + the system user accounts have all the necessary `sudo` permissions. In 89 + particular, cluster devices need `sudo` access to `ssh` so they can read 90 + device keys. 91 + 92 + Generally, these hosts will run the same set of services and configuration that 93 + web hosts run. If you prefer, you can overlay these services and put web and 94 + repository services on the same hosts. See @{article:Clustering Introduction} 95 + for some guidance on overlaying services. 96 + 97 + When a user requests information about a repository that can only be satisfied 98 + by examining a repository working copy, the webserver receiving the request 99 + will make an HTTP service call to a repository server which hosts the 100 + repository to retrieve the data it needs. It will use the result of this query 101 + to respond to the user. 102 + 103 + 104 + Setting up a Cluster Services 105 + ============================= 106 + 107 + To set up clustering, first register the devices that you want to use as part 108 + of the cluster with Almanac. For details, see @{article:Cluster: Devices}. 109 + 110 + NOTE: Once you create a service, new repositories will immediately allocate 111 + on it. You may want to disable repository creation during initial setup. 112 + 113 + Once the hosts are registered as devices, you can create a new service in 114 + Almanac: 115 + 116 + - First, register at least one device according to the device clustering 117 + instructions. 118 + - Create a new service of type **Phabricator Cluster: Repository** in 119 + Almanac. 120 + - Bind this service to all the interfaces on the device or devices. 121 + - For each binding, add a `protocol` key with one of these values: 122 + `ssh`, `http`, `https`. 123 + 124 + For example, a service might look like this: 125 + 126 + - Service: `repos001.mycompany.net` 127 + - Binding: `repo001.mycompany.net:80`, `protocol=http` 128 + - Binding: `repo001.mycompany.net:2222`, `protocol=ssh` 129 + 130 + The service itself has a `closed` property. You can set this to `true` to 131 + disable new repository allocations on this service (for example, if it is 132 + reaching capacity). 133 + 134 + 135 + Migrating to Clustered Services 136 + =============================== 137 + 138 + To convert existing repositories on an install into cluster repositories, you 139 + will generally perform these steps: 140 + 141 + - Register the existing host as a cluster device. 142 + - Configure a single host repository service using //only// that host. 143 + 144 + This puts you in a transitional state where repositories on the host can work 145 + as either on-host repositories or cluster repositories. You can move forward 146 + from here slowly and make sure services still work, with a quick path back to 147 + safety if you run into trouble. 148 + 149 + To move forward, migrate one repository to the service and make sure things 150 + work correctly. If you run into issues, you can back out by migrating the 151 + repository off the service. 152 + 153 + To migrate a repository onto a cluster service, use this command: 154 + 155 + ``` 156 + $ ./bin/repository clusterize <repository> --service <service> 157 + ``` 158 + 159 + To migrate a repository back off a service, use this command: 160 + 161 + ``` 162 + $ ./bin/repoistory clusterize <repository> --remove-service 163 + ``` 164 + 165 + This command only changes how Phabricator connects to the repository; it does 166 + not move any data or make any complex structural changes. 167 + 168 + When Phabricator needs information about a non-clustered repository, it just 169 + runs a command like `git log` directly on disk. When Phabricator needs 170 + information about a clustered repository, it instead makes a service call to 171 + another server, asking that server to run `git log` instead. 172 + 173 + In a single-host cluster the server will make this service call to itself, so 174 + nothing will really change. But this //is// an effective test for most 175 + possible configuration mistakes. 176 + 177 + If your canary repository works well, you can migrate the rest of your 178 + repositories when ready (you can use `bin/repository list` to quickly get a 179 + list of all repository monograms). 180 + 181 + Once all repositories are migrated, you've reached a stable state and can 182 + remain here as long as you want. This state is sufficient to convert daemons, 183 + SSH, and web services into clustered versions and spread them across multiple 184 + machines if those goals are more interesting. 185 + 186 + Obviously, your single-device "cluster" will not be able to survive the loss of 187 + the single repository host, but you can take as long as you want to expand the 188 + cluster and add redundancy. 189 + 190 + After creating a service, you do not need to `clusterize` new repositories: 191 + they will automatically allocate onto an open service. 192 + 193 + When you're ready to expand the cluster, continue below. 194 + 195 + 196 + Expanding a Cluster 197 + =================== 198 + 199 + To expand an existing cluster, follow these general steps: 200 + 201 + - Register new devices in Almanac. 202 + - Add bindings to the new devices to the repository service, also in Almanac. 203 + - Start the daemons on the new devices. 204 + 205 + For instructions on configuring and registering devices, see 206 + @{article:Cluster: Devices}. 207 + 208 + As soon as you add active bindings to a service, Phabricator will begin 209 + synchronizing repositories and sending traffic to the new device. You do not 210 + need to copy any repository data to the device: Phabricator will automatically 211 + synchronize it. 212 + 213 + If you have a large amount of repository data, you may want to help this 214 + process along by copying the repository directory from an existing cluster 215 + device before bringing the new host online. This is optional, but can reduce 216 + the amount of time required to fully synchronize the cluster. 217 + 218 + You do not need to synchronize the most up-to-date data or stop writes during 219 + this process. For example, loading the most recent backup snapshot onto the new 220 + device will substantially reduce the amount of data that needs to be 221 + synchronized. 222 + 223 + 224 + Contracting a Cluster 225 + ===================== 226 + 227 + To reduce the size of an existing cluster, follow these general steps: 228 + 229 + - Disable the bindings from the service to the dead device in Almanac. 230 + 231 + If you are removing a device because it failed abruptly (or removing several 232 + devices at once) it is possible that some repositories will have lost all their 233 + leaders. See "Loss of Leaders" below to understand and resolve this. 96 234 97 235 98 236 Monitoring Services