protected function executeChecks() { $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)); } $refs = PhabricatorDatabaseRef::queryAll(); $refs = mpull($refs, null, 'getRefKey'); // Test if we can connect to each database first. If we can not connect // to a particular database, we only raise a warning: this allows new web // nodes to start during a disaster, when some databases may be correctly // configured but not reachable. $connect_map = array(); $any_connection = false; foreach ($refs as $ref_key => $ref) { $conn_raw = $ref->newManagementConnection(); try { queryfx($conn_raw, 'SELECT 1'); $database_exception = null; $any_connection = true; } catch (AphrontInvalidCredentialsQueryException $ex) { $database_exception = $ex; } catch (AphrontConnectionQueryException $ex) { $database_exception = $ex; } if ($database_exception) { $connect_map[$ref_key] = $database_exception; unset($refs[$ref_key]); } } if ($connect_map) { // This is only a fatal error if we could not connect to anything. If // possible, we still want to start if some database hosts can not be // reached. $is_fatal = !$any_connection; foreach ($connect_map as $ref_key => $database_exception) { $issue = PhabricatorSetupIssue::newDatabaseConnectionIssue($database_exception, $is_fatal); $this->addIssue($issue); } } foreach ($refs as $ref_key => $ref) { if ($this->executeRefChecks($ref)) { return; } } }
private function buildClusterDatabaseStatus() { $viewer = $this->getViewer(); $databases = PhabricatorDatabaseRef::queryAll(); $connection_map = PhabricatorDatabaseRef::getConnectionStatusMap(); $replica_map = PhabricatorDatabaseRef::getReplicaStatusMap(); Javelin::initBehavior('phabricator-tooltips'); $rows = array(); foreach ($databases as $database) { $messages = array(); if ($database->getIsMaster()) { $role_icon = id(new PHUIIconView())->setIcon('fa-database sky')->addSigil('has-tooltip')->setMetadata(array('tip' => pht('Master'))); } else { $role_icon = id(new PHUIIconView())->setIcon('fa-download')->addSigil('has-tooltip')->setMetadata(array('tip' => pht('Replica'))); } if ($database->getDisabled()) { $conn_icon = 'fa-times'; $conn_color = 'grey'; $conn_label = pht('Disabled'); } else { $status = $database->getConnectionStatus(); $info = idx($connection_map, $status, array()); $conn_icon = idx($info, 'icon'); $conn_color = idx($info, 'color'); $conn_label = idx($info, 'label'); if ($status === PhabricatorDatabaseRef::STATUS_OKAY) { $latency = $database->getConnectionLatency(); $latency = (int) (1000000 * $latency); $conn_label = pht('%s us', new PhutilNumber($latency)); } } $connection = array(id(new PHUIIconView())->setIcon("{$conn_icon} {$conn_color}"), ' ', $conn_label); if ($database->getDisabled()) { $replica_icon = 'fa-times'; $replica_color = 'grey'; $replica_label = pht('Disabled'); } else { $status = $database->getReplicaStatus(); $info = idx($replica_map, $status, array()); $replica_icon = idx($info, 'icon'); $replica_color = idx($info, 'color'); $replica_label = idx($info, 'label'); if ($database->getIsMaster()) { if ($status === PhabricatorDatabaseRef::REPLICATION_OKAY) { $replica_icon = 'fa-database'; } } else { switch ($status) { case PhabricatorDatabaseRef::REPLICATION_OKAY: case PhabricatorDatabaseRef::REPLICATION_SLOW: $delay = $database->getReplicaDelay(); if ($delay) { $replica_label = pht('%ss Behind', new PhutilNumber($delay)); } else { $replica_label = pht('Up to Date'); } break; } } } $replication = array(id(new PHUIIconView())->setIcon("{$replica_icon} {$replica_color}"), ' ', $replica_label); $health = $database->getHealthRecord(); $health_up = $health->getUpEventCount(); $health_down = $health->getDownEventCount(); if ($health->getIsHealthy()) { $health_icon = id(new PHUIIconView())->setIcon('fa-plus green'); } else { $health_icon = id(new PHUIIconView())->setIcon('fa-times red'); $messages[] = pht('UNHEALTHY: This database has failed recent health checks. Traffic ' . 'will not be sent to it until it recovers.'); } $health_count = pht('%s / %s', new PhutilNumber($health_up), new PhutilNumber($health_up + $health_down)); $health_status = array($health_icon, ' ', $health_count); $conn_message = $database->getConnectionMessage(); if ($conn_message) { $messages[] = $conn_message; } $replica_message = $database->getReplicaMessage(); if ($replica_message) { $messages[] = $replica_message; } $messages = phutil_implode_html(phutil_tag('br'), $messages); $rows[] = array($role_icon, $database->getHost(), $database->getPort(), $database->getUser(), $connection, $replication, $health_status, $messages); } $table = id(new AphrontTableView($rows))->setNoDataString(pht('Phabricator is not configured in cluster mode.'))->setHeaders(array(null, pht('Host'), pht('Port'), pht('User'), pht('Connection'), pht('Replication'), pht('Health'), pht('Messages')))->setColumnClasses(array(null, null, null, null, null, null, null, 'wide')); $doc_href = PhabricatorEnv::getDoclink('Cluster: Databases'); $header = id(new PHUIHeaderView())->setHeader(pht('Cluster Database Status'))->addActionLink(id(new PHUIButtonView())->setIcon('fa-book')->setHref($doc_href)->setTag('a')->setText(pht('Documentation'))); return id(new PHUIObjectBoxView())->setHeader($header)->setTable($table); }