prod_monitor.drush.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. <?php
  2. /**
  3. * Implementation of hook_drush_command().
  4. */
  5. function prod_monitor_drush_command() {
  6. $items = array();
  7. $items['prod-monitor'] = array(
  8. 'callback' => 'drush_prod_monitor_statusdetail',
  9. 'description' => 'Display the Production Monitor status page',
  10. 'aliases' => array('pmon'),
  11. 'arguments' => array(
  12. 'id' => "ID of the site to view it's status in detail.",
  13. ),
  14. );
  15. $items['prod-monitor-updates'] = array(
  16. 'callback' => 'drush_prod_monitor_updates',
  17. 'description' => 'Display the update module status page',
  18. 'aliases' => array('pmon-up'),
  19. 'arguments' => array(
  20. 'id' => 'ID of the site to view module updates for.',
  21. ),
  22. 'options' => array(
  23. 'check' => 'Check for module updates.',
  24. 'security-only' => 'Only show modules that have security updates available.',
  25. ),
  26. );
  27. $items['prod-monitor-fetch'] = array(
  28. 'callback' => 'drush_prod_monitor_fetch',
  29. 'description' => 'Fetch the status information from a given remote site.',
  30. 'aliases' => array('pmon-fe'),
  31. 'arguments' => array(
  32. 'id' => 'Space delemited list of site IDs to fetch all data for.',
  33. ),
  34. );
  35. $items['prod-monitor-flush'] = array(
  36. 'callback' => 'drush_prod_monitor_flush',
  37. 'description' => "Remove all fetched data for a given site.",
  38. 'aliases' => array('pmon-fl'),
  39. 'arguments' => array(
  40. 'id' => 'Space delemited list of site IDs to be flushed.',
  41. ),
  42. );
  43. $items['prod-monitor-delete'] = array(
  44. 'callback' => 'drush_prod_monitor_delsite',
  45. 'description' => 'Completemy remove a site and all its data.',
  46. 'aliases' => array('pmon-rm'),
  47. 'arguments' => array(
  48. 'id' => 'Space delemited list of site IDs to be deleted.',
  49. ),
  50. );
  51. return $items;
  52. }
  53. /**
  54. * Fetch data callback.
  55. */
  56. function drush_prod_monitor_fetch() {
  57. $args = func_get_args();
  58. // Fetch ALL.
  59. if (empty($args)) {
  60. if (!drush_confirm(dt('Do you really want to fetch the data for ALL remote sites?'))) {
  61. drush_set_error('prod_monitor', dt('Aborting.'));
  62. return;
  63. }
  64. else {
  65. module_load_include('inc', 'prod_monitor', 'includes/prod_monitor.admin');
  66. // Batch process data fetching.
  67. _prod_monitor_fetch_all_data_batcher_create(TRUE, FALSE, FALSE);
  68. drush_backend_batch_process();
  69. }
  70. }
  71. // Fetch one or more sites as requested.
  72. else {
  73. foreach($args as $arg) {
  74. $site = _prod_monitor_get_site($arg);
  75. if (!empty($site['url'])) {
  76. $result = _prod_monitor_retrieve_data($arg, $site);
  77. $site['url'] = _prod_monitor_sanitize_url(rtrim($site['url'], '/'));
  78. if ($result === FALSE) {
  79. drush_print("\033[1;31m" . dt('Error:') . " \033[0m" . dt('Unable to fetch data for') . ' ' . $site['url'] . '!');
  80. }
  81. else {
  82. _prod_monitor_db_connect_check($arg, $site);
  83. drush_print(dt('Sucessfully fetched data for') . ' ' . $site['url'] . '.');
  84. }
  85. }
  86. else {
  87. drush_print("\033[1;31m" . dt('Error:') . " \033[0m" . dt('No site found with ID') . ' ' . $arg . '!');
  88. }
  89. }
  90. }
  91. }
  92. /**
  93. * Flush data callback.
  94. */
  95. function drush_prod_monitor_flush() {
  96. $args = func_get_args();
  97. foreach ($args as $arg) {
  98. $url = _prod_monitor_get_url($arg);
  99. if (!empty($url)) {
  100. if (!drush_confirm(dt('Do you really want to flush all data for') . ' ' . $url . '?')) {
  101. drush_die('Aborting.');
  102. }
  103. $result = _prod_monitor_flush_data($arg);
  104. if ($result === FALSE) {
  105. drush_print("\033[1;31m" . dt('Error:') . " \033[0m" . dt('Unable to flush data!'));
  106. }
  107. else {
  108. drush_print(dt('Stored data successfully flushed.'));
  109. }
  110. }
  111. else {
  112. drush_print("\033[1;31m" . dt('Error:') . " \033[0m" . dt('No site found with ID') . ' ' . $arg . '!');
  113. }
  114. }
  115. }
  116. /**
  117. * Delete site callback.
  118. */
  119. function drush_prod_monitor_delsite() {
  120. $args = func_get_args();
  121. foreach ($args as $arg) {
  122. $url = _prod_monitor_get_url($arg);
  123. if (!empty($url)) {
  124. if (!drush_confirm(dt("Do you really want to delete") . ' ' . $url . ' ' . dt('and all its data?'))) {
  125. drush_die('Aborting.');
  126. }
  127. $result = _prod_monitor_delete_site($arg);
  128. if ($result === FALSE) {
  129. drush_print("\033[1;31m" . dt('Error:') . " \033[0m" . dt('Unable to delete') . $url . '!');
  130. }
  131. else {
  132. drush_print(dt('Website successfully deleted.'));
  133. }
  134. }
  135. else {
  136. drush_print("\033[1;31m" . dt('Error:') . " \033[0m" . dt('No site found with ID') . ' ' . $arg . '!');
  137. }
  138. }
  139. }
  140. /**
  141. * Status page callback
  142. */
  143. function drush_prod_monitor_statusdetail() {
  144. $args = func_get_args();
  145. if (empty($args)) {
  146. _drush_prod_monitor_overview();
  147. }
  148. elseif (is_numeric($args[0])) {
  149. _drush_prod_monitor_detail($args[0]);
  150. }
  151. }
  152. function _drush_prod_monitor_overview() {
  153. $sites = _prod_monitor_get_sites();
  154. // Map error codes to shell colours.
  155. $severity = array (
  156. 'ok' => '1;32',
  157. 'warning' => '1;33',
  158. 'error' => '1;31',
  159. );
  160. $rows = array(array(
  161. dt('ID'),
  162. dt('URL'),
  163. dt('Data'),
  164. dt('Date added'),
  165. dt('Last update'),
  166. dt('Status'),
  167. ));
  168. // TODO: check why the colour coding messes up the tabs for the table
  169. // Worked around this by placing the status column last
  170. foreach ($sites as $id => $site_info) {
  171. $rows[] = array(
  172. $id,
  173. _prod_monitor_sanitize_url(rtrim($site_info['url'], '/')),
  174. (!$site_info['data']) ? dt('Empty') : t('Stored'),
  175. $site_info['added'],
  176. (!$site_info['lastupdate']) ? dt('Not yet updated') : $site_info['lastupdate'],
  177. "\033[" . $severity[$site_info['status']] . 'm' . ucwords($site_info['status']) . "\033[0m",
  178. );
  179. }
  180. drush_print("\033[1m" . dt('Production Monitor status') . "\033[0m\n", 1);
  181. if (count($rows) > 1) {
  182. drush_print_table($rows, TRUE);
  183. drush_print(dt('Use drush prod-monitor [id] to view the details of a specific site.'));
  184. }
  185. else {
  186. drush_print(dt('No sites added yet! Yo can add sites on admin/reports/prod-monitor.'), 1);
  187. }
  188. }
  189. function _drush_prod_monitor_detail($id) {
  190. $site = _prod_monitor_get_site($id, 'all');
  191. if (!isset($site['url'])) {
  192. drush_print("\033[1;31m" . dt('Error:') . " \033[0m" . dt('No site found with ID') . ' ' . $id . '!');
  193. return;
  194. }
  195. // Overall status block
  196. $block = array();
  197. $modules = _prod_monitor_get_site_modules($id);
  198. if(!empty($modules)) {
  199. $prod_mon = $site['data']['prod_mon'];
  200. $cron = dt('Unknown');
  201. if (isset($prod_mon['prod_check_cron_last'])) {
  202. $cron = format_date($prod_mon['prod_check_cron_last'], 'large');
  203. }
  204. $title = dt('Unknown');
  205. $color = "\033[0m";
  206. if ($modules['updates'] > 0) {
  207. switch ($modules['updates']) {
  208. case 1:
  209. $title = dt('None');
  210. break;
  211. case 2:
  212. $color = "\033[1;33m";
  213. $title = dt('Available');
  214. break;
  215. case 3:
  216. $color = "\033[1;31m";
  217. $title = dt('Security risk!');
  218. break;
  219. }
  220. }
  221. $updates = $color . $title . "\033[0m";
  222. // Construct block
  223. $block[] = array("\033[1m" . dt('Overall status') . "\033[0m");
  224. $block[] = array(
  225. dt('Drupal core version'),
  226. $modules['projects']['drupal']['info']['version'],
  227. );
  228. $block[] = array(
  229. dt('Last cron run'),
  230. $cron,
  231. );
  232. $block[] = array(
  233. dt('Updates'),
  234. $updates,
  235. );
  236. }
  237. // cleanup
  238. unset($site['data']['prod_mon']);
  239. unset($modules);
  240. $functions = $site['settings']['functions'];
  241. $nodata = dt('No data recieved yet.');
  242. $url = rtrim($site['url'], '/');
  243. // Map error codes to shell colours.
  244. $severity = array (
  245. REQUIREMENT_INFO => '1',
  246. REQUIREMENT_OK => '1;32',
  247. REQUIREMENT_WARNING => '1;33',
  248. REQUIREMENT_ERROR => '1;31',
  249. );
  250. $error = 0;
  251. $rows = array();
  252. foreach ($functions as $set => $data) {
  253. if (isset($site['data'][$set])) {
  254. $rows[] = array('');
  255. $rows[] = array("\033[1m" . dt($data['title']) . "\033[0m");
  256. if (!empty($site['data'][$set])) {
  257. foreach ($site['data'][$set] as $check => $result) {
  258. $rows[] = array(
  259. $result['title'],
  260. "\033[" . $severity[$result['severity']] . 'm' . strip_tags($result['value']) . "\033[0m",
  261. );
  262. if ($error < $result['severity']) {
  263. $error = $result['severity'];
  264. }
  265. }
  266. }
  267. else {
  268. $rows[] = array($nodata);
  269. }
  270. }
  271. }
  272. // Actual printing.
  273. drush_print("\033[1m" . dt('Production Monitor status for') . ' ' . _prod_monitor_sanitize_url($url) . "\033[0m", 1);
  274. if (!empty($block)) {
  275. drush_print_table($block);
  276. }
  277. if (!empty($rows)) {
  278. drush_print_table($rows);
  279. }
  280. else {
  281. drush_print($nodata, 1);
  282. }
  283. if ($error > 0) {
  284. // Would be cool if we could prefix the admin path with http://<host>/ so it
  285. // will become a clickable link in some terminals. Any ideas?
  286. drush_print("\033[1m" . dt('Some errors were reported!') . "\033[0m " . dt('Check the full status page on') . " \033[1m" . 'admin/reports/prod-monitor/' . $id . '/view' . "\033[0m " . dt('for details.'));
  287. }
  288. }
  289. /**
  290. * Update status page callback.
  291. */
  292. function drush_prod_monitor_updates() {
  293. $id = func_get_args();
  294. // Fetch ALL.
  295. if (empty($id)) {
  296. if (!drush_confirm(dt('Do you really want to check ALL sites for module updates?'))) {
  297. drush_set_error('prod_monitor', dt('Aborting.'));
  298. return;
  299. }
  300. else {
  301. module_load_include('inc', 'prod_monitor', 'includes/prod_monitor.admin');
  302. // Batch process update checking.
  303. _prod_monitor_fetch_all_data_batcher_create(FALSE, TRUE, FALSE);
  304. drush_backend_batch_process();
  305. }
  306. }
  307. // Fetch the site as requested.
  308. else {
  309. $id = $id['0'];
  310. // Get module info.
  311. $modules = _prod_monitor_get_site_modules($id);
  312. $url = _prod_monitor_get_url($id);
  313. if (empty($modules)) {
  314. if (empty($url)) {
  315. drush_set_error('prod_monitor', dt('No site found with ID') . ' ' . $id . '!');
  316. return;
  317. }
  318. else {
  319. drush_set_error('prod_monitor', dt('No module data found for') . ' ' . $url . '!');
  320. return;
  321. }
  322. }
  323. elseif (empty($modules['available'])) {
  324. drush_set_error('prod_monitor', dt('No update data found for') . ' ' . $url . '!');
  325. // No data, ask for refresh.
  326. _drush_prod_monitor_update_refresh($id, $modules);
  327. }
  328. // Refresh if user asked for it.
  329. if (drush_get_option('check')) {
  330. _drush_prod_monitor_update_refresh($id, $modules);
  331. }
  332. $security_only = drush_get_option('security-only');
  333. $last = $modules['lastupdate'];
  334. module_load_include('inc', 'prod_monitor', 'includes/prod_monitor.update');
  335. $projects = _prod_monitor_calculate_project_data($id, $modules['projects'], $modules['available']);
  336. // Cleanup.
  337. unset($modules);
  338. // Table headers.
  339. $rows[] = array(dt('Name'), dt('Installed version'), dt('Proposed version'), dt('Status'));
  340. // Process releases, notifying user of status and building a list of proposed updates
  341. drush_include_engine('update_info', 'drupal', NULL, DRUSH_BASE_PATH . '/commands/pm/update_info');
  342. drush_include(DRUSH_BASE_PATH . '/commands/pm', 'updatecode.pm');
  343. foreach ($projects as $project) {
  344. // Only show security updates if the user requested it.
  345. if ($security_only && $project['status'] !== UPDATE_NOT_SECURE) {
  346. continue;
  347. }
  348. // Add color to the status.
  349. $color = "\033[0m";
  350. switch ($project['status']) {
  351. case UPDATE_CURRENT:
  352. $color = "\033[1;32m";
  353. break;
  354. case UPDATE_NOT_CURRENT:
  355. $color = "\033[1;33m";
  356. break;
  357. case UPDATE_NOT_SECURE:
  358. $color = "\033[1;31m";
  359. break;
  360. }
  361. // Translate status to readable name and fill 'candidate_version'.
  362. $status = pm_update_filter($project);
  363. // Generate row.
  364. $rows[] = array(
  365. $project['name'],
  366. $project['existing_version'],
  367. $project['candidate_version'],
  368. $color . $status . "\033[0m",
  369. );
  370. }
  371. drush_print("\033[1m" . dt('Module update status for') . ' ' . $url . "\033[0m", 1);
  372. drush_print(dt('Update information last refreshed:') . ' ' . ($last ? format_date($last) : dt('Never')) . "\n", 1);
  373. if (count($rows) > 1) {
  374. drush_print_table($rows, TRUE);
  375. }
  376. else {
  377. drush_print("\033[1m" . dt('No updates to show!') . "\033[0m", 1);
  378. }
  379. }
  380. }
  381. /**
  382. * Helper function to refresh update status data.
  383. */
  384. function _drush_prod_monitor_update_refresh($id, &$modules) {
  385. if (!drush_confirm(dt('Would you like to check for module updates now?'))) {
  386. drush_die('Aborting.');
  387. }
  388. else {
  389. drush_print(dt('Refreshing update status information ...'));
  390. module_load_include('inc', 'prod_monitor', 'includes/prod_monitor.update');
  391. $result = _prod_monitor_update_refresh($id, $modules['projects'], $modules['sitekey']);
  392. if (!empty($result)) {
  393. drush_print();
  394. $modules['available'] = $result;
  395. $modules['lastupdate'] = time();
  396. }
  397. else {
  398. drush_set_error('prod_monitor', dt('Failed to refres update status information for') . ' ' . $url . '!');
  399. drush_die('Aborting.');
  400. }
  401. }
  402. }