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;
|
return $this->replicaRefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDisplayName() {
|
||||||
|
return $this->getRefKey();
|
||||||
|
}
|
||||||
|
|
||||||
public function getRefKey() {
|
public function getRefKey() {
|
||||||
$host = $this->getHost();
|
$host = $this->getHost();
|
||||||
|
|
|
@ -89,6 +89,10 @@ final class PhabricatorStorageManagementAPI extends Phobject {
|
||||||
return $this->namespace.'_'.$fragment;
|
return $this->namespace.'_'.$fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDisplayName() {
|
||||||
|
return $this->getRef()->getDisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
public function getDatabaseList(array $patches, $only_living = false) {
|
public function getDatabaseList(array $patches, $only_living = false) {
|
||||||
assert_instances_of($patches, 'PhabricatorStoragePatch');
|
assert_instances_of($patches, 'PhabricatorStoragePatch');
|
||||||
|
|
||||||
|
|
|
@ -21,86 +21,112 @@ final class PhabricatorStorageManagementDestroyWorkflow
|
||||||
}
|
}
|
||||||
|
|
||||||
public function didExecute(PhutilArgumentParser $args) {
|
public function didExecute(PhutilArgumentParser $args) {
|
||||||
$console = PhutilConsole::getConsole();
|
$api = $this->getSingleAPI();
|
||||||
|
|
||||||
|
$host_display = $api->getDisplayName();
|
||||||
|
|
||||||
if (!$this->isDryRun() && !$this->isForce()) {
|
if (!$this->isDryRun() && !$this->isForce()) {
|
||||||
if ($args->getArg('unittest-fixtures')) {
|
if ($args->getArg('unittest-fixtures')) {
|
||||||
$console->writeOut(
|
$warning = pht(
|
||||||
phutil_console_wrap(
|
'Are you completely sure you really want to destroy all unit '.
|
||||||
pht(
|
'test fixure data on host "%s"? This operation can not be undone.',
|
||||||
'Are you completely sure you really want to destroy all unit '.
|
$host_display);
|
||||||
'test fixure data? This operation can not be undone.')));
|
|
||||||
|
echo tsprintf(
|
||||||
|
'%B',
|
||||||
|
id(new PhutilConsoleBlock())
|
||||||
|
->addParagraph($warning)
|
||||||
|
->drawConsoleString());
|
||||||
|
|
||||||
if (!phutil_console_confirm(pht('Destroy all unit test data?'))) {
|
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);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$console->writeOut(
|
$warning = pht(
|
||||||
phutil_console_wrap(
|
'Are you completely sure you really want to permanently destroy '.
|
||||||
pht(
|
'all storage for Phabricator data on host "%s"? This operation '.
|
||||||
'Are you completely sure you really want to permanently destroy '.
|
'can not be undone and your data will not be recoverable if '.
|
||||||
'all storage for Phabricator data? This operation can not be '.
|
'you proceed.',
|
||||||
'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?'))) {
|
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);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!phutil_console_confirm(pht('Really destroy all data forever?'))) {
|
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);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$apis = $this->getMasterAPIs();
|
$patches = $this->getPatches();
|
||||||
foreach ($apis as $api) {
|
|
||||||
$patches = $this->getPatches();
|
|
||||||
|
|
||||||
if ($args->getArg('unittest-fixtures')) {
|
if ($args->getArg('unittest-fixtures')) {
|
||||||
$conn = $api->getConn(null);
|
$conn = $api->getConn(null);
|
||||||
$databases = queryfx_all(
|
$databases = queryfx_all(
|
||||||
$conn,
|
$conn,
|
||||||
'SELECT DISTINCT(TABLE_SCHEMA) AS db '.
|
'SELECT DISTINCT(TABLE_SCHEMA) AS db '.
|
||||||
'FROM INFORMATION_SCHEMA.TABLES '.
|
'FROM INFORMATION_SCHEMA.TABLES '.
|
||||||
'WHERE TABLE_SCHEMA LIKE %>',
|
'WHERE TABLE_SCHEMA LIKE %>',
|
||||||
PhabricatorTestCase::NAMESPACE_PREFIX);
|
PhabricatorTestCase::NAMESPACE_PREFIX);
|
||||||
$databases = ipull($databases, 'db');
|
$databases = ipull($databases, 'db');
|
||||||
} else {
|
} else {
|
||||||
$databases = $api->getDatabaseList($patches);
|
$databases = $api->getDatabaseList($patches);
|
||||||
$databases[] = $api->getDatabaseName('meta_data');
|
$databases[] = $api->getDatabaseName('meta_data');
|
||||||
|
|
||||||
// These are legacy databases that were dropped long ago. See T2237.
|
// These are legacy databases that were dropped long ago. See T2237.
|
||||||
$databases[] = $api->getDatabaseName('phid');
|
$databases[] = $api->getDatabaseName('phid');
|
||||||
$databases[] = $api->getDatabaseName('directory');
|
$databases[] = $api->getDatabaseName('directory');
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($databases as $database) {
|
asort($databases);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->isDryRun()) {
|
foreach ($databases as $database) {
|
||||||
$console->writeOut(
|
if ($this->isDryRun()) {
|
||||||
"%s\n",
|
$this->logInfo(
|
||||||
|
pht('DRY RUN'),
|
||||||
pht(
|
pht(
|
||||||
'Storage on "%s" was destroyed.',
|
'Would drop database "%s" on host "%s".',
|
||||||
$api->getRef()->getRefKey()));
|
$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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue