/src/sacctmgr/sacctmgr.c

https://github.com/cfenoy/slurm · C · 971 lines · 811 code · 60 blank · 100 comment · 229 complexity · 9354f5a906de1fe785217a378dc57a5e MD5 · raw file

  1. /*****************************************************************************\
  2. * sacctmgr.c - administration tool for slurm's accounting.
  3. * provides interface to read, write, update, and configure
  4. * accounting.
  5. *****************************************************************************
  6. * Copyright (C) 2008-2009 Lawrence Livermore National Security.
  7. * Copyright (C) 2002-2007 The Regents of the University of California.
  8. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  9. * Written by Danny Auble <da@llnl.gov>
  10. * CODE-OCEC-09-009. All rights reserved.
  11. *
  12. * This file is part of SLURM, a resource management program.
  13. * For details, see <http://www.schedmd.com/slurmdocs/>.
  14. * Please also read the included file: DISCLAIMER.
  15. *
  16. * SLURM is free software; you can redistribute it and/or modify it under
  17. * the terms of the GNU General Public License as published by the Free
  18. * Software Foundation; either version 2 of the License, or (at your option)
  19. * any later version.
  20. *
  21. * In addition, as a special exception, the copyright holders give permission
  22. * to link the code of portions of this program with the OpenSSL library under
  23. * certain conditions as described in each individual source file, and
  24. * distribute linked combinations including the two. You must obey the GNU
  25. * General Public License in all respects for all of the code used other than
  26. * OpenSSL. If you modify file(s) with this exception, you may extend this
  27. * exception to your version of the file(s), but you are not obligated to do
  28. * so. If you do not wish to do so, delete this exception statement from your
  29. * version. If you delete this exception statement from all source files in
  30. * the program, then also delete it here.
  31. *
  32. * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
  33. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  34. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  35. * details.
  36. *
  37. * You should have received a copy of the GNU General Public License along
  38. * with SLURM; if not, write to the Free Software Foundation, Inc.,
  39. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  40. \*****************************************************************************/
  41. #include "src/sacctmgr/sacctmgr.h"
  42. #include "src/common/xsignal.h"
  43. #include "src/common/proc_args.h"
  44. #define BUFFER_SIZE 4096
  45. char *command_name;
  46. int exit_code; /* sacctmgr's exit code, =1 on any error at any time */
  47. int exit_flag; /* program to terminate if =1 */
  48. int input_words; /* number of words of input permitted */
  49. int one_liner; /* one record per line if =1 */
  50. int quiet_flag; /* quiet=1, verbose=-1, normal=0 */
  51. int readonly_flag; /* make it so you can only run list commands */
  52. int verbosity; /* count of -v options */
  53. int rollback_flag; /* immediate execute=1, else = 0 */
  54. int with_assoc_flag = 0;
  55. void *db_conn = NULL;
  56. uint32_t my_uid = 0;
  57. List g_qos_list = NULL;
  58. bool tree_display = 0;
  59. static void _add_it (int argc, char *argv[]);
  60. static void _archive_it (int argc, char *argv[]);
  61. static void _show_it (int argc, char *argv[]);
  62. static void _modify_it (int argc, char *argv[]);
  63. static void _delete_it (int argc, char *argv[]);
  64. static int _get_command (int *argc, char *argv[]);
  65. static void _print_version( void );
  66. static int _process_command (int argc, char *argv[]);
  67. static void _usage ();
  68. int
  69. main (int argc, char *argv[])
  70. {
  71. int error_code = SLURM_SUCCESS, i, opt_char, input_field_count;
  72. char **input_fields;
  73. log_options_t opts = LOG_OPTS_STDERR_ONLY ;
  74. int local_exit_code = 0;
  75. char *temp = NULL;
  76. int option_index;
  77. static struct option long_options[] = {
  78. {"help", 0, 0, 'h'},
  79. {"usage", 0, 0, 'h'},
  80. {"immediate",0, 0, 'i'},
  81. {"noheader",0, 0, 'n'},
  82. {"oneliner", 0, 0, 'o'},
  83. {"parsable", 0, 0, 'p'},
  84. {"parsable2", 0, 0, 'P'},
  85. {"quiet", 0, 0, 'Q'},
  86. {"readonly", 0, 0, 'r'},
  87. {"associations", 0, 0, 's'},
  88. {"verbose", 0, 0, 'v'},
  89. {"version", 0, 0, 'V'},
  90. {NULL, 0, 0, 0}
  91. };
  92. command_name = argv[0];
  93. rollback_flag = 1;
  94. exit_code = 0;
  95. exit_flag = 0;
  96. input_field_count = 0;
  97. quiet_flag = 0;
  98. readonly_flag = 0;
  99. verbosity = 0;
  100. log_init("sacctmgr", opts, SYSLOG_FACILITY_DAEMON, NULL);
  101. while((opt_char = getopt_long(argc, argv, "hionpPQrsvV",
  102. long_options, &option_index)) != -1) {
  103. switch (opt_char) {
  104. case (int)'?':
  105. fprintf(stderr, "Try \"sacctmgr --help\" "
  106. "for more information\n");
  107. exit(1);
  108. break;
  109. case (int)'h':
  110. _usage ();
  111. exit(exit_code);
  112. break;
  113. case (int)'i':
  114. rollback_flag = 0;
  115. break;
  116. case (int)'o':
  117. one_liner = 1;
  118. break;
  119. case (int)'n':
  120. print_fields_have_header = 0;
  121. break;
  122. case (int)'p':
  123. print_fields_parsable_print =
  124. PRINT_FIELDS_PARSABLE_ENDING;
  125. break;
  126. case (int)'P':
  127. print_fields_parsable_print =
  128. PRINT_FIELDS_PARSABLE_NO_ENDING;
  129. break;
  130. case (int)'Q':
  131. quiet_flag = 1;
  132. break;
  133. case (int)'r':
  134. readonly_flag = 1;
  135. break;
  136. case (int)'s':
  137. with_assoc_flag = 1;
  138. break;
  139. case (int)'v':
  140. quiet_flag = -1;
  141. verbosity++;
  142. break;
  143. case (int)'V':
  144. _print_version();
  145. exit(exit_code);
  146. break;
  147. default:
  148. exit_code = 1;
  149. fprintf(stderr, "getopt error, returned %c\n",
  150. opt_char);
  151. exit(exit_code);
  152. }
  153. }
  154. if (argc > MAX_INPUT_FIELDS) /* bogus input, but continue anyway */
  155. input_words = argc;
  156. else
  157. input_words = 128;
  158. input_fields = (char **) xmalloc (sizeof (char *) * input_words);
  159. if (optind < argc) {
  160. for (i = optind; i < argc; i++) {
  161. input_fields[input_field_count++] = argv[i];
  162. }
  163. }
  164. if (verbosity) {
  165. opts.stderr_level += verbosity;
  166. opts.prefix_level = 1;
  167. log_alter(opts, 0, NULL);
  168. }
  169. /* Check to see if we are running a supported accounting plugin */
  170. temp = slurm_get_accounting_storage_type();
  171. if(strcasecmp(temp, "accounting_storage/slurmdbd")
  172. && strcasecmp(temp, "accounting_storage/mysql")) {
  173. fprintf (stderr, "You are not running a supported "
  174. "accounting_storage plugin\n(%s).\n"
  175. "Only 'accounting_storage/slurmdbd' "
  176. "and 'accounting_storage/mysql' are supported.\n",
  177. temp);
  178. xfree(temp);
  179. exit(1);
  180. }
  181. xfree(temp);
  182. errno = 0;
  183. db_conn = slurmdb_connection_get();
  184. if(errno != SLURM_SUCCESS) {
  185. int tmp_errno = errno;
  186. if((input_field_count == 2) &&
  187. (!strncasecmp(argv[2], "Configuration", strlen(argv[1]))) &&
  188. ((!strncasecmp(argv[1], "list", strlen(argv[0]))) ||
  189. (!strncasecmp(argv[1], "show", strlen(argv[0]))))) {
  190. if(tmp_errno == ESLURM_DB_CONNECTION) {
  191. tmp_errno = 0;
  192. sacctmgr_list_config(true);
  193. } else
  194. sacctmgr_list_config(false);
  195. }
  196. errno = tmp_errno;
  197. if(errno)
  198. error("Problem talking to the database: %m");
  199. exit(1);
  200. }
  201. my_uid = getuid();
  202. if (input_field_count)
  203. exit_flag = 1;
  204. else
  205. error_code = _get_command (&input_field_count, input_fields);
  206. while (error_code == SLURM_SUCCESS) {
  207. error_code = _process_command (input_field_count,
  208. input_fields);
  209. if (error_code || exit_flag)
  210. break;
  211. error_code = _get_command (&input_field_count, input_fields);
  212. /* This is here so if someone made a mistake we allow
  213. * them to fix it and let the process happen since there
  214. * are checks for global exit_code we need to reset it.
  215. */
  216. if(exit_code) {
  217. local_exit_code = exit_code;
  218. exit_code = 0;
  219. }
  220. }
  221. if(local_exit_code)
  222. exit_code = local_exit_code;
  223. acct_storage_g_close_connection(&db_conn);
  224. slurm_acct_storage_fini();
  225. if(g_qos_list)
  226. list_destroy(g_qos_list);
  227. exit(exit_code);
  228. }
  229. #if !HAVE_READLINE
  230. /*
  231. * Alternative to readline if readline is not available
  232. */
  233. static char *_getline(const char *prompt)
  234. {
  235. char buf[4096];
  236. char *line;
  237. int len;
  238. printf("%s", prompt);
  239. /* we only set this here to avoid a warning. We throw it away
  240. later. */
  241. line = fgets(buf, 4096, stdin);
  242. len = strlen(buf);
  243. if ((len > 0) && (buf[len-1] == '\n'))
  244. buf[len-1] = '\0';
  245. else
  246. len++;
  247. line = malloc (len * sizeof(char));
  248. return strncpy(line, buf, len);
  249. }
  250. #endif
  251. /*
  252. * _get_command - get a command from the user
  253. * OUT argc - location to store count of arguments
  254. * OUT argv - location to store the argument list
  255. */
  256. static int
  257. _get_command (int *argc, char **argv)
  258. {
  259. char *in_line;
  260. static char *last_in_line = NULL;
  261. int i, in_line_size;
  262. static int last_in_line_size = 0;
  263. *argc = 0;
  264. #if HAVE_READLINE
  265. in_line = readline ("sacctmgr: ");
  266. #else
  267. in_line = _getline("sacctmgr: ");
  268. #endif
  269. if (in_line == NULL)
  270. return 0;
  271. else if (strncmp (in_line, "#", 1) == 0) {
  272. free (in_line);
  273. return 0;
  274. } else if (strcmp (in_line, "!!") == 0) {
  275. free (in_line);
  276. in_line = last_in_line;
  277. in_line_size = last_in_line_size;
  278. } else {
  279. if (last_in_line)
  280. free (last_in_line);
  281. last_in_line = in_line;
  282. last_in_line_size = in_line_size = strlen (in_line);
  283. }
  284. #if HAVE_READLINE
  285. add_history(in_line);
  286. #endif
  287. /* break in_line into tokens */
  288. for (i = 0; i < in_line_size; i++) {
  289. bool double_quote = false, single_quote = false;
  290. if (in_line[i] == '\0')
  291. break;
  292. if (isspace ((int) in_line[i]))
  293. continue;
  294. if (((*argc) + 1) > MAX_INPUT_FIELDS) { /* bogus input line */
  295. exit_code = 1;
  296. fprintf (stderr,
  297. "%s: can not process over %d words\n",
  298. command_name, input_words);
  299. return E2BIG;
  300. }
  301. argv[(*argc)++] = &in_line[i];
  302. for (i++; i < in_line_size; i++) {
  303. if (in_line[i] == '\042') {
  304. double_quote = !double_quote;
  305. continue;
  306. }
  307. if (in_line[i] == '\047') {
  308. single_quote = !single_quote;
  309. continue;
  310. }
  311. if (in_line[i] == '\0')
  312. break;
  313. if (double_quote || single_quote)
  314. continue;
  315. if (isspace ((int) in_line[i])) {
  316. in_line[i] = '\0';
  317. break;
  318. }
  319. }
  320. }
  321. return 0;
  322. }
  323. static void _print_version(void)
  324. {
  325. print_slurm_version();
  326. if (quiet_flag == -1) {
  327. long version = slurm_api_version();
  328. printf("slurm_api_version: %ld, %ld.%ld.%ld\n", version,
  329. SLURM_VERSION_MAJOR(version),
  330. SLURM_VERSION_MINOR(version),
  331. SLURM_VERSION_MICRO(version));
  332. }
  333. }
  334. /*
  335. * _process_command - process the user's command
  336. * IN argc - count of arguments
  337. * IN argv - the arguments
  338. * RET 0 or errno (only for errors fatal to sacctmgr)
  339. */
  340. static int
  341. _process_command (int argc, char *argv[])
  342. {
  343. int command_len = 0;
  344. if (argc < 1) {
  345. exit_code = 1;
  346. if (quiet_flag == -1)
  347. fprintf(stderr, "no input");
  348. return 0;
  349. }
  350. command_len = strlen(argv[0]);
  351. if (strncasecmp (argv[0], "associations",
  352. MAX(command_len, 3)) == 0) {
  353. with_assoc_flag = 1;
  354. } else if (strncasecmp (argv[0], "dump", MAX(command_len, 3)) == 0) {
  355. sacctmgr_dump_cluster((argc - 1), &argv[1]);
  356. } else if (strncasecmp (argv[0], "help", MAX(command_len, 2)) == 0) {
  357. if (argc > 1) {
  358. exit_code = 1;
  359. fprintf (stderr,
  360. "too many arguments for keyword:%s\n",
  361. argv[0]);
  362. }
  363. _usage ();
  364. } else if (strncasecmp (argv[0], "load", MAX(command_len, 2)) == 0) {
  365. load_sacctmgr_cfg_file((argc - 1), &argv[1]);
  366. } else if (strncasecmp (argv[0], "oneliner",
  367. MAX(command_len, 1)) == 0) {
  368. if (argc > 1) {
  369. exit_code = 1;
  370. fprintf (stderr,
  371. "too many arguments for keyword:%s\n",
  372. argv[0]);
  373. }
  374. one_liner = 1;
  375. } else if (strncasecmp (argv[0], "quiet", MAX(command_len, 4)) == 0) {
  376. if (argc > 1) {
  377. exit_code = 1;
  378. fprintf (stderr, "too many arguments for keyword:%s\n",
  379. argv[0]);
  380. }
  381. quiet_flag = 1;
  382. } else if ((strncasecmp (argv[0], "exit", MAX(command_len, 4)) == 0) ||
  383. (strncasecmp (argv[0], "\\q", MAX(command_len, 2)) == 0) ||
  384. (strncasecmp (argv[0], "quit", MAX(command_len, 4)) == 0)) {
  385. if (argc > 1) {
  386. exit_code = 1;
  387. fprintf (stderr,
  388. "too many arguments for keyword:%s\n",
  389. argv[0]);
  390. }
  391. exit_flag = 1;
  392. } else if ((strncasecmp (argv[0], "add", MAX(command_len, 3)) == 0) ||
  393. (strncasecmp (argv[0], "create",
  394. MAX(command_len, 3)) == 0)) {
  395. _add_it((argc - 1), &argv[1]);
  396. } else if ((strncasecmp (argv[0], "archive",
  397. MAX(command_len, 3)) == 0)) {
  398. _archive_it((argc - 1), &argv[1]);
  399. } else if ((strncasecmp (argv[0], "show", MAX(command_len, 3)) == 0) ||
  400. (strncasecmp (argv[0], "list", MAX(command_len, 3)) == 0)) {
  401. _show_it((argc - 1), &argv[1]);
  402. } else if (!strncasecmp (argv[0], "modify", MAX(command_len, 1))
  403. || !strncasecmp (argv[0], "update", MAX(command_len, 1))) {
  404. _modify_it((argc - 1), &argv[1]);
  405. } else if ((strncasecmp (argv[0], "delete",
  406. MAX(command_len, 3)) == 0) ||
  407. (strncasecmp (argv[0], "remove",
  408. MAX(command_len, 3)) == 0)) {
  409. _delete_it((argc - 1), &argv[1]);
  410. } else if (strncasecmp (argv[0], "verbose", MAX(command_len, 4)) == 0) {
  411. if (argc > 1) {
  412. exit_code = 1;
  413. fprintf (stderr,
  414. "too many arguments for %s keyword\n",
  415. argv[0]);
  416. }
  417. quiet_flag = -1;
  418. } else if (strncasecmp (argv[0], "readonly",
  419. MAX(command_len, 4)) == 0) {
  420. if (argc > 1) {
  421. exit_code = 1;
  422. fprintf (stderr,
  423. "too many arguments for %s keyword\n",
  424. argv[0]);
  425. }
  426. readonly_flag = 1;
  427. } else if (strncasecmp (argv[0], "rollup", MAX(command_len, 2)) == 0) {
  428. time_t my_start = 0;
  429. time_t my_end = 0;
  430. uint16_t archive_data = 0;
  431. if (argc > 4) {
  432. exit_code = 1;
  433. fprintf (stderr,
  434. "too many arguments for %s keyword\n",
  435. argv[0]);
  436. }
  437. if(argc > 1)
  438. my_start = parse_time(argv[1], 1);
  439. if(argc > 2)
  440. my_end = parse_time(argv[2], 1);
  441. if(argc > 3)
  442. archive_data = atoi(argv[3]);
  443. if(acct_storage_g_roll_usage(db_conn, my_start,
  444. my_end, archive_data)
  445. == SLURM_SUCCESS) {
  446. if(commit_check("Would you like to commit rollup?")) {
  447. acct_storage_g_commit(db_conn, 1);
  448. } else {
  449. printf(" Rollup Discarded\n");
  450. acct_storage_g_commit(db_conn, 0);
  451. }
  452. }
  453. } else if (strncasecmp (argv[0], "version", MAX(command_len, 4)) == 0) {
  454. if (argc > 1) {
  455. exit_code = 1;
  456. fprintf (stderr,
  457. "too many arguments for %s keyword\n",
  458. argv[0]);
  459. }
  460. _print_version();
  461. } else {
  462. exit_code = 1;
  463. fprintf (stderr, "invalid keyword: %s\n", argv[0]);
  464. }
  465. return 0;
  466. }
  467. /*
  468. * _add_it - add the entity per the supplied arguments
  469. * IN argc - count of arguments
  470. * IN argv - list of arguments
  471. */
  472. static void _add_it (int argc, char *argv[])
  473. {
  474. int error_code = SLURM_SUCCESS;
  475. int command_len = 0;
  476. if(readonly_flag) {
  477. exit_code = 1;
  478. fprintf(stderr, "Can't run this command in readonly mode.\n");
  479. return;
  480. }
  481. if(!argv[0])
  482. goto helpme;
  483. command_len = strlen(argv[0]);
  484. /* reset the connection to get the most recent stuff */
  485. acct_storage_g_commit(db_conn, 0);
  486. /* First identify the entity to add */
  487. if (strncasecmp (argv[0], "Account", MAX(command_len, 1)) == 0
  488. || !strncasecmp (argv[0], "Acct", MAX(command_len, 4))) {
  489. error_code = sacctmgr_add_account((argc - 1), &argv[1]);
  490. } else if (strncasecmp (argv[0], "Cluster", MAX(command_len, 2)) == 0) {
  491. error_code = sacctmgr_add_cluster((argc - 1), &argv[1]);
  492. } else if (strncasecmp (argv[0], "Coordinator",
  493. MAX(command_len, 2)) == 0) {
  494. error_code = sacctmgr_add_coord((argc - 1), &argv[1]);
  495. } else if (strncasecmp (argv[0], "QOS", MAX(command_len, 1)) == 0) {
  496. error_code = sacctmgr_add_qos((argc - 1), &argv[1]);
  497. } else if (strncasecmp (argv[0], "User", MAX(command_len, 1)) == 0) {
  498. error_code = sacctmgr_add_user((argc - 1), &argv[1]);
  499. } else {
  500. helpme:
  501. exit_code = 1;
  502. fprintf(stderr, "No valid entity in add command\n");
  503. fprintf(stderr, "Input line must include, ");
  504. fprintf(stderr, "\"Account\", \"Cluster\", \"Coordinator\", ");
  505. fprintf(stderr, "\"QOS\", or \"User\"\n");
  506. }
  507. if (error_code == SLURM_ERROR) {
  508. exit_code = 1;
  509. }
  510. }
  511. /*
  512. * _archive_it - archive the entity per the supplied arguments
  513. * IN argc - count of arguments
  514. * IN argv - list of arguments
  515. */
  516. static void _archive_it (int argc, char *argv[])
  517. {
  518. int error_code = SLURM_SUCCESS;
  519. int command_len = 0;
  520. if(readonly_flag) {
  521. exit_code = 1;
  522. fprintf(stderr, "Can't run this command in readonly mode.\n");
  523. return;
  524. }
  525. if(!argv[0])
  526. goto helpme;
  527. command_len = strlen(argv[0]);
  528. /* reset the connection to get the most recent stuff */
  529. acct_storage_g_commit(db_conn, 0);
  530. /* First identify the entity to add */
  531. if (strncasecmp (argv[0], "dump", MAX(command_len, 1)) == 0) {
  532. error_code = sacctmgr_archive_dump((argc - 1), &argv[1]);
  533. } else if (strncasecmp (argv[0], "load", MAX(command_len, 1)) == 0) {
  534. error_code = sacctmgr_archive_load((argc - 1), &argv[1]);
  535. } else {
  536. helpme:
  537. exit_code = 1;
  538. fprintf(stderr, "No valid entity in archive command\n");
  539. fprintf(stderr, "Input line must include, ");
  540. fprintf(stderr, "\"Dump\", or \"load\"\n");
  541. }
  542. if (error_code == SLURM_ERROR) {
  543. exit_code = 1;
  544. }
  545. }
  546. /*
  547. * _show_it - list the slurm configuration per the supplied arguments
  548. * IN argc - count of arguments
  549. * IN argv - list of arguments
  550. * undocumented association options wopi and wopl
  551. * without parent info and without parent limits
  552. */
  553. static void _show_it (int argc, char *argv[])
  554. {
  555. int error_code = SLURM_SUCCESS;
  556. int command_len = 0;
  557. if(!argv[0])
  558. goto helpme;
  559. command_len = strlen(argv[0]);
  560. /* reset the connection to get the most recent stuff */
  561. acct_storage_g_commit(db_conn, 0);
  562. /* First identify the entity to list */
  563. if (strncasecmp (argv[0], "Accounts", MAX(command_len, 2)) == 0
  564. || !strncasecmp (argv[0], "Acct", MAX(command_len, 4))) {
  565. error_code = sacctmgr_list_account((argc - 1), &argv[1]);
  566. } else if (strncasecmp (argv[0], "Associations",
  567. MAX(command_len, 2)) == 0) {
  568. error_code = sacctmgr_list_association((argc - 1), &argv[1]);
  569. } else if (strncasecmp (argv[0], "Clusters",
  570. MAX(command_len, 2)) == 0) {
  571. error_code = sacctmgr_list_cluster((argc - 1), &argv[1]);
  572. } else if (strncasecmp (argv[0], "Configuration",
  573. MAX(command_len, 2)) == 0) {
  574. error_code = sacctmgr_list_config(true);
  575. } else if (strncasecmp (argv[0], "Events",
  576. MAX(command_len, 1)) == 0) {
  577. error_code = sacctmgr_list_event((argc - 1), &argv[1]);
  578. } else if (strncasecmp (argv[0], "Problems",
  579. MAX(command_len, 1)) == 0) {
  580. error_code = sacctmgr_list_problem((argc - 1), &argv[1]);
  581. } else if (strncasecmp (argv[0], "QOS", MAX(command_len, 1)) == 0) {
  582. error_code = sacctmgr_list_qos((argc - 1), &argv[1]);
  583. } else if (!strncasecmp (argv[0], "Transactions", MAX(command_len, 1))
  584. || !strncasecmp (argv[0], "Txn", MAX(command_len, 1))) {
  585. error_code = sacctmgr_list_txn((argc - 1), &argv[1]);
  586. } else if (strncasecmp (argv[0], "Users", MAX(command_len, 1)) == 0) {
  587. error_code = sacctmgr_list_user((argc - 1), &argv[1]);
  588. } else if (strncasecmp (argv[0], "WCKeys", MAX(command_len, 1)) == 0) {
  589. error_code = sacctmgr_list_wckey((argc - 1), &argv[1]);
  590. } else {
  591. helpme:
  592. exit_code = 1;
  593. fprintf(stderr, "No valid entity in list command\n");
  594. fprintf(stderr, "Input line must include ");
  595. fprintf(stderr, "\"Account\", \"Association\", \"Cluster\", "
  596. "\"Configuration\",\n\"Event\", \"Problem\", "
  597. "\"QOS\", \"Transaction\", \"User\", or \"WCKey\"\n");
  598. }
  599. if (error_code == SLURM_ERROR) {
  600. exit_code = 1;
  601. }
  602. }
  603. /*
  604. * _modify_it - modify the slurm configuration per the supplied arguments
  605. * IN argc - count of arguments
  606. * IN argv - list of arguments
  607. */
  608. static void _modify_it (int argc, char *argv[])
  609. {
  610. int error_code = SLURM_SUCCESS;
  611. int command_len = 0;
  612. if(readonly_flag) {
  613. exit_code = 1;
  614. fprintf(stderr, "Can't run this command in readonly mode.\n");
  615. return;
  616. }
  617. if(!argv[0])
  618. goto helpme;
  619. command_len = strlen(argv[0]);
  620. /* reset the connection to get the most recent stuff */
  621. acct_storage_g_commit(db_conn, 0);
  622. /* First identify the entity to modify */
  623. if (strncasecmp (argv[0], "Accounts", MAX(command_len, 1)) == 0
  624. || !strncasecmp (argv[0], "Acct", MAX(command_len, 4))) {
  625. error_code = sacctmgr_modify_account((argc - 1), &argv[1]);
  626. } else if (strncasecmp (argv[0], "Clusters",
  627. MAX(command_len, 1)) == 0) {
  628. error_code = sacctmgr_modify_cluster((argc - 1), &argv[1]);
  629. } else if (strncasecmp (argv[0], "Job", MAX(command_len, 1)) == 0) {
  630. error_code = sacctmgr_modify_job((argc - 1), &argv[1]);
  631. } else if (strncasecmp (argv[0], "QOSs", MAX(command_len, 1)) == 0) {
  632. error_code = sacctmgr_modify_qos((argc - 1), &argv[1]);
  633. } else if (strncasecmp (argv[0], "Users", MAX(command_len, 1)) == 0) {
  634. error_code = sacctmgr_modify_user((argc - 1), &argv[1]);
  635. } else {
  636. helpme:
  637. exit_code = 1;
  638. fprintf(stderr, "No valid entity in modify command\n");
  639. fprintf(stderr, "Input line must include ");
  640. fprintf(stderr, "\"Account\", \"Cluster\", \"Job\", \"QOS\", "
  641. "or \"User\"\n");
  642. }
  643. if (error_code == SLURM_ERROR) {
  644. exit_code = 1;
  645. }
  646. }
  647. /*
  648. * _delete_it - delete the slurm configuration per the supplied arguments
  649. * IN argc - count of arguments
  650. * IN argv - list of arguments
  651. */
  652. static void _delete_it (int argc, char *argv[])
  653. {
  654. int error_code = SLURM_SUCCESS;
  655. int command_len = 0;
  656. if(readonly_flag) {
  657. exit_code = 1;
  658. fprintf(stderr, "Can't run this command in readonly mode.\n");
  659. return;
  660. }
  661. if(!argv[0])
  662. goto helpme;
  663. command_len = strlen(argv[0]);
  664. /* reset the connection to get the most recent stuff */
  665. acct_storage_g_commit(db_conn, 0);
  666. /* First identify the entity to delete */
  667. if (strncasecmp (argv[0], "Accounts", MAX(command_len, 1)) == 0
  668. || !strncasecmp (argv[0], "Acct", MAX(command_len, 4))) {
  669. error_code = sacctmgr_delete_account((argc - 1), &argv[1]);
  670. } else if (strncasecmp (argv[0], "Clusters",
  671. MAX(command_len, 2)) == 0) {
  672. error_code = sacctmgr_delete_cluster((argc - 1), &argv[1]);
  673. } else if (strncasecmp (argv[0], "Coordinators",
  674. MAX(command_len, 2)) == 0) {
  675. error_code = sacctmgr_delete_coord((argc - 1), &argv[1]);
  676. } else if (strncasecmp (argv[0], "QOS", MAX(command_len, 2)) == 0) {
  677. error_code = sacctmgr_delete_qos((argc - 1), &argv[1]);
  678. } else if (strncasecmp (argv[0], "Users", MAX(command_len, 1)) == 0) {
  679. error_code = sacctmgr_delete_user((argc - 1), &argv[1]);
  680. } else {
  681. helpme:
  682. exit_code = 1;
  683. fprintf(stderr, "No valid entity in delete command\n");
  684. fprintf(stderr, "Input line must include ");
  685. fprintf(stderr, "\"Account\", \"Cluster\", \"Coordinator\", ");
  686. fprintf(stderr, "\"QOS\", or \"User\"\n");
  687. }
  688. if (error_code == SLURM_ERROR) {
  689. exit_code = 1;
  690. }
  691. }
  692. /* _usage - show the valid sacctmgr commands */
  693. void _usage () {
  694. printf ("\
  695. sacctmgr [<OPTION>] [<COMMAND>] \n\
  696. Valid <OPTION> values are: \n\
  697. -h or --help: equivalent to \"help\" command \n\
  698. -i or --immediate: commit changes immediately \n\
  699. -n or --noheader: no header will be added to the beginning of output \n\
  700. -o or --oneliner: equivalent to \"oneliner\" command \n\
  701. -p or --parsable: output will be '|' delimited with a '|' at the end \n\
  702. -P or --parsable2: output will be '|' delimited without a '|' at the end\n\
  703. -Q or --quiet: equivalent to \"quiet\" command \n\
  704. -r or --readonly: equivalent to \"readonly\" command \n\
  705. -s or --associations: equivalent to \"associations\" command \n\
  706. -v or --verbose: equivalent to \"verbose\" command \n\
  707. -V or --version: equivalent to \"version\" command \n\
  708. \n\
  709. <keyword> may be omitted from the execute line and sacctmgr will execute \n\
  710. in interactive mode. It will process commands as entered until explicitly\n\
  711. terminated. \n\
  712. \n\
  713. Valid <COMMAND> values are: \n\
  714. add <ENTITY> <SPECS> add entity \n\
  715. archive <DUMP/LOAD> <SPECS> \n\
  716. Archive past jobs and/or steps, or load them \n\
  717. back into the databse. \n\
  718. associations when using show/list will list the \n\
  719. associations associated with the entity. \n\
  720. delete <ENTITY> <SPECS> delete the specified entity(s) \n\
  721. dump <CLUSTER> [File=<FILENAME>] \n\
  722. dump database information of the \n\
  723. specified cluster to the flat file. \n\
  724. Will default to clustername.cfg if no file \n\
  725. is given. \n\
  726. exit terminate sacctmgr \n\
  727. help print this description of use. \n\
  728. list <ENTITY> [<SPECS>] display info of identified entity, default \n\
  729. is display all. \n\
  730. load <FILE> [<SPECS>] read in the file to update the database \n\
  731. with the file contents. <SPECS> here consist \n\
  732. of 'cluster=', and 'clean'. The 'cluster=' \n\
  733. will override the cluster name given in the \n\
  734. file. The 'clean' option will remove what is\n\
  735. already in the system for this cluster and \n\
  736. replace it with the file. If the clean option\n\
  737. is not given only new additions or \n\
  738. modifications will be done, no deletions. \n\
  739. modify <ENTITY> <SPECS> modify entity \n\
  740. oneliner report output one record per line. \n\
  741. parsable output will be | delimited with an ending '|'\n\
  742. parsable2 output will be | delimited without an ending '|'\n\
  743. quiet print no messages other than error messages. \n\
  744. quit terminate this command. \n\
  745. readonly makes it so no modification can happen. \n\
  746. show same as list \n\
  747. verbose enable detailed logging. \n\
  748. version display tool version number. \n\
  749. !! Repeat the last command entered. \n\
  750. \n\
  751. <ENTITY> may be \"account\", \"association\", \"cluster\", \n\
  752. \"configuration\", \"coordinator\", \"event\", \"job\", \n\
  753. \"problem\", \"qos\", \"transaction\", \"user\" or \"wckey\"\n\
  754. \n\
  755. <SPECS> are different for each command entity pair. \n\
  756. list account - Clusters=, Descriptions=, Format=, \n\
  757. Names=, Organizations=, Parents=, WithAssoc, \n\
  758. WithDeleted, WithCoordinators, WithRawQOS, \n\
  759. and WOPLimits \n\
  760. add account - Clusters=, DefaultQOS=, Description=, Fairshare=,\n\
  761. GrpCPUMins=, GrpCPUs=, GrpJobs=, GrpMemory=, \n\
  762. GrpNodes=, GrpSubmitJob=, GrpWall=, MaxCPUMins=,\n\
  763. MaxCPUs=, MaxJobs=, MaxNodes=, MaxSubmitJobs=, \n\
  764. MaxWall=, Names=, Organization=, Parent=, \n\
  765. and QosLevel= \n\
  766. modify account - (set options) DefaultQOS=, Description=, \n\
  767. Fairshare=, GrpCPUMins=, GrpCPURunMins=, \n\
  768. GrpCPUs=, GrpJobs=, GrpMemory=, GrpNodes=, \n\
  769. GrpSubmitJob=, GrpWall=, MaxCPUMins=, \n\
  770. MaxCPURunMins=, MaxCPUs=, \n\
  771. MaxJobs=, MaxNodes=, MaxSubmitJobs=, MaxWall=, \n\
  772. Names=, Organization=, Parent=, and QosLevel= \n\
  773. RawUsage= (with admin privileges only) \n\
  774. (where options) Clusters=, DefaultQOS=, \n\
  775. Descriptions=, Names=, Organizations=, \n\
  776. Parent=, and QosLevel= \n\
  777. delete account - Clusters=, DefaultQOS=, Descriptions=, Names=, \n\
  778. Organizations=, and Parents= \n\
  779. \n\
  780. list associations - Accounts=, Clusters=, Format=, ID=, OnlyDefaults,\n\
  781. Partitions=, Parent=, Tree, Users=, \n\
  782. WithSubAccounts, WithDeleted, WOLimits, \n\
  783. WOPInfo, and WOPLimits \n\
  784. \n\
  785. list cluster - Classification=, DefaultQOS=, Flags=, Format=, \n\
  786. Names=, RPC=, and WOLimits \n\
  787. add cluster - DefaultQOS=, Fairshare=, GrpCPUs=, GrpJobs=, \n\
  788. GrpMemory=, GrpNodes=, GrpSubmitJob=, MaxCPUMins=,\n\
  789. MaxJobs=, MaxNodes=, MaxSubmitJobs=, MaxWall=, \n\
  790. Name=, and QosLevel= \n\
  791. modify cluster - (set options) DefaultQOS=, Fairshare=, GrpCPUs=,\n\
  792. GrpJobs=, GrpMemory=, GrpNodes=, GrpSubmitJob=, \n\
  793. MaxCPUMins=, MaxJobs=, MaxNodes=, MaxSubmitJobs=,\n\
  794. MaxWall=, and QosLevel= \n\
  795. (where options) Classification=, Flags=, \n\
  796. and Names= \n\
  797. delete cluster - Classification=, DefaultQOS=, Flags=, and Names=\n\
  798. \n\
  799. add coordinator - Accounts=, and Names= \n\
  800. delete coordinator - Accounts=, and Names= \n\
  801. \n\
  802. list events - All_Clusters, All_Time, Clusters=, End=, Events=,\n\
  803. Format=, MaxCPUs=, MinCPUs=, Nodes=, Reason=, \n\
  804. Start=, States=, and User= \n\
  805. \n\
  806. modify job - (set options) DerivedExitCode=, Comment= \n\
  807. (where options) JobID=, Cluster= \n\
  808. \n\
  809. list qos - Descriptions=, Format=, Id=, Names=, \n\
  810. PreemptMode=, and WithDeleted \n\
  811. add qos - Description=, Flags=, GraceTime=, GrpCPUMins=, \n\
  812. GGrpCPUs=, GrpJobs=, GrpMemory=, GrpNodes=, \n\
  813. GrpSubmitJob=, GrpWall=, MaxCPUMins=, MaxCPUs=,\n\
  814. MaxCPUsPerUser=, MaxJobs=, MaxNodesPerUser=, \n\
  815. MaxCPUsPerUser=, MaxNodes=, MaxSubmitJobs=, \n\
  816. MaxWall=, Names=, Preempt=, PreemptMode=, \n\
  817. Priority=, UsageFactor=, and UsageThreshold= \n\
  818. modify qos - (set options) Description=, Flags=, GraceTime=,\n\
  819. GrpCPUMins=, GrpCPURunMins=, GrpCPUs=, GrpJobs=,\n\
  820. GrpMemory=, GrpNodes=, GrpSubmitJob=, GrpWall=,\n\
  821. MaxCPUMins=, MaxCPURunMins=, MaxCPUs=, \n\
  822. MaxCPUsPerUser=, MaxJobs=, MaxNodes=, \n\
  823. MaxNodesPerUser=, MaxSubmitJobs=, MaxWall=, \n\
  824. Names=, Preempt=, PreemptMode=, Priority=, \n\
  825. UsageFactor=, and UsageThreshold= \n\
  826. (where options) Descriptions=, ID=, Names= \n\
  827. and PreemptMode= \n\
  828. delete qos - Descriptions=, ID=, Names=, and PreemptMode= \n\
  829. \n\
  830. list transactions - Accounts=, Action=, Actor=, Clusters=, End=, \n\
  831. Format=, ID=, Start=, User=, and WithAssoc \n\
  832. \n\
  833. list user - AdminLevel=, DefaultAccount=, \n\
  834. DefaultWCKey=, Format=, Names=, \n\
  835. QosLevel=, WithAssoc, WithCoordinators, \n\
  836. WithDeleted, WithRawQOS, and WOPLimits \n\
  837. add user - Accounts=, AdminLevel=, Clusters=, \n\
  838. DefaultAccount=, DefaultQOS=, DefaultWCKey=, \n\
  839. Fairshare=, MaxCPUMins=, MaxCPUs=, \n\
  840. MaxJobs=, MaxNodes=, MaxSubmitJobs=, MaxWall=, \n\
  841. Names=, Partitions=, and QosLevel= \n\
  842. modify user - (set options) AdminLevel=, DefaultAccount=, \n\
  843. DefaultQOS=, DefaultWCKey=, Fairshare=, \n\
  844. MaxCPUMins=, MaxCPUs=, MaxJobs=, MaxNodes=, \n\
  845. MaxSubmitJobs=, MaxWall=, and QosLevel=, \n\
  846. RawUsage= (with admin privileges only) \n\
  847. (where options) Accounts=, AdminLevel=, \n\
  848. Clusters=, DefaultAccount=, Names=, \n\
  849. Partitions=, and QosLevel= \n\
  850. delete user - Accounts=, AdminLevel=, Clusters=, \n\
  851. DefaultAccount=, DefaultWCKey=, and Names= \n\
  852. \n\
  853. list wckey - Clusters=, End=, Format=, ID=, Names=, \n\
  854. Start=, User=, and WithDeleted \n\
  855. \n\
  856. archive dump - Directory=, Events, Jobs, \n\
  857. PurgeEventAfter=, PurgeJobAfter=, \n\
  858. PurgeStepAfter=, PurgeSuspendAfter=, \n\
  859. Script=, Steps, and Suspend \n\
  860. \n\
  861. archive load - File=, or Insert= \n\
  862. \n\
  863. Format options are different for listing each entity pair. \n\
  864. \n\
  865. One can get an number of characters by following the field option with \n\
  866. a %%NUMBER option. i.e. format=name%%30 will print 30 chars of field name.\n\
  867. \n\
  868. Account - Account, CoordinatorList, Description, \n\
  869. Organization \n\
  870. \n\
  871. Association - Account, Cluster, DefaultQOS, Fairshare, \n\
  872. GrpCPUMins, GrpCPURunMins, GrpCPUs, GrpJobs, \n\
  873. GrpMemory, GrpNodes, GrpSubmitJob, GrpWall, \n\
  874. ID, LFT, MaxCPUMins, MaxCPURunMins, MaxCPUs, \n\
  875. MaxJobs, MaxNodes, MaxSubmitJobs, MaxWall, QOS,\n\
  876. ParentID, ParentName, Partition, RawQOS, RGT, \n\
  877. User \n\
  878. \n\
  879. Cluster - Classification, Cluster, ClusterNodes, \n\
  880. ControlHost, ControlPort, CpuCount, DefaultQOS,\n\
  881. Fairshare, Flags, GrpCPUMins, GrpCPUs, GrpJobs,\n\
  882. GrpMemory, GrpNodes, GrpSubmitJob, MaxCPUMins, \n\
  883. MaxCPUs, MaxJobs, MaxNodes, MaxSubmitJobs, \n\
  884. MaxWall, NodeCount, PluginIDSelect, RPC \n\
  885. \n\
  886. Event - Cluster, ClusterNodes, CPUs, Duration, End, \n\
  887. Event, EventRaw, NodeName, Reason, Start, \n\
  888. State, StateRaw, User \n\
  889. \n\
  890. QOS - Description, Flags, GraceTime, GrpCPUMins, \n\
  891. GrpCPURunMins, GrpCPUs, GrpJobs, GrpMemory, \n\
  892. GrpNodes, GrpSubmitJob, GrpWall, ID, MaxCPUMins,\n\
  893. MaxCPURunMins, MaxCPUs, MaxCPUsPerUser, \n\
  894. MaxJobs, MaxNodes, MaxNodesPerUser, \n\
  895. MaxSubmitJobs, MaxWall, Name, \n\
  896. Preempt, PreemptMode, Priority, UsageFactor, \n\
  897. UsageThreshold \n\
  898. \n\
  899. Transactions - Action, Actor, Info, TimeStamp, Where \n\
  900. \n\
  901. User - AdminLevel, CoordinatorList, DefaultAccount, \n\
  902. DefaultWCKey, User \n\
  903. \n\
  904. WCKey - Cluster, ID, Name, User \n\
  905. \n\
  906. Account/User WithAssoc option will also honor \n\
  907. all of the options for Association. \n\
  908. \n\
  909. \n\
  910. All commands entitys, and options are case-insensitive. \n\n");
  911. }