| /*****************************************************************************\ |
| * archive_functions.c - functions dealing with archive in the |
| * accounting system. |
| ***************************************************************************** |
| * Copyright (C) 2008 Lawrence Livermore National Security. |
| * Copyright (C) 2002-2007 The Regents of the University of California. |
| * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). |
| * Written by Danny Auble <da@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. |
| \*****************************************************************************/ |
| |
| #include <sys/stat.h> |
| |
| #include "src/sacctmgr/sacctmgr.h" |
| #include "src/common/proc_args.h" |
| #include "src/common/util-net.h" |
| |
| static int _set_cond(int *start, int argc, char **argv, |
| slurmdb_archive_cond_t *arch_cond) |
| { |
| int i; |
| int set = 0; |
| int end = 0; |
| int command_len = 0; |
| uint32_t tmp; |
| slurmdb_job_cond_t *job_cond = NULL; |
| |
| if (!arch_cond) { |
| error("No arch_cond given"); |
| return -1; |
| } |
| if (!arch_cond->job_cond) |
| arch_cond->job_cond = xmalloc(sizeof(slurmdb_job_cond_t)); |
| job_cond = arch_cond->job_cond; |
| |
| for (i=(*start); i<argc; i++) { |
| int op_type; |
| end = parse_option_end(argv[i], &op_type, &command_len); |
| if (!common_verify_option_syntax(argv[i], op_type, false)) |
| continue; |
| |
| if (!end && !xstrncasecmp(argv[i], "where", |
| MAX(command_len, 5))) { |
| continue; |
| } else if (!end && !xstrncasecmp(argv[i], "events", |
| MAX(command_len, 1))) { |
| arch_cond->purge_event |= SLURMDB_PURGE_ARCHIVE; |
| set = 1; |
| } else if (!end && !xstrncasecmp(argv[i], "jobs", |
| MAX(command_len, 1))) { |
| arch_cond->purge_job |= SLURMDB_PURGE_ARCHIVE; |
| set = 1; |
| } else if (!end && !xstrncasecmp(argv[i], "reservations", |
| MAX(command_len, 1))) { |
| arch_cond->purge_resv |= SLURMDB_PURGE_ARCHIVE; |
| set = 1; |
| } else if (!end && !xstrncasecmp(argv[i], "steps", |
| MAX(command_len, 1))) { |
| arch_cond->purge_step |= SLURMDB_PURGE_ARCHIVE; |
| set = 1; |
| } else if (!end && !xstrncasecmp(argv[i], "suspend", |
| MAX(command_len, 1))) { |
| arch_cond->purge_suspend |= SLURMDB_PURGE_ARCHIVE; |
| set = 1; |
| } else if (!end && !xstrncasecmp(argv[i], "txn", |
| MAX(command_len, 1))) { |
| arch_cond->purge_txn |= SLURMDB_PURGE_ARCHIVE; |
| set = 1; |
| } else if (!end && !xstrncasecmp(argv[i], "usage", |
| MAX(command_len, 1))) { |
| arch_cond->purge_usage |= SLURMDB_PURGE_ARCHIVE; |
| set = 1; |
| } else if (!end |
| || !xstrncasecmp(argv[i], "Clusters", |
| MAX(command_len, 1))) { |
| if (!job_cond->cluster_list) |
| job_cond->cluster_list = list_create(xfree_ptr); |
| slurm_addto_char_list(job_cond->cluster_list, |
| argv[i]+end); |
| set = 1; |
| } else if (!xstrncasecmp(argv[i], "Accounts", |
| MAX(command_len, 2))) { |
| if (!job_cond->acct_list) |
| job_cond->acct_list = list_create(xfree_ptr); |
| slurm_addto_char_list(job_cond->acct_list, |
| argv[i]+end); |
| set = 1; |
| } else if (!xstrncasecmp(argv[i], "Associations", |
| MAX(command_len, 2))) { |
| if (!job_cond->associd_list) |
| job_cond->associd_list = list_create(xfree_ptr); |
| slurm_addto_char_list(job_cond->associd_list, |
| argv[i]+end); |
| set = 1; |
| } else if (!xstrncasecmp(argv[i], "Directory", |
| MAX(command_len, 2))) { |
| arch_cond->archive_dir = |
| strip_quotes(argv[i]+end, NULL, 0); |
| set = 1; |
| } else if (!xstrncasecmp(argv[i], "End", MAX(command_len, 1))) { |
| job_cond->usage_end = parse_time(argv[i]+end, 1); |
| set = 1; |
| } else if (!xstrncasecmp(argv[i], "Gid", MAX(command_len, 2))) { |
| if (!job_cond->groupid_list) |
| job_cond->groupid_list = list_create(xfree_ptr); |
| slurm_addto_char_list(job_cond->groupid_list, |
| argv[i]+end); |
| set = 1; |
| } else if (!xstrncasecmp(argv[i], "Jobs", |
| MAX(command_len, 1))) { |
| char *end_char = NULL, *start_char = argv[i] + end; |
| slurm_selected_step_t *selected_step = NULL; |
| char *dot = NULL; |
| if (!job_cond->step_list) |
| job_cond->step_list = list_create(xfree_ptr); |
| |
| while ((end_char = strstr(start_char, ","))) { |
| end_char[0] = '\0'; |
| while (isspace(start_char[0])) |
| start_char++; /* discard whitespace */ |
| if (start_char[0] == '\0') |
| continue; |
| selected_step = xmalloc( |
| sizeof(slurm_selected_step_t)); |
| selected_step->array_task_id = NO_VAL; |
| selected_step->het_job_offset = NO_VAL; |
| list_append(job_cond->step_list, selected_step); |
| |
| dot = strstr(start_char, "."); |
| if (dot == NULL) { |
| debug2("No jobstep requested"); |
| selected_step->step_id.step_id = NO_VAL; |
| } else { |
| *dot++ = 0; |
| selected_step->step_id.step_id = |
| atoi(dot); |
| } |
| selected_step->step_id.step_het_comp = NO_VAL; |
| selected_step->step_id.job_id = |
| atoi(start_char); |
| start_char = end_char + 1; |
| } |
| |
| set = 1; |
| } else if (!xstrncasecmp(argv[i], "Partitions", |
| MAX(command_len, 2))) { |
| if (!job_cond->partition_list) |
| job_cond->partition_list = |
| list_create(xfree_ptr); |
| slurm_addto_char_list(job_cond->partition_list, |
| argv[i]+end); |
| set = 1; |
| } else if (!xstrncasecmp(argv[i], "PurgeEventAfter", |
| MAX(command_len, 10))) { |
| if ((tmp = slurmdb_parse_purge(argv[i]+end)) |
| == NO_VAL) { |
| exit_code = 1; |
| } else { |
| arch_cond->purge_event |= tmp; |
| set = 1; |
| } |
| } else if (!xstrncasecmp(argv[i], "PurgeJobAfter", |
| MAX(command_len, 10))) { |
| if ((tmp = slurmdb_parse_purge(argv[i]+end)) |
| == NO_VAL) { |
| exit_code = 1; |
| } else { |
| arch_cond->purge_job |= tmp; |
| set = 1; |
| } |
| } else if (!xstrncasecmp(argv[i], "PurgeResvAfter", |
| MAX(command_len, 10))) { |
| if ((tmp = slurmdb_parse_purge(argv[i]+end)) |
| == NO_VAL) { |
| exit_code = 1; |
| } else { |
| arch_cond->purge_resv |= tmp; |
| set = 1; |
| } |
| } else if (!xstrncasecmp(argv[i], "PurgeStepAfter", |
| MAX(command_len, 10))) { |
| if ((tmp = slurmdb_parse_purge(argv[i]+end)) |
| == NO_VAL) { |
| exit_code = 1; |
| } else { |
| arch_cond->purge_step |= tmp; |
| set = 1; |
| } |
| } else if (!xstrncasecmp(argv[i], "PurgeSuspendAfter", |
| MAX(command_len, 10))) { |
| if ((tmp = slurmdb_parse_purge(argv[i]+end)) |
| == NO_VAL) { |
| exit_code = 1; |
| } else { |
| arch_cond->purge_suspend |= tmp; |
| set = 1; |
| } |
| } else if (!xstrncasecmp(argv[i], "PurgeTXNAfter", |
| MAX(command_len, 10))) { |
| if ((tmp = slurmdb_parse_purge(argv[i]+end)) |
| == NO_VAL) { |
| exit_code = 1; |
| } else { |
| arch_cond->purge_txn |= tmp; |
| set = 1; |
| } |
| } else if (!xstrncasecmp(argv[i], "PurgeUsageAfter", |
| MAX(command_len, 10))) { |
| if ((tmp = slurmdb_parse_purge(argv[i]+end)) |
| == NO_VAL) { |
| exit_code = 1; |
| } else { |
| arch_cond->purge_usage |= tmp; |
| set = 1; |
| } |
| } else if (!xstrncasecmp(argv[i], "PurgeEventMonths", |
| MAX(command_len, 6))) { |
| if (get_uint(argv[i]+end, &tmp, "PurgeEventMonths") |
| != SLURM_SUCCESS) { |
| exit_code = 1; |
| } else { |
| arch_cond->purge_event |= tmp; |
| arch_cond->purge_event |= SLURMDB_PURGE_MONTHS; |
| set = 1; |
| } |
| } else if (!xstrncasecmp(argv[i], "PurgeJobMonths", |
| MAX(command_len, 6))) { |
| if (get_uint(argv[i]+end, &tmp, "PurgeJobMonths") |
| != SLURM_SUCCESS) { |
| exit_code = 1; |
| } else { |
| arch_cond->purge_job |= tmp; |
| arch_cond->purge_job |= SLURMDB_PURGE_MONTHS; |
| set = 1; |
| } |
| } else if (!xstrncasecmp(argv[i], "PurgeResvMonths", |
| MAX(command_len, 6))) { |
| if (get_uint(argv[i]+end, &tmp, "PurgeResvMonths") |
| != SLURM_SUCCESS) { |
| exit_code = 1; |
| } else { |
| arch_cond->purge_resv |= tmp; |
| arch_cond->purge_resv |= SLURMDB_PURGE_MONTHS; |
| set = 1; |
| } |
| } else if (!xstrncasecmp(argv[i], "PurgeStepMonths", |
| MAX(command_len, 7))) { |
| if (get_uint(argv[i]+end, &tmp, "PurgeStepMonths") |
| != SLURM_SUCCESS) { |
| exit_code = 1; |
| } else { |
| arch_cond->purge_step |= tmp; |
| arch_cond->purge_step |= SLURMDB_PURGE_MONTHS; |
| set = 1; |
| } |
| } else if (!xstrncasecmp(argv[i], "PurgeSuspendMonths", |
| MAX(command_len, 7))) { |
| if (get_uint(argv[i]+end, &tmp, "PurgeSuspendMonths") |
| != SLURM_SUCCESS) { |
| exit_code = 1; |
| } else { |
| arch_cond->purge_suspend |= tmp; |
| arch_cond->purge_suspend |
| |= SLURMDB_PURGE_MONTHS; |
| set = 1; |
| } |
| } else if (!xstrncasecmp(argv[i], "PurgeTXNMonths", |
| MAX(command_len, 6))) { |
| if (get_uint(argv[i]+end, &tmp, "PurgeTXNMonths") |
| != SLURM_SUCCESS) { |
| exit_code = 1; |
| } else { |
| arch_cond->purge_txn |= tmp; |
| arch_cond->purge_txn |
| |= SLURMDB_PURGE_MONTHS; |
| set = 1; |
| } |
| } else if (!xstrncasecmp(argv[i], "PurgeUsageMonths", |
| MAX(command_len, 6))) { |
| if (get_uint(argv[i]+end, &tmp, "PurgeUsageMonths") |
| != SLURM_SUCCESS) { |
| exit_code = 1; |
| } else { |
| arch_cond->purge_usage |= tmp; |
| arch_cond->purge_usage |
| |= SLURMDB_PURGE_MONTHS; |
| set = 1; |
| } |
| } else if (!xstrncasecmp(argv[i], "Start", |
| MAX(command_len, 2))) { |
| job_cond->usage_start = parse_time(argv[i]+end, 1); |
| set = 1; |
| } else if (!xstrncasecmp(argv[i], "Script", |
| MAX(command_len, 2))) { |
| arch_cond->archive_script = |
| strip_quotes(argv[i]+end, NULL, 0); |
| set = 1; |
| } else if (!xstrncasecmp(argv[i], "Users", |
| MAX(command_len, 1))) { |
| if (!job_cond->userid_list) |
| job_cond->userid_list = list_create(xfree_ptr); |
| if (slurm_addto_id_char_list(job_cond->userid_list, |
| argv[i]+end, false) > 0) |
| set = 1; |
| else |
| exit_code = 1; |
| } else { |
| exit_code=1; |
| fprintf(stderr, " Unknown condition: %s\n", argv[i]); |
| } |
| } |
| |
| (*start) = i; |
| |
| return set; |
| } |
| |
| extern int sacctmgr_archive_dump(int argc, char **argv) |
| { |
| char *warning = NULL; |
| int rc = SLURM_SUCCESS; |
| slurmdb_archive_cond_t *arch_cond = |
| xmalloc(sizeof(slurmdb_archive_cond_t)); |
| int i; |
| struct stat st; |
| |
| for (i = 0; i < argc; i++) { |
| int command_len = strlen(argv[i]); |
| if (!xstrncasecmp(argv[i], "Where", MAX(command_len, 5)) |
| || !xstrncasecmp(argv[i], "Set", MAX(command_len, 3))) |
| i++; |
| _set_cond(&i, argc, argv, arch_cond); |
| } |
| |
| if (!arch_cond->purge_event) |
| arch_cond->purge_event = NO_VAL; |
| if (!arch_cond->purge_job) |
| arch_cond->purge_job = NO_VAL; |
| if (!arch_cond->purge_resv) |
| arch_cond->purge_resv = NO_VAL; |
| if (!arch_cond->purge_step) |
| arch_cond->purge_step = NO_VAL; |
| if (!arch_cond->purge_suspend) |
| arch_cond->purge_suspend = NO_VAL; |
| if (!arch_cond->purge_txn) |
| arch_cond->purge_txn = NO_VAL; |
| if (!arch_cond->purge_usage) |
| arch_cond->purge_usage = NO_VAL; |
| |
| if (exit_code) { |
| slurmdb_destroy_archive_cond(arch_cond); |
| return SLURM_ERROR; |
| } |
| |
| if (arch_cond->archive_dir) { |
| if (stat(arch_cond->archive_dir, &st) < 0) { |
| exit_code = errno; |
| fprintf(stderr, " dump: Failed to stat %s: %s\n " |
| "Note: For archive dump, " |
| "the directory must be on " |
| "the calling host.\n", |
| arch_cond->archive_dir, slurm_strerror(errno)); |
| slurmdb_destroy_archive_cond(arch_cond); |
| return SLURM_ERROR; |
| } |
| |
| if (!(st.st_mode & S_IFDIR)) { |
| errno = EACCES; |
| fprintf(stderr, " dump: " |
| "archive dir %s isn't a directory\n", |
| arch_cond->archive_dir); |
| slurmdb_destroy_archive_cond(arch_cond); |
| return SLURM_ERROR; |
| } |
| |
| if (access(arch_cond->archive_dir, W_OK) < 0) { |
| errno = EACCES; |
| fprintf(stderr, " dump: " |
| "archive dir %s is not writable\n", |
| arch_cond->archive_dir); |
| slurmdb_destroy_archive_cond(arch_cond); |
| return SLURM_ERROR; |
| } |
| } |
| |
| if (arch_cond->archive_script) { |
| if (stat(arch_cond->archive_script, &st) < 0) { |
| exit_code = errno; |
| fprintf(stderr, " dump: Failed to stat %s: %s\n " |
| "Note: For archive dump, the script must be on " |
| "the calling host.\n", |
| arch_cond->archive_script, |
| slurm_strerror(errno)); |
| slurmdb_destroy_archive_cond(arch_cond); |
| return SLURM_ERROR; |
| } |
| if (!(st.st_mode & S_IFREG)) { |
| errno = EACCES; |
| fprintf(stderr, " dump: " |
| "archive script %s isn't a regular file\n", |
| arch_cond->archive_script); |
| slurmdb_destroy_archive_cond(arch_cond); |
| return SLURM_ERROR; |
| } |
| |
| if (access(arch_cond->archive_script, X_OK) < 0) { |
| errno = EACCES; |
| fprintf(stderr, " dump: " |
| "archive script %s is not executable\n", |
| arch_cond->archive_script); |
| slurmdb_destroy_archive_cond(arch_cond); |
| return SLURM_ERROR; |
| } |
| } |
| |
| warning = "This may result in loss of accounting database records (if Purge* options enabled).\nAre you sure you want to continue?"; |
| if (commit_check(warning)) { |
| rc = slurmdb_archive(db_conn, arch_cond); |
| if (rc != SLURM_SUCCESS) { |
| exit_code = 1; |
| fprintf(stderr, " Problem dumping archive: %s\n", |
| slurm_strerror(rc)); |
| rc = SLURM_ERROR; |
| } |
| } else { |
| printf(" Changes Discarded\n"); |
| } |
| |
| slurmdb_destroy_archive_cond(arch_cond); |
| |
| return rc; |
| } |
| |
| extern int sacctmgr_archive_load(int argc, char **argv) |
| { |
| int rc = SLURM_SUCCESS; |
| slurmdb_archive_rec_t *arch_rec = |
| xmalloc(sizeof(slurmdb_archive_rec_t)); |
| int i, command_len = 0; |
| |
| for (i = 0; i < argc; i++) { |
| int op_type; |
| int end = parse_option_end(argv[i], &op_type, &command_len); |
| if (!common_verify_option_syntax(argv[i], op_type, false)) |
| continue; |
| |
| if (!end |
| || !xstrncasecmp(argv[i], "File", MAX(command_len, 1))) { |
| arch_rec->archive_file = |
| strip_quotes(argv[i]+end, NULL, 0); |
| if (!is_full_path(arch_rec->archive_file)) { |
| char *file = arch_rec->archive_file; |
| arch_rec->archive_file = |
| make_full_path(arch_rec->archive_file); |
| xfree(file); |
| } |
| } else if (!xstrncasecmp(argv[i], "Insert", |
| MAX(command_len, 2))) { |
| arch_rec->insert = strip_quotes(argv[i]+end, NULL, 1); |
| } else { |
| exit_code = 1; |
| fprintf(stderr, " Unknown option: %s\n", argv[i]); |
| } |
| } |
| |
| if (exit_code) { |
| slurmdb_destroy_archive_rec(arch_rec); |
| return SLURM_ERROR; |
| } |
| |
| rc = slurmdb_archive_load(db_conn, arch_rec); |
| if (rc == SLURM_SUCCESS) { |
| if (commit_check("Would you like to commit changes?")) { |
| rc = slurmdb_connection_commit(db_conn, 1); |
| if (rc != SLURM_SUCCESS) |
| fprintf(stderr, |
| "Error committing changes: %s\n", |
| slurm_strerror(rc)); |
| } else { |
| printf(" Changes Discarded\n"); |
| rc = slurmdb_connection_commit(db_conn, 0); |
| if (rc != SLURM_SUCCESS) |
| fprintf(stderr, |
| "Error rolling back changes: %s\n", |
| slurm_strerror(rc)); |
| } |
| } else { |
| exit_code = 1; |
| fprintf(stderr, " Problem loading archive file: %s\n", |
| slurm_strerror(rc)); |
| |
| if (rc == EACCES || rc == EISDIR || rc == ENOENT) |
| fprintf(stderr, " Note: For archive load, the file must be accessible on the slurmdbd host.\n"); |
| |
| rc = SLURM_ERROR; |
| } |
| |
| slurmdb_destroy_archive_rec(arch_rec); |
| |
| return rc; |
| } |