1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-09-19 16:58:48 +02:00

Make "bin/storage destroy" target individual hosts in database cluster mode

Summary:
Ref T13336. Currently, "bin/storage destroy" destroys every master. This is wonderfully destructive, but if replication fails it's useful to be able to destroy only a replica.

Operate on a single host, and require "--host" to target the operation in cluster mode, so `bin/storage destroy --host dbreplica001` is a useful operation.

Test Plan: Ran `bin/storage destroy` with various flags locally. Will destroy `secure002` and refresh replication.

Maniphest Tasks: T13336

Differential Revision: https://secure.phabricator.com/D20784
This commit is contained in:
epriestley 2019-09-04 10:02:51 -07:00
parent f7290bbbf2
commit 764db4869c
3 changed files with 87 additions and 54 deletions

View file

@ -221,6 +221,9 @@ final class PhabricatorDatabaseRef
return $this->replicaRefs;
}
public function getDisplayName() {
return $this->getRefKey();
}
public function getRefKey() {
$host = $this->getHost();

View file

@ -89,6 +89,10 @@ final class PhabricatorStorageManagementAPI extends Phobject {
return $this->namespace.'_'.$fragment;
}
public function getDisplayName() {
return $this->getRef()->getDisplayName();
}
public function getDatabaseList(array $patches, $only_living = false) {
assert_instances_of($patches, 'PhabricatorStoragePatch');

View file

@ -21,86 +21,112 @@ final class PhabricatorStorageManagementDestroyWorkflow
}
public function didExecute(PhutilArgumentParser $args) {
$console = PhutilConsole::getConsole();
$api = $this->getSingleAPI();
$host_display = $api->getDisplayName();
if (!$this->isDryRun() && !$this->isForce()) {
if ($args->getArg('unittest-fixtures')) {
$console->writeOut(
phutil_console_wrap(
pht(
'Are you completely sure you really want to destroy all unit '.
'test fixure data? This operation can not be undone.')));
$warning = pht(
'Are you completely sure you really want to destroy all unit '.
'test fixure data on host "%s"? This operation can not be undone.',
$host_display);
echo tsprintf(
'%B',
id(new PhutilConsoleBlock())
->addParagraph($warning)
->drawConsoleString());
if (!phutil_console_confirm(pht('Destroy all unit test data?'))) {
$console->writeOut("%s\n", pht('Cancelled.'));
$this->logFail(
pht('CANCELLED'),
pht('User cancelled operation.'));
exit(1);
}
} else {
$console->writeOut(
phutil_console_wrap(
pht(
'Are you completely sure you really want to permanently destroy '.
'all storage for Phabricator data? This operation can not be '.
'undone and your data will not be recoverable if you proceed.')));
$warning = pht(
'Are you completely sure you really want to permanently destroy '.
'all storage for Phabricator data on host "%s"? This operation '.
'can not be undone and your data will not be recoverable if '.
'you proceed.',
$host_display);
echo tsprintf(
'%B',
id(new PhutilConsoleBlock())
->addParagraph($warning)
->drawConsoleString());
if (!phutil_console_confirm(pht('Permanently destroy all data?'))) {
$console->writeOut("%s\n", pht('Cancelled.'));
$this->logFail(
pht('CANCELLED'),
pht('User cancelled operation.'));
exit(1);
}
if (!phutil_console_confirm(pht('Really destroy all data forever?'))) {
$console->writeOut("%s\n", pht('Cancelled.'));
$this->logFail(
pht('CANCELLED'),
pht('User cancelled operation.'));
exit(1);
}
}
}
$apis = $this->getMasterAPIs();
foreach ($apis as $api) {
$patches = $this->getPatches();
$patches = $this->getPatches();
if ($args->getArg('unittest-fixtures')) {
$conn = $api->getConn(null);
$databases = queryfx_all(
$conn,
'SELECT DISTINCT(TABLE_SCHEMA) AS db '.
'FROM INFORMATION_SCHEMA.TABLES '.
'WHERE TABLE_SCHEMA LIKE %>',
PhabricatorTestCase::NAMESPACE_PREFIX);
$databases = ipull($databases, 'db');
} else {
$databases = $api->getDatabaseList($patches);
$databases[] = $api->getDatabaseName('meta_data');
if ($args->getArg('unittest-fixtures')) {
$conn = $api->getConn(null);
$databases = queryfx_all(
$conn,
'SELECT DISTINCT(TABLE_SCHEMA) AS db '.
'FROM INFORMATION_SCHEMA.TABLES '.
'WHERE TABLE_SCHEMA LIKE %>',
PhabricatorTestCase::NAMESPACE_PREFIX);
$databases = ipull($databases, 'db');
} else {
$databases = $api->getDatabaseList($patches);
$databases[] = $api->getDatabaseName('meta_data');
// These are legacy databases that were dropped long ago. See T2237.
$databases[] = $api->getDatabaseName('phid');
$databases[] = $api->getDatabaseName('directory');
}
// These are legacy databases that were dropped long ago. See T2237.
$databases[] = $api->getDatabaseName('phid');
$databases[] = $api->getDatabaseName('directory');
}
foreach ($databases as $database) {
if ($this->isDryRun()) {
$console->writeOut(
"%s\n",
pht("DRYRUN: Would drop database '%s'.", $database));
} else {
$console->writeOut(
"%s\n",
pht("Dropping database '%s'...", $database));
queryfx(
$api->getConn(null),
'DROP DATABASE IF EXISTS %T',
$database);
}
}
asort($databases);
if (!$this->isDryRun()) {
$console->writeOut(
"%s\n",
foreach ($databases as $database) {
if ($this->isDryRun()) {
$this->logInfo(
pht('DRY RUN'),
pht(
'Storage on "%s" was destroyed.',
$api->getRef()->getRefKey()));
'Would drop database "%s" on host "%s".',
$database,
$host_display));
} else {
$this->logWarn(
pht('DESTROY'),
pht(
'Dropping database "%s" on host "%s"...',
$database,
$host_display));
queryfx(
$api->getConn(null),
'DROP DATABASE IF EXISTS %T',
$database);
}
}
if (!$this->isDryRun()) {
$this->logOkay(
pht('DONE'),
pht(
'Storage on "%s" was destroyed.',
$host_display));
}
return 0;
}