blob: 0219326a820992a9a7215b5a7d3af8d793ac74ca [file] [log] [blame]
/****************************************************************************\
* opts.c - strigger command line option processing functions
*****************************************************************************
* Copyright (C) 2006-2007 The Regents of the University of California.
* Copyright (C) 2008-2010 Lawrence Livermore National Security.
* Copyright (C) SchedMD LLC.
* Written by Morris Jette <jette1@llnl.gov>
* CODE-OCEC-09-009. All rights reserved.
*
* This file is part of Slurm, a resource management program.
* For details, see <https://slurm.schedmd.com/>.
* Please also read the included file: DISCLAIMER.
*
* Slurm is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* In addition, as a special exception, the copyright holders give permission
* to link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two. You must obey the GNU
* General Public License in all respects for all of the code used other than
* OpenSSL. If you modify file(s) with this exception, you may extend this
* exception to your version of the file(s), but you are not obligated to do
* so. If you do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source files in
* the program, then also delete it here.
*
* Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along
* with Slurm; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\*****************************************************************************/
#define _GNU_SOURCE
#include <ctype.h>
#include <getopt.h>
#include <limits.h>
#include <pwd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "src/common/xmalloc.h"
#include "src/common/xstring.h"
#include "src/common/proc_args.h"
#include "src/common/uid.h"
#include "src/strigger/strigger.h"
#define OPT_LONG_HELP 0x100
#define OPT_LONG_USAGE 0x101
#define OPT_LONG_SET 0x102
#define OPT_LONG_GET 0x103
#define OPT_LONG_CLEAR 0x104
#define OPT_LONG_USER 0x105
#define OPT_LONG_FLAGS 0x108
#define OPT_LONG_BURST_BUFFER 0x109
#define OPT_LONG_DRAINING 0x10a
#define OPT_LONG_AUTOCOMP 0x10b
/* getopt_long options, integers but not characters */
/* FUNCTIONS */
static void _help( void );
static void _init_options( void );
static void _print_options( void );
static void _usage( void );
static void _validate_options( void );
struct strigger_parameters params;
/*
* parse_command_line, fill in params data structure with data
*/
extern void parse_command_line(int argc, char **argv)
{
int opt_char;
int option_index;
uid_t some_uid;
long tmp_l;
static struct option long_options[] = {
{"autocomplete", required_argument, 0, OPT_LONG_AUTOCOMP},
{"primary_slurmctld_failure", no_argument, 0, 'a'},
{"primary_slurmctld_resumed_operation", no_argument, 0, 'A'},
{"primary_slurmctld_resumed_control", no_argument, 0, 'b'},
{"backup_slurmctld_failure", no_argument, 0, 'B'},
{"backup_slurmctld_resumed_operation", no_argument, 0, 'c'},
{"backup_slurmctld_assumed_control", no_argument, 0, 'C'},
{"down", no_argument, 0, 'd'},
{"drained", no_argument, 0, 'D'},
{"primary_slurmctld_acct_buffer_full", no_argument, 0, 'e'},
{"fini", no_argument, 0, 'f'},
{"fail", no_argument, 0, 'F'},
{"primary_slurmdbd_failure", no_argument, 0, 'g'},
{"primary_slurmdbd_resumed_operation", no_argument, 0, 'G'},
{"primary_database_failure", no_argument, 0, 'h'},
{"primary_database_resumed_operation", no_argument, 0, 'H'},
{"id", required_argument, 0, 'i'},
{"idle", no_argument, 0, 'I'},
{"jobid", required_argument, 0, 'j'},
{"cluster", required_argument, 0, 'M'},
{"clusters", required_argument, 0, 'M'},
{"node", optional_argument, 0, 'n'},
{"noheader", no_argument, 0, 'N'},
{"offset", required_argument, 0, 'o'},
{"program", required_argument, 0, 'p'},
{"quiet", no_argument, 0, 'Q'},
{"reconfig", no_argument, 0, 'r'},
{"time", no_argument, 0, 't'},
{"up", no_argument, 0, 'u'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"burst_buffer", no_argument, 0, OPT_LONG_BURST_BUFFER},
{"clear", no_argument, 0, OPT_LONG_CLEAR},
{"flags", required_argument, 0, OPT_LONG_FLAGS},
{"get", no_argument, 0, OPT_LONG_GET},
{"help", no_argument, 0, OPT_LONG_HELP},
{"set", no_argument, 0, OPT_LONG_SET},
{"usage", no_argument, 0, OPT_LONG_USAGE},
{"user", required_argument, 0, OPT_LONG_USER},
{"draining", no_argument, 0, OPT_LONG_DRAINING},
{"resume", no_argument, 0, 'R'},
{NULL, 0, 0, 0}
};
_init_options();
optind = 0;
while ((opt_char = getopt_long(argc, argv,
"aAbBcCdDeFfgGhHi:Ij:M:n::No:p:QrRtuvV",
long_options, &option_index)) != -1) {
switch (opt_char) {
case (int)'?':
fprintf(stderr, "Try \"strigger --help\" for "
"more information\n");
exit(1);
break;
case (int)'a':
params.pri_ctld_fail = true;
break;
case (int)'A':
params.pri_ctld_res_op = true;
break;
case (int)'b':
params.pri_ctld_res_ctrl = true;
break;
case (int)'B':
params.bu_ctld_fail = true;
break;
case (int)'c':
params.bu_ctld_res_op = true;
break;
case (int)'C':
params.bu_ctld_as_ctrl = true;
break;
case (int)'d':
params.node_down = true;
break;
case (int)'D':
params.node_drained = true;
break;
case (int)'e':
params.pri_ctld_acct_buffer_full = true;
break;
case (int)'f':
params.job_fini = true;
break;
case (int)'F':
params.node_fail = true;
break;
case (int)'g':
params.pri_dbd_fail = true;
break;
case (int)'G':
params.pri_dbd_res_op = true;
break;
case (int)'h':
params.pri_db_fail = true;
break;
case (int)'H':
params.pri_db_res_op = true;
break;
case (int)'i':
if (!optarg) /* CLANG Fix */
break;
params.trigger_id = atoi(optarg);
break;
case (int)'I':
params.node_idle = true;
break;
case (int)'j':
if (!optarg) /* CLANG Fix */
break;
tmp_l = atol(optarg);
if (tmp_l <= 0) {
error("Invalid jobid %s", optarg);
exit(1);
}
params.job_id = tmp_l;
break;
case (int) 'M':
FREE_NULL_LIST(params.clusters);
if (slurm_get_cluster_info(&(params.clusters),
optarg, 0)) {
print_db_notok(optarg, 0);
fatal("Could not get cluster information");
}
working_cluster_rec = list_peek(params.clusters);
break;
case (int)'n':
xfree(params.node_id);
if (optarg)
params.node_id = xstrdup(optarg);
else
params.node_id = xstrdup("*");
break;
case (int)'N':
params.no_header = true;
break;
case (int)'o':
if (!optarg) /* CLANG Fix */
break;
params.offset = atoi(optarg);
break;
case (int)'p':
xfree(params.program);
params.program = xstrdup(optarg);
break;
case (int)'Q':
params.quiet = true;
break;
case (int)'r':
params.reconfig = true;
break;
case (int)'R':
params.node_resume = true;
break;
case (int)'t':
params.time_limit = true;
break;
case (int)'u':
params.node_up = true;
break;
case (int) 'v':
params.verbose++;
break;
case (int) 'V':
print_slurm_version();
exit(0);
case (int) OPT_LONG_BURST_BUFFER:
params.burst_buffer = true;
break;
case (int) OPT_LONG_HELP:
_help();
exit(0);
case (int) OPT_LONG_USAGE:
_usage();
exit(0);
case (int) OPT_LONG_CLEAR:
params.mode_clear = true;
break;
case (int) OPT_LONG_FLAGS:
if (!optarg) /* CLANG Fix */
break;
if (!xstrncasecmp(optarg, "perm", 4))
params.flags = TRIGGER_FLAG_PERM;
else {
error("Invalid flags %s", optarg);
exit(1);
}
break;
case (int) OPT_LONG_GET:
params.mode_get = true;
break;
case (int) OPT_LONG_SET:
params.mode_set = true;
break;
case (int) OPT_LONG_USER:
if (uid_from_string(optarg, &some_uid) !=
SLURM_SUCCESS) {
error("Invalid user %s", optarg);
exit(1);
}
params.user_id = (uint32_t) some_uid;
break;
case (int) OPT_LONG_DRAINING:
params.node_draining = true;
break;
case OPT_LONG_AUTOCOMP:
suggest_completion(long_options, optarg);
exit(0);
break;
}
}
if (params.verbose)
_print_options();
_validate_options();
}
/* initialize the parameters */
static void _init_options( void )
{
params.mode_set = false;
params.mode_get = false;
params.mode_clear = false;
params.burst_buffer = false;
params.pri_ctld_fail = false;
params.pri_ctld_res_op = false;
params.pri_ctld_res_ctrl = false;
params.pri_ctld_acct_buffer_full = false;
params.bu_ctld_fail = false;
params.bu_ctld_res_op = false;
params.bu_ctld_as_ctrl = false;
params.flags = 0;
params.no_header = false;
params.node_down = false;
params.node_drained = false;
params.node_draining = false;
params.node_fail = false;
params.node_idle = false;
params.trigger_id = 0;
params.job_fini = false;
params.pri_dbd_fail = false;
params.pri_dbd_res_op = false;
params.pri_db_fail = false;
params.pri_db_res_op = false;
params.job_id = 0;
params.node_id = NULL;
params.node_resume = false;
params.offset = 0;
params.program = NULL;
params.quiet = false;
params.reconfig = false;
params.time_limit = false;
params.node_up = false;
params.user_id = NO_VAL;
params.verbose = 0;
}
/* print the parameters specified */
static void _print_options( void )
{
verbose("-----------------------------");
verbose("set = %s", params.mode_set ? "true" : "false");
verbose("get = %s", params.mode_get ? "true" : "false");
verbose("clear = %s", params.mode_clear ? "true" : "false");
verbose("burst_buffer = %s", params.burst_buffer ? "true" : "false");
verbose("flags = %u", params.flags);
verbose("job_id = %u", params.job_id);
verbose("job_fini = %s", params.job_fini ? "true" : "false");
verbose("no_header = %s", params.no_header ? "true" : "false");
verbose("node_down = %s", params.node_down ? "true" : "false");
verbose("node_drained = %s", params.node_drained ? "true" : "false");
verbose("node_draining = %s", params.node_draining ? "true" : "false");
verbose("node_fail = %s", params.node_fail ? "true" : "false");
verbose("node_idle = %s", params.node_idle ? "true" : "false");
verbose("node_up = %s", params.node_up ? "true" : "false");
verbose("node = %s", params.node_id);
verbose("offset = %d secs", params.offset);
verbose("program = %s", params.program);
verbose("quiet = %s", params.quiet ? "true" : "false");
verbose("reconfig = %s", params.reconfig ? "true" : "false");
verbose("resume = %s", params.node_resume ? "true" : "false");
verbose("time_limit = %s", params.time_limit ? "true" : "false");
verbose("trigger_id = %u", params.trigger_id);
if (params.user_id == NO_VAL)
verbose("user_id = N/A");
else
verbose("user_id = %u", params.user_id);
verbose("verbose = %d", params.verbose);
verbose("primary_slurmctld_failure = %s",
params.pri_ctld_fail ? "true" : "false");
verbose("primary_slurmctld_resumed_operation = %s",
params.pri_ctld_res_op ? "true" : "false");
verbose("primary_slurmctld_resumed_control = %s",
params.pri_ctld_res_ctrl ? "true" : "false");
verbose("primary_slurmctld_acct_buffer_full = %s",
params.pri_ctld_acct_buffer_full ? "true" : "false");
verbose("backup_slurmctld_failure = %s",
params.bu_ctld_fail ? "true" : "false");
verbose("backup_slurmctld_resumed_operation = %s",
params.bu_ctld_res_op ? "true" : "false");
verbose("backup_slurmctld_as_ctrl = %s",
params.bu_ctld_as_ctrl ? "true" : "false");
verbose("primary_slurmdbd_failure = %s",
params.pri_dbd_fail ? "true" : "false");
verbose("primary_slurmdbd_resumed_operation = %s",
params.pri_dbd_res_op ? "true" : "false");
verbose("primary_database_failure = %s",
params.pri_db_fail ? "true" : "false");
verbose("primary_database_resumed_operation = %s",
params.pri_db_res_op ? "true" : "false");
verbose("-----------------------------");
}
static void _validate_options( void )
{
if ((params.mode_set + params.mode_get + params.mode_clear) != 1) {
error("You must use exactly one of the following options: "
"--set, --get or --clear");
exit(1);
}
if (params.mode_clear && (params.user_id == NO_VAL) &&
(params.trigger_id == 0) && (params.job_id == 0)) {
error("You must specify a --id, --jobid, or --user to clear");
exit(1);
}
if (params.mode_set &&
((params.node_down + params.node_drained + params.node_fail +
params.node_idle + params.node_up + params.reconfig +
params.job_fini + params.time_limit +
params.node_draining + params.node_resume + params.burst_buffer +
params.pri_ctld_fail + params.pri_ctld_res_op +
params.pri_ctld_res_ctrl + params.pri_ctld_acct_buffer_full +
params.bu_ctld_fail + params.bu_ctld_res_op +
params.bu_ctld_as_ctrl + params.pri_dbd_fail +
params.pri_dbd_res_op + params.pri_db_fail +
params.pri_db_res_op) == 0)) {
error("You must specify a trigger");
exit(1);
}
if (params.mode_set && (params.program == NULL)) {
error("You must specify a --program value");
exit(1);
}
if (((params.job_fini + params.time_limit) != 0)
&& (params.job_id == 0)) {
error("You must specify a --jobid value");
exit(1);
}
if (params.program && (params.program[0] != '/')) {
error("The --program value must start with \"/\"");
exit(1);
}
if (params.program) {
int i;
struct stat buf;
char *program = xstrdup(params.program);
for (i = 0; program[i]; i++) {
if (isspace(program[i])) {
program[i] = '\0';
break;
}
}
if (stat(program, &buf)) {
error("Invalid --program value, file not found");
exit(1);
}
if (!S_ISREG(buf.st_mode)) {
error("Invalid --program value, not regular file");
exit(1);
}
xfree(program);
}
if ((params.offset < -32000) || (params.offset > 32000)) {
error("The --offset parameter must be between +/-32000");
exit(1);
}
}
static void _usage( void )
{
printf("Usage: strigger [--set | --get | --clear | --version] "
"[-aAbBcCdDefFgGhHiIjnNopQrtuv]\n");
}
static void _help( void )
{
printf ("\
Usage: strigger [--set | --get | --clear] [OPTIONS]\n\
--set create a trigger\n\
--get get trigger information\n\
--clear delete a trigger\n\n\
--burst_buffer trigger event on burst buffer error\n\
-a, --primary_slurmctld_failure\n\
trigger event when primary slurmctld fails\n\
-A, --primary_slurmctld_resumed_operation\n\
trigger event on primary slurmctld resumed operation\n\
after failure\n\
-b, --primary_slurmctld_resumed_control\n\
trigger event on primary slurmctld resumed control\n\
-B, --backup_slurmctld_failure\n\
trigger event when backup slurmctld fails\n\
-c, --backup_slurmctld_resumed_operation\n\
trigger event when backup slurmctld resumed operation\n\
after failure\n\
-C, --backup_slurmctld_assumed_control\n\
trigger event when backup slurmctld assumed control\n\
-d, --down trigger event when node goes DOWN\n\
-D, --drained trigger event when node becomes DRAINED\n\
--draining trigger event when node is DRAINING but not already\n\
DRAINED\n\
-e, --primary_slurmctld_acct_buffer_full\n\
trigger event when primary slurmctld acct buffer full\n\
-F, --fail trigger event when node is expected to FAIL\n\
-f, --fini trigger event when job finishes\n\
--flags=perm trigger event flag (perm = permanent)\n\n\
-g, --primary_slurmdbd_failure\n\
trigger when primary slurmdbd fails\n\
-G, --primary_slurmdbd_resumed_operation\n\
trigger when primary slurmdbd resumed operation after\n\
failure\n\
-h, --primary_database_failure\n\
trigger when primary database fails\n\
-H, --primary_database_resumed_operation\n\
trigger when primary database resumed operation after\n\
failure\n\
-i, --id=# a trigger's ID number\n\
-I, --idle trigger event when node remains IDLE\n\
-j, --jobid=# trigger related to specific jobid\n\
-M, --cluster=name cluster to issue commands to. Default is\n\
current cluster. cluster with no name will\n\
reset to default.\n\
NOTE: SlurmDBD must up.\n\
-n, --node[=host] trigger related to specific node, all nodes by default\n\
-N, --noheader Do not print the message header\n\
-o, --offset=# trigger's offset time from event, negative to precede\n\
-p, --program=path pathname of program to execute when triggered\n\
-Q, --quiet quiet mode (suppress informational messages)\n\
-r, --reconfig trigger event on configuration changes\n\
-R, --resume trigger event when node is set to RESUME state\n\
-t, --time trigger event on job's time limit\n\
-u, --up trigger event when node returned to service from DOWN \n\
state\n\
--user a user name or ID to filter triggers by\n\
-v, --verbose print detailed event logging\n\
-V, --version print version information and exit\n\
\nHelp options:\n\
--help show this help message\n\
--usage display brief usage message\n");
}