From 209fda499d481131c5cd0c4a0b84f4fcc992bd8f Mon Sep 17 00:00:00 2001 From: Philipp Storz Date: Sat, 4 May 2013 21:17:34 +0200 Subject: [PATCH] Extend cancel command to be able to cancel all running jobs Especially when testing, it would be a very nice feature to be able to cancel multiple jobs at once. For the first step, it would be nice to be able to cancel all jobs. Also useful would be to be able to cancel, jobs of a certain state, e.g. cancel state=waiting Fixes #144: Extend cancel command to be able to cancel all running jobs --- src/dird/ua_cmds.c | 22 +++-- src/dird/ua_select.c | 230 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 195 insertions(+), 57 deletions(-) diff --git a/src/dird/ua_cmds.c b/src/dird/ua_cmds.c index 715dee726d5..bb894c974bd 100644 --- a/src/dird/ua_cmds.c +++ b/src/dird/ua_cmds.c @@ -106,7 +106,7 @@ static struct cmdstruct commands[] = { { NT_("automount"), automount_cmd, _("Automount after label"), NT_("on | off"), false }, { NT_("cancel"), cancel_cmd, _("Cancel a job"), - NT_("storage= jobid= job= ujobid="), false }, + NT_("storage= | jobid= | job= | ujobid= | state= | all yes"), false }, { NT_("create"), create_cmd, _("Create DB Pool from resource"), NT_("pool="), false }, { NT_("delete"), delete_cmd, _("Delete volume, pool or job"), @@ -189,7 +189,9 @@ static struct cmdstruct commands[] = { { NT_("status"), status_cmd, _("Report status"), NT_("all | dir= | director | client= | storage= slots | days=nnn"), true }, { NT_("setbandwidth"), setbwlimit_cmd, _("Sets bandwidth"), - NT_("storage= limit= client= jobid= job= ujobid="), true }, + NT_("client= | storage= | jobid= |\n" + "\tjob= | ujobid= state= | all\n" + "\tlimit= yes"), true }, { NT_("setdebug"), setdebug_cmd, _("Sets debug level"), NT_("level= trace=0/1 client= | dir | storage= | all"), true }, { NT_("setip"), setip_cmd, _("Sets new client address -- if authorized"), @@ -476,7 +478,7 @@ static inline int cancel_storage_daemon_job(UAContext *ua, const char *cmd) /* * See what JobId to cancel on the storage daemon. */ - i = find_arg_with_value(ua, "jobid"); + i = find_arg_with_value(ua, NT_("jobid")); if (i >= 0) { if (!is_a_number(ua->argv[i])) { ua->warning_msg(_("JobId %s not a number\n"), ua->argv[i]); @@ -529,7 +531,7 @@ static int cancel_cmd(UAContext *ua, const char *cmd) /* * See if we need to explicitly cancel a storage daemon Job. */ - i = find_arg_with_value(ua, "storage"); + i = find_arg_with_value(ua, NT_("storage")); if (i >= 0) { return cancel_storage_daemon_job(ua, cmd); } else { @@ -820,11 +822,13 @@ static int setbwlimit_cmd(UAContext *ua, const char *cmd) "job", "jobid", "ujobid", + "all", + "state", NULL }; memset(Job, 0, sizeof(Job)); - i = find_arg_with_value(ua, "limit"); + i = find_arg_with_value(ua, NT_("limit")); if (i >= 0) { limit = atoi(ua->argv[i]) * 1024; } @@ -869,7 +873,7 @@ static int setbwlimit_cmd(UAContext *ua, const char *cmd) } delete selection; - } else if (find_arg(ua, "storage") >= 0) { + } else if (find_arg(ua, NT_("storage")) >= 0) { store = get_storage_resource(ua, false /* no default */); } else { client = get_client_resource(ua); @@ -1117,7 +1121,7 @@ static int setdebug_cmd(UAContext *ua, const char *cmd) Dmsg1(120, "setdebug:%s:\n", cmd); level = -1; - i = find_arg_with_value(ua, "level"); + i = find_arg_with_value(ua, NT_("level")); if (i >= 0) { level = atoi(ua->argv[i]); } @@ -1129,7 +1133,7 @@ static int setdebug_cmd(UAContext *ua, const char *cmd) } /* Look for trace flag. -1 => not change */ - i = find_arg_with_value(ua, "trace"); + i = find_arg_with_value(ua, NT_("trace")); if (i >= 0) { trace_flag = atoi(ua->argv[i]); if (trace_flag > 0) { @@ -1138,7 +1142,7 @@ static int setdebug_cmd(UAContext *ua, const char *cmd) } /* Look for hangup (debug only)flag. -1 => not change */ - i = find_arg_with_value(ua, "hangup"); + i = find_arg_with_value(ua, NT_("hangup")); if (i >= 0) { hangup = atoi(ua->argv[i]); } diff --git a/src/dird/ua_select.c b/src/dird/ua_select.c index 6b8944b448d..fa9cb00642c 100644 --- a/src/dird/ua_select.c +++ b/src/dird/ua_select.c @@ -290,7 +290,7 @@ JOBRES *select_job_resource(UAContext *ua) JOBRES *get_restore_job(UAContext *ua) { JOBRES *job; - int i = find_arg_with_value(ua, "restorejob"); + int i = find_arg_with_value(ua, NT_("restorejob")); if (i >= 0 && acl_access_ok(ua, Job_ACL, ua->argv[i])) { job = (JOBRES *)GetResWithName(R_JOB, ua->argv[i]); if (job && job->JobType == JT_RESTORE) { @@ -592,7 +592,7 @@ int select_media_dbr(UAContext *ua, MEDIA_DBR *mr) *err=0; mr->clear(); - i = find_arg_with_value(ua, "volume"); + i = find_arg_with_value(ua, NT_("volume")); if (i >= 0) { if (is_name_valid(ua->argv[i], &err)) { bstrncpy(mr->VolumeName, ua->argv[i], sizeof(mr->VolumeName)); @@ -670,7 +670,7 @@ POOLRES *get_pool_resource(UAContext *ua) POOLRES *pool = NULL; int i; - i = find_arg_with_value(ua, "pool"); + i = find_arg_with_value(ua, NT_("pool")); if (i >= 0 && acl_access_ok(ua, Pool_ACL, ua->argv[i])) { pool = (POOLRES *)GetResWithName(R_POOL, ua->argv[i]); if (pool) { @@ -1001,7 +1001,7 @@ int get_storage_drive(UAContext *ua, STORERES *store) char drivename[10]; /* Get drive for autochanger if possible */ - i = find_arg_with_value(ua, "drive"); + i = find_arg_with_value(ua, NT_("drive")); if (i >= 0) { drive = atoi(ua->argv[i]); } else if (store && store->autochanger) { @@ -1034,7 +1034,7 @@ int get_storage_slot(UAContext *ua, STORERES *store) { int i, slot = -1; /* Get slot for autochanger if possible */ - i = find_arg_with_value(ua, "slot"); + i = find_arg_with_value(ua, NT_("slot")); if (i >=0) { slot = atoi(ua->argv[i]); } else if (store && store->autochanger) { @@ -1062,7 +1062,7 @@ int get_media_type(UAContext *ua, char *MediaType, int max_media) STORERES *store; int i; - i = find_arg_with_value(ua, "mediatype"); + i = find_arg_with_value(ua, NT_("mediatype")); if (i >= 0) { bstrncpy(MediaType, ua->argv[i], max_media); return 1; @@ -1129,8 +1129,8 @@ alist *select_jobs(UAContext *ua, const char *reason) int cnt = 0; int njobs = 0; JCR *jcr = NULL; - char JobName[MAX_NAME_LENGTH]; - char temp[256]; + bool select_all = false; + bool select_by_state = false; alist *selected_jobids; const char *lst[] = { "job", @@ -1138,9 +1138,34 @@ alist *select_jobs(UAContext *ua, const char *reason) "ujobid", NULL }; + enum { + none, + all_jobs, + created_jobs, + blocked_jobs, + waiting_jobs, + running_jobs + } selection_criterium; + /* + * Allocate a list for holding the selected JobIds. + */ selected_jobids = New(alist(10, owned_by_alist)); + /* + * See if "all" is given. + */ + if (find_arg(ua, NT_("all")) > 0) { + select_all = true; + } + + /* + * See if "state=" is given. + */ + if (find_arg_with_value(ua, NT_("state")) > 0) { + select_by_state = true; + } + /* * See if there are any jobid, job or ujobid keywords. */ @@ -1189,23 +1214,29 @@ alist *select_jobs(UAContext *ua, const char *reason) } } + /* + * If we didn't select any Jobs using jobid, job or ujobid keywords try other selections. + */ if (cnt == 0) { char buf[1000]; - int tjobs = 0; /* total # number jobs */ - /* Count Jobs running */ + int tjobs = 0; /* Total # number jobs */ + + /* + * Count Jobs running + */ foreach_jcr(jcr) { - if (jcr->JobId == 0) { /* this is us */ + if (jcr->JobId == 0) { /* This is us */ continue; } - tjobs++; /* count of all jobs */ + tjobs++; /* Count of all jobs */ if (!acl_access_ok(ua, Job_ACL, jcr->res.job->name())) { - continue; /* skip not authorized */ + continue; /* Skip not authorized */ } - njobs++; /* count of authorized jobs */ + njobs++; /* Count of authorized jobs */ } endeach_jcr(jcr); - if (njobs == 0) { /* no authorized */ + if (njobs == 0) { /* No authorized */ if (tjobs == 0) { ua->send_msg(_("No Jobs running.\n")); } else { @@ -1214,49 +1245,152 @@ alist *select_jobs(UAContext *ua, const char *reason) goto bail_out; } - start_prompt(ua, _("Select Job:\n")); - foreach_jcr(jcr) { - char ed1[50]; - if (jcr->JobId == 0) { /* this is us */ - continue; + if (select_all || select_by_state) { + /* + * Set selection criterium. + */ + if (select_all) { + selection_criterium = all_jobs; + } else { + i = find_arg_with_value(ua, NT_("state")); + if (i > 0) { + selection_criterium = none; + + if (bstrcasecmp(ua->argv[i], NT_("created"))) { + selection_criterium = created_jobs; + } + + if (bstrcasecmp(ua->argv[i], NT_("blocked"))) { + selection_criterium = blocked_jobs; + } + + if (bstrcasecmp(ua->argv[i], NT_("waiting"))) { + selection_criterium = waiting_jobs; + } + + if (bstrcasecmp(ua->argv[i], NT_("running"))) { + selection_criterium = running_jobs; + } + + if (selection_criterium == none) { + ua->error_msg(_("Illegal state either created, blocked, waiting or running\n")); + goto bail_out; + } + } } - if (!acl_access_ok(ua, Job_ACL, jcr->res.job->name())) { - continue; /* skip not authorized */ + + /* + * Select from all available Jobs the Jobs matching the selection criterium. + */ + foreach_jcr(jcr) { + if (jcr->JobId == 0) { /* This is us */ + continue; + } + + if (!acl_access_ok(ua, Job_ACL, jcr->res.job->name())) { + continue; /* Skip not authorized */ + } + + /* + * See if we need to select this JobId. + */ + switch (selection_criterium) { + case all_jobs: + break; + case created_jobs: + if (jcr->JobStatus != JS_Created) { + continue; + } + break; + case blocked_jobs: + if (!jcr->job_started || jcr->JobStatus != JS_Blocked) { + continue; + } + break; + case waiting_jobs: + if (!job_waiting(jcr)) { + continue; + } + break; + case running_jobs: + if (!jcr->job_started || jcr->JobStatus != JS_Running) { + continue; + } + break; + default: + break; + } + + insert_selected_jobid(selected_jobids, jcr->JobId); + ua->send_msg(_("Selected Job %d for cancelling\n") , jcr->JobId); } - bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job); - add_prompt(ua, buf); - } - endeach_jcr(jcr); - bsnprintf(temp, sizeof(temp), _("Choose Job to %s"), _(reason)); - if (do_prompt(ua, _("Job"), temp, buf, sizeof(buf)) < 0) { - goto bail_out; - } - if (bstrcmp(reason, "cancel")) { - if (ua->api && njobs == 1) { - char nbuf[1000]; - bsnprintf(nbuf, sizeof(nbuf), _("Cancel: %s\n\n%s"), buf, - _("Confirm cancel?")); - if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) { + + if (selected_jobids->empty()) { + ua->send_msg(_("No Jobs selected.\n")); + goto bail_out; + } + + /* + * Only ask for confirmation when not in batch mode and there is no yes on the cmdline. + */ + if (!ua->batch && find_arg(ua, NT_("yes")) == -1) { + if (!get_yesno(ua, _("Confirm cancel (yes/no): ")) || ua->pint32_val == 0) { goto bail_out; } - } else { - if (njobs == 1) { - if (!get_yesno(ua, _("Confirm cancel (yes/no): ")) || ua->pint32_val == 0) { + } + } else { + char temp[256]; + char JobName[MAX_NAME_LENGTH]; + + /* + * Interactivly select a Job. + */ + start_prompt(ua, _("Select Job:\n")); + foreach_jcr(jcr) { + char ed1[50]; + if (jcr->JobId == 0) { /* This is us */ + continue; + } + if (!acl_access_ok(ua, Job_ACL, jcr->res.job->name())) { + continue; /* Skip not authorized */ + } + bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job); + add_prompt(ua, buf); + } + endeach_jcr(jcr); + + bsnprintf(temp, sizeof(temp), _("Choose Job to %s"), _(reason)); + if (do_prompt(ua, _("Job"), temp, buf, sizeof(buf)) < 0) { + goto bail_out; + } + + if (bstrcmp(reason, "cancel")) { + if (ua->api && njobs == 1) { + char nbuf[1000]; + + bsnprintf(nbuf, sizeof(nbuf), _("Cancel: %s\n\n%s"), buf, _("Confirm cancel?")); + if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) { goto bail_out; } + } else { + if (njobs == 1) { + if (!get_yesno(ua, _("Confirm cancel (yes/no): ")) || ua->pint32_val == 0) { + goto bail_out; + } + } } } - } - sscanf(buf, "JobId=%d Job=%127s", &njobs, JobName); - jcr = get_jcr_by_full_name(JobName); - if (!jcr) { - ua->warning_msg(_("Job \"%s\" not found.\n"), JobName); - goto bail_out; - } - insert_selected_jobid(selected_jobids, jcr->JobId); + sscanf(buf, "JobId=%d Job=%127s", &njobs, JobName); + jcr = get_jcr_by_full_name(JobName); + if (!jcr) { + ua->warning_msg(_("Job \"%s\" not found.\n"), JobName); + goto bail_out; + } - free_jcr(jcr); + insert_selected_jobid(selected_jobids, jcr->JobId); + free_jcr(jcr); + } } return selected_jobids;