Cluster.php 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975
  1. <?php
  2. /*
  3. * Licensed to the Apache Software Foundation (ASF) under one
  4. * or more contributor license agreements. See the NOTICE file
  5. * distributed with this work for additional information
  6. * regarding copyright ownership. The ASF licenses this file
  7. * to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance
  9. * with the License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. */
  19. include_once "../db/OrchestratorDB.php";
  20. include_once "../db/Transaction.php";
  21. include_once "../puppet/PuppetInvoker.php";
  22. include_once "State.php";
  23. class Cluster {
  24. public $name;
  25. public $db;
  26. public $puppet;
  27. private $logger;
  28. private $state;
  29. private $currentAction;
  30. public function __construct($clusterName, $db, $puppet) {
  31. $this->name = $clusterName;
  32. $this->db = $db;
  33. $this->puppet = $puppet;
  34. $this->logger = new HMCLogger("Cluster:".$clusterName);
  35. $this->state = "";
  36. $this->currentAction = "";
  37. }
  38. public function resetSubTxnId() {
  39. $GLOBALS["SUB_TXN_ID"] = 1;
  40. }
  41. /**
  42. * Function to install, configure and start HDP across the whole cluster
  43. * @param transaction transactionId for the operation
  44. */
  45. public function deployHDP($transaction) {
  46. $this->currentAction = "INSTALL";
  47. $result = $this->_deployHDP($transaction, TRUE);
  48. if ($result['result'] !== 0) {
  49. return $result;
  50. }
  51. $this->resetSubTxnId();
  52. $this->db->reset();
  53. return $this->_deployHDP($transaction, FALSE);
  54. }
  55. private function _deployHDP($transaction, $dryRun) {
  56. $services = $this->db->getClusterServices();
  57. if ($services == FALSE) {
  58. $this->logger->log_error("Failed to get cluster services.");
  59. return array("result" => -1, "error" => "Failed to get cluster services from DB.");
  60. }
  61. $n = count($services);
  62. $this->logger->log_info("Deploying HDP with $n services.... DryRun=$dryRun");
  63. $result = $this->_installAllServices($services,
  64. $transaction->createSubTransaction(), $dryRun);
  65. if ($result['result'] !== 0) {
  66. $this->logger->log_error("Failed to install services.");
  67. return $result;
  68. }
  69. $result = $this->_startAllServices($services,
  70. $transaction->createSubTransaction(), $dryRun);
  71. $this->resetSubTxnId();
  72. $this->db->reset();
  73. return $result;
  74. }
  75. private function _uninstallAllServices($services, $transaction, $dryRun,
  76. $wipeoutData = FALSE) {
  77. $n = count($services);
  78. $this->logger->log_info("Uninstalling HDP with $n services.... DryRun=$dryRun");
  79. $this->setState(State::UNINSTALLING, $transaction, $dryRun);
  80. $svcTxnMap = array();
  81. foreach($services as $service) {
  82. $svcTxnMap[$service->name] = $transaction->createSubTransaction();
  83. }
  84. // Mark all as uninstalled before the actual kick so
  85. // that desired state kicks in
  86. foreach($services as $service) {
  87. $result = $service->uninstall($svcTxnMap[$service->name], $dryRun);
  88. if ($result['result'] != 0) {
  89. $this->setState(State::FAILED, $transaction, $dryRun);
  90. $service->setState(State::FAILED, $svcTxnMap[$service->name], $dryRun, TRUE);
  91. return $result;
  92. }
  93. }
  94. // Real Run
  95. if (!$dryRun) {
  96. $result = $this->db->getAllNodes();
  97. if ($result['result'] !== 0) {
  98. $this->logger->log_error("UnInstalling HDP failed with: " . $result['error']);
  99. $this->setState(State::FAILED, $transaction, $dryRun);
  100. foreach($services as $service) {
  101. $service->setState(State::FAILED, $svcTxnMap[$service->name], $dryRun, TRUE);
  102. }
  103. return $result;
  104. }
  105. $wipeoutFlag = "false";
  106. if ($wipeoutData) {
  107. $wipeoutFlag = "true";
  108. }
  109. $nodes = $result["nodes"];
  110. $result = $this->puppet->kickPuppet($nodes, $transaction, $this->name,
  111. $result["componentMapping"], array ("wipeoff_data" => $wipeoutFlag));
  112. $this->logger->log_debug("Puppet kick response for uninstalling "
  113. . "cluster=" . $this->name
  114. . ", txn=" . $transaction->toString()
  115. . ", response=" . print_r($result, true));
  116. // handle puppet response
  117. $opStatus = array( "nodeReport" =>
  118. array ( "PUPPET_KICK_FAILED" => $result[KICKFAILED],
  119. "PUPPET_OPERATION_FAILED" => $result[FAILEDNODES],
  120. "PUPPET_OPERATION_TIMEDOUT" => $result[TIMEDOUTNODES],
  121. "PUPPET_OPERATION_SUCCEEDED" => $result[SUCCESSFULLNODES]));
  122. $this->logger->log_info("Persisting puppet report for uninstall HDP");
  123. $this->db->persistTransactionOpStatus($transaction,
  124. json_encode($opStatus));
  125. if ($result['result'] != 0) {
  126. $this->logger->log_error("UnInstalling HDP failed with: " . $result['error']);
  127. $this->setState(State::FAILED, $transaction, $dryRun);
  128. foreach($services as $service) {
  129. $service->setState(State::FAILED, $svcTxnMap[$service->name], $dryRun, TRUE);
  130. }
  131. return $result;
  132. }
  133. if (count($nodes) > 0
  134. && count($result[SUCCESSFULLNODES]) == 0) {
  135. $this->logger->log_error("Puppet kick failed, no successful nodes");
  136. $this->setState(State::FAILED, $transaction, $dryRun);
  137. foreach($services as $service) {
  138. $service->setState(State::FAILED, $svcTxnMap[$service->name], $dryRun, TRUE);
  139. }
  140. return array ( "result" => -3,
  141. "error" => "Puppet kick failed on all nodes");
  142. }
  143. }
  144. $this->setState(STATE::UNINSTALLED, $transaction, $dryRun);
  145. $this->logger->log_info("Uninstalling HDP with $n services complete. DRYRUN=$dryRun");
  146. return array("result" => 0, "error" => "");
  147. }
  148. private function _uninstallAll($transaction, $dryRun, $wipeoutData = FALSE) {
  149. $services = $this->db->getClusterServices();
  150. if ($services == FALSE) {
  151. $this->logger->log_error("Failed to get cluster services.");
  152. return array("result" => -1, "error" => "Failed to get cluster services from DB.");
  153. }
  154. $this->logger->log_info("Uninstalling HDP.... DryRun=$dryRun");
  155. $result = $this->_stopAllServices($services,
  156. $transaction->createSubTransaction(), $dryRun);
  157. if ($result['result'] !== 0) {
  158. $this->logger->log_error("Failed to stop services.");
  159. return $result;
  160. }
  161. $result = $this->_uninstallAllServices($services,
  162. $transaction->createSubTransaction(), $dryRun, $wipeoutData);
  163. if ($result['result'] !== 0) {
  164. $this->logger->log_error("Failed to uninstall services.");
  165. return $result;
  166. }
  167. return $result;
  168. }
  169. /**
  170. * Function to stop & uninstall HDP across the whole cluster
  171. * @param transaction transactionId for the operation
  172. */
  173. public function uninstallHDP($transaction, $wipeoutData = FALSE) {
  174. $this->currentAction = "Uninstall";
  175. $this->logger->log_info("Uninstalling HDP, wipeoutDataFlag="
  176. . $wipeoutData);
  177. $this->_uninstallAll($transaction->createSubTransaction(), TRUE,
  178. $wipeoutData);
  179. $this->resetSubTxnId();
  180. $this->db->reset();
  181. return $this->_uninstallAll($transaction->createSubTransaction(), FALSE,
  182. $wipeoutData);
  183. }
  184. /**
  185. * Function to deploy all the required rpms and start all required
  186. * services on a given node
  187. * @param transaction transactionId for the operation
  188. * @param array $nodes Hostnames of the nodes to be deployed
  189. */
  190. public function deployNodes($transaction, $nodes) {
  191. // get components which this node maps to
  192. // set state to install for required components
  193. // kick puppet to install on single node
  194. // set state for host to same state as the component state ( started/stopped )
  195. // kick puppet for this single node
  196. $this->logger->log_info("Deploying nodes " . implode(",", $nodes));
  197. $hostRoles = $this->db->getNodeRolesAndState($nodes);
  198. if ($hostRoles['result'] !== 0) {
  199. $this->logger->log_error("Error obtaining host role state info from DB"
  200. . ", error=" . $hostRoles["error"]);
  201. return $hostRoles;
  202. }
  203. $hostCompMapping = array();
  204. // array ( "svcName" => "compName" => ( "state" => , "hosts" => array (nodes) );
  205. foreach ($hostRoles["hosts"] as $hostName => $hostInfo) {
  206. if (!isset($hostInfo["services"])) {
  207. continue;
  208. }
  209. foreach ($hostInfo["services"] as $svcName => $svcInfo) {
  210. if (!isset($svcInfo["components"])) {
  211. continue;
  212. }
  213. foreach ($svcInfo["components"] as $compName => $compInfo) {
  214. if (!isset($hostCompMapping[$svcName])) {
  215. $hostCompMapping[$svcName] = array();
  216. }
  217. if (!isset($hostCompMapping[$svcName][$compName])) {
  218. $hostCompMapping[$svcName][$compName] = array();
  219. }
  220. if (!isset($compInfo["state"])) {
  221. $compInfo["state"] = "UNKNOWN";
  222. }
  223. $state = State::getStateFromString($compInfo["state"]);
  224. if (!isset($hostCompMapping[$svcName][$compName]["state"])) {
  225. $hostCompMapping[$svcName][$compName]["state"] = $state;
  226. }
  227. if (!isset($hostCompMapping[$svcName][$compName]["hosts"])) {
  228. $hostCompMapping[$svcName][$compName]["hosts"] = array();
  229. }
  230. array_push($hostCompMapping[$svcName][$compName]["hosts"],
  231. $hostName);
  232. }
  233. }
  234. }
  235. $result = $this->_installNodes($transaction->createSubTransaction(),
  236. $hostCompMapping, TRUE);
  237. if ($result['result'] !== 0) {
  238. return $result;
  239. }
  240. $result = $this->_startNodes($transaction->createSubTransaction(),
  241. $hostCompMapping, TRUE);
  242. if ($result['result'] !== 0) {
  243. return $result;
  244. }
  245. $result = $this->_restartDashboardAndNagios($transaction->createSubTransaction(),
  246. TRUE);
  247. if ($result['result'] !== 0) {
  248. return $result;
  249. }
  250. $this->resetSubTxnId();
  251. $this->db->reset();
  252. $result = $this->_installNodes($transaction->createSubTransaction(),
  253. $hostCompMapping, FALSE);
  254. if ($result['result'] !== 0) {
  255. return $result;
  256. }
  257. $result = $this->_startNodes($transaction->createSubTransaction(),
  258. $hostCompMapping, FALSE);
  259. if ($result['result'] !== 0) {
  260. return $result;
  261. }
  262. $result = $this->_restartDashboardAndNagios($transaction->createSubTransaction(),
  263. FALSE);
  264. return $result;
  265. }
  266. private function _restartDashboardAndNagios($transaction, $dryRun,
  267. $restartNagiosOnly = FALSE) {
  268. $this->currentAction = "ReconfigureMonitoring";
  269. $this->logger->log_info("Restarting dashboard and nagios, dryRun=" . $dryRun);
  270. // check if nagios installed and needs to be restarted
  271. $nagiosComp = $this->db->getNagiosServerComponent();
  272. $restartNagios = FALSE;
  273. if ($nagiosComp !== FALSE) {
  274. if ($nagiosComp->state == STATE::STARTED) {
  275. $restartNagios = TRUE;
  276. }
  277. }
  278. // check if dashboard installed and needs to be restarted
  279. $restartDashboard = FALSE;
  280. if (!$restartNagiosOnly) {
  281. $dashboardComp = $this->db->getDashboardServerComponent();
  282. if ($dashboardComp !== FALSE) {
  283. if ($dashboardComp->state == STATE::STARTED) {
  284. $restartDashboard = TRUE;
  285. }
  286. }
  287. }
  288. $this->setState(State::STOPPING, $transaction, $dryRun);
  289. if ($restartNagios) {
  290. $this->logger->log_info("Stopping Nagios Server");
  291. $result = $nagiosComp->stop($transaction->createSubTransaction(), $dryRun);
  292. if ($result["result"] != 0) {
  293. $this->setState(State::FAILED, $transaction, $dryRun);
  294. $this->logger->log_error("Failed to stop nagios server, error"
  295. . $result["error"]);
  296. return $result;
  297. }
  298. }
  299. if ($restartDashboard) {
  300. $this->logger->log_info("Stopping Dashboard");
  301. $result = $dashboardComp->stop($transaction->createSubTransaction(), $dryRun);
  302. if ($result["result"] != 0) {
  303. $this->setState(State::FAILED, $transaction, $dryRun);
  304. $this->logger->log_error("Failed to stop dashboard server, error"
  305. . $result["error"]);
  306. return $result;
  307. }
  308. }
  309. $this->setState(State::STARTING, $transaction, $dryRun);
  310. if ($restartDashboard) {
  311. $this->logger->log_info("Starting Dashboard");
  312. $result = $dashboardComp->start($transaction->createSubTransaction(), $dryRun);
  313. if ($result["result"] != 0) {
  314. $this->setState(State::FAILED, $transaction, $dryRun);
  315. $this->logger->log_error("Failed to start dashboard server, error"
  316. . $result["error"]);
  317. return $result;
  318. }
  319. }
  320. if ($restartNagios) {
  321. $this->logger->log_info("Starting Nagios Server");
  322. $result = $nagiosComp->start($transaction->createSubTransaction(), $dryRun);
  323. if ($result["result"] != 0) {
  324. $this->setState(State::FAILED, $transaction, $dryRun);
  325. $this->logger->log_error("Failed to start nagios server, error"
  326. . $result["error"]);
  327. return $result;
  328. }
  329. }
  330. $this->setState(State::STARTED, $transaction, $dryRun);
  331. return array ( "result" => 0, "error" => "");
  332. }
  333. private function _installNodes($transaction, $hostCompMapping, $dryRun) {
  334. $this->logger->log_info("Installing on nodes dryRun=" . $dryRun);
  335. $this->currentAction = "InstallNodes";
  336. $hostsToInstall = array();
  337. $allHosts = array();
  338. $compMapping = array();
  339. foreach ($hostCompMapping as $svcName => $svcInfo) {
  340. $hostsToInstall[$svcName] = array();
  341. foreach ($svcInfo as $compName => $compInfo) {
  342. $hostsToInstall[$svcName][$compName] = array();
  343. if ($compInfo["state"] == State::INSTALLED
  344. || $compInfo["state"] == State::STARTED
  345. || $compInfo["state"] == State::STOPPED
  346. || $compInfo["state"] == State::FAILED) {
  347. $hostsToInstall[$svcName][$compName] = $compInfo["hosts"];
  348. $allHosts = array_merge($allHosts, $compInfo["hosts"]);
  349. $compMapping[$compName] = $compInfo["hosts"];
  350. }
  351. }
  352. }
  353. if (count($allHosts) == 0) {
  354. return array("result" => 0, "error" => "");
  355. }
  356. $allHosts = array_unique($allHosts);
  357. // set state in DB to installing for the required hosts
  358. if ($dryRun) {
  359. $this->setState(State::INSTALLING, $transaction, $dryRun);
  360. } else {
  361. $this->db->setHostsState($hostsToInstall, State::INSTALLING);
  362. $this->setState(State::INSTALLING, $transaction, $dryRun);
  363. // send kick to hosts
  364. $result = $this->puppet->kickPuppet($allHosts, $transaction, $this->name,
  365. $compMapping);
  366. $this->logger->log_debug("Puppet kick response for installing "
  367. . " cluster=" . $this->name
  368. . ", txn=" . $transaction->toString()
  369. . ", response=" . print_r($result, true));
  370. // handle puppet response
  371. $opStatus = array ( "nodeReport" =>
  372. array ( "PUPPET_KICK_FAILED" => $result[KICKFAILED],
  373. "PUPPET_OPERATION_FAILED" => $result[FAILEDNODES],
  374. "PUPPET_OPERATION_TIMEDOUT" => $result[TIMEDOUTNODES],
  375. "PUPPET_OPERATION_SUCCEEDED" => $result[SUCCESSFULLNODES]));
  376. $this->logger->log_info("Persisting puppet report for deploying nodes");
  377. $this->db->persistTransactionOpStatus($transaction,
  378. json_encode($opStatus));
  379. if ($result['result'] != 0) {
  380. $this->logger->log_error("Installing nodes failed with: " . $result['error']);
  381. $this->setState(State::FAILED, $transaction, $dryRun);
  382. $this->db->setHostsState($allHosts, State::FAILED);
  383. return $result;
  384. }
  385. if (count($allHosts) > 0
  386. && count($result[SUCCESSFULLNODES]) == 0) {
  387. $this->logger->log_error("Puppet kick failed, no successful nodes");
  388. $this->setState(State::FAILED, $transaction, $dryRun);
  389. $this->db->setHostsState($hostsToInstall, State::FAILED);
  390. return array ( "result" => -3,
  391. "error" => "Puppet kick failed on all nodes");
  392. }
  393. $this->db->setHostsState($hostsToInstall, State::INSTALLED);
  394. $this->setState(State::INSTALLED, $transaction, $dryRun);
  395. }
  396. return array("result" => 0, "error" => "");
  397. }
  398. private function _startNodes($transaction, $hostCompMapping, $dryRun) {
  399. $this->logger->log_info("Starting nodes dryRun=" . $dryRun);
  400. $this->currentAction = "StartNodes";
  401. $hostsToStart = array();
  402. $kickHosts = array();
  403. $noOpHosts = array();
  404. $compMapping = array();
  405. foreach ($hostCompMapping as $svcName => $svcInfo) {
  406. $hostsToStart[$svcName] = array();
  407. foreach ($svcInfo as $compName => $compInfo) {
  408. $hostsToStart[$svcName][$compName] = array();
  409. if ($compInfo["state"] == State::STARTED) {
  410. $hostsToStart[$svcName][$compName] = $compInfo["hosts"];
  411. $kickHosts = array_merge($kickHosts, $compInfo["hosts"]);
  412. $compMapping[$compName] = $compInfo["hosts"];
  413. } else {
  414. $noOpHosts[$svcName][$compName] = $compInfo["hosts"];
  415. }
  416. }
  417. }
  418. // set state for remaining hosts to stopped or installed as needed?
  419. if (!$dryRun) {
  420. $result = $this->db->matchHostStateToComponent($noOpHosts);
  421. if ($result['result'] != 0) {
  422. $this->logger->log_error("Could not update the state for hosts in no-op list"
  423. . ", error=" . $result["error"]);
  424. return $result;
  425. }
  426. }
  427. if (count($kickHosts) == 0) {
  428. return array("result" => 0, "error" => "");
  429. }
  430. $kickHosts = array_unique($kickHosts);
  431. // set state in DB to starting for the required hosts
  432. if ($dryRun) {
  433. $this->setState(State::STARTING, $transaction, $dryRun);
  434. } else {
  435. $this->db->setHostsState($hostsToStart, State::STARTING);
  436. $this->setState(State::STARTING, $transaction, $dryRun);
  437. // send kick to hosts
  438. $result = $this->puppet->kickPuppet($kickHosts, $transaction,
  439. $this->name, $compMapping);
  440. $this->logger->log_debug("Puppet kick response for installing "
  441. . " cluster=" . $this->name
  442. . ", txn=" . $transaction->toString()
  443. . ", response=" . print_r($result, true));
  444. // handle puppet response
  445. $opStatus = array ( "nodeReport" =>
  446. array ( "PUPPET_KICK_FAILED" => $result[KICKFAILED],
  447. "PUPPET_OPERATION_FAILED" => $result[FAILEDNODES],
  448. "PUPPET_OPERATION_TIMEDOUT" => $result[TIMEDOUTNODES],
  449. "PUPPET_OPERATION_SUCCEEDED" => $result[SUCCESSFULLNODES]));
  450. $this->logger->log_info("Persisting puppet report for deploying nodes");
  451. $this->db->persistTransactionOpStatus($transaction,
  452. json_encode($opStatus));
  453. if ($result['result'] != 0) {
  454. $this->logger->log_error("Starting nodes failed with: " . $result['error']);
  455. $this->setState(State::FAILED, $transaction, $dryRun);
  456. $this->db->setHostsState($hostsToStart, State::FAILED);
  457. return $result;
  458. }
  459. if (count($kickHosts) > 0
  460. && count($result[SUCCESSFULLNODES]) == 0) {
  461. $this->logger->log_error("Puppet kick failed, no successful nodes");
  462. $this->setState(State::FAILED, $transaction, $dryRun);
  463. $this->db->setHostsState($hostsToStart, State::FAILED);
  464. return array ( "result" => -3,
  465. "error" => "Puppet kick failed on all nodes");
  466. }
  467. // set state in DB to started
  468. $this->db->setHostsState($hostsToStart, State::STARTED);
  469. $this->setState(State::STARTED, $transaction, $dryRun);
  470. }
  471. return array("result" => 0, "error" => "");
  472. }
  473. /**
  474. * Function to install all the services in order.
  475. * @param transaction transactionId for the operation
  476. */
  477. function installAllServices($transaction) {
  478. $services = $this->db->getClusterServices();
  479. $result = $this->_installAllServices($services, $transaction, TRUE);
  480. if ($result['result'] !== 0) {
  481. return $result;
  482. }
  483. $this->resetSubTxnId();
  484. $this->db->reset();
  485. return $this->_installAllServices($services, $transaction, FALSE);
  486. }
  487. private function _installAllServices($services, $transaction, $dryRun) {
  488. $n = count($services);
  489. $this->logger->log_info("Installing HDP with $n services... DryRun=$dryRun");
  490. $this->setState(State::INSTALLING, $transaction, $dryRun);
  491. $svcTxnMap = array();
  492. foreach ($services as $service) {
  493. $svcTxnMap[$service->name] = $transaction->createSubTransaction();
  494. }
  495. // Mark all as installed before the actual kick so
  496. // that desired state kicks in
  497. foreach ($services as $service) {
  498. $result = $this->installService($svcTxnMap[$service->name], $service, $dryRun);
  499. if ($result['result'] !== 0) {
  500. $this->setState(State::FAILED, $transaction, $dryRun);
  501. $service->setState(State::FAILED, $svcTxnMap[$service->name], $dryRun, FALSE);
  502. return $result;
  503. }
  504. }
  505. // Special case...
  506. if (!$dryRun) {
  507. $result = $this->db->getAllNodes();
  508. if ($result['result'] !== 0) {
  509. $this->logger->log_error("Installing HDP failed with: " . $result['error']);
  510. $this->setState(State::FAILED, $transaction, $dryRun);
  511. foreach ($services as $service) {
  512. $service->setState(State::FAILED, $svcTxnMap[$service->name], $dryRun, FALSE);
  513. }
  514. return $result;
  515. }
  516. $nodes = $result["nodes"];
  517. $result = $this->puppet->kickPuppet($nodes, $transaction, $this->name,
  518. $result["componentMapping"]);
  519. $this->logger->log_debug("Puppet kick response for installing "
  520. . " cluster=" . $this->name
  521. . ", txn=" . $transaction->toString()
  522. . ", response=" . print_r($result, true));
  523. // handle puppet response
  524. $opStatus = array ( "nodeReport" =>
  525. array ( "PUPPET_KICK_FAILED" => $result[KICKFAILED],
  526. "PUPPET_OPERATION_FAILED" => $result[FAILEDNODES],
  527. "PUPPET_OPERATION_TIMEDOUT" => $result[TIMEDOUTNODES],
  528. "PUPPET_OPERATION_SUCCEEDED" => $result[SUCCESSFULLNODES]));
  529. $this->logger->log_info("Persisting puppet report for install HDP");
  530. $this->db->persistTransactionOpStatus($transaction,
  531. json_encode($opStatus));
  532. if ($result['result'] != 0) {
  533. $this->logger->log_error("Installing HDP failed with: " . $result['error']);
  534. $this->setState(State::FAILED, $transaction, $dryRun);
  535. foreach ($services as $service) {
  536. $service->setState(State::FAILED, $svcTxnMap[$service->name], $dryRun, FALSE);
  537. }
  538. return $result;
  539. }
  540. if (count($nodes) > 0
  541. && count($result[SUCCESSFULLNODES]) == 0) {
  542. $this->logger->log_error("Puppet kick failed, no successful nodes");
  543. $this->setState(State::FAILED, $transaction, $dryRun);
  544. foreach ($services as $service) {
  545. $service->setState(State::FAILED, $svcTxnMap[$service->name], $dryRun, FALSE);
  546. }
  547. return array ( "result" => -3,
  548. "error" => "Puppet kick failed on all nodes");
  549. }
  550. }
  551. // TODO - Update DB with transaction
  552. $this->setState(State::INSTALLED, $transaction, $dryRun);
  553. $this->logger->log_info("Installing HDP with $n services complete. DRYRUN=$dryRun");
  554. return array("result" => 0, "error" => "");
  555. }
  556. /**
  557. * Function to start all the services in order.
  558. * @param transaction transactionId for the operation
  559. */
  560. public function startAllServices($transaction) {
  561. $services = $this->db->getClusterServices();
  562. $n = count($services);
  563. $this->logger->log_info("Starting $n services");
  564. $result = $this->_startAllServices($services, $transaction, TRUE);
  565. if ($result['result'] !== 0) {
  566. return $result;
  567. }
  568. $this->resetSubTxnId();
  569. $this->db->reset();
  570. $services = $this->db->getClusterServices();
  571. return $this->_startAllServices($services, $transaction, FALSE);
  572. }
  573. public function startServices($transaction, $serviceNames) {
  574. $services = $this->db->getServices($serviceNames);
  575. $result = $this->_startAllServices($services, $transaction, TRUE);
  576. if ($result['result'] !== 0) {
  577. return $result;
  578. }
  579. $this->resetSubTxnId();
  580. $this->db->reset();
  581. $services = $this->db->getServices($serviceNames);
  582. return $this->_startAllServices($services, $transaction, FALSE);
  583. }
  584. private function _startAllServices($services, $transaction, $dryRun) {
  585. $n = count($services);
  586. $this->logger->log_info("Starting HDP with $n services...");
  587. foreach ($services as $service) {
  588. $result = $this->startService($transaction->createSubTransaction(), $service, $dryRun);
  589. if ($result['result'] !== 0) {
  590. return $result;
  591. }
  592. }
  593. // TODO - Update DB with transaction
  594. $this->logger->log_info("Starting HDP with $n services complete. ");
  595. return array("result" => 0, "error" => "");
  596. }
  597. /**
  598. * Function to stop all the services in order.
  599. * @param transaction transactionId for the operation
  600. */
  601. public function stopAllServices($transaction) {
  602. $services = $this->db->getClusterServices();
  603. $n = count($services);
  604. $this->logger->log_info("Stopping $n services");
  605. $result = $this->_stopAllServices($services, $transaction, TRUE);
  606. if ($result['result'] !== 0) {
  607. return $result;
  608. }
  609. $this->resetSubTxnId();
  610. $this->db->reset();
  611. $services = $this->db->getClusterServices();
  612. return $this->_stopAllServices($services, $transaction, FALSE);
  613. }
  614. public function stopServices($transaction, $serviceNames) {
  615. $services = $this->db->getServices($serviceNames);
  616. $result = $this->_stopAllServices($services, $transaction, TRUE);
  617. if ($result['result'] !== 0) {
  618. return $result;
  619. }
  620. $this->resetSubTxnId();
  621. $this->db->reset();
  622. $services = $this->db->getServices($serviceNames);
  623. return $this->_stopAllServices($services, $transaction, FALSE);
  624. }
  625. private function _stopAllServices($services, $transaction, $dryRun) {
  626. $n = count($services);
  627. $this->logger->log_info("Stopping HDP with $n services... DryRun=$dryRun");
  628. foreach ($services as $service) {
  629. $result = $this->stopService($transaction->createSubTransaction(),
  630. $service, $dryRun);
  631. if ($result['result'] !== 0) {
  632. return $result;
  633. }
  634. }
  635. // TODO - Update DB with transaction
  636. $this->logger->log_info("Stopping HDP with $n services complete. DryRun=$dryRun");
  637. return array("result" => 0, "error" => "");
  638. }
  639. /**
  640. * Function to install a given service.
  641. * @param transaction transactionId for the operation
  642. * @param service service to be installed
  643. * @param dryRun dry-run?
  644. */
  645. private function installService($transaction, $service, $dryRun) {
  646. $this->logger->log_info("Installing service $service->name ...");
  647. $result = $service->install($transaction, $dryRun);
  648. $this->logger->log_info("Installing service $service->name complete. ");
  649. return $result;
  650. }
  651. /**
  652. * Function to start a given service.
  653. * Should ensure required dependent services are up and running.
  654. * This could be done in the puppet layer.
  655. * @param transaction transactionId for the operation
  656. * @param service service to be started
  657. * @param dryRun dry-run?
  658. */
  659. private function startService($transaction, $service, $dryRun) {
  660. $this->logger->log_info("Starting service $service->name ...");
  661. $result = $service->start($transaction, $dryRun);
  662. $this->logger->log_info("Starting service $service->name complete. "
  663. . "Result=" . $result["result"]);
  664. return $result;
  665. }
  666. /**
  667. * Function to stop a given service.
  668. * Should ensure required dependent services are not running.
  669. * This could be done in the puppet layer.
  670. * @param transaction transactionId for the operation
  671. * @param service service to be stopped
  672. * @param dryRun dry-run?
  673. */
  674. private function stopService($transaction, $service, $dryRun) {
  675. $this->logger->log_info("Stopping service $service->name ...");
  676. $result = $service->stop($transaction, $dryRun);
  677. $this->logger->log_info("Stopping service $service->name complete. "
  678. . "Result=" . $result["result"]);
  679. return $result;
  680. }
  681. /**
  682. * Function to reconfigure a set of services by first stopping the services and
  683. * the required dependencies, re-pushing new configs to required nodes and
  684. * restarting all the required services.
  685. * @param transaction transactionId for the operation
  686. * @param serviceNames services to be reconfigured
  687. */
  688. public function reconfigureServices($transaction, $serviceNames) {
  689. $result = $this->_reconfigureServices($transaction, $serviceNames, TRUE);
  690. if ($result['result'] !== 0) {
  691. return $result;
  692. }
  693. $this->resetSubTxnId();
  694. $this->db->reset();
  695. return $this->_reconfigureServices($transaction, $serviceNames, FALSE);
  696. }
  697. private function getServices($serviceNames) {
  698. $services = array();
  699. foreach ($serviceNames as $serviceName) {
  700. $service = $this->db->getService($serviceName);
  701. if ($service === FALSE) {
  702. return array("result" => -1, "error" => "Failed to get Service for $serviceName");
  703. }
  704. array_push($services, $service);
  705. }
  706. return array("result" => 0, "error" => "", "services" => $services);
  707. }
  708. private function getUniqueServices($services) {
  709. $uniques = array();
  710. foreach ($services as $service) {
  711. $uniques[$service->name] = $service;
  712. }
  713. return array_values($uniques);
  714. }
  715. private function _reconfigureServices($transaction, $serviceNames, $dryRun) {
  716. $serviceList = implode($serviceNames, ",");
  717. $this->currentAction = "Reconfigure";
  718. $this->logger->log_debug("reconfigureServices for ($serviceList) DRYRUN=$dryRun");
  719. $result = $this->getServices($serviceNames);
  720. if ($result["result"] != 0) {
  721. $this->logger->log_error("Failed to get Service objects.");
  722. return $result;
  723. }
  724. $services = $result["services"];
  725. $svcsToStart = array();
  726. foreach ($services as $svcObj) {
  727. if ($svcObj->state == STATE::STARTED || $svcObj->state == STATE::STARTING) {
  728. array_push($svcsToStart, $svcObj->name);
  729. }
  730. }
  731. // get all dependents recursively for all the services that will be
  732. // reconfigured
  733. $dependents = array();
  734. foreach ($serviceNames as $serviceName) {
  735. $svcDeps = $this->db->getRecursiveServiceDependents($serviceName);
  736. if ($svcDeps === FALSE) {
  737. continue;
  738. }
  739. $dependents = array_merge($dependents, $svcDeps);
  740. }
  741. $dependents = array_unique($dependents);
  742. foreach ($dependents as $serviceName) {
  743. $svc = $this->db->getService($serviceName);
  744. if ($svc !== FALSE) {
  745. array_push($services, $svc);
  746. if ($svc->state == STATE::STARTED || $svc->state == STATE::STARTING) {
  747. array_push($svcsToStart, $serviceName);
  748. }
  749. }
  750. }
  751. $services = $this->getUniqueServices($services);
  752. // HACK!!!!! restart nagios everytime a service is reconfigured as
  753. // nagios runs checks on almost all services
  754. $nagiosComp = $this->db->getNagiosServerComponent();
  755. $restartNagios = FALSE;
  756. if ($nagiosComp !== FALSE) {
  757. if ($nagiosComp->state == STATE::STARTED) {
  758. $restartNagios = TRUE;
  759. }
  760. }
  761. // Stop the services
  762. $this->logger->log_debug("reconfigureServices: Stopping services ($serviceList) dryRun=$dryRun");
  763. foreach ($services as $service) {
  764. $result = $this->stopService($transaction->createSubTransaction(), $service, $dryRun);
  765. if ($result['result'] !== 0) {
  766. $this->logger->log_error("Failed to stop service $service->name with " . $result["error"]);
  767. return $result;
  768. }
  769. }
  770. $this->logger->log_debug("reconfigureServices: Installing services ($serviceList) dryRun=$dryRun");
  771. $result = $this->_installAllServices($services, $transaction->createSubTransaction(), $dryRun);
  772. if ($result['result'] !== 0) {
  773. $this->logger->log_error("Failed to install services with " . $result["error"]);
  774. return $result;
  775. }
  776. $serviceToStartList = implode(",", $svcsToStart);
  777. // Start the services
  778. $this->logger->log_debug("reconfigureServices: Starting services ($serviceToStartList) dryRun=$dryRun");
  779. // Start all services and dependents which were in a started state initially
  780. // that would have been stopped as a result of reconfiguration
  781. foreach ($svcsToStart as $serviceName) {
  782. $service = $this->db->getService($serviceName);
  783. $result = $this->startService($transaction->createSubTransaction(), $service, $dryRun);
  784. if ($result['result'] !== 0) {
  785. $this->logger->log_error("Failed to start service $service->name with " . $result["error"]);
  786. return $result;
  787. }
  788. }
  789. if ($restartNagios) {
  790. $this->logger->log_info("Restarting Nagios Server after reconfiguration");
  791. $result = $this->_restartDashboardAndNagios(
  792. $transaction->getNextSubTransaction(), $dryRun, TRUE);
  793. if ($result["result"] != 0) {
  794. $this->logger->log_error("Failed to restart nagios server, error"
  795. . $result["error"]);
  796. return $result;
  797. }
  798. }
  799. return array("result" => 0, "error" => "");
  800. }
  801. /**
  802. * Run smoke tests on a given services.
  803. * @param transaction transaction
  804. * @param serviceNames service names
  805. */
  806. public function smokeServices($transaction, $serviceNames) {
  807. $serviceList = implode($serviceNames, ",");
  808. $this->logger->log_debug("smokeServices: Smoking services ($serviceList)");
  809. $result = $this->getServices($serviceNames);
  810. if ($result["result"] != 0) {
  811. $this->logger->log_error("Failed to get Service objects.");
  812. return $result;
  813. }
  814. $services = $result["services"];
  815. // Smoke the services
  816. foreach ($services as $service) {
  817. $this->logger->log_debug("About to smoke $service->name");
  818. $result = $service->smoke($transaction->createSubTransaction(), FALSE);
  819. if ($result['result'] != 0) {
  820. $this->logger->log_error("Failed to smoke service $service->name with " . $result["error"]);
  821. return $result;
  822. } else {
  823. $this->logger->log_debug("Succesfully smoked service $service->name");
  824. }
  825. }
  826. $this->resetSubTxnId();
  827. $this->db->reset();
  828. return array("result" => 0, "error" =>"");
  829. }
  830. /**
  831. *
  832. */
  833. private function setState($state, $transaction, $dryRun) {
  834. $txnProgress = getTransactionProgressFromState($state);
  835. // $desc = "CLUSTER"."-".$this->currentAction."-". TransactionProgress::$PROGRESS[$txnProgress];
  836. $desc = getActionDescription("Cluster", $this->currentAction, TransactionProgress::$PROGRESS[$txnProgress]);
  837. if ($dryRun) {
  838. // $desc = "CLUSTER"."-".$this->currentAction."-PENDING";
  839. $desc = getActionDescription("Cluster", $this->currentAction, "PENDING");
  840. }
  841. $result =
  842. $this->db->persistTransaction($transaction, State::$STATE[$state],
  843. $desc, TransactionProgress::$PROGRESS[$txnProgress],
  844. "CLUSTER", $dryRun);
  845. if ($result['result'] !== 0) {
  846. $this->state == State::FAILED;
  847. $this->logger->log_error($this->name." - ".State::$STATE[$state]);
  848. return $result;
  849. }
  850. $this->state = $state;
  851. $this->logger->log_info("$this->name - " . State::$STATE[$state]);
  852. return array("result" => 0, "error" => "");
  853. }
  854. }
  855. ?>