protected function executeChecks()
 {
     $master = PhabricatorDatabaseRef::getMasterDatabaseRef();
     if (!$master) {
         // If we're implicitly in read-only mode during disaster recovery,
         // don't bother with these setup checks.
         return;
     }
     $conn_raw = $master->newManagementConnection();
     try {
         queryfx($conn_raw, 'SELECT 1');
         $database_exception = null;
     } catch (AphrontInvalidCredentialsQueryException $ex) {
         $database_exception = $ex;
     } catch (AphrontConnectionQueryException $ex) {
         $database_exception = $ex;
     }
     if ($database_exception) {
         $issue = PhabricatorSetupIssue::newDatabaseConnectionIssue($database_exception);
         $this->addIssue($issue);
         return;
     }
     $engines = queryfx_all($conn_raw, 'SHOW ENGINES');
     $engines = ipull($engines, 'Support', 'Engine');
     $innodb = idx($engines, 'InnoDB');
     if ($innodb != 'YES' && $innodb != 'DEFAULT') {
         $message = pht("The 'InnoDB' engine is not available in MySQL. Enable InnoDB in " . "your MySQL configuration." . "\n\n" . "(If you aleady created tables, MySQL incorrectly used some other " . "engine to create them. You need to convert them or drop and " . "reinitialize them.)");
         $this->newIssue('mysql.innodb')->setName(pht('MySQL InnoDB Engine Not Available'))->setMessage($message)->setIsFatal(true);
         return;
     }
     $namespace = PhabricatorEnv::getEnvConfig('storage.default-namespace');
     $databases = queryfx_all($conn_raw, 'SHOW DATABASES');
     $databases = ipull($databases, 'Database', 'Database');
     if (empty($databases[$namespace . '_meta_data'])) {
         $message = pht("Run the storage upgrade script to setup Phabricator's database " . "schema.");
         $this->newIssue('storage.upgrade')->setName(pht('Setup MySQL Schema'))->setMessage($message)->setIsFatal(true)->addCommand(hsprintf('<tt>phabricator/ $</tt> ./bin/storage upgrade'));
     } else {
         $conn_meta = $master->newApplicationConnection($namespace . '_meta_data');
         $applied = queryfx_all($conn_meta, 'SELECT patch FROM patch_status');
         $applied = ipull($applied, 'patch', 'patch');
         $all = PhabricatorSQLPatchList::buildAllPatches();
         $diff = array_diff_key($all, $applied);
         if ($diff) {
             $this->newIssue('storage.patch')->setName(pht('Upgrade MySQL Schema'))->setMessage(pht("Run the storage upgrade script to upgrade Phabricator's " . "database schema. Missing patches:<br />%s<br />", phutil_implode_html(phutil_tag('br'), array_keys($diff))))->addCommand(hsprintf('<tt>phabricator/ $</tt> ./bin/storage upgrade'));
         }
     }
     $host = PhabricatorEnv::getEnvConfig('mysql.host');
     $matches = null;
     if (preg_match('/^([^:]+):(\\d+)$/', $host, $matches)) {
         $host = $matches[1];
         $port = $matches[2];
         $this->newIssue('storage.mysql.hostport')->setName(pht('Deprecated mysql.host Format'))->setSummary(pht('Move port information from `%s` to `%s` in your config.', 'mysql.host', 'mysql.port'))->setMessage(pht('Your `%s` configuration contains a port number, but this usage ' . 'is deprecated. Instead, put the port number in `%s`.', 'mysql.host', 'mysql.port'))->addPhabricatorConfig('mysql.host')->addPhabricatorConfig('mysql.port')->addCommand(hsprintf('<tt>phabricator/ $</tt> ./bin/config set mysql.host %s', $host))->addCommand(hsprintf('<tt>phabricator/ $</tt> ./bin/config set mysql.port %s', $port));
     }
 }
 protected function executeChecks()
 {
     $conf = PhabricatorEnv::newObjectFromConfig('mysql.configuration-provider');
     $conn_user = $conf->getUser();
     $conn_pass = $conf->getPassword();
     $conn_host = $conf->getHost();
     $conn_port = $conf->getPort();
     ini_set('mysql.connect_timeout', 2);
     $config = array('user' => $conn_user, 'pass' => $conn_pass, 'host' => $conn_host, 'port' => $conn_port, 'database' => null);
     $conn_raw = PhabricatorEnv::newObjectFromConfig('mysql.implementation', array($config));
     try {
         queryfx($conn_raw, 'SELECT 1');
     } catch (AphrontConnectionQueryException $ex) {
         $message = pht("Unable to connect to MySQL!\n\n" . "%s\n\n" . "Make sure Phabricator and MySQL are correctly configured.", $ex->getMessage());
         $this->newIssue('mysql.connect')->setName(pht('Can Not Connect to MySQL'))->setMessage($message)->setIsFatal(true)->addRelatedPhabricatorConfig('mysql.host')->addRelatedPhabricatorConfig('mysql.port')->addRelatedPhabricatorConfig('mysql.user')->addRelatedPhabricatorConfig('mysql.pass');
         return;
     }
     $engines = queryfx_all($conn_raw, 'SHOW ENGINES');
     $engines = ipull($engines, 'Support', 'Engine');
     $innodb = idx($engines, 'InnoDB');
     if ($innodb != 'YES' && $innodb != 'DEFAULT') {
         $message = pht("The 'InnoDB' engine is not available in MySQL. Enable InnoDB in " . "your MySQL configuration." . "\n\n" . "(If you aleady created tables, MySQL incorrectly used some other " . "engine to create them. You need to convert them or drop and " . "reinitialize them.)");
         $this->newIssue('mysql.innodb')->setName(pht('MySQL InnoDB Engine Not Available'))->setMessage($message)->setIsFatal(true);
         return;
     }
     $namespace = PhabricatorEnv::getEnvConfig('storage.default-namespace');
     $databases = queryfx_all($conn_raw, 'SHOW DATABASES');
     $databases = ipull($databases, 'Database', 'Database');
     if (empty($databases[$namespace . '_meta_data'])) {
         $message = pht("Run the storage upgrade script to setup Phabricator's database " . "schema.");
         $this->newIssue('storage.upgrade')->setName(pht('Setup MySQL Schema'))->setMessage($message)->setIsFatal(true)->addCommand(hsprintf('<tt>phabricator/ $</tt> ./bin/storage upgrade'));
     } else {
         $config['database'] = $namespace . '_meta_data';
         $conn_meta = PhabricatorEnv::newObjectFromConfig('mysql.implementation', array($config));
         $applied = queryfx_all($conn_meta, 'SELECT patch FROM patch_status');
         $applied = ipull($applied, 'patch', 'patch');
         $all = PhabricatorSQLPatchList::buildAllPatches();
         $diff = array_diff_key($all, $applied);
         if ($diff) {
             $this->newIssue('storage.patch')->setName(pht('Upgrade MySQL Schema'))->setMessage(pht("Run the storage upgrade script to upgrade Phabricator's " . "database schema. Missing patches:<br />%s<br />", phutil_implode_html(phutil_tag('br'), array_keys($diff))))->addCommand(hsprintf('<tt>phabricator/ $</tt> ./bin/storage upgrade'));
         }
     }
     $host = PhabricatorEnv::getEnvConfig('mysql.host');
     $matches = null;
     if (preg_match('/^([^:]+):(\\d+)$/', $host, $matches)) {
         $host = $matches[1];
         $port = $matches[2];
         $this->newIssue('storage.mysql.hostport')->setName(pht('Deprecated mysql.host Format'))->setSummary(pht('Move port information from `%s` to `%s` in your config.', 'mysql.host', 'mysql.port'))->setMessage(pht('Your `%s` configuration contains a port number, but this usage ' . 'is deprecated. Instead, put the port number in `%s`.', 'mysql.host', 'mysql.port'))->addPhabricatorConfig('mysql.host')->addPhabricatorConfig('mysql.port')->addCommand(hsprintf('<tt>phabricator/ $</tt> ./bin/config set mysql.host %s', $host))->addCommand(hsprintf('<tt>phabricator/ $</tt> ./bin/config set mysql.port %s', $port));
     }
 }
 private function getDatabaseNames()
 {
     $api = $this->getAPI();
     $patches = PhabricatorSQLPatchList::buildAllPatches();
     return $api->getDatabaseList($patches, $only_living = true);
 }
Exemplo n.º 4
0
if ($args->getArg('password') === null) {
    // This is already a PhutilOpaqueEnvelope.
    $password = $conf->getPassword();
} else {
    // Put this in a PhutilOpaqueEnvelope.
    $password = new PhutilOpaqueEnvelope($args->getArg('password'));
    PhabricatorEnv::overrideConfig('mysql.pass', $args->getArg('password'));
}
$api = new PhabricatorStorageManagementAPI();
$api->setUser($args->getArg('user'));
PhabricatorEnv::overrideConfig('mysql.user', $args->getArg('user'));
$api->setHost($default_host);
$api->setPort($default_port);
$api->setPassword($password);
$api->setNamespace($args->getArg('namespace'));
$api->setDisableUTF8MB4($args->getArg('disable-utf8mb4'));
try {
    queryfx($api->getConn(null), 'SELECT 1');
} catch (AphrontQueryException $ex) {
    $message = phutil_console_format("**%s**\n\n%s\n\n**%s**: %s\n", pht('Bad Administrative Credentials'), pht('Unable to connect to MySQL using the administrative credentials ' . 'provided with the __%s__ and __%s__ flags. Check that ' . 'you have entered them correctly.', '--user', '--password'), pht('Raw MySQL Error'), $ex->getMessage());
    echo phutil_console_wrap($message);
    exit(1);
}
$workflows = id(new PhutilSymbolLoader())->setAncestorClass('PhabricatorStorageManagementWorkflow')->loadObjects();
$patches = PhabricatorSQLPatchList::buildAllPatches();
foreach ($workflows as $workflow) {
    $workflow->setAPI($api);
    $workflow->setPatches($patches);
}
$workflows[] = new PhutilHelpArgumentWorkflow();
$args->parseWorkflows($workflows);
 private function executeRefChecks(PhabricatorDatabaseRef $ref)
 {
     $conn_raw = $ref->newManagementConnection();
     $ref_key = $ref->getRefKey();
     $engines = queryfx_all($conn_raw, 'SHOW ENGINES');
     $engines = ipull($engines, 'Support', 'Engine');
     $innodb = idx($engines, 'InnoDB');
     if ($innodb != 'YES' && $innodb != 'DEFAULT') {
         $message = pht('The "InnoDB" engine is not available in MySQL (on host "%s"). ' . 'Enable InnoDB in your MySQL configuration.' . "\n\n" . '(If you aleady created tables, MySQL incorrectly used some other ' . 'engine to create them. You need to convert them or drop and ' . 'reinitialize them.)', $ref_key);
         $this->newIssue('mysql.innodb')->setName(pht('MySQL InnoDB Engine Not Available'))->setMessage($message)->setIsFatal(true);
         return true;
     }
     $namespace = PhabricatorEnv::getEnvConfig('storage.default-namespace');
     $databases = queryfx_all($conn_raw, 'SHOW DATABASES');
     $databases = ipull($databases, 'Database', 'Database');
     if (empty($databases[$namespace . '_meta_data'])) {
         $message = pht('Run the storage upgrade script to setup databases (host "%s" has ' . 'not been initialized).', $ref_key);
         $this->newIssue('storage.upgrade')->setName(pht('Setup MySQL Schema'))->setMessage($message)->setIsFatal(true)->addCommand(hsprintf('<tt>phabricator/ $</tt> ./bin/storage upgrade'));
         return true;
     }
     $conn_meta = $ref->newApplicationConnection($namespace . '_meta_data');
     $applied = queryfx_all($conn_meta, 'SELECT patch FROM patch_status');
     $applied = ipull($applied, 'patch', 'patch');
     $all = PhabricatorSQLPatchList::buildAllPatches();
     $diff = array_diff_key($all, $applied);
     if ($diff) {
         $message = pht('Run the storage upgrade script to upgrade databases (host "%s" is ' . 'out of date). Missing patches: %s.', $ref_key, implode(', ', array_keys($diff)));
         $this->newIssue('storage.patch')->setName(pht('Upgrade MySQL Schema'))->setIsFatal(true)->setMessage($message)->addCommand(hsprintf('<tt>phabricator/ $</tt> ./bin/storage upgrade'));
         return true;
     }
     // NOTE: It's possible that replication is broken but we have not been
     // granted permission to "SHOW SLAVE STATUS" so we can't figure it out.
     // We allow this kind of configuration and survive these checks, trusting
     // that operations knows what they're doing. This issue is shown on the
     // "Database Servers" console.
     switch ($ref->getReplicaStatus()) {
         case PhabricatorDatabaseRef::REPLICATION_MASTER_REPLICA:
             $message = pht('Database host "%s" is configured as a master, but is replicating ' . 'another host. This is dangerous and can mangle or destroy data. ' . 'Only replicas should be replicating. Stop replication on the ' . 'host or reconfigure Phabricator.', $ref->getRefKey());
             $this->newIssue('db.master.replicating')->setName(pht('Replicating Master'))->setIsFatal(true)->setMessage($message);
             return true;
         case PhabricatorDatabaseRef::REPLICATION_REPLICA_NONE:
         case PhabricatorDatabaseRef::REPLICATION_NOT_REPLICATING:
             if (!$ref->getIsMaster()) {
                 $message = pht('Database replica "%s" is listed as a replica, but is not ' . 'currently replicating. You are vulnerable to data loss if ' . 'the master fails.', $ref->getRefKey());
                 // This isn't a fatal because it can normally only put data at risk,
                 // not actually do anything destructive or unrecoverable.
                 $this->newIssue('db.replica.not-replicating')->setName(pht('Nonreplicating Replica'))->setMessage($message);
             }
             break;
     }
     // If we have more than one master, we require that the cluster database
     // configuration written to each database node is exactly the same as the
     // one we are running with.
     $masters = PhabricatorDatabaseRef::getAllMasterDatabaseRefs();
     if (count($masters) > 1) {
         $state_actual = queryfx_one($conn_meta, 'SELECT stateValue FROM %T WHERE stateKey = %s', PhabricatorStorageManagementAPI::TABLE_HOSTSTATE, 'cluster.databases');
         if ($state_actual) {
             $state_actual = $state_actual['stateValue'];
         }
         $state_expect = $ref->getPartitionStateForCommit();
         if ($state_expect !== $state_actual) {
             $message = pht('Database host "%s" has a configured cluster state which disagrees ' . 'with the state on this host ("%s"). Run `bin/storage partition` ' . 'to commit local state to the cluster. This host may have started ' . 'with an out-of-date configuration.', $ref->getRefKey(), php_uname('n'));
             $this->newIssue('db.state.desync')->setName(pht('Cluster Configuration Out of Sync'))->setMessage($message)->setIsFatal(true);
             return true;
         }
     }
 }