mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 06:42:42 +01: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:
parent
f7290bbbf2
commit
764db4869c
3 changed files with 87 additions and 54 deletions
|
@ -221,6 +221,9 @@ final class PhabricatorDatabaseRef
|
|||
return $this->replicaRefs;
|
||||
}
|
||||
|
||||
public function getDisplayName() {
|
||||
return $this->getRefKey();
|
||||
}
|
||||
|
||||
public function getRefKey() {
|
||||
$host = $this->getHost();
|
||||
|
|
|
@ -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');
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue