From fff8a68702de7d712a67c1d72ea7139220f37b39 Mon Sep 17 00:00:00 2001 From: VladimirStarostenkov Date: Thu, 13 Dec 2012 10:55:13 -0800 Subject: [PATCH 1/4] Unit tests for non static functions --- src/server/svr_jobfunc.c | 176 +++++++- src/server/svr_jobfunc.h | 56 +-- src/server/test/svr_jobfunc/scaffolding.c | 130 ++++-- .../test/svr_jobfunc/test_svr_jobfunc.c | 391 +++++++++++++++++- 4 files changed, 666 insertions(+), 87 deletions(-) diff --git a/src/server/svr_jobfunc.c b/src/server/svr_jobfunc.c index ac1e304d54..daf9341175 100644 --- a/src/server/svr_jobfunc.c +++ b/src/server/svr_jobfunc.c @@ -123,6 +123,7 @@ #include "resource.h" #include "server.h" #include "queue.h" +#include "dynamic_string.h" #include "pbs_job.h" #include "work_task.h" #include "pbs_error.h" @@ -140,13 +141,15 @@ #include "ji_mutex.h" #include "user_info.h" #include "svr_jobfunc.h" +#include "job_func.h" #define MSG_LEN_LONG 160 /* Private Functions */ -void default_std(job *, int key, dynamic_string *ds); -void eval_checkpoint(pbs_attribute *j, pbs_attribute *q); +static void default_std(job *, int key, dynamic_string *ds); +static void eval_checkpoint(pbs_attribute *j, pbs_attribute *q); +static int count_queued_jobs(pbs_queue *pque, char *user); /* Global Data Items: */ @@ -181,7 +184,7 @@ extern int procs_requested(char *spec); /* Private Functions */ #ifndef NDEBUG -void correct_ct(); +static void correct_ct(); #endif /* NDEBUG */ /* sync w/#define JOB_STATE_XXX */ @@ -285,7 +288,7 @@ const char *PJobSubState[] = -int insert_into_alljobs_by_rank( +static int insert_into_alljobs_by_rank( struct all_jobs *aj, job *pjob, @@ -357,7 +360,7 @@ int svr_enquejob( pbs_attribute *pattrjb; attribute_def *pdef; pbs_queue *pque; - int rc; + int rc = -1; char log_buf[LOCAL_LOG_BUF_SIZE]; time_t time_now = time(NULL); char job_id[PBS_MAXSVRJOBID+1]; @@ -366,6 +369,12 @@ int svr_enquejob( int user_jobs = 0; int array_jobs = 0; + if (pjob == NULL) + { + log_err(rc, __func__, "NULL job pointer input"); + return(rc); + } + /* make sure queue is still there, there exists a small window ... */ strcpy(job_id, pjob->ji_qs.ji_jobid); /* ji_qs.ji_queue now holds the name of the destination queue */ @@ -440,7 +449,9 @@ int svr_enquejob( insert_job_after_index(&alljobs, prev_job_index, pjob); if (has_sv_qs_mutex == FALSE) + { lock_sv_qs_mutex(server.sv_qs_mutex, __func__); + } server.sv_qs.sv_numjobs++; @@ -477,7 +488,9 @@ int svr_enquejob( { unlock_queue(pque, __func__, "not array_template check", LOGLEVEL); if (rc == ALREADY_IN_LIST) + { rc = PBSE_NONE; + } return(rc); } @@ -823,6 +836,12 @@ int svr_setjobstate( char log_buf[LOCAL_LOG_BUF_SIZE]; time_t time_now = time(NULL); + if (pjob == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input job pointer"); + return(PBSE_BAD_PARAMETER); + } + if (LOGLEVEL >= 2) { sprintf(log_buf, "%s: setting job %s state from %s-%s to %s-%s (%d-%d)\n", @@ -967,6 +986,22 @@ void svr_evaljobstate( int forceeval) { + if (pjob == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input job pointer"); + return; + } + if (newstate == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input newstate pointer"); + return; + } + if (newsub == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input newsub pointer"); + return; + } + if ((forceeval == 0) && ((pjob->ji_qs.ji_state == JOB_STATE_RUNNING) || (pjob->ji_qs.ji_state == JOB_STATE_TRANSIT))) @@ -1054,7 +1089,7 @@ char *get_variable( * Returns: pointer to struct resource or NULL */ -resource *get_resource( +static resource *get_resource( pbs_attribute *p_queattr, /* I */ pbs_attribute *p_svrattr, /* I */ @@ -1098,7 +1133,7 @@ resource *get_resource( * does not make use of comp_resc_eq or comp_resc_nc */ -int chk_svr_resc_limit( +static int chk_svr_resc_limit( pbs_attribute *jobatr, /* I */ pbs_queue *pque, /* I */ @@ -1541,7 +1576,7 @@ int chk_svr_resc_limit( * @return the number of jobs, or -1 on error */ -int count_queued_jobs( +static int count_queued_jobs( pbs_queue *pque, /* I */ char *user) /* I */ @@ -1578,6 +1613,17 @@ int chk_resc_limits( int resc_lt; int resc_gt; + if (pattr == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input pbs_attribute pointer"); + return(PBSE_BAD_PARAMETER); + } + if (pque == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input pbs_queue pointer"); + return(PBSE_BAD_PARAMETER); + } + if (EMsg != NULL) EMsg[0] = '\0'; @@ -1648,6 +1694,17 @@ int svr_chkque( int j = 0; char jobid[PBS_MAXSVRJOBID+1]; + if (pjob == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input job pointer"); + return PBSE_BAD_PARAMETER; + } + if (pque == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input pbs_queue pointer"); + return PBSE_BAD_PARAMETER; + } + strcpy(jobid, pjob->ji_qs.ji_jobid); if (EMsg != NULL) @@ -1952,10 +2009,12 @@ int svr_chkque( if (pque->qu_attr[QA_ATR_Enabled].at_val.at_long == 0) { if (EMsg) + { snprintf(EMsg, 1024, "queue is disabled: user %s, queue %s", pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, pque->qu_qs.qu_name); + } return(PBSE_QUNOENB); } @@ -1976,11 +2035,13 @@ int svr_chkque( if ((total_jobs + array_jobs) >= pque->qu_attr[QA_ATR_MaxJobs].at_val.at_long) { if (EMsg) + { snprintf(EMsg, 1024, "total number of jobs in queue exceeds the queue limit: " "user %s, queue %s", pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, pque->qu_qs.qu_name); + } return(PBSE_MAXQUED); } @@ -2115,6 +2176,12 @@ int svr_chkque( } else { + + if (pque->qu_attr->at_val.at_str == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "pque->qu_attr->at_val.at_str uninitialized"); + return PBSE_BAD_PARAMETER; + } if (strcmp(pque->qu_attr->at_val.at_str, "Execution") == 0) { /* job routed to Execution queue successfully */ @@ -2144,7 +2211,7 @@ int svr_chkque( * If indeed the case, re-evaluate and set the job state. */ -void job_wait_over( +static void job_wait_over( struct work_task *pwt) @@ -2228,6 +2295,17 @@ int job_set_wait( long when; job *pjob = (job *)j; + if (pattr == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input pbs_attribute pointer"); + return PBSE_BAD_PARAMETER; + } + if (pjob == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input job pointer"); + return PBSE_BAD_PARAMETER; + } + if ((pattr->at_flags & ATR_VFLAG_SET) == 0) { return(PBSE_NONE); @@ -2254,7 +2332,7 @@ int job_set_wait( * "job_name".[e|o]job_sequence_number */ -void default_std( +static void default_std( job *pjob, int key, /* 'e' for stderr, 'o' for stdout */ @@ -2321,6 +2399,17 @@ char *prefix_std_file( char *qsubhost; char *wdir; + if (pjob == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input job pointer"); + return(NULL); + } + if (ds == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input dynamic_string pointer"); + return(NULL); + } + qsubhost = get_variable(pjob, pbs_o_host); wdir = get_variable(pjob, "PBS_O_WORKDIR"); @@ -2391,6 +2480,22 @@ char *add_std_filename( dynamic_string *ds) { + if (pjob == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input job pointer"); + return(NULL); + } + if (path == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input path pointer"); + return(NULL); + } + if (ds == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input dynamic_string pointer"); + return(NULL); + } + append_dynamic_string(ds, path); append_char_to_dynamic_string(ds, '/'); @@ -2450,7 +2555,7 @@ void get_jobowner( * @param *dflt */ -void set_deflt_resc( +static void set_deflt_resc( pbs_attribute *jb, pbs_attribute *dflt) @@ -2622,6 +2727,17 @@ void set_resc_deflt( { char log_buf[LOCAL_LOG_BUF_SIZE]; + if (pjob == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input job pointer"); + return; + } + if (pque == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input pbs_queue pointer"); + return; + } + /* If execution queue has checkpoint defaults specified, but job does not have * checkpoint values, then set defaults on the job. */ @@ -2669,6 +2785,12 @@ void set_statechar( static char *statechar = "TQHWREC"; static char suspend = 'S'; + if (pjob == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input job pointer"); + return; + } + if ((pjob->ji_qs.ji_state == JOB_STATE_RUNNING) && (pjob->ji_qs.ji_svrflags & JOB_SVFLG_Suspend)) { @@ -2701,7 +2823,7 @@ void set_statechar( * to the queue min time. */ -void eval_checkpoint( +static void eval_checkpoint( pbs_attribute *jobckp, /* job's checkpoint pbs_attribute */ pbs_attribute *queckp) /* queue's checkpoint pbs_attribute */ @@ -2753,7 +2875,7 @@ void eval_checkpoint( * all of the counts and log a message. */ -void correct_ct() +static void correct_ct() { int i; @@ -2862,6 +2984,8 @@ int lock_ji_mutex( log_record(PBSEVENT_DEBUG, PBS_EVENTCLASS_NODE, id, err_msg); } + if (pjob->ji_mutex != NULL) + { if (pthread_mutex_lock(pjob->ji_mutex) != 0) { if (logging >= 20) @@ -2872,6 +2996,12 @@ int lock_ji_mutex( } rc = PBSE_MUTEX; } + } + else + { + rc = -1; + log_err(rc, __func__, "Uninitialized mutex pass to pthread_mutex_lock!"); + } if (err_msg != NULL) free(err_msg); @@ -2901,15 +3031,23 @@ int unlock_ji_mutex( log_record(PBSEVENT_DEBUG, PBS_EVENTCLASS_NODE, id, err_msg); } - if (pthread_mutex_unlock(pjob->ji_mutex) != 0) + if (pjob->ji_mutex != NULL) { - if (logging >= 20) + if (pthread_mutex_unlock(pjob->ji_mutex) != 0) { - snprintf(err_msg, MSG_LEN_LONG, "ALERT: cannot unlock job %s mutex in method %s", - pjob->ji_qs.ji_jobid, id); - log_record(PBSEVENT_DEBUG, PBS_EVENTCLASS_NODE, id, err_msg); + if (logging >= 20) + { + snprintf(err_msg, MSG_LEN_LONG, "ALERT: cannot unlock job %s mutex in method %s", + pjob->ji_qs.ji_jobid, id); + log_record(PBSEVENT_DEBUG, PBS_EVENTCLASS_NODE, id, err_msg); + } + rc = PBSE_MUTEX; } - rc = PBSE_MUTEX; + } + else + { + rc = -1; + log_err(rc, __func__, "Uninitialized mutex pass to pthread_mutex_unlock!"); } if (err_msg != NULL) diff --git a/src/server/svr_jobfunc.h b/src/server/svr_jobfunc.h index 1ea43309d5..aca9e82edd 100644 --- a/src/server/svr_jobfunc.h +++ b/src/server/svr_jobfunc.h @@ -2,53 +2,63 @@ #define _SVR_JOBFUNC_H #include "license_pbs.h" /* See here for the software license */ -#include "pbs_job.h" /* job */ -#include "attribute.h" /* pbs_attribute */ -#include "resource.h" /* resource_def */ -#include "queue.h" /* pbs_queue */ -#include "dynamic_string.h" +//#include "pbs_job.h" /* struct job */ +//#include "attribute.h" /* struct pbs_attribute */ +//#include "resource.h" /* struct resource_def */ +//#include "queue.h" /* struct pbs_queue */ +//#include "dynamic_string.h" -int svr_enquejob(job *pjob, int has_sv_qs_mutex, int); +/*Forward declarations*/ +struct job; +struct pbs_attribute; +struct resource; +struct resource_def; +struct pbs_queue; +struct dynamic_string; + +/*static int insert_into_alljobs_by_rank(struct all_jobs *aj, struct job *pjob, char *jobid);*/ + +int svr_enquejob(struct job *pjob, int has_sv_qs_mutex, int); int svr_dequejob(char *job_id, int); -int svr_setjobstate(job *pjob, int newstate, int newsubstate, int); +int svr_setjobstate(struct job *pjob, int newstate, int newsubstate, int); -void svr_evaljobstate(job *pjob, int *newstate, int *newsub, int forceeval); +void svr_evaljobstate(struct job *pjob, int *newstate, int *newsub, int forceeval); -char *get_variable(job *pjob, char *variable); +char *get_variable(struct job *pjob, char *variable); -resource *get_resource(pbs_attribute *p_queattr, pbs_attribute *p_svrattr, resource_def *rscdf, int *fromQueue); +/* static struct resource *get_resource(struct pbs_attribute *p_queattr, struct pbs_attribute *p_svrattr, struct resource_def *rscdf, int *fromQueue);*/ -/* static int chk_svr_resc_limit(pbs_attribute *jobatr, pbs_queue *pque, int qtype, char *EMsg); */ +/* static int chk_svr_resc_limit(struct pbs_attribute *jobatr, struct pbs_queue *pque, int qtype, char *EMsg); */ -int count_queued_jobs(pbs_queue *pque, char *user); +/* static int count_queued_jobs(struct pbs_queue *pque, char *user);*/ -int chk_resc_limits(pbs_attribute *pattr, pbs_queue *pque, char *EMsg); +int chk_resc_limits(struct pbs_attribute *pattr, struct pbs_queue *pque, char *EMsg); -int svr_chkque(job *pjob, pbs_queue *pque, char *hostname, int mtype, char *EMsg); +int svr_chkque(struct job *pjob, struct pbs_queue *pque, char *hostname, int mtype, char *EMsg); /* static void job_wait_over(struct work_task *pwt); */ -int job_set_wait(pbs_attribute *pattr, void *pjob, int mode); +int job_set_wait(struct pbs_attribute *pattr, void *pjob, int mode); -/* static void default_std(job *pjob, int key, char *to); */ +/* static void default_std(struct job *pjob, int key, char *to); */ -char *prefix_std_file(job *pjob, dynamic_string *ds, int key); +char *prefix_std_file(struct job *pjob, struct dynamic_string *ds, int key); -char *add_std_filename(job *pjob, char * path, int key, dynamic_string *ds); +char *add_std_filename(struct job *pjob, char * path, int key, struct dynamic_string *ds); void get_jobowner(char *from, char *to); -/* static void set_deflt_resc(pbs_attribute *jb, pbs_attribute *dflt); */ +/* static void set_deflt_resc(struct pbs_attribute *jb, struct pbs_attribute *dflt); */ -void set_resc_deflt(job *pjob, pbs_attribute *ji_wattr, int has_queue_mutex); +void set_resc_deflt(struct job *pjob, struct pbs_attribute *ji_wattr, int has_queue_mutex); -void set_chkpt_deflt(job *pjob, pbs_queue *pque); +void set_chkpt_deflt(struct job *pjob, struct pbs_queue *pque); -void set_statechar(job *pjob); +void set_statechar(struct job *pjob); -/* static void eval_checkpoint(pbs_attribute *jobckp, pbs_attribute *queckp); */ +/* static void eval_checkpoint(struct pbs_attribute *jobckp, struct pbs_attribute *queckp); */ #ifndef NDEBUG /* static void correct_ct(); */ diff --git a/src/server/test/svr_jobfunc/scaffolding.c b/src/server/test/svr_jobfunc/scaffolding.c index 9608ee7ed3..302c92ed95 100644 --- a/src/server/test/svr_jobfunc/scaffolding.c +++ b/src/server/test/svr_jobfunc/scaffolding.c @@ -11,7 +11,6 @@ #include "work_task.h" /* work_task */ #include "sched_cmds.h" /* SCH_SCHEDULE_NULL */ #include "list_link.h" /* list_link */ -#include "user_info.h" int svr_resc_size = 0; @@ -41,8 +40,21 @@ resource *add_resource_entry(pbs_attribute *pattr, resource_def *prdef) pbs_queue *find_queuebyname(char *quename) { - fprintf(stderr, "The call to find_queuebyname to be mocked!!\n"); - exit(1); + pbs_queue *pq = (pbs_queue *)calloc(1, sizeof(pbs_queue)); + + pq->qu_qs.qu_type = QTYPE_Unset; + + pq->qu_mutex = calloc(1, sizeof(pthread_mutex_t)); + pq->qu_jobs = calloc(1, sizeof(struct all_jobs)); + pq->qu_jobs_array_sum = calloc(1, sizeof(struct all_jobs)); + + snprintf(pq->qu_qs.qu_name, sizeof(pq->qu_qs.qu_name), "%s", quename); + + /* set up the user info struct */ + pq->qu_uih = calloc(1, sizeof(user_info_holder)); + + fprintf(stderr, "This mock find_queuebyname returns new pbs_queue!!\n"); + return(pq); } void account_record(int acctype, job *pjob, char *text) @@ -53,26 +65,39 @@ void account_record(int acctype, job *pjob, char *text) char *arst_string(char *str, pbs_attribute *pattr) { - fprintf(stderr, "The call to arst_string to be mocked!!\n"); - exit(1); + fprintf(stderr, "This mock arst_string always returns NULL!!\n"); + return(NULL); } int job_save(job *pjob, int updatetype, int mom_port) { - fprintf(stderr, "The call to job_save to be mocked!!\n"); - exit(1); + fprintf(stderr, "This mock job_save always returns 0!!\n"); + return(0); } long attr_ifelse_long(pbs_attribute *attr1, pbs_attribute *attr2, long deflong) { - fprintf(stderr, "The call to attr_ifelse_long to be mocked!!\n"); - exit(1); + fprintf(stderr, "This mock attr_ifelse_long always returns 0!!\n"); + return(0); } pbs_queue *get_jobs_queue(job **pjob) { - fprintf(stderr, "The call to get_jobs_queue to be mocked!!\n"); - exit(1); + pbs_queue *pq = (pbs_queue *)calloc(1, sizeof(pbs_queue)); + + pq->qu_qs.qu_type = QTYPE_Unset; + + pq->qu_mutex = calloc(1, sizeof(pthread_mutex_t)); + pq->qu_jobs = calloc(1, sizeof(struct all_jobs)); + pq->qu_jobs_array_sum = calloc(1, sizeof(struct all_jobs)); + + snprintf(pq->qu_qs.qu_name, sizeof(pq->qu_qs.qu_name), "%s", "qu_name"); + + /* set up the user info struct */ + pq->qu_uih = calloc(1, sizeof(user_info_holder)); + + fprintf(stderr, "This mock get_jobs_queue returns new pbs_queue!!\n"); + return(pq); } int procs_available(int proc_ct) @@ -101,8 +126,8 @@ int insert_job_after(struct all_jobs *aj, job *already_in, job *pjob) int has_job(struct all_jobs *aj, job *pjob) { - fprintf(stderr, "The call to has_job to be mocked!!\n"); - exit(1); + fprintf(stderr, "This mock has_job always returns 0!!\n"); + return(0); } struct work_task *set_task(enum work_type type, long event_id, void (*func)(), void *parm, int get_lock) @@ -113,8 +138,8 @@ struct work_task *set_task(enum work_type type, long event_id, void (*func)(), v int insert_job(struct all_jobs *aj, job *pjob) { - fprintf(stderr, "The call to insert_job to be mocked!!\n"); - exit(1); + fprintf(stderr, "This mock insert_job always returns 0!!\n"); + return(0); } int procs_requested(char *spec) @@ -137,20 +162,20 @@ job *next_job(struct all_jobs *aj, int *iter) job *next_job_from_back(struct all_jobs *aj, int *iter) { - fprintf(stderr, "The call to next_job_from_back to be mocked!!\n"); - exit(1); + fprintf(stderr, "This mock next_job_from_back always returns NULL!!\n"); + return(NULL); } int comp_resc2(struct pbs_attribute *attr, struct pbs_attribute *with, int IsQueueCentric, char *EMsg, enum compare_types type) { - fprintf(stderr, "The call to comp_resc2 to be mocked!!\n"); - exit(1); + fprintf(stderr, "This mock comp_resc2 always returns 0!!\n"); + return(0); } resource_def *find_resc_def(resource_def *rscdf, char *name, int limit) { - fprintf(stderr, "The call to find_resc_def to be mocked!!\n"); - exit(1); + fprintf(stderr, "This mock find_resc_def always returns NULL!!\n"); + return(NULL); } char * csv_find_string(char *csv_str, char *search_str) @@ -173,38 +198,49 @@ work_task *next_task(all_tasks *at, int *iter) pbs_queue *next_queue(all_queues *aq, int *iter) { - fprintf(stderr, "The call to next_queue to be mocked!!\n"); - exit(1); + fprintf(stderr, "This mock next_queue always returns NULL!!\n"); + return(NULL); } int remove_job(struct all_jobs *aj, job *pjob) { - fprintf(stderr, "The call to remove_job to be mocked!!\n"); - exit(1); + fprintf(stderr, "This mock remove_job always returns PBSE_JOB_RECYCLED!!\n"); + return(PBSE_JOB_RECYCLED); } int set_jobexid(job *pjob, pbs_attribute *attrry, char *EMsg) { - fprintf(stderr, "The call to set_jobexid to be mocked!!\n"); - exit(1); + fprintf(stderr, "This mock set_jobexid always returns 0!!\n"); + return(0); } int site_acl_check(job *pjob, pbs_queue *pque) { - fprintf(stderr, "The call to site_acl_check to be mocked!!\n"); - exit(1); + fprintf(stderr, "This mock site_acl_check always returns 0!!\n"); + return(0); } resource *find_resc_entry(pbs_attribute *pattr, resource_def *rscdf) { - fprintf(stderr, "The call to find_resc_entry to be mocked!!\n"); - exit(1); + fprintf(stderr, "This mock find_resc_entry always returns 0!!\n"); + return(0); } job *svr_find_job(char *jobid, int get_subjob) { - fprintf(stderr, "The call to find_job to be mocked!!\n"); - exit(1); + char *job_id = "job_id"; + + if (jobid != NULL) + { + if (strcmp(job_id,jobid) == 0) + { + static struct job job_id_job; + memset(&job_id_job, 0, sizeof(job_id_job)); + return(&job_id_job); + } + } + + return(NULL); } int insert_job_first(struct all_jobs *aj, job *pjob) @@ -215,14 +251,14 @@ int insert_job_first(struct all_jobs *aj, job *pjob) int unlock_queue(struct pbs_queue *the_queue, const char *id, char *msg, int logging) { - fprintf(stderr, "The call to unlock_queue to be mocked!!\n"); - exit(1); + fprintf(stderr, "This mock unlock_queue always returns 0!!\n"); + return(0); } int acl_check(pbs_attribute *pattr, char *name, int type) { - fprintf(stderr, "The call to acl_check to be mocked!!\n"); - exit(1); + fprintf(stderr, "This mock acl_check always returns 0!!\n"); + return(0); } int insert_task(all_tasks *at, work_task *wt) @@ -239,8 +275,8 @@ void free_str(struct pbs_attribute *attr) void *get_next(list_link pl, char *file, int line) { - fprintf(stderr, "The call to get_next to be mocked!!\n"); - exit(1); + fprintf(stderr, "This mock get_next always returns NULL!!\n"); + return(NULL); } int append_dynamic_string (dynamic_string *ds, const char *str) @@ -301,3 +337,19 @@ int decrement_queued_jobs( { return(0); } + +int get_jobs_index(struct all_jobs *aj, struct job *pjob) + { + fprintf(stderr, "This mock get_jobs_index always returns 0!!\n"); + return(0); + } + +void log_err(int error, const char *func_id, char *msg) {} + +void log_event(int eventtype, int objclass, const char *objname, char *text) {} +/* +int unlock_ji_mutex(job *pjob, const char *id, char *msg, int logging) + { + fprintf(stderr, "This mock unlock_ji_mutex always returns 0!!\n"); + return(0); + }*/ diff --git a/src/server/test/svr_jobfunc/test_svr_jobfunc.c b/src/server/test/svr_jobfunc/test_svr_jobfunc.c index c4f8af0b98..18fd2d42c5 100644 --- a/src/server/test/svr_jobfunc/test_svr_jobfunc.c +++ b/src/server/test/svr_jobfunc/test_svr_jobfunc.c @@ -1,33 +1,412 @@ #include "license_pbs.h" /* See here for the software license */ #include "svr_jobfunc.h" +#include "pbs_job.h" +#include "server.h" +#include "queue.h" +#include "attribute.h" #include "test_svr_jobfunc.h" #include #include #include "pbs_error.h" -START_TEST(test_one) +START_TEST(svr_enquejob_test) { + struct job test_job; + int result = PBSE_NONE; + /*initialize_globals*/ + server.sv_qs_mutex = calloc(1, sizeof(pthread_mutex_t)); + server.sv_attr_mutex = calloc(1, sizeof(pthread_mutex_t)); + server.sv_jobstates_mutex = calloc(1, sizeof(pthread_mutex_t)); + + pthread_mutex_init(server.sv_qs_mutex,NULL); + pthread_mutex_init(server.sv_attr_mutex,NULL); + pthread_mutex_init(server.sv_jobstates_mutex,NULL); + + memset(&test_job, 0, sizeof(test_job)); + + result = svr_enquejob(NULL, 0, 0); + fail_unless(result != PBSE_NONE, "NULL input pointer fail"); + + result = svr_enquejob(&test_job, 0, 0); + /*Need more complicated mocking in order to have other result than PBSE_JOBNOTFOUND*/ + fail_unless(result == PBSE_JOBNOTFOUND, "svr_enquejob fail: %d", result); + + } +END_TEST + +START_TEST(svr_dequejob_test) + { + char *job_id = "job_id"; + int result = PBSE_NONE; + + result = svr_dequejob(NULL, 0); + fail_unless(result != PBSE_NONE, "NULL input pointer fail"); + + result = svr_dequejob("", 0); + fail_unless(result == PBSE_JOBNOTFOUND, "empty input string fail"); + + result = svr_dequejob(job_id, 0); + fail_unless(result == PBSE_JOBNOTFOUND, "svr_dequejob fail"); + } +END_TEST + +START_TEST(svr_setjobstate_test) + { + struct job test_job; + int result = PBSE_NONE; + + memset(&test_job, 0, sizeof(test_job)); + + /*initialize_globals*/ + server.sv_qs_mutex = calloc(1, sizeof(pthread_mutex_t)); + server.sv_attr_mutex = calloc(1, sizeof(pthread_mutex_t)); + server.sv_jobstates_mutex = calloc(1, sizeof(pthread_mutex_t)); + + pthread_mutex_init(server.sv_qs_mutex,NULL); + pthread_mutex_init(server.sv_attr_mutex,NULL); + pthread_mutex_init(server.sv_jobstates_mutex,NULL); + + result = svr_setjobstate(NULL, 0, 0, 0); + fail_unless(result == PBSE_BAD_PARAMETER, "NULL input pointer fail"); + + result = svr_setjobstate(&test_job, 0, 0, 0); + fail_unless(result == PBSE_NONE, "svr_setjobstate fail"); + + result = svr_setjobstate(&test_job, 1, 2, 3); + fail_unless(result == PBSE_NONE, "svr_setjobstate fail"); } END_TEST -START_TEST(test_two) +START_TEST(svr_evaljobstate_test) { + struct job test_job; + int state = 0; + int substate = 0; + + memset(&test_job, 0, sizeof(test_job)); + + svr_evaljobstate(NULL, &state, &substate, 0); + svr_evaljobstate(&test_job, NULL, &substate, 0); + svr_evaljobstate(&test_job, &state, NULL, 0); + + test_job.ji_qs.ji_state = JOB_STATE_RUNNING; + svr_evaljobstate(&test_job, &state, &substate, 0); + fail_unless(test_job.ji_qs.ji_state == state, "svr_setjobstate state fail case 1"); + fail_unless(test_job.ji_qs.ji_substate == substate, "svr_setjobstate substate fail case 1"); + memset(&test_job, 0, sizeof(test_job)); + + test_job.ji_wattr[JOB_ATR_hold].at_val.at_long = 1; + svr_evaljobstate(&test_job, &state, &substate, 0); + fail_unless(test_job.ji_qs.ji_state == state, "svr_setjobstate state fail case 2"); + fail_unless(test_job.ji_qs.ji_substate == substate, "svr_setjobstate substate fail case 2"); + memset(&test_job, 0, sizeof(test_job)); + + test_job.ji_wattr[JOB_ATR_stagein].at_flags = 1; + svr_evaljobstate(&test_job, &state, &substate, 0); + fail_unless(test_job.ji_qs.ji_state == state, "svr_setjobstate state fail case 3"); + fail_unless(test_job.ji_qs.ji_substate == substate, "svr_setjobstate substate fail case 3"); + memset(&test_job, 0, sizeof(test_job)); + svr_evaljobstate(&test_job, &state, &substate, 0); + fail_unless(test_job.ji_qs.ji_state == state, "svr_setjobstate state fail case 4"); + fail_unless(test_job.ji_qs.ji_substate == substate, "svr_setjobstate substate fail case 4"); + memset(&test_job, 0, sizeof(test_job)); + + svr_evaljobstate(&test_job, &state, &substate, 1); + fail_unless(JOB_STATE_QUEUED == state, "svr_setjobstate state fail case 5"); + fail_unless(JOB_SUBSTATE_QUEUED == substate, "svr_setjobstate substate fail case 5"); } END_TEST +START_TEST(get_variable_test) + { + struct job test_job; + char* variable = "variable"; + char* result = NULL; + + memset(&test_job, 0, sizeof(test_job)); + + result = get_variable(NULL, variable); + fail_unless(result == NULL, "NULL input job pointer fail"); + + result = get_variable(&test_job, NULL); + fail_unless(result == NULL, "NULL input variable string pointer fail"); + + result = get_variable(&test_job, variable); + fail_unless(result == NULL, "svr_setjobstate fail"); + + } +END_TEST + +START_TEST(chk_resc_limits_test) + { + struct pbs_attribute test_attribute; + struct pbs_queue test_queue; + char message[] = "message"; + int result = -1; + + /*initialize_globals*/ + server.sv_qs_mutex = calloc(1, sizeof(pthread_mutex_t)); + server.sv_attr_mutex = calloc(1, sizeof(pthread_mutex_t)); + server.sv_jobstates_mutex = calloc(1, sizeof(pthread_mutex_t)); + + pthread_mutex_init(server.sv_qs_mutex,NULL); + pthread_mutex_init(server.sv_attr_mutex,NULL); + pthread_mutex_init(server.sv_jobstates_mutex,NULL); + + memset(&test_attribute, 0, sizeof(test_attribute)); + memset(&test_queue, 0, sizeof(test_queue)); + + result = chk_resc_limits(NULL, &test_queue, message); + fail_unless(result == PBSE_BAD_PARAMETER, "NULL input pbs_attribute pointer fail"); + + result = chk_resc_limits(&test_attribute, NULL, message); + fail_unless(result == PBSE_BAD_PARAMETER, "NULL input pbs_queue pointer fail"); + + result = chk_resc_limits(&test_attribute, &test_queue, NULL); + fail_unless(result == PBSE_NONE, "chk_resc_limits with NULL message pointer fail"); + + result = chk_resc_limits(&test_attribute, &test_queue, message); + fail_unless(result == PBSE_NONE, "chk_resc_limits fail"); + + } +END_TEST + +START_TEST(svr_chkque_test) + { + struct job test_job; + struct pbs_queue test_queue; + char* hostname = "hostname"; + int result = -1; + + /*initialize_globals*/ + server.sv_qs_mutex = calloc(1, sizeof(pthread_mutex_t)); + server.sv_attr_mutex = calloc(1, sizeof(pthread_mutex_t)); + server.sv_jobstates_mutex = calloc(1, sizeof(pthread_mutex_t)); + + pthread_mutex_init(server.sv_qs_mutex,NULL); + pthread_mutex_init(server.sv_attr_mutex,NULL); + pthread_mutex_init(server.sv_jobstates_mutex,NULL); + + memset(&test_job, 0, sizeof(test_job)); + memset(&test_queue, 0, sizeof(test_queue)); + + result = svr_chkque(NULL, &test_queue, hostname, 0, NULL); + fail_unless(result == PBSE_BAD_PARAMETER, "NULL input job pointer fail"); + + result = svr_chkque(&test_job, NULL, hostname, 0, NULL); + fail_unless(result == PBSE_BAD_PARAMETER, "NULL input pbs_queue pointer fail"); + + result = svr_chkque(&test_job, &test_queue, NULL, 0, NULL); + fail_unless(result != PBSE_NONE, "NULL input hostname pointer fail"); + + test_queue.qu_qs.qu_type = QTYPE_Execution; + result = svr_chkque(&test_job, &test_queue, hostname, 0, NULL); + fail_unless(result == PBSE_QUNOENB, "svr_chkque fail"); + + test_queue.qu_attr[QA_ATR_Enabled].at_val.at_long = 1; + result = svr_chkque(&test_job, &test_queue, hostname, 0, NULL); + fail_unless(result == PBSE_BAD_PARAMETER, "svr_chkque fail"); + + test_queue.qu_attr[QA_ATR_AclGroupEnabled].at_val.at_long = 1; + result = svr_chkque(&test_job, &test_queue, hostname, 0, NULL); + fail_unless(result != PBSE_NONE, "svr_chkque fail"); + } +END_TEST + +START_TEST(job_set_wait_test) + { + struct job test_job; + struct pbs_attribute test_attribute; + int result = -1; + + memset(&test_job, 0, sizeof(test_job)); + memset(&test_attribute, 0, sizeof(test_attribute)); + + result = job_set_wait(NULL, &test_job, 0); + fail_unless(result == PBSE_BAD_PARAMETER, "NULL input attribute pointer fail"); + + result = job_set_wait(&test_attribute, NULL, 0); + fail_unless(result == PBSE_BAD_PARAMETER, "NULL input job pointer fail"); + + result = job_set_wait(&test_attribute, &test_job, 0); + fail_unless(result == PBSE_NONE, "job_set_wait fail"); + } +END_TEST + +START_TEST(prefix_std_file_test) + { + struct job test_job; + struct dynamic_string test_string; + char *result = NULL; + + memset(&test_job, 0, sizeof(test_job)); + memset(&test_string, 0, sizeof(test_string)); + + result = prefix_std_file(NULL, &test_string, 0); + fail_unless(result == NULL, "NULL input job pointer fail"); + + result = prefix_std_file(&test_job, NULL, 0); + fail_unless(result == NULL, "NULL input dynamic_string pointer fail"); + + result = prefix_std_file(&test_job, &test_string, 0); + fail_unless(result == NULL, "prefix_std_file fail"); + + } +END_TEST + +START_TEST(add_std_filename_test) + { + struct job test_job; + char* path = "path"; + struct dynamic_string test_string; + char* result = NULL; + char* at_str = "string"; + + memset(&test_job, 0, sizeof(test_job)); + memset(&test_string, 0, sizeof(test_string)); + test_job.ji_wattr[JOB_ATR_jobname].at_val.at_str = at_str; + + result = add_std_filename(NULL, path, 0, &test_string); + fail_unless(result == NULL, "NULL input job pointer fail"); + + result = add_std_filename(&test_job, NULL, 0, &test_string); + fail_unless(result == NULL, "NULL input path pointer fail"); + + result = add_std_filename(&test_job, path, 0, NULL); + fail_unless(result == NULL, "NULL input dynamic_string pointer fail"); + + result = add_std_filename(&test_job, path, 0, &test_string); + fail_unless(result == NULL, "add_std_filename fail"); + + } +END_TEST + +START_TEST(get_jobowner_test) + { + char* from = "owner@host"; + char to[PBS_MAXUSER+1]; + + memset(to, 0, sizeof(to)); + + get_jobowner(NULL, to); + get_jobowner(from, NULL); + + get_jobowner(from, to); + fail_unless(strcmp(to,"owner") == 0, "get_jobowner fail"); + + } +END_TEST + +START_TEST(set_resc_deflt_test) + { + struct job test_job; + struct pbs_attribute test_attribute; + + /*initialize_globals*/ + server.sv_qs_mutex = calloc(1, sizeof(pthread_mutex_t)); + server.sv_attr_mutex = calloc(1, sizeof(pthread_mutex_t)); + server.sv_jobstates_mutex = calloc(1, sizeof(pthread_mutex_t)); + + pthread_mutex_init(server.sv_qs_mutex,NULL); + pthread_mutex_init(server.sv_attr_mutex,NULL); + pthread_mutex_init(server.sv_jobstates_mutex,NULL); + + memset(&test_job, 0, sizeof(test_job)); + memset(&test_attribute, 0, sizeof(test_attribute)); + + set_resc_deflt(NULL, &test_attribute, 0); + set_resc_deflt(&test_job, NULL, 0); + set_resc_deflt(&test_job, &test_attribute, 0); + set_resc_deflt(&test_job, &test_attribute, 1); + } +END_TEST + +START_TEST(set_chkpt_deflt_test) + { + struct job test_job; + struct pbs_queue test_queue; + + memset(&test_job, 0, sizeof(test_job)); + memset(&test_queue, 0, sizeof(test_queue)); + + set_chkpt_deflt(NULL, &test_queue); + set_chkpt_deflt(&test_job, NULL); + set_chkpt_deflt(&test_job, &test_queue); + } +END_TEST + +START_TEST(set_statechar_test) + { + struct job test_job; + + memset(&test_job, 0, sizeof(test_job)); + + set_statechar(NULL); + set_statechar(&test_job); + } +END_TEST + Suite *svr_jobfunc_suite(void) { Suite *s = suite_create("svr_jobfunc_suite methods"); - TCase *tc_core = tcase_create("test_one"); - tcase_add_test(tc_core, test_one); + TCase *tc_core = tcase_create("svr_enquejob_test"); + tcase_add_test(tc_core, svr_enquejob_test); + suite_add_tcase(s, tc_core); + + tc_core = tcase_create("svr_dequejob_test"); + tcase_add_test(tc_core, svr_dequejob_test); + suite_add_tcase(s, tc_core); + + tc_core = tcase_create("svr_setjobstate_test"); + tcase_add_test(tc_core, svr_setjobstate_test); + suite_add_tcase(s, tc_core); + + tc_core = tcase_create("svr_evaljobstate_test"); + tcase_add_test(tc_core, svr_evaljobstate_test); + suite_add_tcase(s, tc_core); + + tc_core = tcase_create("get_variable_test"); + tcase_add_test(tc_core, get_variable_test); + suite_add_tcase(s, tc_core); + + tc_core = tcase_create("chk_resc_limits_test"); + tcase_add_test(tc_core, chk_resc_limits_test); + suite_add_tcase(s, tc_core); + + tc_core = tcase_create("svr_chkque_test"); + tcase_add_test(tc_core, svr_chkque_test); + suite_add_tcase(s, tc_core); + + tc_core = tcase_create("job_set_wait_test"); + tcase_add_test(tc_core, job_set_wait_test); + suite_add_tcase(s, tc_core); + + tc_core = tcase_create("prefix_std_file_test"); + tcase_add_test(tc_core, prefix_std_file_test); + suite_add_tcase(s, tc_core); + + tc_core = tcase_create("add_std_filename_test"); + tcase_add_test(tc_core, add_std_filename_test); + suite_add_tcase(s, tc_core); + + tc_core = tcase_create("get_jobowner_test"); + tcase_add_test(tc_core, get_jobowner_test); + suite_add_tcase(s, tc_core); + + tc_core = tcase_create("set_resc_deflt_test"); + tcase_add_test(tc_core, set_resc_deflt_test); + suite_add_tcase(s, tc_core); + + tc_core = tcase_create("set_chkpt_deflt_test"); + tcase_add_test(tc_core, set_chkpt_deflt_test); suite_add_tcase(s, tc_core); - tc_core = tcase_create("test_two"); - tcase_add_test(tc_core, test_two); + tc_core = tcase_create("set_statechar_test"); + tcase_add_test(tc_core, set_statechar_test); suite_add_tcase(s, tc_core); return s; From 3facb48b6e8ae165569badeca3df8c92469780de Mon Sep 17 00:00:00 2001 From: VladimirStarostenkov Date: Fri, 14 Dec 2012 08:58:48 -0800 Subject: [PATCH 2/4] svr_chkque split into several static functions "Extract method" for code readability, easier unit testing*, future refactoring and optimization. *static functions are not tested separately, but it is easier to track each of them being called --- src/server/svr_jobfunc.c | 954 ++++++++++++++++++++++----------------- 1 file changed, 552 insertions(+), 402 deletions(-) diff --git a/src/server/svr_jobfunc.c b/src/server/svr_jobfunc.c index daf9341175..8d84d27945 100644 --- a/src/server/svr_jobfunc.c +++ b/src/server/svr_jobfunc.c @@ -1661,500 +1661,670 @@ int chk_resc_limits( +static int check_execution_uid_and_gid( -/* - * svr_chkque - check if job can enter a queue - * - * returns 0 for yes, 1 for no - * - * NOTE: the following fields must be set in the job struture before - * calling svr_chkque(): ji_wattr[JOB_ATR_job_owner] - * NOTE: calls chk_resc_limits() to validate resource request - * - * Also if the job is being considered for an execution queue, then - * set_jobexid() will be called. - */ - -int svr_chkque( - - job *pjob, - pbs_queue *pque, - char *hostname, - int mtype, /* MOVE_TYPE_* type, see server_limits.h */ - char *EMsg) /* O (optional,minsize=1024) */ - + struct job *const pjob, + char *const EMsg) { - int i; - int failed_group_acl = 0; - int failed_user_acl = 0; - int user_jobs; - int total_jobs; + int return_code = PBSE_NONE; /* Optimistic assumption */ - struct array_strings *pas; - int j = 0; - char jobid[PBS_MAXSVRJOBID+1]; - - if (pjob == NULL) - { - log_err(PBSE_BAD_PARAMETER, __func__, "NULL input job pointer"); - return PBSE_BAD_PARAMETER; - } - if (pque == NULL) + if (!(pjob->ji_wattr[JOB_ATR_euser].at_flags & ATR_VFLAG_SET) || + !(pjob->ji_wattr[JOB_ATR_egroup].at_flags & ATR_VFLAG_SET)) { - log_err(PBSE_BAD_PARAMETER, __func__, "NULL input pbs_queue pointer"); - return PBSE_BAD_PARAMETER; + return_code = set_jobexid(pjob, pjob->ji_wattr, EMsg); /* PBSE_BADUSER or GRP */ } - strcpy(jobid, pjob->ji_qs.ji_jobid); + return(return_code); + } - if (EMsg != NULL) - EMsg[0] = '\0'; +static int check_queue_disallowed_types( - /* - * 1. If the queue is an Execution queue ... - * This is checked first because 1a - 1c are more damaging - * (see local_move() in svr_movejob.c) - */ + struct job *const pjob, + struct pbs_queue *const pque, + char *const EMsg) + { + int return_code = PBSE_NONE; /* Optimistic assumption */ + int i = 0; - if (pque->qu_qs.qu_type == QTYPE_Execution) + if (pque->qu_attr[QA_ATR_DisallowedTypes].at_flags & ATR_VFLAG_SET) { - /* 1a. if not already set, set up execution uid/gid/name */ - - if (!(pjob->ji_wattr[JOB_ATR_euser].at_flags & ATR_VFLAG_SET) || - !(pjob->ji_wattr[JOB_ATR_egroup].at_flags & ATR_VFLAG_SET)) + for (i = 0; + i < (pque->qu_attr[QA_ATR_DisallowedTypes]).at_val.at_arst->as_usedptr; + i++) { - if ((i = set_jobexid(pjob, pjob->ji_wattr, EMsg)) != 0) + /* if job is interactive...*/ + + if ((pjob->ji_wattr[JOB_ATR_interactive].at_flags & ATR_VFLAG_SET) && + (pjob->ji_wattr[JOB_ATR_interactive].at_val.at_long > 0)) { - return(i); /* PBSE_BADUSER or GRP */ + if (pque->qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst != NULL) + { + if (strcmp(Q_DT_interactive, + pque->qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst->as_string[i]) == 0) + { + if (EMsg) + snprintf(EMsg, 1024, + "interactive job is not allowed for queue: user %s, queue %s", + pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, + pque->qu_qs.qu_name); + + return(PBSE_NOINTERACTIVE); + } + } } - } + else /* else job is batch... */ + { + if (strcmp(Q_DT_batch, + pque->qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst->as_string[i]) == 0) + { + if (EMsg) + snprintf(EMsg, 1024, + "batch job is not allowed for queue: user %s, queue %s", + pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, + pque->qu_qs.qu_name); - /* 1b. check site restrictions -- Currently site_acl_check is a stub */ + return(PBSE_NOBATCH); + } + } - if (site_acl_check(pjob, pque)) - { - if (EMsg) - snprintf(EMsg, 1024, - "site_acl_check() failed: user %s, queue %s", - pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, - pque->qu_qs.qu_name); + if (strcmp(Q_DT_rerunable, + pque->qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst->as_string[i]) == 0 + && (pjob->ji_wattr[JOB_ATR_rerunable].at_flags & ATR_VFLAG_SET && + pjob->ji_wattr[JOB_ATR_rerunable].at_val.at_long > 0)) + { + if (EMsg) + snprintf(EMsg, 1024, + "rerunable job is not allowed for queue: user %s, queue %s", + pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, + pque->qu_qs.qu_name); - return(PBSE_PERM); - } + return(PBSE_NORERUNABLE); + } - /* 1c. cannot have an unknown resource */ + if (strcmp(Q_DT_nonrerunable, + pque->qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst->as_string[i]) == 0 + && (!(pjob->ji_wattr[JOB_ATR_rerunable].at_flags & ATR_VFLAG_SET) || + pjob->ji_wattr[JOB_ATR_rerunable].at_val.at_long == 0)) + { + if (EMsg) + snprintf(EMsg, 1024, + "only rerunable jobs are allowed for queue: user %s, queue %s", + pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, + pque->qu_qs.qu_name); - if (find_resc_entry( - &pjob->ji_wattr[JOB_ATR_resource], - &svr_resc_def[svr_resc_size - 1]) != 0) - { - if (EMsg) + return(PBSE_NONONRERUNABLE); + } + if (strcmp(Q_DT_fault_tolerant, + pque->qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst->as_string[i]) == 0 + && ((pjob->ji_wattr[JOB_ATR_fault_tolerant].at_flags & ATR_VFLAG_SET) && + pjob->ji_wattr[JOB_ATR_fault_tolerant].at_val.at_long != 0)) { - snprintf(EMsg, 1024, - "detected request for an unknown resource"); + if (EMsg) + snprintf(EMsg, 1024, + "fault_tolerant jobs are not allowed for queue: user %s, queue %s", + pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, + pque->qu_qs.qu_name); + + return(PBSE_NOFAULTTOLERANT); + } + + if (strcmp(Q_DT_fault_intolerant, + pque->qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst->as_string[i]) == 0 + && (!(pjob->ji_wattr[JOB_ATR_fault_tolerant].at_flags & ATR_VFLAG_SET) || + pjob->ji_wattr[JOB_ATR_fault_tolerant].at_val.at_long == 0)) + { + if (EMsg) + snprintf(EMsg, 1024, + "only fault_tolerant jobs are allowed for queue: user %s, queue %s", + pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, + pque->qu_qs.qu_name); + + return(PBSE_NOFAULTINTOLERANT); + } + if (strcmp(Q_DT_job_array, + pque->qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst->as_string[i]) == 0 + && (pjob->ji_wattr[JOB_ATR_job_array_request].at_flags & ATR_VFLAG_SET)) + { + if (EMsg) + snprintf(EMsg, 1024, + "job arrays are not allowed for queue: queue %s", + pque->qu_qs.qu_name); + return(PBSE_NOJOBARRAYS); } - return(PBSE_UNKRESC); } + } - /* 1d. cannot have an unknown pbs_attribute */ + return(return_code); + } - if (pjob->ji_wattr[JOB_ATR_UNKN].at_flags & ATR_VFLAG_SET) +/* Special return constant for check_queue_group_ACL function */ +static const int FAILED_GROUP_ACL = -1; +static int check_queue_group_ACL( + + struct job *const pjob, + struct pbs_queue *const pque, + const int mtype, /* MOVE_TYPE_* type, see server_limits.h */ + char *const EMsg) + { + int return_code = PBSE_NONE; /* Optimistic assumption */ + + if (pque->qu_attr[QA_ATR_AclGroupEnabled].at_val.at_long) + { + int rc; + int slpygrp; + struct array_strings *pas; + + pthread_mutex_lock(server.sv_attr_mutex); + slpygrp = attr_ifelse_long( + &pque->qu_attr[QA_ATR_AclGroupSloppy], + &server.sv_attr[SRV_ATR_AclGroupSloppy], + 0); + pthread_mutex_unlock(server.sv_attr_mutex); + + rc = acl_check( + &pque->qu_attr[QA_ATR_AclGroup], + pjob->ji_wattr[JOB_ATR_egroup].at_val.at_str, + ACL_Group); + + if ((rc == 0) && slpygrp) { - if (EMsg) - snprintf(EMsg, 1024, - "detected presence of an unknown attribute"); + /* try again looking at the gids */ - return(PBSE_NOATTR); + rc = acl_check( + &pque->qu_attr[QA_ATR_AclGroup], + pjob->ji_wattr[JOB_ATR_egroup].at_val.at_str, + ACL_Gid); } - /* 1e. check queue's disallowed_types */ - - if (pque->qu_attr[QA_ATR_DisallowedTypes].at_flags & ATR_VFLAG_SET) + if ((rc == 0) && slpygrp && + (!(pjob->ji_wattr[JOB_ATR_grouplst].at_flags & ATR_VFLAG_SET))) { - for (i = 0; - i < (pque->qu_attr[QA_ATR_DisallowedTypes]).at_val.at_arst->as_usedptr; - i++) + /* check group acl against all accessible groups */ + + struct group *grp; + int i = 0; + int j = 0; + + char uname[PBS_MAXUSER + 1]; + + snprintf(uname, sizeof(uname), "%s", pjob->ji_wattr[JOB_ATR_euser].at_val.at_str); + + /* fetch the groups in the ACL and look for matching user membership */ + + pas = pque->qu_attr[QA_ATR_AclGroup].at_val.at_arst; + + for (i = 0; pas != NULL && i < pas->as_usedptr;i++) { - /* if job is interactive...*/ + if ((grp = getgrnam(pas->as_string[i])) == NULL) + continue; - if ((pjob->ji_wattr[JOB_ATR_interactive].at_flags & ATR_VFLAG_SET) && - (pjob->ji_wattr[JOB_ATR_interactive].at_val.at_long > 0)) + for (j = 0;grp->gr_mem[j] != NULL;j++) { - if (pque->qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst != NULL) + if (!strcmp(grp->gr_mem[j], uname)) { - if (strcmp(Q_DT_interactive, - pque->qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst->as_string[i]) == 0) - { - if (EMsg) - snprintf(EMsg, 1024, - "interactive job is not allowed for queue: user %s, queue %s", - pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, - pque->qu_qs.qu_name); + rc = 1; - return(PBSE_NOINTERACTIVE); - } + break; } } - else /* else job is batch... */ - { - if (strcmp(Q_DT_batch, - pque->qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst->as_string[i]) == 0) - { - if (EMsg) - snprintf(EMsg, 1024, - "batch job is not allowed for queue: user %s, queue %s", - pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, - pque->qu_qs.qu_name); - return(PBSE_NOBATCH); - } - } + if (rc == 1) + break; + } + } /* END if (rc == 0) && slpygrp && ...) */ - if (strcmp(Q_DT_rerunable, - pque->qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst->as_string[i]) == 0 - && (pjob->ji_wattr[JOB_ATR_rerunable].at_flags & ATR_VFLAG_SET && - pjob->ji_wattr[JOB_ATR_rerunable].at_val.at_long > 0)) - { - if (EMsg) - snprintf(EMsg, 1024, - "rerunable job is not allowed for queue: user %s, queue %s", - pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, - pque->qu_qs.qu_name); + if (rc == 0) + { + /* ACL not satisfied */ - return(PBSE_NORERUNABLE); - } + if (mtype != MOVE_TYPE_MgrMv) /* ok if mgr */ + { + int logic_or; - if (strcmp(Q_DT_nonrerunable, - pque->qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst->as_string[i]) == 0 - && (!(pjob->ji_wattr[JOB_ATR_rerunable].at_flags & ATR_VFLAG_SET) || - pjob->ji_wattr[JOB_ATR_rerunable].at_val.at_long == 0)) - { - if (EMsg) - snprintf(EMsg, 1024, - "only rerunable jobs are allowed for queue: user %s, queue %s", - pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, - pque->qu_qs.qu_name); + pthread_mutex_lock(server.sv_attr_mutex); + logic_or = attr_ifelse_long(&pque->qu_attr[QA_ATR_AclLogic], + &server.sv_attr[SRV_ATR_AclLogic], + 0); + pthread_mutex_unlock(server.sv_attr_mutex); - return(PBSE_NONONRERUNABLE); - } - if (strcmp(Q_DT_fault_tolerant, - pque->qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst->as_string[i]) == 0 - && ((pjob->ji_wattr[JOB_ATR_fault_tolerant].at_flags & ATR_VFLAG_SET) && - pjob->ji_wattr[JOB_ATR_fault_tolerant].at_val.at_long != 0)) + if (logic_or && pque->qu_attr[QA_ATR_AclUserEnabled].at_val.at_long) { - if (EMsg) - snprintf(EMsg, 1024, - "fault_tolerant jobs are not allowed for queue: user %s, queue %s", - pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, - pque->qu_qs.qu_name); + /* only fail if neither user nor group acls can be met */ - return(PBSE_NOFAULTTOLERANT); + return(FAILED_GROUP_ACL); } - - if (strcmp(Q_DT_fault_intolerant, - pque->qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst->as_string[i]) == 0 - && (!(pjob->ji_wattr[JOB_ATR_fault_tolerant].at_flags & ATR_VFLAG_SET) || - pjob->ji_wattr[JOB_ATR_fault_tolerant].at_val.at_long == 0)) + else { - if (EMsg) - snprintf(EMsg, 1024, - "only fault_tolerant jobs are allowed for queue: user %s, queue %s", - pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, - pque->qu_qs.qu_name); + /* no user acl, fail immediately */ + if (EMsg) snprintf(EMsg, 1024, + "group ACL is not satisfied: user %s, queue %s", + pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, + pque->qu_qs.qu_name); - return(PBSE_NOFAULTINTOLERANT); - } - if (strcmp(Q_DT_job_array, - pque->qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst->as_string[i]) == 0 - && (pjob->ji_wattr[JOB_ATR_job_array_request].at_flags & ATR_VFLAG_SET)) - { - if (EMsg) - snprintf(EMsg, 1024, - "job arrays are not allowed for queue: queue %s", - pque->qu_qs.qu_name); - return(PBSE_NOJOBARRAYS); + return(PBSE_PERM); } - } - } /* END if (pque->qu_attr[QA_ATR_DisallowedTypes].at_flags & ATR_VFLAG_SET) */ + } + } /* END if (pque->qu_attr[QA_ATR_AclGroupEnabled].at_val.at_long) */ - /* 1f. if enabled, check the queue's group ACL */ + return(return_code); + } + +static int check_queue_host_ACL( + + struct job *const pjob, + struct pbs_queue *const pque, + char *const hostname, + char *const EMsg) + { + int return_code = PBSE_NONE; /* Optimistic assumption */ - if (pque->qu_attr[QA_ATR_AclGroupEnabled].at_val.at_long) + if (pque->qu_attr[QA_ATR_AclHostEnabled].at_val.at_long) + { + if (acl_check(&pque->qu_attr[QA_ATR_AclHost], hostname, ACL_Host) == 0) { - int rc; - int slpygrp; + if (EMsg) + snprintf(EMsg, 1024, + "host ACL rejected the submitting host: user %s, queue %s, host %s", + pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, + pque->qu_qs.qu_name, + hostname); + + return(PBSE_BADHOST); + } + } + + return(return_code); + } + +/* Special return constant for check_queue_group_ACL function */ +static const int FAILED_USER_ACL = -2; +static int check_queue_user_ACL( + + struct job *const pjob, + struct pbs_queue *const pque, + char *const EMsg) + { + int return_code = PBSE_NONE; /* Optimistic assumption */ + + if (pque->qu_attr[QA_ATR_AclUserEnabled].at_val.at_long) + { + if (acl_check( + &pque->qu_attr[QA_ATR_AclUsers], + pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, + ACL_User) == 0) + { + int logic_or; pthread_mutex_lock(server.sv_attr_mutex); - slpygrp = attr_ifelse_long( - &pque->qu_attr[QA_ATR_AclGroupSloppy], - &server.sv_attr[SRV_ATR_AclGroupSloppy], - 0); + logic_or = attr_ifelse_long(&pque->qu_attr[QA_ATR_AclLogic], + &server.sv_attr[SRV_ATR_AclLogic], + 0); pthread_mutex_unlock(server.sv_attr_mutex); - rc = acl_check( - &pque->qu_attr[QA_ATR_AclGroup], - pjob->ji_wattr[JOB_ATR_egroup].at_val.at_str, - ACL_Group); + if (logic_or && pque->qu_attr[QA_ATR_AclGroupEnabled].at_val.at_long) + { + /* only fail if neither user nor group acls can be met */ - if ((rc == 0) && slpygrp) + return(FAILED_USER_ACL); + } + else { - /* try again looking at the gids */ + /* no group acl, fail immediately */ + if (EMsg) + snprintf(EMsg, 1024, + "user ACL rejected the submitting user: user %s, queue %s", + pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, + pque->qu_qs.qu_name); - rc = acl_check( - &pque->qu_attr[QA_ATR_AclGroup], - pjob->ji_wattr[JOB_ATR_egroup].at_val.at_str, - ACL_Gid); + return(PBSE_PERM); } + } + } - if ((rc == 0) && slpygrp && - (!(pjob->ji_wattr[JOB_ATR_grouplst].at_flags & ATR_VFLAG_SET))) - { - /* check group acl against all accessible groups */ + return(return_code); + } - struct group *grp; - int i; +static int check_queue_job_limit( - char uname[PBS_MAXUSER + 1]; + struct job *const pjob, + struct pbs_queue *const pque, + char *const EMsg) + { + int return_code = PBSE_NONE; /* Optimistic assumption */ + int array_jobs = 0; - snprintf(uname, sizeof(uname), "%s", pjob->ji_wattr[JOB_ATR_euser].at_val.at_str); + /* set the number of array jobs in this request if applicable */ + if (pjob->ji_is_array_template) + { + array_jobs = num_array_jobs( + pjob->ji_wattr[JOB_ATR_job_array_request].at_val.at_str); - /* fetch the groups in the ACL and look for matching user membership */ + /* only add if there wasn't an error. if there is, fail elsewhere */ + if (array_jobs > 0) + { + /* when not an array, user_jobs is the current number of jobs, not + * the number of jobs that will be added. For this reason, the + * comparison below is >= and this needs to be decremented by 1 */ + array_jobs--; + } + else + { + array_jobs = 0; + } + } - pas = pque->qu_attr[QA_ATR_AclGroup].at_val.at_arst; + if ((pque->qu_attr[QA_ATR_MaxJobs].at_flags & ATR_VFLAG_SET)) + { + int total_jobs = 0; + unlock_ji_mutex(pjob, __func__, "1", LOGLEVEL); + total_jobs = count_queued_jobs(pque, NULL); - for (i = 0; pas != NULL && i < pas->as_usedptr;i++) - { - if ((grp = getgrnam(pas->as_string[i])) == NULL) - continue; + lock_ji_mutex(pjob, __func__, "1", LOGLEVEL); + if (pjob->ji_being_recycled == TRUE) + { + unlock_ji_mutex(pjob, __func__, "1", LOGLEVEL); + return(PBSE_JOB_RECYCLED); + } - for (j = 0;grp->gr_mem[j] != NULL;j++) - { - if (!strcmp(grp->gr_mem[j], uname)) - { - rc = 1; + if ((total_jobs + array_jobs) >= pque->qu_attr[QA_ATR_MaxJobs].at_val.at_long) + { + if (EMsg) + { + snprintf(EMsg, 1024, + "total number of jobs in queue exceeds the queue limit: " + "user %s, queue %s", + pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, + pque->qu_qs.qu_name); + } - break; - } - } + return(PBSE_MAXQUED); + } + } - if (rc == 1) - break; - } - } /* END if (rc == 0) && slpygrp && ...) */ + if ((pque->qu_attr[QA_ATR_MaxUserJobs].at_flags & ATR_VFLAG_SET) && + (pque->qu_attr[QA_ATR_MaxUserJobs].at_val.at_long >= 0)) + { + int user_jobs = 0; - if (rc == 0) - { - /* ACL not satisfied */ + /* count number of jobs user has in queue */ + unlock_ji_mutex(pjob, __func__, NULL, 0); - if (mtype != MOVE_TYPE_MgrMv) /* ok if mgr */ - { - int logic_or; + user_jobs = count_queued_jobs(pque, + pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str); - pthread_mutex_lock(server.sv_attr_mutex); - logic_or = attr_ifelse_long(&pque->qu_attr[QA_ATR_AclLogic], - &server.sv_attr[SRV_ATR_AclLogic], - 0); - pthread_mutex_unlock(server.sv_attr_mutex); + lock_ji_mutex(pjob, __func__, "1", LOGLEVEL); + if (pjob->ji_being_recycled == TRUE) + { + unlock_ji_mutex(pjob, __func__, "1", LOGLEVEL); + return(PBSE_JOB_RECYCLED); + } - if (logic_or && pque->qu_attr[QA_ATR_AclUserEnabled].at_val.at_long) - { - /* only fail if neither user nor group acls can be met */ + if ((user_jobs + array_jobs) >= pque->qu_attr[QA_ATR_MaxUserJobs].at_val.at_long) + { + if (EMsg) + snprintf(EMsg, 1024, + "total number of current user's jobs exceeds the queue limit: " + "user %s, queue %s", + pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, + pque->qu_qs.qu_name); - failed_group_acl = 1; - } - else - { - /* no user acl, fail immediately */ - if (EMsg) snprintf(EMsg, 1024, - "group ACL is not satisfied: user %s, queue %s", - pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, - pque->qu_qs.qu_name); + return(PBSE_MAXUSERQUED); + } + } - return(PBSE_PERM); - } - } - } - } /* END if (pque->qu_attr[QA_ATR_AclGroupEnabled].at_val.at_long) */ - } /* END if (pque->qu_qs.qu_type == QTYPE_Execution) */ + return(return_code); + } - /* checks 2 and 3 are bypassed for a move by manager or qorder */ +static int check_queue_enabled( - if ((mtype != MOVE_TYPE_MgrMv) && (mtype != MOVE_TYPE_Order)) - { - int array_jobs = 0; + struct job *const pjob, + struct pbs_queue *const pque, + char *const EMsg) + { + int return_code = PBSE_NONE; /* Optimistic assumption */ - /* set the number of array jobs in this request if applicable */ - if (pjob->ji_is_array_template) + if (pque->qu_attr[QA_ATR_Enabled].at_val.at_long == 0) + { + if (EMsg) { - array_jobs = num_array_jobs( - pjob->ji_wattr[JOB_ATR_job_array_request].at_val.at_str); - - /* only add if there wasn't an error. if there is, fail elsewhere */ - if (array_jobs > 0) - { - /* when not an array, user_jobs is the current number of jobs, not - * the number of jobs that will be added. For this reason, the - * comparison below is >= and this needs to be decremented by 1 */ - array_jobs--; - } - else - { - array_jobs = 0; - } + snprintf(EMsg, 1024, + "queue is disabled: user %s, queue %s", + pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, + pque->qu_qs.qu_name); } - /* 2. the queue must be enabled and the job limit not exceeded */ - if (pque->qu_attr[QA_ATR_Enabled].at_val.at_long == 0) + return(PBSE_QUNOENB); + } + + return(return_code); + } + +static int check_local_route( + + struct job *const pjob, + struct pbs_queue *const pque, + const int mtype, /* MOVE_TYPE_* type, see server_limits.h */ + char *const EMsg) + { + int return_code = PBSE_NONE; /* Optimistic assumption */ + + /* if "from_route_only" is true, only local route allowed */ + if ((pque->qu_attr[QA_ATR_FromRouteOnly].at_flags & ATR_VFLAG_SET) && + (pque->qu_attr[QA_ATR_FromRouteOnly].at_val.at_long == 1)) + { + if (mtype == MOVE_TYPE_Move) /* ok if not plain user */ { if (EMsg) - { snprintf(EMsg, 1024, - "queue is disabled: user %s, queue %s", + "queue accepts only routed jobs, no direct submission: " + "user %s, queue %s", pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, pque->qu_qs.qu_name); - } - return(PBSE_QUNOENB); + return(PBSE_QACESS); } + } + return(return_code); + } + +static int are_job_resources_in_limits_of_queue( + + struct job *const pjob, + struct pbs_queue *const pque, + char *const EMsg) + { + int return_code = PBSE_NONE; /* Optimistic assumption */ + int check_limits = chk_resc_limits(&pjob->ji_wattr[JOB_ATR_resource], pque, EMsg); - if ((pque->qu_attr[QA_ATR_MaxJobs].at_flags & ATR_VFLAG_SET)) + if (check_limits != 0) + { + /* FAILURE */ + return(check_limits); + } + else + { + if (pque->qu_attr->at_val.at_str == NULL) { - unlock_ji_mutex(pjob, __func__, "1", LOGLEVEL); - total_jobs = count_queued_jobs(pque, NULL); + log_err(PBSE_BAD_PARAMETER, __func__, "pque->qu_attr->at_val.at_str uninitialized"); + return PBSE_BAD_PARAMETER; + } + if (strcmp(pque->qu_attr->at_val.at_str, "Execution") == 0) + { + /* job routed to Execution queue successfully */ + /* unset job's procct resource */ + resource_def *pctdef; + resource *pctresc; + pctdef = find_resc_def(svr_resc_def, "procct", svr_resc_size); + if ((pctresc = find_resc_entry(&pjob->ji_wattr[JOB_ATR_resource], pctdef)) != NULL) + pctdef->rs_free(&pctresc->rs_value); + } + } - lock_ji_mutex(pjob, __func__, "1", LOGLEVEL); - if (pjob->ji_being_recycled == TRUE) - { - unlock_ji_mutex(pjob, __func__, "1", LOGLEVEL); - return(PBSE_JOB_RECYCLED); - } + return(return_code); + } - if ((total_jobs + array_jobs) >= pque->qu_attr[QA_ATR_MaxJobs].at_val.at_long) - { - if (EMsg) - { - snprintf(EMsg, 1024, - "total number of jobs in queue exceeds the queue limit: " - "user %s, queue %s", - pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, - pque->qu_qs.qu_name); - } +/* + * svr_chkque - check if job can enter a queue + * + * returns 0 for yes, 1 for no + * + * NOTE: the following fields must be set in the job struture before + * calling svr_chkque(): ji_wattr[JOB_ATR_job_owner] + * NOTE: calls chk_resc_limits() to validate resource request + * + * Also if the job is being considered for an execution queue, then + * set_jobexid() will be called. + */ - return(PBSE_MAXQUED); - } - } +int svr_chkque( - if ((pque->qu_attr[QA_ATR_MaxUserJobs].at_flags & ATR_VFLAG_SET) && - (pque->qu_attr[QA_ATR_MaxUserJobs].at_val.at_long >= 0)) - { - /* count number of jobs user has in queue */ - unlock_ji_mutex(pjob, __func__, NULL, 0); + job *pjob, + pbs_queue *pque, + char *hostname, + int mtype, /* MOVE_TYPE_* type, see server_limits.h */ + char *EMsg) /* O (optional,minsize=1024) */ + + { + int failed_group_acl = 0; + int failed_host_acl = 0; + int failed_user_acl = 0; + + if (pjob == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input job pointer"); + return PBSE_BAD_PARAMETER; + } + if (pque == NULL) + { + log_err(PBSE_BAD_PARAMETER, __func__, "NULL input pbs_queue pointer"); + return PBSE_BAD_PARAMETER; + } + + if (EMsg != NULL) + EMsg[0] = '\0'; - user_jobs = count_queued_jobs(pque, - pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str); - lock_ji_mutex(pjob, __func__, "1", LOGLEVEL); - if (pjob->ji_being_recycled == TRUE) + /* + * 1. If the queue is an Execution queue ... + * This is checked first because 1a - 1c are more damaging + * (see local_move() in svr_movejob.c) + */ + if (pque->qu_qs.qu_type == QTYPE_Execution) + { + /* 1a. if not already set, set up execution uid/gid/name */ + int can_be_established = 0; + int are_allowed = 0; + + can_be_established = check_execution_uid_and_gid(pjob, EMsg); + if (can_be_established != PBSE_NONE) { - unlock_ji_mutex(pjob, __func__, "1", LOGLEVEL); - return(PBSE_JOB_RECYCLED); + return(can_be_established); } - if ((user_jobs + array_jobs) >= pque->qu_attr[QA_ATR_MaxUserJobs].at_val.at_long) - { - if (EMsg) - snprintf(EMsg, 1024, - "total number of current user's jobs exceeds the queue limit: " - "user %s, queue %s", - pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, - pque->qu_qs.qu_name); + /* 1b. check site restrictions -- Currently site_acl_check is a stub */ + if (site_acl_check(pjob, pque)) + { + if (EMsg) + snprintf(EMsg, 1024, + "site_acl_check() failed: user %s, queue %s", + pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, + pque->qu_qs.qu_name); - return(PBSE_MAXUSERQUED); + return(PBSE_PERM); + } + + /* 1c. cannot have an unknown resource */ + if (find_resc_entry( + &pjob->ji_wattr[JOB_ATR_resource], + &svr_resc_def[svr_resc_size - 1]) != 0) + { + if (EMsg) + { + snprintf(EMsg, 1024, + "detected request for an unknown resource"); } + + return(PBSE_UNKRESC); } - /* 3. if "from_route_only" is true, only local route allowed */ + /* 1d. cannot have an unknown pbs_attribute */ + if (pjob->ji_wattr[JOB_ATR_UNKN].at_flags & ATR_VFLAG_SET) + { + if (EMsg) + snprintf(EMsg, 1024, + "detected presence of an unknown attribute"); + + return(PBSE_NOATTR); + } - if ((pque->qu_attr[QA_ATR_FromRouteOnly].at_flags & ATR_VFLAG_SET) && - (pque->qu_attr[QA_ATR_FromRouteOnly].at_val.at_long == 1)) + /* 1e. check queue's disallowed_types */ + are_allowed = check_queue_disallowed_types(pjob, pque, EMsg); + if (are_allowed != PBSE_NONE) { - if (mtype == MOVE_TYPE_Move) /* ok if not plain user */ - { - if (EMsg) - snprintf(EMsg, 1024, - "queue accepts only routed jobs, no direct submission: " - "user %s, queue %s", - pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, - pque->qu_qs.qu_name); + return(are_allowed); + } - return(PBSE_QACESS); - } + /* 1f. if enabled, check the queue's group ACL */ + failed_group_acl = check_queue_group_ACL(pjob, pque, mtype, EMsg); + if (failed_group_acl == PBSE_PERM) + { + return(failed_group_acl); } - } + } /* END if (pque->qu_qs.qu_type == QTYPE_Execution) */ - /* checks 4, 5, and 6 are bypassed for a move by manager */ - if (mtype != MOVE_TYPE_MgrMv) + /* checks 2 and 3 are bypassed for a move by manager or qorder */ + if ((mtype != MOVE_TYPE_MgrMv) && (mtype != MOVE_TYPE_Order)) { - /* 4. if enabled, check the queue's host ACL */ + int queue_job_limit = 0; + int queue_enabled = 0; + int local_route = 0; - if (pque->qu_attr[QA_ATR_AclHostEnabled].at_val.at_long) + /* 2. the queue must be enabled and the job limit not exceeded */ + queue_enabled = check_queue_enabled(pjob, pque, EMsg); + if (queue_enabled != PBSE_NONE) { - if (acl_check(&pque->qu_attr[QA_ATR_AclHost], hostname, ACL_Host) == 0) - { - if (EMsg) - snprintf(EMsg, 1024, - "host ACL rejected the submitting host: user %s, queue %s, host %s", - pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, - pque->qu_qs.qu_name, - hostname); - - return(PBSE_BADHOST); - } + return(queue_enabled); } - /* 5. if enabled, check the queue's user ACL */ + queue_job_limit = check_queue_job_limit(pjob, pque, EMsg); + if (queue_job_limit != PBSE_NONE) + { + return(queue_job_limit); + } - if (pque->qu_attr[QA_ATR_AclUserEnabled].at_val.at_long) + /* 3. if "from_route_only" is true, only local route allowed */ + local_route = check_local_route(pjob, pque, mtype, EMsg); + if (local_route != PBSE_NONE) { - if (acl_check( - &pque->qu_attr[QA_ATR_AclUsers], - pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, - ACL_User) == 0) - { - int logic_or; + return(local_route); + } + } - pthread_mutex_lock(server.sv_attr_mutex); - logic_or = attr_ifelse_long(&pque->qu_attr[QA_ATR_AclLogic], - &server.sv_attr[SRV_ATR_AclLogic], - 0); - pthread_mutex_unlock(server.sv_attr_mutex); + /* checks 4, 5, and 6 are bypassed for a move by manager */ - if (logic_or && pque->qu_attr[QA_ATR_AclGroupEnabled].at_val.at_long) - { - /* only fail if neither user nor group acls can be met */ + if (mtype != MOVE_TYPE_MgrMv) + { + int job_resources_in_limits_of_queue = 0; - failed_user_acl = 1; - } - else - { - /* no group acl, fail immediately */ - if (EMsg) - snprintf(EMsg, 1024, - "user ACL rejected the submitting user: user %s, queue %s", - pjob->ji_wattr[JOB_ATR_job_owner].at_val.at_str, - pque->qu_qs.qu_name); + /* 4. if enabled, check the queue's host ACL */ + failed_host_acl = check_queue_host_ACL(pjob, pque, hostname, EMsg); + if (failed_host_acl != PBSE_NONE) + { + return(failed_host_acl); + } - return(PBSE_PERM); - } - } + /* 5. if enabled, check the queue's user ACL */ + failed_user_acl = check_queue_user_ACL(pjob, pque, EMsg); + if (failed_user_acl == PBSE_PERM) + { + return(failed_user_acl); } /* 5.5. if failed user and group acls, fail */ - if (failed_group_acl && failed_user_acl) { if (EMsg) snprintf(EMsg, 1024, @@ -2167,37 +2337,17 @@ int svr_chkque( } /* 6. resources of the job must be in the limits of the queue */ - - if ((i = chk_resc_limits(&pjob->ji_wattr[JOB_ATR_resource], pque, EMsg)) != 0) + job_resources_in_limits_of_queue = are_job_resources_in_limits_of_queue(pjob, pque, EMsg); + if (job_resources_in_limits_of_queue != PBSE_NONE) { - /* FAILURE */ - - return(i); + return(job_resources_in_limits_of_queue); } - else - { - if (pque->qu_attr->at_val.at_str == NULL) - { - log_err(PBSE_BAD_PARAMETER, __func__, "pque->qu_attr->at_val.at_str uninitialized"); - return PBSE_BAD_PARAMETER; - } - if (strcmp(pque->qu_attr->at_val.at_str, "Execution") == 0) - { - /* job routed to Execution queue successfully */ - /* unset job's procct resource */ - resource_def *pctdef; - resource *pctresc; - pctdef = find_resc_def(svr_resc_def, "procct", svr_resc_size); - if ((pctresc = find_resc_entry(&pjob->ji_wattr[JOB_ATR_resource], pctdef)) != NULL) - pctdef->rs_free(&pctresc->rs_value); - } - } } /* END if (mtype != MOVE_TYPE_MgrMv) */ /* SUCCESS - job can enter queue */ - return(0); + return(PBSE_NONE); } /* END svr_chkque() */ @@ -2986,16 +3136,16 @@ int lock_ji_mutex( if (pjob->ji_mutex != NULL) { - if (pthread_mutex_lock(pjob->ji_mutex) != 0) - { - if (logging >= 20) + if (pthread_mutex_lock(pjob->ji_mutex) != 0) { - snprintf(err_msg, MSG_LEN_LONG, "ALERT: cannot lock job %s mutex in method %s", - pjob->ji_qs.ji_jobid, id); - log_record(PBSEVENT_DEBUG, PBS_EVENTCLASS_NODE, id, err_msg); + if (logging >= 20) + { + snprintf(err_msg, MSG_LEN_LONG, "ALERT: cannot lock job %s mutex in method %s", + pjob->ji_qs.ji_jobid, id); + log_record(PBSEVENT_DEBUG, PBS_EVENTCLASS_NODE, id, err_msg); + } + rc = PBSE_MUTEX; } - rc = PBSE_MUTEX; - } } else { From 1436ecd1b2855d5e22a86c3acddf8b991514a0df Mon Sep 17 00:00:00 2001 From: VladimirStarostenkov Date: Fri, 14 Dec 2012 10:28:59 -0800 Subject: [PATCH 3/4] Several test cases for svr_chkque --- .../test/svr_jobfunc/test_svr_jobfunc.c | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/server/test/svr_jobfunc/test_svr_jobfunc.c b/src/server/test/svr_jobfunc/test_svr_jobfunc.c index 18fd2d42c5..c78c53127f 100644 --- a/src/server/test/svr_jobfunc/test_svr_jobfunc.c +++ b/src/server/test/svr_jobfunc/test_svr_jobfunc.c @@ -179,6 +179,7 @@ START_TEST(svr_chkque_test) { struct job test_job; struct pbs_queue test_queue; + struct array_strings disallowed_types_array_strings; char* hostname = "hostname"; int result = -1; @@ -214,6 +215,45 @@ START_TEST(svr_chkque_test) test_queue.qu_attr[QA_ATR_AclGroupEnabled].at_val.at_long = 1; result = svr_chkque(&test_job, &test_queue, hostname, 0, NULL); fail_unless(result != PBSE_NONE, "svr_chkque fail"); + + + /* several test cases for check_queue_disallowed_types (not all)*/ + memset(&test_job, 0, sizeof(test_job)); + memset(&test_queue, 0, sizeof(test_queue)); + memset(&disallowed_types_array_strings, + 0, + sizeof(disallowed_types_array_strings)); + + test_queue.qu_qs.qu_type = QTYPE_Execution; + test_queue.qu_attr[QA_ATR_DisallowedTypes].at_flags = ATR_VFLAG_SET; + test_queue.qu_attr[QA_ATR_DisallowedTypes].at_val.at_arst = &disallowed_types_array_strings; + char* some_string = "some_string"; + disallowed_types_array_strings.as_string[0] = some_string; + disallowed_types_array_strings.as_usedptr = 1; + + result = svr_chkque(&test_job, &test_queue, hostname, 0, NULL); + fail_unless(result == PBSE_QUNOENB, "svr_chkque some_string fail"); + + disallowed_types_array_strings.as_string[0] = Q_DT_batch; + result = svr_chkque(&test_job, &test_queue, hostname, 0, NULL); + fail_unless(result == PBSE_NOBATCH, "svr_chkque PBSE_NOBATCH fail"); + + disallowed_types_array_strings.as_string[0] = Q_DT_rerunable; + test_job.ji_wattr[JOB_ATR_rerunable].at_flags = ATR_VFLAG_SET; + test_job.ji_wattr[JOB_ATR_rerunable].at_val.at_long = 1; + result = svr_chkque(&test_job, &test_queue, hostname, 0, NULL); + fail_unless(result == PBSE_NORERUNABLE, "svr_chkque PBSE_NORERUNABLE fail"); + + disallowed_types_array_strings.as_string[0] = Q_DT_nonrerunable; + test_job.ji_wattr[JOB_ATR_rerunable].at_val.at_long = 0; + result = svr_chkque(&test_job, &test_queue, hostname, 0, NULL); + fail_unless(result == PBSE_NONONRERUNABLE, "svr_chkque PBSE_NONONRERUNABLE fail"); + + disallowed_types_array_strings.as_usedptr = 2; + disallowed_types_array_strings.as_string[0] = some_string; + disallowed_types_array_strings.as_string[1] = Q_DT_fault_intolerant; + result = svr_chkque(&test_job, &test_queue, hostname, 0, NULL); + fail_unless(result == PBSE_NOFAULTINTOLERANT, "svr_chkque PBSE_NOFAULTINTOLERANT fail"); } END_TEST From 1492be4476e78c26fe2a5e3595a601bbf1978211 Mon Sep 17 00:00:00 2001 From: VladimirStarostenkov Date: Fri, 14 Dec 2012 10:31:10 -0800 Subject: [PATCH 4/4] Remove commented includes --- src/server/svr_jobfunc.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/server/svr_jobfunc.h b/src/server/svr_jobfunc.h index aca9e82edd..76eac2f5b3 100644 --- a/src/server/svr_jobfunc.h +++ b/src/server/svr_jobfunc.h @@ -2,12 +2,6 @@ #define _SVR_JOBFUNC_H #include "license_pbs.h" /* See here for the software license */ -//#include "pbs_job.h" /* struct job */ -//#include "attribute.h" /* struct pbs_attribute */ -//#include "resource.h" /* struct resource_def */ -//#include "queue.h" /* struct pbs_queue */ -//#include "dynamic_string.h" - /*Forward declarations*/ struct job; struct pbs_attribute;