feat(xce-test-cli-ux): migrate all flag-accepting commands to flagspec
Migrates 17 commands (cmd_hello, cmd_jobinfo, cmd_jobrun, cmd_jobsub, cmd_resval, cmd_jobkill, cmd_jobckpt, cmd_qctrl, cmd_hostctrl, cmd_runtasks, cmd_setpend, cmd_jobstart, cmd_jobfinish, cmd_jobfail, cmd_resupdate, cmd_walcompare, join_worker_parse_attrs) from raw getopt()/hand-rolled parsing to the shared flagspec_t + getopt_long mechanism, so every one now uniformly rejects an unrecognized or malformed flag with a usage summary and, where a close match exists, a suggestion. cmd_walcompare's hand-rolled parser needed a leading '+' in its optstring to preserve its pre-migration flags-only-before- positionals behavior. Also fixes bug-1704: cmd_qctrl's uninitialized action variable, now sentineled and rejected when unset, mirroring cmd_hostctrl's existing pattern -- this also makes the destructive- command gate's -i/-c detection (task 3.3) safe to rely on. Every existing short flag's letter, value format, and default is unchanged for a valid invocation. 1357/1357 across the full controller suite (+4), 0 regressions. Task 3.1 of .kiro/specs/xce-test-cli-ux/tasks.md. Requirements: 2.1, 2.2, 2.3, 2.4, 6.1, 6.2, 6.3, 6.4, 10.1, 10.2, 10.3 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019jaMf9QEwpugH2W9KAuc7f
This commit is contained in:
parent
878a42fb48
commit
f152c59e75
6 changed files with 883 additions and 92 deletions
|
|
@ -25,6 +25,11 @@
|
|||
#include "controller.capnp.h"
|
||||
#include "ctrlstatus_fmt.h" /* ctrlstatus_format_time_ms (task 6.3) */
|
||||
#include "delay.h"
|
||||
#include "flagspec.h" /* shared flagspec_t descriptor-table flag parsing,
|
||||
* rejection (with typo suggestion), and help
|
||||
* rendering (xce-test-cli-ux tasks 1.1/1.2); every
|
||||
* flag-accepting command below migrates onto this
|
||||
* (task 3.1) */
|
||||
#include "idgen.h"
|
||||
#include "preason.h"
|
||||
#include "walcompare.h" /* cross-member committed-prefix divergence (cmd_walcompare) */
|
||||
|
|
@ -1311,39 +1316,77 @@ int cmd_waldump(int argc, char* argv[])
|
|||
* committed-vs-uncommitted classification for each divergence (task 1.1). Exit
|
||||
* 0 = identical, nonzero = divergence or load error — so it doubles as a
|
||||
* scripted assertion. */
|
||||
/* Both flags are long-only (no short letter ever existed for either --
|
||||
* cmd_walcompare was the one command using a fully hand-rolled long-flag
|
||||
* parser, per xce-test-cli-ux task 3.1's explicit scope). Their synthetic
|
||||
* getopt_long() `val`s are FLAGSPEC_LONG_ONLY_BASE + <index in this table>
|
||||
* (flagspec.h) -- the enum below names those indices so the switch below
|
||||
* doesn't rely on bare magic numbers. */
|
||||
enum { WALCOMPARE_OPT_REPORT = 0, WALCOMPARE_OPT_COMMITTED = 1 };
|
||||
|
||||
static const flagspec_t walcompare_flags[] = {
|
||||
{ 0, "report", "report", no_argument, 0, NULL },
|
||||
{ 0, "committed", "committed", required_argument, 0,
|
||||
"derive the shared boundary from members' CRC-intact tips" },
|
||||
};
|
||||
#define WALCOMPARE_NFLAGS \
|
||||
(sizeof(walcompare_flags) / sizeof(walcompare_flags[0]))
|
||||
|
||||
int cmd_walcompare(int argc, char* argv[])
|
||||
{
|
||||
uint64_t committed = 0; /* 0 = derive the shared boundary */
|
||||
int report = 0; /* --report => full per-member machine table */
|
||||
int ai = 1;
|
||||
uint64_t committed = 0; /* 0 = derive the shared boundary */
|
||||
int report = 0; /* --report => full per-member machine table */
|
||||
int opt;
|
||||
struct option long_opts[WALCOMPARE_NFLAGS + 1];
|
||||
char optstring[8];
|
||||
char posix_optstring[sizeof(optstring) + 1];
|
||||
|
||||
/* Optional flags (any order): --report, --committed N. */
|
||||
for (;;) {
|
||||
if (argc > ai && strcmp(argv[ai], "--report") == 0) {
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
|
||||
if (flagspec_build_opts(walcompare_flags, WALCOMPARE_NFLAGS, long_opts,
|
||||
optstring, sizeof(optstring))
|
||||
< 0) {
|
||||
fprintf(stderr,
|
||||
"xce_test: walcompare: internal error building flag table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Leading '+' (GNU getopt extension): stop at the first non-option
|
||||
* argument instead of permuting argv -- matches the pre-migration
|
||||
* hand-rolled parser's exact behavior (flags recognized only before the
|
||||
* positional member paths; both flags here are long-only, so the built
|
||||
* optstring is empty and this is simply "+"). */
|
||||
posix_optstring[0] = '+';
|
||||
strcpy(posix_optstring + 1, optstring);
|
||||
|
||||
while ((opt = getopt_long(argc, argv, posix_optstring, long_opts, NULL))
|
||||
!= -1) {
|
||||
switch (opt) {
|
||||
case FLAGSPEC_LONG_ONLY_BASE + WALCOMPARE_OPT_REPORT:
|
||||
report = 1;
|
||||
ai += 1;
|
||||
continue;
|
||||
}
|
||||
if (argc > ai && strcmp(argv[ai], "--committed") == 0) {
|
||||
if (argc <= ai + 1) {
|
||||
fprintf(stderr, "walcompare: --committed needs an LSN\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case FLAGSPEC_LONG_ONLY_BASE + WALCOMPARE_OPT_COMMITTED: {
|
||||
char* end = NULL;
|
||||
unsigned long v = strtoul(argv[ai + 1], &end, 10);
|
||||
if (end == argv[ai + 1] || *end != '\0') {
|
||||
unsigned long v = strtoul(optarg, &end, 10);
|
||||
if (end == optarg || *end != '\0') {
|
||||
fprintf(stderr, "walcompare: bad --committed LSN '%s'\n",
|
||||
argv[ai + 1]);
|
||||
optarg);
|
||||
return -1;
|
||||
}
|
||||
committed = (uint64_t)v;
|
||||
ai += 2;
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
case '?':
|
||||
return flagspec_reject(
|
||||
"walcompare", walcompare_flags, WALCOMPARE_NFLAGS,
|
||||
argv[optind - 1],
|
||||
"walcompare [--report] [--committed <N>] <memberA> "
|
||||
"<memberB> [more...]");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
int n = argc - ai;
|
||||
int n = argc - optind;
|
||||
if (n < 2) {
|
||||
fprintf(stderr,
|
||||
"usage: walcompare [--report] [--committed N] <memberA> "
|
||||
|
|
@ -1357,7 +1400,7 @@ int cmd_walcompare(int argc, char* argv[])
|
|||
|
||||
walcompare_member_t members[16];
|
||||
for (int i = 0; i < n; i++) {
|
||||
members[i].path = argv[ai + i];
|
||||
members[i].path = argv[optind + i];
|
||||
members[i].committed_lsn = committed; /* 0 => derive shared boundary */
|
||||
}
|
||||
|
||||
|
|
@ -1661,16 +1704,33 @@ int cmd_quit(int argc, char* argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const flagspec_t hello_flags[] = {
|
||||
{ 'c', "count", "count", required_argument, 0, "1" },
|
||||
{ 'm', "message", "message", required_argument, 0,
|
||||
"\"Greeting from xce client\"" },
|
||||
};
|
||||
#define HELLO_NFLAGS (sizeof(hello_flags) / sizeof(hello_flags[0]))
|
||||
|
||||
int cmd_hello(int argc, char* argv[])
|
||||
{
|
||||
int rc = 0;
|
||||
int opt;
|
||||
char* msg = "Greeting from xce client";
|
||||
int count = 1;
|
||||
int rc = 0;
|
||||
int opt;
|
||||
char* msg = "Greeting from xce client";
|
||||
int count = 1;
|
||||
struct option long_opts[HELLO_NFLAGS + 1];
|
||||
char optstring[32];
|
||||
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "c:m:")) != -1) {
|
||||
if (flagspec_build_opts(hello_flags, HELLO_NFLAGS, long_opts, optstring,
|
||||
sizeof(optstring))
|
||||
< 0) {
|
||||
fprintf(stderr, "xce_test: hello: internal error building flag table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
count = atoi(optarg);
|
||||
|
|
@ -1678,13 +1738,10 @@ int cmd_hello(int argc, char* argv[])
|
|||
case 'm':
|
||||
msg = optarg;
|
||||
break;
|
||||
default:
|
||||
/* -w was never implemented (getopt string above is "c:m:" only)
|
||||
* -- this hint previously advertised a nonexistent -w wait_usec
|
||||
* flag; corrected to match the actual accepted options. */
|
||||
fprintf(stderr, " hello [-c count] [-m message]\n");
|
||||
return -1;
|
||||
break;
|
||||
case '?':
|
||||
return flagspec_reject("hello", hello_flags, HELLO_NFLAGS,
|
||||
argv[optind - 1],
|
||||
"hello [-c <count>] [-m <message>]");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2335,13 +2392,30 @@ static void print_jobinfo(xce_job_t* job)
|
|||
}
|
||||
}
|
||||
|
||||
static const flagspec_t jobinfo_flags[] = {
|
||||
{ 'j', "jobid", "jobid", required_argument, 1, NULL },
|
||||
};
|
||||
#define JOBINFO_NFLAGS (sizeof(jobinfo_flags) / sizeof(jobinfo_flags[0]))
|
||||
|
||||
int cmd_jobinfo(int argc, char* argv[])
|
||||
{
|
||||
int opt;
|
||||
int opt;
|
||||
struct option long_opts[JOBINFO_NFLAGS + 1];
|
||||
char optstring[16];
|
||||
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "j:")) != -1) {
|
||||
if (flagspec_build_opts(jobinfo_flags, JOBINFO_NFLAGS, long_opts,
|
||||
optstring, sizeof(optstring))
|
||||
< 0) {
|
||||
fprintf(stderr,
|
||||
"xce_test: jobinfo: internal error building flag table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL))
|
||||
!= -1) {
|
||||
uint64_t jobid;
|
||||
xce_job_t* job;
|
||||
int rc = 0;
|
||||
|
|
@ -2362,6 +2436,10 @@ int cmd_jobinfo(int argc, char* argv[])
|
|||
}
|
||||
|
||||
break;
|
||||
case '?':
|
||||
return flagspec_reject("jobinfo", jobinfo_flags, JOBINFO_NFLAGS,
|
||||
argv[optind - 1],
|
||||
"jobinfo -j <jobid> [-j <jobid> ...]");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -2409,6 +2487,12 @@ static int fill_job_alloc(xce_job_alloc_t* jalloc, int nhosts,
|
|||
|
||||
return 0;
|
||||
}
|
||||
static const flagspec_t jobrun_flags[] = {
|
||||
{ 'm', "host", "host", required_argument, 0, "1 task; repeatable up to 5" },
|
||||
{ 'j', "jobid", "jobid", required_argument, 1, NULL },
|
||||
};
|
||||
#define JOBRUN_NFLAGS (sizeof(jobrun_flags) / sizeof(jobrun_flags[0]))
|
||||
|
||||
int cmd_jobrun(int argc, char* argv[])
|
||||
{
|
||||
int rc;
|
||||
|
|
@ -2418,13 +2502,25 @@ int cmd_jobrun(int argc, char* argv[])
|
|||
xce_job_alloc_t jalloc;
|
||||
xce_job_dispatch_t jdispatch
|
||||
= { .njobs = 1, .allocs = (xce_job_alloc_t*[]) { &jalloc } };
|
||||
int nhosts = 0;
|
||||
char* host;
|
||||
int count;
|
||||
int nhosts = 0;
|
||||
char* host;
|
||||
int count;
|
||||
struct option long_opts[JOBRUN_NFLAGS + 1];
|
||||
char optstring[16];
|
||||
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "m:j:")) != -1) {
|
||||
if (flagspec_build_opts(jobrun_flags, JOBRUN_NFLAGS, long_opts, optstring,
|
||||
sizeof(optstring))
|
||||
< 0) {
|
||||
fprintf(stderr,
|
||||
"xce_test: jobrun: internal error building flag table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL))
|
||||
!= -1) {
|
||||
switch (opt) {
|
||||
case 'm':
|
||||
if (nhosts >= MAX_TASK_HOSTS) {
|
||||
|
|
@ -2460,6 +2556,10 @@ int cmd_jobrun(int argc, char* argv[])
|
|||
return -1;
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
return flagspec_reject(
|
||||
"jobrun", jobrun_flags, JOBRUN_NFLAGS, argv[optind - 1],
|
||||
"jobrun -j <jobid> [-m <host>[:<ntasks>]] [-m ...]");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2510,6 +2610,18 @@ static int build_job_exdata(xce_job_submit_t* submit)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const flagspec_t jobsub_flags[] = {
|
||||
{ 'u', "user", "user", required_argument, 1, NULL },
|
||||
{ 'q', "queue", "queue", required_argument, 1, NULL },
|
||||
{ 'R', "resreq", "resreq", required_argument, 0,
|
||||
"\"type == any\"" },
|
||||
{ 'c', "command-line", "command-line", required_argument, 1, NULL },
|
||||
{ 'n', "ntasks", "ntasks", required_argument, 0, "1" },
|
||||
{ 'x', "exdata", "exdata", required_argument, 0, NULL },
|
||||
{ 'a', "array-size", "arraysize", required_argument, 0, "1" },
|
||||
};
|
||||
#define JOBSUB_NFLAGS (sizeof(jobsub_flags) / sizeof(jobsub_flags[0]))
|
||||
|
||||
int cmd_jobsub(int argc, char* argv[])
|
||||
{
|
||||
int rc = 0;
|
||||
|
|
@ -2524,8 +2636,11 @@ int cmd_jobsub(int argc, char* argv[])
|
|||
uint32_t min = 1, max = 1;
|
||||
uint32_t arsize = 1;
|
||||
char jobidStr[128];
|
||||
struct option long_opts[JOBSUB_NFLAGS + 1];
|
||||
char optstring[32];
|
||||
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
|
||||
memset(&submit, 0x0, sizeof(submit));
|
||||
submit.start_info
|
||||
|
|
@ -2535,7 +2650,16 @@ int cmd_jobsub(int argc, char* argv[])
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
while ((opt = getopt(argc, argv, "u:q:R:c:x:n:a:")) != -1) {
|
||||
if (flagspec_build_opts(jobsub_flags, JOBSUB_NFLAGS, long_opts, optstring,
|
||||
sizeof(optstring))
|
||||
< 0) {
|
||||
fprintf(stderr,
|
||||
"xce_test: jobsub: internal error building flag table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL))
|
||||
!= -1) {
|
||||
switch (opt) {
|
||||
case 'u':
|
||||
submit.user = strdup(optarg);
|
||||
|
|
@ -2578,10 +2702,11 @@ int cmd_jobsub(int argc, char* argv[])
|
|||
arsize = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf(
|
||||
"jobsub -u <user> -q <queue> -R <resreq> -c <command line>\n");
|
||||
rc = -EINVAL;
|
||||
case '?':
|
||||
rc = flagspec_reject(
|
||||
"jobsub", jobsub_flags, JOBSUB_NFLAGS, argv[optind - 1],
|
||||
"jobsub -u <user> -q <queue> -c <cmdline> [-R <resreq>] "
|
||||
"[-n <min>[,<max>]] [-x <exdata>] [-a <arraysize>]");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
|
@ -2790,6 +2915,13 @@ static void format_bytes_human(double bytes, char* buf, size_t bufsize)
|
|||
snprintf(buf, bufsize, "%.2f %s", val, UNITS[i]);
|
||||
}
|
||||
|
||||
static const flagspec_t resval_flags[] = {
|
||||
{ 'n', "resname", "resname", required_argument, 1, NULL },
|
||||
{ 'm', "host", "host", required_argument, 0,
|
||||
"required unless the resource is cluster-wide" },
|
||||
};
|
||||
#define RESVAL_NFLAGS (sizeof(resval_flags) / sizeof(resval_flags[0]))
|
||||
|
||||
int cmd_resval(int argc, char* argv[])
|
||||
{
|
||||
char* host = NULL;
|
||||
|
|
@ -2797,10 +2929,22 @@ int cmd_resval(int argc, char* argv[])
|
|||
xce_resval_t** vals = NULL;
|
||||
int opt;
|
||||
int rc;
|
||||
struct option long_opts[RESVAL_NFLAGS + 1];
|
||||
char optstring[16];
|
||||
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "n:m:")) != -1) {
|
||||
if (flagspec_build_opts(resval_flags, RESVAL_NFLAGS, long_opts, optstring,
|
||||
sizeof(optstring))
|
||||
< 0) {
|
||||
fprintf(stderr,
|
||||
"xce_test: resval: internal error building flag table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL))
|
||||
!= -1) {
|
||||
switch (opt) {
|
||||
case 'n':
|
||||
res = strdup(optarg);
|
||||
|
|
@ -2808,11 +2952,13 @@ int cmd_resval(int argc, char* argv[])
|
|||
case 'm':
|
||||
host = strdup(optarg);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "resval -n resname [-m host]\n");
|
||||
case '?':
|
||||
rc = flagspec_reject("resval", resval_flags, RESVAL_NFLAGS,
|
||||
argv[optind - 1],
|
||||
"resval -n <resname> [-m <host>]");
|
||||
FREEUP(host);
|
||||
FREEUP(res);
|
||||
return -1;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2863,6 +3009,12 @@ int cmd_resval(int argc, char* argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const flagspec_t jobkill_flags[] = {
|
||||
{ 's', "signal", "signal", required_argument, 0, "SIGTERM" },
|
||||
{ 'j', "jobid", "jobid", required_argument, 1, NULL },
|
||||
};
|
||||
#define JOBKILL_NFLAGS (sizeof(jobkill_flags) / sizeof(jobkill_flags[0]))
|
||||
|
||||
int cmd_jobkill(int argc, char* argv[])
|
||||
{
|
||||
int signo;
|
||||
|
|
@ -2872,11 +3024,23 @@ int cmd_jobkill(int argc, char* argv[])
|
|||
xce_jobctrl_t jobctrl;
|
||||
xce_signal_t siginfo;
|
||||
char jobidStr[64];
|
||||
struct option long_opts[JOBKILL_NFLAGS + 1];
|
||||
char optstring[16];
|
||||
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
signo = SIGTERM;
|
||||
|
||||
while ((opt = getopt(argc, argv, "s:j:")) != -1) {
|
||||
if (flagspec_build_opts(jobkill_flags, JOBKILL_NFLAGS, long_opts,
|
||||
optstring, sizeof(optstring))
|
||||
< 0) {
|
||||
fprintf(stderr,
|
||||
"xce_test: jobkill: internal error building flag table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL))
|
||||
!= -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
signo = atoi(optarg);
|
||||
|
|
@ -2884,8 +3048,10 @@ int cmd_jobkill(int argc, char* argv[])
|
|||
case 'j':
|
||||
parse_jobid(&jobid, optarg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case '?':
|
||||
return flagspec_reject("jobkill", jobkill_flags, JOBKILL_NFLAGS,
|
||||
argv[optind - 1],
|
||||
"jobkill -j <jobid> [-s <signo>]");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2912,6 +3078,16 @@ int cmd_jobkill(int argc, char* argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const flagspec_t jobckpt_flags[] = {
|
||||
{ 'k', "kill", "kill", no_argument, 0,
|
||||
NULL },
|
||||
{ 'j', "jobid", "jobid", required_argument, 1,
|
||||
NULL },
|
||||
{ 'm', "checkpoint-method", "checkpoint-method", required_argument, 0,
|
||||
"\"default\"" },
|
||||
};
|
||||
#define JOBCKPT_NFLAGS (sizeof(jobckpt_flags) / sizeof(jobckpt_flags[0]))
|
||||
|
||||
int cmd_jobckpt(int argc, char* argv[])
|
||||
{
|
||||
uint64_t jobid = 0;
|
||||
|
|
@ -2920,11 +3096,23 @@ int cmd_jobckpt(int argc, char* argv[])
|
|||
xce_jobctrl_t jobctrl;
|
||||
xce_ckpt_options_t ckptoption;
|
||||
char jobidStr[64];
|
||||
struct option long_opts[JOBCKPT_NFLAGS + 1];
|
||||
char optstring[16];
|
||||
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
ckptoption.kill = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "kj:m:")) != -1) {
|
||||
if (flagspec_build_opts(jobckpt_flags, JOBCKPT_NFLAGS, long_opts,
|
||||
optstring, sizeof(optstring))
|
||||
< 0) {
|
||||
fprintf(stderr,
|
||||
"xce_test: jobckpt: internal error building flag table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL))
|
||||
!= -1) {
|
||||
switch (opt) {
|
||||
case 'k':
|
||||
ckptoption.kill = 1;
|
||||
|
|
@ -2935,8 +3123,10 @@ int cmd_jobckpt(int argc, char* argv[])
|
|||
case 'm':
|
||||
ckptoption.method = optarg;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case '?':
|
||||
return flagspec_reject("jobckpt", jobckpt_flags, JOBCKPT_NFLAGS,
|
||||
argv[optind - 1],
|
||||
"jobckpt -j <jobid> [-k] [-m <method>]");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2964,17 +3154,44 @@ int cmd_jobckpt(int argc, char* argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const flagspec_t qctrl_flags[] = {
|
||||
{ 'a', "activate", "activate", no_argument, 0, NULL },
|
||||
{ 'i', "deactivate", "deactivate", no_argument, 0, NULL },
|
||||
{ 'o', "open", "open", no_argument, 0, NULL },
|
||||
{ 'c', "close", "close", no_argument, 0, NULL },
|
||||
{ 'q', "queue", "queue", required_argument, 1, NULL },
|
||||
};
|
||||
#define QCTRL_NFLAGS (sizeof(qctrl_flags) / sizeof(qctrl_flags[0]))
|
||||
|
||||
int cmd_qctrl(int argc, char* argv[])
|
||||
{
|
||||
int opt;
|
||||
int rc;
|
||||
xce_queuectrl_t queuectrl;
|
||||
int action;
|
||||
/* bug-1704 fix: initialize to the QUEUE_DO_NONE sentinel (xce/types.h)
|
||||
* and reject post-loop if it is still unset -- mirrors cmd_hostctrl's
|
||||
* existing HOST_DO_NONE sentinel-and-reject pattern immediately below.
|
||||
* Before this fix, `action` had no initializer and no post-loop check,
|
||||
* so an invocation giving -q but none of -a/-i/-o/-c transmitted
|
||||
* indeterminate stack memory as the queue action. */
|
||||
int action = QUEUE_DO_NONE;
|
||||
char* queue = NULL;
|
||||
struct option long_opts[QCTRL_NFLAGS + 1];
|
||||
char optstring[16];
|
||||
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "aiociq:")) != -1) {
|
||||
if (flagspec_build_opts(qctrl_flags, QCTRL_NFLAGS, long_opts, optstring,
|
||||
sizeof(optstring))
|
||||
< 0) {
|
||||
fprintf(stderr,
|
||||
"xce_test: qctrl: internal error building flag table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL))
|
||||
!= -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
action = QUEUE_ACTIVE;
|
||||
|
|
@ -2991,8 +3208,11 @@ int cmd_qctrl(int argc, char* argv[])
|
|||
case 'q':
|
||||
queue = strdup(optarg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case '?':
|
||||
FREEUP(queue);
|
||||
return flagspec_reject("qctrl", qctrl_flags, QCTRL_NFLAGS,
|
||||
argv[optind - 1],
|
||||
"qctrl -q <queue> [-a] [-i] [-o] [-c]");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3001,6 +3221,16 @@ int cmd_qctrl(int argc, char* argv[])
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* bug-1704 fix (continued): reject rather than send an indeterminate
|
||||
* action when none of -a/-i/-o/-c (nor their long forms) was given. */
|
||||
if (action == QUEUE_DO_NONE) {
|
||||
fprintf(stderr,
|
||||
"you need to specify one of -a/--activate, -i/--deactivate, "
|
||||
"-o/--open, or -c/--close\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
queuectrl.action = action;
|
||||
queuectrl.queue = queue;
|
||||
|
||||
|
|
@ -3024,17 +3254,36 @@ int cmd_qctrl(int argc, char* argv[])
|
|||
* but are rejected -EINVAL server-side today, so no flag is offered for them
|
||||
* here). Used by the config-upgrade chaotic soak (task 8.6) to set a host's
|
||||
* admin status before/around a config upgrade and assert it survives. */
|
||||
static const flagspec_t hostctrl_flags[] = {
|
||||
{ 'o', "open", "open", no_argument, 0, NULL },
|
||||
{ 'c', "close", "close", no_argument, 0, NULL },
|
||||
{ 'h', "host", "host", required_argument, 1, NULL },
|
||||
};
|
||||
#define HOSTCTRL_NFLAGS (sizeof(hostctrl_flags) / sizeof(hostctrl_flags[0]))
|
||||
|
||||
int cmd_hostctrl(int argc, char* argv[])
|
||||
{
|
||||
int opt;
|
||||
int rc;
|
||||
xce_hostctrl_t hostctrl;
|
||||
int action = HOST_DO_NONE;
|
||||
int action = HOST_DO_NONE;
|
||||
char* hostname = NULL;
|
||||
struct option long_opts[HOSTCTRL_NFLAGS + 1];
|
||||
char optstring[16];
|
||||
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "och:")) != -1) {
|
||||
if (flagspec_build_opts(hostctrl_flags, HOSTCTRL_NFLAGS, long_opts,
|
||||
optstring, sizeof(optstring))
|
||||
< 0) {
|
||||
fprintf(stderr,
|
||||
"xce_test: hostctrl: internal error building flag table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL))
|
||||
!= -1) {
|
||||
switch (opt) {
|
||||
case 'o':
|
||||
action = HOST_OPEN;
|
||||
|
|
@ -3045,8 +3294,11 @@ int cmd_hostctrl(int argc, char* argv[])
|
|||
case 'h':
|
||||
hostname = strdup(optarg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case '?':
|
||||
FREEUP(hostname);
|
||||
return flagspec_reject("hostctrl", hostctrl_flags,
|
||||
HOSTCTRL_NFLAGS, argv[optind - 1],
|
||||
"hostctrl -h <hostname> (-o|-c)");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3150,6 +3402,19 @@ int cmd_upgradeconfig(int argc, char* argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const flagspec_t runtasks_flags[] = {
|
||||
{ 'm', "host", "host", required_argument, 0,
|
||||
"1 task; repeatable up to 5" },
|
||||
{ 'u', "user", "user", required_argument, 0, NULL },
|
||||
{ 'c', "command-line", "command-line", required_argument, 0, NULL },
|
||||
{ 'x', "exdata", "exdata", required_argument, 0, NULL },
|
||||
{ 'd', "dir", "dir", required_argument, 0, NULL },
|
||||
{ 'j', "jobid", "jobid", required_argument, 0, NULL },
|
||||
{ 't', "launch-type", "launch-type", required_argument, 0,
|
||||
"\"mpi\" if >1 total tasks, else \"sequential\"" },
|
||||
};
|
||||
#define RUNTASKS_NFLAGS (sizeof(runtasks_flags) / sizeof(runtasks_flags[0]))
|
||||
|
||||
int cmd_runtasks(int argc, char* argv[])
|
||||
{
|
||||
xce_taskhost_t hosts[MAX_TASK_HOSTS];
|
||||
|
|
@ -3167,10 +3432,22 @@ int cmd_runtasks(int argc, char* argv[])
|
|||
char* launch_type = NULL;
|
||||
int i;
|
||||
uint64_t jobid = 0;
|
||||
struct option long_opts[RUNTASKS_NFLAGS + 1];
|
||||
char optstring[32];
|
||||
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "m:u:c:x:d:j:t:")) != -1) {
|
||||
if (flagspec_build_opts(runtasks_flags, RUNTASKS_NFLAGS, long_opts,
|
||||
optstring, sizeof(optstring))
|
||||
< 0) {
|
||||
fprintf(stderr,
|
||||
"xce_test: taskrun: internal error building flag table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL))
|
||||
!= -1) {
|
||||
switch (opt) {
|
||||
case 'm':
|
||||
if (nhosts >= MAX_TASK_HOSTS) {
|
||||
|
|
@ -3229,8 +3506,12 @@ int cmd_runtasks(int argc, char* argv[])
|
|||
case 't':
|
||||
launch_type = strdup(optarg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case '?':
|
||||
return flagspec_reject(
|
||||
"taskrun", runtasks_flags, RUNTASKS_NFLAGS,
|
||||
argv[optind - 1],
|
||||
"taskrun [-j <jobid>] [-m <host>[:<n>]]... [-u <user>] "
|
||||
"[-c <cmdline>] [-x <exdata>] [-d <dir>] [-t <launch_type>]");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3311,6 +3592,12 @@ static int add_pendreason(xce_job_preason_t* preason, char* s)
|
|||
return add_job_preason(preason, code, phost, pres);
|
||||
}
|
||||
|
||||
static const flagspec_t setpend_flags[] = {
|
||||
{ 'j', "jobid", "jobid", required_argument, 1, NULL },
|
||||
{ 'p', "reason", "reason", required_argument, 1, NULL },
|
||||
};
|
||||
#define SETPEND_NFLAGS (sizeof(setpend_flags) / sizeof(setpend_flags[0]))
|
||||
|
||||
int cmd_setpend(int argc, char* argv[])
|
||||
{
|
||||
int opt;
|
||||
|
|
@ -3318,11 +3605,23 @@ int cmd_setpend(int argc, char* argv[])
|
|||
xce_pendreason_t preason = { .reasons = &jreasons };
|
||||
xce_preason_set_t reasons
|
||||
= { .nreasons = 1, .reasons = (xce_pendreason_t*[]) { &preason } };
|
||||
int rc = 0;
|
||||
int rc = 0;
|
||||
struct option long_opts[SETPEND_NFLAGS + 1];
|
||||
char optstring[16];
|
||||
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "j:p:")) != -1) {
|
||||
if (flagspec_build_opts(setpend_flags, SETPEND_NFLAGS, long_opts,
|
||||
optstring, sizeof(optstring))
|
||||
< 0) {
|
||||
fprintf(stderr,
|
||||
"xce_test: setpend: internal error building flag table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL))
|
||||
!= -1) {
|
||||
int rc = 0;
|
||||
switch (opt) {
|
||||
case 'j':
|
||||
|
|
@ -3335,6 +3634,10 @@ int cmd_setpend(int argc, char* argv[])
|
|||
return rc;
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
return flagspec_reject(
|
||||
"setpend", setpend_flags, SETPEND_NFLAGS, argv[optind - 1],
|
||||
"setpend -j <jobid> -p <reason> [-p <reason> ...]");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3405,6 +3708,13 @@ int cmd_join_worker(int argc, char* argv[])
|
|||
* apply_committed_entry()) that a real worker's report would, without
|
||||
* requiring a real scheduler dispatch (on_job_start only requires the job to
|
||||
* already exist in jobmgr, i.e. have been submitted). */
|
||||
static const flagspec_t jobstart_flags[] = {
|
||||
{ 'j', "jobid", "jobid", required_argument, 1, NULL },
|
||||
{ 'p', "pid", "pid", required_argument, 0,
|
||||
"this xce_test process's own pid" },
|
||||
};
|
||||
#define JOBSTART_NFLAGS (sizeof(jobstart_flags) / sizeof(jobstart_flags[0]))
|
||||
|
||||
int cmd_jobstart(int argc, char* argv[])
|
||||
{
|
||||
int rc;
|
||||
|
|
@ -3413,11 +3723,23 @@ int cmd_jobstart(int argc, char* argv[])
|
|||
unsigned int pid = 0;
|
||||
unsigned int pids[1];
|
||||
job_pidinfo_t info;
|
||||
struct option long_opts[JOBSTART_NFLAGS + 1];
|
||||
char optstring[16];
|
||||
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
memset(&info, 0x0, sizeof(info));
|
||||
|
||||
while ((opt = getopt(argc, argv, "j:p:")) != -1) {
|
||||
if (flagspec_build_opts(jobstart_flags, JOBSTART_NFLAGS, long_opts,
|
||||
optstring, sizeof(optstring))
|
||||
< 0) {
|
||||
fprintf(stderr,
|
||||
"xce_test: jstart: internal error building flag table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL))
|
||||
!= -1) {
|
||||
switch (opt) {
|
||||
case 'j':
|
||||
parse_jobid(&jobid, optarg);
|
||||
|
|
@ -3425,9 +3747,10 @@ int cmd_jobstart(int argc, char* argv[])
|
|||
case 'p':
|
||||
pid = (unsigned int)atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
printf(" jstart -j jobid [-p pid]\n");
|
||||
return -EINVAL;
|
||||
case '?':
|
||||
return flagspec_reject("jstart", jobstart_flags, JOBSTART_NFLAGS,
|
||||
argv[optind - 1],
|
||||
"jstart -j <jobid> [-p <pid>]");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3456,6 +3779,12 @@ int cmd_jobstart(int argc, char* argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const flagspec_t jobfinish_flags[] = {
|
||||
{ 'j', "jobid", "jobid", required_argument, 1, NULL },
|
||||
{ 'c', "exit-code", "exit-code", required_argument, 0, "0" },
|
||||
};
|
||||
#define JOBFINISH_NFLAGS (sizeof(jobfinish_flags) / sizeof(jobfinish_flags[0]))
|
||||
|
||||
int cmd_jobfinish(int argc, char* argv[])
|
||||
{
|
||||
int rc;
|
||||
|
|
@ -3463,6 +3792,8 @@ int cmd_jobfinish(int argc, char* argv[])
|
|||
uint64_t jobid = 0;
|
||||
int code = 0;
|
||||
xce_jobfinish_t finish;
|
||||
struct option long_opts[JOBFINISH_NFLAGS + 1];
|
||||
char optstring[16];
|
||||
|
||||
/* raft-apply-decoupling task 7.2: reset optind so repeated jfinish
|
||||
* invocations within one xce_test process (the fact-stream soak scenario
|
||||
|
|
@ -3474,8 +3805,18 @@ int cmd_jobfinish(int argc, char* argv[])
|
|||
* cmd_ handlers in this file already follow (e.g. cmd_join_worker just
|
||||
* above, cmd_jobsub, cmd_resupdate). */
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "j:c:")) != -1) {
|
||||
if (flagspec_build_opts(jobfinish_flags, JOBFINISH_NFLAGS, long_opts,
|
||||
optstring, sizeof(optstring))
|
||||
< 0) {
|
||||
fprintf(stderr,
|
||||
"xce_test: jfinish: internal error building flag table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL))
|
||||
!= -1) {
|
||||
switch (opt) {
|
||||
case 'j':
|
||||
parse_jobid(&jobid, optarg);
|
||||
|
|
@ -3483,9 +3824,10 @@ int cmd_jobfinish(int argc, char* argv[])
|
|||
case 'c':
|
||||
code = atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
printf(" jfinish -j jobid [-c exitcode]\n");
|
||||
return -EINVAL;
|
||||
case '?':
|
||||
return flagspec_reject("jfinish", jobfinish_flags,
|
||||
JOBFINISH_NFLAGS, argv[optind - 1],
|
||||
"jfinish -j <jobid> [-c <exitcode>]");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3516,6 +3858,14 @@ int cmd_jobfinish(int argc, char* argv[])
|
|||
* -> apply_job_fail_transition() at apply time. Reuses the existing
|
||||
* job_failinfo_t shape already exercised internally by this file's own
|
||||
* notify_job_fail() helper (used by run_job() on a local exec failure). */
|
||||
static const flagspec_t jobfail_flags[] = {
|
||||
{ 'j', "jobid", "jobid", required_argument, 1, NULL },
|
||||
{ 'c', "failure-code", "failure-code", required_argument, 0, "0" },
|
||||
{ 's', "stage", "stage", required_argument, 0,
|
||||
"JOB_EXEC_STAGE_POST_EXEC" },
|
||||
};
|
||||
#define JOBFAIL_NFLAGS (sizeof(jobfail_flags) / sizeof(jobfail_flags[0]))
|
||||
|
||||
int cmd_jobfail(int argc, char* argv[])
|
||||
{
|
||||
int rc;
|
||||
|
|
@ -3524,11 +3874,23 @@ int cmd_jobfail(int argc, char* argv[])
|
|||
int code = 0;
|
||||
int stage = JOB_EXEC_STAGE_POST_EXEC;
|
||||
job_failinfo_t failinfo;
|
||||
struct option long_opts[JOBFAIL_NFLAGS + 1];
|
||||
char optstring[16];
|
||||
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
memset(&failinfo, 0x0, sizeof(failinfo));
|
||||
|
||||
while ((opt = getopt(argc, argv, "j:c:s:")) != -1) {
|
||||
if (flagspec_build_opts(jobfail_flags, JOBFAIL_NFLAGS, long_opts,
|
||||
optstring, sizeof(optstring))
|
||||
< 0) {
|
||||
fprintf(stderr,
|
||||
"xce_test: jfail: internal error building flag table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL))
|
||||
!= -1) {
|
||||
switch (opt) {
|
||||
case 'j':
|
||||
parse_jobid(&jobid, optarg);
|
||||
|
|
@ -3539,9 +3901,10 @@ int cmd_jobfail(int argc, char* argv[])
|
|||
case 's':
|
||||
stage = atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
printf(" jfail -j jobid [-c code] [-s stage]\n");
|
||||
return -EINVAL;
|
||||
case '?':
|
||||
return flagspec_reject(
|
||||
"jfail", jobfail_flags, JOBFAIL_NFLAGS, argv[optind - 1],
|
||||
"jfail -j <jobid> [-c <code>] [-s <stage>]");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3758,6 +4121,14 @@ static void resupdate_report_one(char* name, char* host, xce_val_t* sent)
|
|||
}
|
||||
}
|
||||
|
||||
static const flagspec_t resupdate_flags[] = {
|
||||
{ 'n', "resname", "resname", required_argument, 1, NULL },
|
||||
{ 'v', "value", "value", required_argument, 1, NULL },
|
||||
{ 't', "value-type", "value-type", required_argument, 0,
|
||||
"numeric unless overridden" },
|
||||
};
|
||||
#define RESUPDATE_NFLAGS (sizeof(resupdate_flags) / sizeof(resupdate_flags[0]))
|
||||
|
||||
int cmd_resupdate(int argc, char* argv[])
|
||||
{
|
||||
#define MAX_N_RES (16)
|
||||
|
|
@ -3770,15 +4141,28 @@ int cmd_resupdate(int argc, char* argv[])
|
|||
int type_override = RESVAL_TYPE_UNKNOWN;
|
||||
int opt;
|
||||
int rc;
|
||||
struct option long_opts[RESUPDATE_NFLAGS + 1];
|
||||
char optstring[16];
|
||||
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
nres = 0;
|
||||
|
||||
if (flagspec_build_opts(resupdate_flags, RESUPDATE_NFLAGS, long_opts,
|
||||
optstring, sizeof(optstring))
|
||||
< 0) {
|
||||
fprintf(stderr,
|
||||
"xce_test: resupdate: internal error building flag table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* -t is deferred: it applies to the pair most recently opened by -n
|
||||
* (design.md's documented order is -n/-v/[-t]), so a pending pair's
|
||||
* set_resval() call is deferred until the NEXT -n or end-of-args --
|
||||
* not fired immediately on -v as before -- so a trailing -t still has
|
||||
* a chance to be seen for that same pair. */
|
||||
while ((opt = getopt(argc, argv, "n:v:t:")) != -1) {
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL))
|
||||
!= -1) {
|
||||
switch (opt) {
|
||||
case 'n':
|
||||
if (resname != NULL) {
|
||||
|
|
@ -3827,6 +4211,12 @@ int cmd_resupdate(int argc, char* argv[])
|
|||
printf("ignore -t `%s' as no res name found\n", optarg);
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
return flagspec_reject(
|
||||
"resupdate", resupdate_flags, RESUPDATE_NFLAGS,
|
||||
argv[optind - 1],
|
||||
"resupdate -n <resname> -v <value> [-t <numeric|string>] "
|
||||
"[-n <resname> -v <value> [-t <numeric|string>] ...]");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue