blob: 6c7f7e7df8fc02c7697084bed2dc24678e53fcd1 [file] [log] [blame]
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
include_once "../db/OrchestratorDB.php";
include_once "../db/Transaction.php";
include_once "../puppet/PuppetInvoker.php";
include_once "State.php";
class Cluster {
public $name;
public $db;
public $puppet;
private $logger;
private $state;
private $currentAction;
public function __construct($clusterName, $db, $puppet) {
$this->name = $clusterName;
$this->db = $db;
$this->puppet = $puppet;
$this->logger = new HMCLogger("Cluster:".$clusterName);
$this->state = "";
$this->currentAction = "";
}
public function resetSubTxnId() {
$GLOBALS["SUB_TXN_ID"] = 1;
}
/**
* Function to install, configure and start HDP across the whole cluster
* @param transaction transactionId for the operation
*/
public function deployHDP($transaction) {
$this->currentAction = "Cluster install";
$result = $this->_deployHDP($transaction, TRUE);
if ($result['result'] !== 0) {
return $result;
}
$this->resetSubTxnId();
$this->db->reset();
return $this->_deployHDP($transaction, FALSE);
}
private function _deployHDP($transaction, $dryRun) {
$services = $this->db->getClusterServices();
if ($services == FALSE) {
$this->logger->log_error("Failed to get cluster services.");
return array("result" => -1, "error" => "Failed to get cluster services from DB.");
}
$n = count($services);
$this->logger->log_info("Deploying HDP with $n services.... DryRun=$dryRun");
$result = $this->_installAllServices($services,
$transaction->createSubTransaction(), $dryRun);
if ($result['result'] !== 0) {
$this->logger->log_error("Failed to install services.");
return $result;
}
$result = $this->_startAllServices($services,
$transaction->createSubTransaction(), $dryRun);
$this->resetSubTxnId();
$this->db->reset();
return $result;
}
private function _uninstallAllServices($services, $transaction, $dryRun,
$wipeoutData = FALSE) {
$n = count($services);
$this->logger->log_info("Uninstalling HDP with $n services.... DryRun=$dryRun");
$this->setState(State::UNINSTALLING, $transaction, $dryRun);
$svcTxnMap = array();
foreach($services as $service) {
$svcTxnMap[$service->name] = $transaction->createSubTransaction();
}
// Mark all as uninstalled before the actual kick so
// that desired state kicks in
foreach($services as $service) {
$result = $service->uninstall($svcTxnMap[$service->name], $dryRun);
if ($result['result'] != 0) {
$this->setState(State::FAILED, $transaction, $dryRun);
$service->setState(State::FAILED, $svcTxnMap[$service->name], $dryRun, TRUE);
return $result;
}
}
// Real Run
if (!$dryRun) {
$result = $this->db->getAllNodes();
if ($result['result'] !== 0) {
$this->logger->log_error("UnInstalling HDP failed with: " . $result['error']);
$this->setState(State::FAILED, $transaction, $dryRun);
foreach($services as $service) {
$service->setState(State::FAILED, $svcTxnMap[$service->name], $dryRun, TRUE);
}
return $result;
}
$wipeoutFlag = "false";
if ($wipeoutData) {
$wipeoutFlag = "true";
}
$nodes = $result["nodes"];
$this->logger->log_debug("Kicking puppet for uninstalling "
. "cluster=" . $this->name
. ", txn=" . $transaction->toString());
$startTime = time();
$result = $this->puppet->kickPuppet($nodes, $transaction, $this->name,
$result["componentMapping"], array ("wipeoff_data" => $wipeoutFlag));
$this->logger->log_debug("Puppet kick response for uninstalling "
. "cluster=" . $this->name
. ", txn=" . $transaction->toString()
. ", response=" . print_r($result, true));
// handle puppet response
$timeTaken = time() - $startTime;
$opStatus = array(
"stats" =>
array (
"NODE_COUNT" => count($nodes),
"TIME_TAKEN_SECS" => $timeTaken),
"nodeReport" =>
array ( "PUPPET_KICK_FAILED" => $result[KICKFAILED],
"PUPPET_OPERATION_FAILED" => $result[FAILEDNODES],
"PUPPET_OPERATION_TIMEDOUT" => $result[TIMEDOUTNODES],
"PUPPET_OPERATION_SUCCEEDED" => $result[SUCCESSFULLNODES]));
$this->logger->log_info("Persisting puppet report for uninstall HDP");
$this->db->persistTransactionOpStatus($transaction,
json_encode($opStatus));
if ($result['result'] != 0) {
$this->logger->log_error("UnInstalling HDP failed with: " . $result['error']);
$this->setState(State::FAILED, $transaction, $dryRun);
foreach($services as $service) {
$service->setState(State::FAILED, $svcTxnMap[$service->name], $dryRun, TRUE);
}
return $result;
}
if (count($nodes) > 0
&& count($result[SUCCESSFULLNODES]) == 0) {
$this->logger->log_error("Puppet kick failed, no successful nodes");
$this->setState(State::FAILED, $transaction, $dryRun);
foreach($services as $service) {
$service->setState(State::FAILED, $svcTxnMap[$service->name], $dryRun, TRUE);
}
return array ( "result" => -3,
"error" => "Puppet kick failed on all nodes");
}
}
$this->setState(STATE::UNINSTALLED, $transaction, $dryRun);
$this->logger->log_info("Uninstalling HDP with $n services complete. DRYRUN=$dryRun");
return array("result" => 0, "error" => "");
}
private function _uninstallAll($transaction, $dryRun, $wipeoutData = FALSE) {
$services = $this->db->getClusterServices();
if ($services == FALSE) {
$this->logger->log_error("Failed to get cluster services.");
return array("result" => -1, "error" => "Failed to get cluster services from DB.");
}
// reverse order of services
// should cause NAGIOS to stop first
$services = array_reverse($services);
$this->logger->log_info("Uninstalling HDP.... DryRun=$dryRun");
$result = $this->_stopAllServices($services,
$transaction->createSubTransaction(), $dryRun);
if ($result['result'] !== 0) {
$this->logger->log_error("Failed to stop services.");
return $result;
}
$result = $this->_uninstallAllServices($services,
$transaction->createSubTransaction(), $dryRun, $wipeoutData);
if ($result['result'] !== 0) {
$this->logger->log_error("Failed to uninstall services.");
return $result;
}
return $result;
}
/**
* Function to stop & uninstall HDP across the whole cluster
* @param transaction transactionId for the operation
*/
public function uninstallHDP($transaction, $wipeoutData = FALSE) {
$this->currentAction = "Cluster uninstall";
$this->logger->log_info("Uninstalling HDP, wipeoutDataFlag="
. $wipeoutData);
$this->_uninstallAll($transaction->createSubTransaction(), TRUE,
$wipeoutData);
$this->resetSubTxnId();
$this->db->reset();
return $this->_uninstallAll($transaction->createSubTransaction(), FALSE,
$wipeoutData);
}
/**
* Function to deploy all the required rpms and start all required
* services on a given node
* @param transaction transactionId for the operation
* @param array $nodes Hostnames of the nodes to be deployed
*/
public function deployNodes($transaction, $nodes) {
// get components which this node maps to
// set state to install for required components
// kick puppet to install on single node
// set state for host to same state as the component state ( started/stopped )
// kick puppet for this single node
$this->logger->log_info("Deploying nodes " . implode(",", $nodes));
$hostRoles = $this->db->getNodeRolesAndState($nodes);
if ($hostRoles['result'] !== 0) {
$this->logger->log_error("Error obtaining host role state info from DB"
. ", error=" . $hostRoles["error"]);
return $hostRoles;
}
$hostCompMapping = array();
// array ( "svcName" => "compName" => ( "state" => , "hosts" => array (nodes) );
foreach ($hostRoles["hosts"] as $hostName => $hostInfo) {
if (!isset($hostInfo["services"])) {
continue;
}
foreach ($hostInfo["services"] as $svcName => $svcInfo) {
if (!isset($svcInfo["components"])) {
continue;
}
foreach ($svcInfo["components"] as $compName => $compInfo) {
if (!isset($hostCompMapping[$svcName])) {
$hostCompMapping[$svcName] = array();
}
if (!isset($hostCompMapping[$svcName][$compName])) {
$hostCompMapping[$svcName][$compName] = array();
}
if (!isset($compInfo["state"])) {
$compInfo["state"] = "UNKNOWN";
}
$state = State::getStateFromString($compInfo["state"]);
if (!isset($hostCompMapping[$svcName][$compName]["state"])) {
$hostCompMapping[$svcName][$compName]["state"] = $state;
}
if (!isset($hostCompMapping[$svcName][$compName]["hosts"])) {
$hostCompMapping[$svcName][$compName]["hosts"] = array();
}
array_push($hostCompMapping[$svcName][$compName]["hosts"],
$hostName);
}
}
}
$result = $this->_installNodes($transaction->createSubTransaction(),
$hostCompMapping, TRUE);
if ($result['result'] !== 0) {
return $result;
}
$result = $this->_startNodes($transaction->createSubTransaction(),
$hostCompMapping, TRUE);
if ($result['result'] !== 0) {
return $result;
}
$result = $this->_restartDashboardAndNagios($transaction->createSubTransaction(),
TRUE);
if ($result['result'] !== 0) {
return $result;
}
$this->resetSubTxnId();
$this->db->reset();
$result = $this->_installNodes($transaction->createSubTransaction(),
$hostCompMapping, FALSE);
if ($result['result'] !== 0) {
return $result;
}
$result = $this->_startNodes($transaction->createSubTransaction(),
$hostCompMapping, FALSE);
if ($result['result'] !== 0) {
return $result;
}
$result = $this->_restartDashboardAndNagios($transaction->createSubTransaction(),
FALSE);
return $result;
}
private function _restartDashboardAndNagios($transaction, $dryRun,
$restartNagiosOnly = FALSE) {
$this->currentAction = "Reconfigure Nagios/Ganglia";
$this->logger->log_info("Restarting dashboard and nagios, dryRun=" . $dryRun);
// check if nagios installed and needs to be restarted
$nagiosComp = $this->db->getNagiosServerComponent();
$restartNagios = FALSE;
if ($nagiosComp !== FALSE) {
if ($nagiosComp->state == STATE::STARTED) {
$restartNagios = TRUE;
}
}
// check if dashboard installed and needs to be restarted
$restartDashboard = FALSE;
if (!$restartNagiosOnly) {
$dashboardComp = $this->db->getDashboardServerComponent();
if ($dashboardComp !== FALSE) {
if ($dashboardComp->state == STATE::STARTED) {
$restartDashboard = TRUE;
}
}
}
$this->setState(State::STOPPING, $transaction, $dryRun);
if ($restartNagios) {
$this->logger->log_info("Stopping Nagios Server");
$result = $nagiosComp->stop($transaction->createSubTransaction(), $dryRun);
if ($result["result"] != 0) {
$this->setState(State::FAILED, $transaction, $dryRun);
$nagiosService = $this->db->getService("NAGIOS2");
if ($nagiosService !== FALSE) {
$nagiosService->setState(STATE::FAILED,
$transaction->createSubTransaction(), $dryRun, FALSE);
}
$this->logger->log_error("Failed to stop nagios server, error"
. $result["error"]);
return $result;
}
}
if ($restartDashboard) {
$this->logger->log_info("Stopping Dashboard");
$result = $dashboardComp->stop($transaction->createSubTransaction(), $dryRun);
if ($result["result"] != 0) {
$this->setState(State::FAILED, $transaction, $dryRun);
$this->logger->log_error("Failed to stop dashboard server, error"
. $result["error"]);
return $result;
}
}
$this->setState(State::STARTING, $transaction, $dryRun);
if ($restartDashboard) {
$this->logger->log_info("Starting Dashboard");
$result = $dashboardComp->start($transaction->createSubTransaction(), $dryRun);
if ($result["result"] != 0) {
$this->setState(State::FAILED, $transaction, $dryRun);
$dashboardService = $this->db->getService("DASHBOARD");
if ($dashboardService !== FALSE) {
$dashboardService->setState(STATE::FAILED,
$transaction->createSubTransaction(), $dryRun, FALSE);
}
$this->logger->log_error("Failed to start dashboard server, error"
. $result["error"]);
return $result;
}
}
if ($restartNagios) {
$this->logger->log_info("Starting Nagios Server");
$result = $nagiosComp->start($transaction->createSubTransaction(), $dryRun);
if ($result["result"] != 0) {
$this->setState(State::FAILED, $transaction, $dryRun);
$this->logger->log_error("Failed to start nagios server, error"
. $result["error"]);
return $result;
}
}
$this->setState(State::STARTED, $transaction, $dryRun);
return array ( "result" => 0, "error" => "");
}
private function _installNodes($transaction, $hostCompMapping, $dryRun) {
$this->logger->log_info("Installing on nodes dryRun=" . $dryRun);
$this->currentAction = "Install nodes";
$hostsToInstall = array();
$allHosts = array();
$compMapping = array();
foreach ($hostCompMapping as $svcName => $svcInfo) {
$hostsToInstall[$svcName] = array();
foreach ($svcInfo as $compName => $compInfo) {
$hostsToInstall[$svcName][$compName] = array();
if ($compInfo["state"] == State::INSTALLED
|| $compInfo["state"] == State::STARTED
|| $compInfo["state"] == State::STOPPED
|| $compInfo["state"] == State::FAILED) {
$hostsToInstall[$svcName][$compName] = $compInfo["hosts"];
$allHosts = array_merge($allHosts, $compInfo["hosts"]);
$compMapping[$compName] = $compInfo["hosts"];
}
}
}
if (count($allHosts) == 0) {
return array("result" => 0, "error" => "");
}
$allHosts = array_unique($allHosts);
// set state in DB to installing for the required hosts
if ($dryRun) {
$this->setState(State::INSTALLING, $transaction, $dryRun);
} else {
$this->db->setHostsState($hostsToInstall, State::INSTALLING);
$this->setState(State::INSTALLING, $transaction, $dryRun);
// send kick to hosts
$this->logger->log_debug("Kicking puppet for installing nodes on "
. " cluster=" . $this->name
. ", txn=" . $transaction->toString());
$startTime = time();
$result = $this->puppet->kickPuppet($allHosts, $transaction, $this->name,
$compMapping);
$this->logger->log_debug("Puppet kick response for installing nodes on"
. " cluster=" . $this->name
. ", txn=" . $transaction->toString()
. ", response=" . print_r($result, true));
// handle puppet response
$timeTaken = time() - $startTime;
$opStatus = array(
"stats" =>
array (
"NODE_COUNT" => count($allHosts),
"TIME_TAKEN_SECS" => $timeTaken),
"nodeReport" =>
array ( "PUPPET_KICK_FAILED" => $result[KICKFAILED],
"PUPPET_OPERATION_FAILED" => $result[FAILEDNODES],
"PUPPET_OPERATION_TIMEDOUT" => $result[TIMEDOUTNODES],
"PUPPET_OPERATION_SUCCEEDED" => $result[SUCCESSFULLNODES]));
$this->logger->log_info("Persisting puppet report for deploying nodes");
$this->db->persistTransactionOpStatus($transaction,
json_encode($opStatus));
if ($result['result'] != 0) {
$this->logger->log_error("Installing nodes failed with: " . $result['error']);
$this->setState(State::FAILED, $transaction, $dryRun);
$this->db->setHostsState($allHosts, State::FAILED);
return $result;
}
if (count($allHosts) > 0
&& count($result[SUCCESSFULLNODES]) == 0) {
$this->logger->log_error("Puppet kick failed, no successful nodes");
$this->setState(State::FAILED, $transaction, $dryRun);
$this->db->setHostsState($hostsToInstall, State::FAILED);
return array ( "result" => -3,
"error" => "Puppet kick failed on all nodes");
}
$this->db->setHostsState($hostsToInstall, State::INSTALLED);
$this->setState(State::INSTALLED, $transaction, $dryRun);
}
return array("result" => 0, "error" => "");
}
private function _startNodes($transaction, $hostCompMapping, $dryRun) {
$this->logger->log_info("Starting nodes dryRun=" . $dryRun);
$this->currentAction = "Start nodes";
$hostsToStart = array();
$kickHosts = array();
$noOpHosts = array();
$compMapping = array();
foreach ($hostCompMapping as $svcName => $svcInfo) {
$hostsToStart[$svcName] = array();
foreach ($svcInfo as $compName => $compInfo) {
$hostsToStart[$svcName][$compName] = array();
if ($compInfo["state"] == State::STARTED) {
$hostsToStart[$svcName][$compName] = $compInfo["hosts"];
$kickHosts = array_merge($kickHosts, $compInfo["hosts"]);
$compMapping[$compName] = $compInfo["hosts"];
} else {
$noOpHosts[$svcName][$compName] = $compInfo["hosts"];
}
}
}
// set state for remaining hosts to stopped or installed as needed?
if (!$dryRun) {
$result = $this->db->matchHostStateToComponent($noOpHosts);
if ($result['result'] != 0) {
$this->logger->log_error("Could not update the state for hosts in no-op list"
. ", error=" . $result["error"]);
return $result;
}
}
if (count($kickHosts) == 0) {
return array("result" => 0, "error" => "");
}
$kickHosts = array_unique($kickHosts);
// set state in DB to starting for the required hosts
if ($dryRun) {
$this->setState(State::STARTING, $transaction, $dryRun);
} else {
$this->db->setHostsState($hostsToStart, State::STARTING);
$this->setState(State::STARTING, $transaction, $dryRun);
// send kick to hosts
$this->logger->log_debug("Kicking puppet for starting nodes on"
. " cluster=" . $this->name
. ", txn=" . $transaction->toString());
$startTime = time();
$result = $this->puppet->kickPuppet($kickHosts, $transaction,
$this->name, $compMapping);
$this->logger->log_debug("Puppet kick response for starting nodes on"
. " cluster=" . $this->name
. ", txn=" . $transaction->toString()
. ", response=" . print_r($result, true));
// handle puppet response
$timeTaken = time() - $startTime;
$opStatus = array(
"stats" =>
array (
"NODE_COUNT" => count($kickHosts),
"TIME_TAKEN_SECS" => $timeTaken),
"nodeReport" =>
array ( "PUPPET_KICK_FAILED" => $result[KICKFAILED],
"PUPPET_OPERATION_FAILED" => $result[FAILEDNODES],
"PUPPET_OPERATION_TIMEDOUT" => $result[TIMEDOUTNODES],
"PUPPET_OPERATION_SUCCEEDED" => $result[SUCCESSFULLNODES]));
$this->logger->log_info("Persisting puppet report for deploying nodes");
$this->db->persistTransactionOpStatus($transaction,
json_encode($opStatus));
if ($result['result'] != 0) {
$this->logger->log_error("Starting nodes failed with: " . $result['error']);
$this->setState(State::FAILED, $transaction, $dryRun);
$this->db->setHostsState($hostsToStart, State::FAILED);
return $result;
}
if (count($kickHosts) > 0
&& count($result[SUCCESSFULLNODES]) == 0) {
$this->logger->log_error("Puppet kick failed, no successful nodes");
$this->setState(State::FAILED, $transaction, $dryRun);
$this->db->setHostsState($hostsToStart, State::FAILED);
return array ( "result" => -3,
"error" => "Puppet kick failed on all nodes");
}
// set state in DB to started
$this->db->setHostsState($hostsToStart, State::STARTED);
$this->setState(State::STARTED, $transaction, $dryRun);
}
return array("result" => 0, "error" => "");
}
/**
* Function to install all the services in order.
* @param transaction transactionId for the operation
*/
function installAllServices($transaction) {
$services = $this->db->getClusterServices();
$result = $this->_installAllServices($services, $transaction, TRUE);
if ($result['result'] !== 0) {
return $result;
}
$this->resetSubTxnId();
$this->db->reset();
return $this->_installAllServices($services, $transaction, FALSE);
}
private function _installAllServices($services, $transaction, $dryRun) {
$n = count($services);
$this->logger->log_info("Installing HDP with $n services... DryRun=$dryRun");
$this->setState(State::INSTALLING, $transaction, $dryRun);
$svcTxnMap = array();
foreach ($services as $service) {
$svcTxnMap[$service->name] = $transaction->createSubTransaction();
}
// Mark all as installed before the actual kick so
// that desired state kicks in
foreach ($services as $service) {
$result = $this->installService($svcTxnMap[$service->name], $service, $dryRun);
if ($result['result'] !== 0) {
$this->setState(State::FAILED, $transaction, $dryRun);
$service->setState(State::FAILED, $svcTxnMap[$service->name], $dryRun, FALSE);
return $result;
}
}
// Special case...
if (!$dryRun) {
$result = $this->db->getAllNodes();
if ($result['result'] !== 0) {
$this->logger->log_error("Installing HDP failed with: " . $result['error']);
$this->setState(State::FAILED, $transaction, $dryRun);
foreach ($services as $service) {
$service->setState(State::FAILED, $svcTxnMap[$service->name], $dryRun, FALSE);
}
return $result;
}
$nodes = $result["nodes"];
$this->logger->log_debug("Kicking puppet for installing"
. " cluster=" . $this->name
. ", txn=" . $transaction->toString());
$startTime = time();
$result = $this->puppet->kickPuppet($nodes, $transaction, $this->name,
$result["componentMapping"]);
$this->logger->log_debug("Puppet kick response for installing"
. " cluster=" . $this->name
. ", txn=" . $transaction->toString()
. ", response=" . print_r($result, true));
// handle puppet response
$timeTaken = time() - $startTime;
$opStatus = array(
"stats" =>
array (
"NODE_COUNT" => count($nodes),
"TIME_TAKEN_SECS" => $timeTaken),
"nodeReport" =>
array ( "PUPPET_KICK_FAILED" => $result[KICKFAILED],
"PUPPET_OPERATION_FAILED" => $result[FAILEDNODES],
"PUPPET_OPERATION_TIMEDOUT" => $result[TIMEDOUTNODES],
"PUPPET_OPERATION_SUCCEEDED" => $result[SUCCESSFULLNODES]));
$this->logger->log_info("Persisting puppet report for install HDP");
$this->db->persistTransactionOpStatus($transaction,
json_encode($opStatus));
if ($result['result'] != 0) {
$this->logger->log_error("Installing HDP failed with: " . $result['error']);
$this->setState(State::FAILED, $transaction, $dryRun);
foreach ($services as $service) {
$service->setState(State::FAILED, $svcTxnMap[$service->name], $dryRun, FALSE);
}
return $result;
}
if (count($nodes) > 0
&& count($result[SUCCESSFULLNODES]) == 0) {
$this->logger->log_error("Puppet kick failed, no successful nodes");
$this->setState(State::FAILED, $transaction, $dryRun);
foreach ($services as $service) {
$service->setState(State::FAILED, $svcTxnMap[$service->name], $dryRun, FALSE);
}
return array ( "result" => -3,
"error" => "Puppet kick failed on all nodes");
}
}
// TODO - Update DB with transaction
$this->setState(State::INSTALLED, $transaction, $dryRun);
$this->logger->log_info("Installing HDP with $n services complete. DRYRUN=$dryRun");
return array("result" => 0, "error" => "");
}
/**
* Function to start all the services in order.
* @param transaction transactionId for the operation
*/
public function startAllServices($transaction) {
$services = $this->db->getClusterServices();
$n = count($services);
$this->logger->log_info("Starting $n services");
$result = $this->_startAllServices($services, $transaction, TRUE);
if ($result['result'] !== 0) {
return $result;
}
$this->resetSubTxnId();
$this->db->reset();
$services = $this->db->getClusterServices();
return $this->_startAllServices($services, $transaction, FALSE);
}
public function startServices($transaction, $serviceNames) {
$services = $this->db->getServices($serviceNames);
$result = $this->_startAllServices($services, $transaction, TRUE);
if ($result['result'] !== 0) {
return $result;
}
$this->resetSubTxnId();
$this->db->reset();
$services = $this->db->getServices($serviceNames);
return $this->_startAllServices($services, $transaction, FALSE);
}
private function _startAllServices($services, $transaction, $dryRun) {
$n = count($services);
$this->logger->log_info("Starting HDP with $n services...");
foreach ($services as $service) {
$result = $this->startService($transaction->createSubTransaction(), $service, $dryRun);
if ($result['result'] !== 0) {
return $result;
}
}
// TODO - Update DB with transaction
$this->logger->log_info("Starting HDP with $n services complete. ");
return array("result" => 0, "error" => "");
}
/**
* Function to stop all the services in order.
* @param transaction transactionId for the operation
*/
public function stopAllServices($transaction) {
$services = $this->db->getClusterServices();
$n = count($services);
$this->logger->log_info("Stopping $n services");
$result = $this->_stopAllServices($services, $transaction, TRUE);
if ($result['result'] !== 0) {
return $result;
}
$this->resetSubTxnId();
$this->db->reset();
$services = $this->db->getClusterServices();
return $this->_stopAllServices($services, $transaction, FALSE);
}
public function stopServices($transaction, $serviceNames) {
$services = $this->db->getServices($serviceNames);
$result = $this->_stopAllServices($services, $transaction, TRUE);
if ($result['result'] !== 0) {
return $result;
}
$this->resetSubTxnId();
$this->db->reset();
$services = $this->db->getServices($serviceNames);
return $this->_stopAllServices($services, $transaction, FALSE);
}
private function _stopAllServices($services, $transaction, $dryRun) {
$n = count($services);
$this->logger->log_info("Stopping HDP with $n services... DryRun=$dryRun");
foreach ($services as $service) {
$result = $this->stopService($transaction->createSubTransaction(),
$service, $dryRun);
if ($result['result'] !== 0) {
return $result;
}
}
// TODO - Update DB with transaction
$this->logger->log_info("Stopping HDP with $n services complete. DryRun=$dryRun");
return array("result" => 0, "error" => "");
}
/**
* Function to install a given service.
* @param transaction transactionId for the operation
* @param service service to be installed
* @param dryRun dry-run?
*/
private function installService($transaction, $service, $dryRun) {
$this->logger->log_info("Installing service $service->name ...");
$result = $service->install($transaction, $dryRun);
$this->logger->log_info("Installing service $service->name complete. ");
return $result;
}
/**
* Function to start a given service.
* Should ensure required dependent services are up and running.
* This could be done in the puppet layer.
* @param transaction transactionId for the operation
* @param service service to be started
* @param dryRun dry-run?
*/
private function startService($transaction, $service, $dryRun) {
$this->logger->log_info("Starting service $service->name ...");
$result = $service->start($transaction, $dryRun);
$this->logger->log_info("Starting service $service->name complete. "
. "Result=" . $result["result"]);
return $result;
}
/**
* Function to stop a given service.
* Should ensure required dependent services are not running.
* This could be done in the puppet layer.
* @param transaction transactionId for the operation
* @param service service to be stopped
* @param dryRun dry-run?
*/
private function stopService($transaction, $service, $dryRun) {
$this->logger->log_info("Stopping service $service->name ...");
$result = $service->stop($transaction, $dryRun);
$this->logger->log_info("Stopping service $service->name complete. "
. "Result=" . $result["result"]);
return $result;
}
/**
* Function to reconfigure a set of services by first stopping the services and
* the required dependencies, re-pushing new configs to required nodes and
* restarting all the required services.
* @param transaction transactionId for the operation
* @param serviceNames services to be reconfigured
*/
public function reconfigureServices($transaction, $serviceNames) {
$result = $this->_reconfigureServices($transaction, $serviceNames, TRUE);
if ($result['result'] !== 0) {
return $result;
}
$this->resetSubTxnId();
$this->db->reset();
return $this->_reconfigureServices($transaction, $serviceNames, FALSE);
}
private function getServices($serviceNames) {
$services = array();
foreach ($serviceNames as $serviceName) {
$service = $this->db->getService($serviceName);
if ($service === FALSE) {
return array("result" => -1, "error" => "Failed to get Service for $serviceName");
}
array_push($services, $service);
}
return array("result" => 0, "error" => "", "services" => $services);
}
private function getUniqueServices($services) {
$uniques = array();
foreach ($services as $service) {
$uniques[$service->name] = $service;
}
return array_values($uniques);
}
private function _reconfigureServices($transaction, $serviceNames, $dryRun) {
$serviceList = implode($serviceNames, ",");
$this->currentAction = "Reconfigure";
$this->logger->log_debug("reconfigureServices for ($serviceList) DRYRUN=$dryRun");
$result = $this->getServices($serviceNames);
if ($result["result"] != 0) {
$this->logger->log_error("Failed to get Service objects.");
return $result;
}
$services = $result["services"];
$servicesToSetToStoppedState = array();
$svcsToStart = array();
foreach ($services as $svcObj) {
if ($svcObj->state == STATE::STARTED || $svcObj->state == STATE::STARTING) {
array_push($svcsToStart, $svcObj->name);
} else if ($svcObj->state == STATE::STOPPED) {
array_push($servicesToSetToStoppedState, $svcObj->name);
}
}
// get all dependents recursively for all the services that will be
// reconfigured
$dependents = array();
foreach ($serviceNames as $serviceName) {
$svcDeps = $this->db->getRecursiveServiceDependents($serviceName);
if ($svcDeps === FALSE) {
continue;
}
$dependents = array_merge($dependents, $svcDeps);
}
$dependents = array_unique($dependents);
foreach ($dependents as $serviceName) {
$svc = $this->db->getService($serviceName);
if ($svc !== FALSE) {
array_push($services, $svc);
if ($svc->state == STATE::STARTED || $svc->state == STATE::STARTING) {
array_push($svcsToStart, $serviceName);
} else if ($svc->state == STATE::STOPPED) {
array_push($servicesToSetToStoppedState, $serviceName);
}
}
}
$services = $this->getUniqueServices($services);
// HACK!!!!! restart nagios everytime a service is reconfigured as
// nagios runs checks on almost all services
$nagiosComp = $this->db->getNagiosServerComponent();
$restartNagios = FALSE;
if ($nagiosComp !== FALSE) {
if ($nagiosComp->state == STATE::STARTED) {
$restartNagios = TRUE;
}
}
// Stop the services
$this->logger->log_debug("reconfigureServices: Stopping services ($serviceList) dryRun=$dryRun");
foreach ($services as $service) {
$result = $this->stopService($transaction->createSubTransaction(), $service, $dryRun);
if ($result['result'] !== 0) {
$this->logger->log_error("Failed to stop service $service->name with " . $result["error"]);
return $result;
}
}
$this->logger->log_debug("reconfigureServices: Installing services ($serviceList) dryRun=$dryRun");
$result = $this->_installAllServices($services, $transaction->createSubTransaction(), $dryRun);
if ($result['result'] !== 0) {
$this->logger->log_error("Failed to install services with " . $result["error"]);
return $result;
}
$serviceToStartList = implode(",", $svcsToStart);
// Start the services
$this->logger->log_debug("reconfigureServices: Starting services ($serviceToStartList) dryRun=$dryRun");
// Start all services and dependents which were in a started state initially
// that would have been stopped as a result of reconfiguration
foreach ($svcsToStart as $serviceName) {
$service = $this->db->getService($serviceName);
$result = $this->startService($transaction->createSubTransaction(), $service, $dryRun);
if ($result['result'] !== 0) {
$this->logger->log_error("Failed to start service $service->name with " . $result["error"]);
return $result;
}
}
// Set the originally stopped services back to stopped state
foreach ($servicesToSetToStoppedState as $serviceName) {
$service = $this->db->getService($serviceName);
$this->logger->log_info("Setting state to STOPPED for service "
. $service->name);
$service->setState(STATE::STOPPED,
$transaction->createSubTransaction(), $dryRun, FALSE);
}
if ($restartNagios) {
$this->logger->log_info("Restarting Nagios Server after reconfiguration");
$result = $this->_restartDashboardAndNagios(
$transaction->getNextSubTransaction(), $dryRun, TRUE);
if ($result["result"] != 0) {
$this->logger->log_error("Failed to restart nagios server, error"
. $result["error"]);
return $result;
}
}
return array("result" => 0, "error" => "");
}
/**
* Run smoke tests on a given services.
* @param transaction transaction
* @param serviceNames service names
*/
public function smokeServices($transaction, $serviceNames) {
$serviceList = implode($serviceNames, ",");
$this->logger->log_debug("smokeServices: Smoking services ($serviceList)");
$result = $this->getServices($serviceNames);
if ($result["result"] != 0) {
$this->logger->log_error("Failed to get Service objects.");
return $result;
}
$services = $result["services"];
// Smoke the services
foreach ($services as $service) {
$this->logger->log_debug("About to smoke $service->name");
$result = $service->smoke($transaction->createSubTransaction(), FALSE);
if ($result['result'] != 0) {
$this->logger->log_error("Failed to smoke service $service->name with " . $result["error"]);
return $result;
} else {
$this->logger->log_debug("Succesfully smoked service $service->name");
}
}
$this->resetSubTxnId();
$this->db->reset();
return array("result" => 0, "error" =>"");
}
/**
*
*/
private function setState($state, $transaction, $dryRun) {
$txnProgress = getTransactionProgressFromState($state);
// $desc = "CLUSTER"."-".$this->currentAction."-". TransactionProgress::$PROGRESS[$txnProgress];
$desc = getActionDescription("", $this->currentAction, TransactionProgress::$PROGRESS[$txnProgress]);
if ($dryRun) {
// $desc = "CLUSTER"."-".$this->currentAction."-PENDING";
$desc = getActionDescription("", $this->currentAction, "PENDING");
}
$result =
$this->db->persistTransaction($transaction, State::$STATE[$state],
$desc, TransactionProgress::$PROGRESS[$txnProgress],
"CLUSTER", $dryRun);
if ($result['result'] !== 0) {
$this->state == State::FAILED;
$this->logger->log_error($this->name." - ".State::$STATE[$state]);
return $result;
}
$this->state = $state;
$this->logger->log_info("$this->name - " . State::$STATE[$state]);
return array("result" => 0, "error" => "");
}
}
?>