diff --git a/src/cmds/pbsnodes.c b/src/cmds/pbsnodes.c index ab0bbf0..61658c7 100644 --- a/src/cmds/pbsnodes.c +++ b/src/cmds/pbsnodes.c @@ -207,10 +207,11 @@ static void prt_node_attr( continue; } - printf(" %s = %s\n", + if (pat->resource != NULL && (strcmp(pat->resource,"") != 0)) + printf("\t%s.%s = %s\n", pat->name, pat->resource, pat->value); + else + printf("\t%s = %s\n", pat->name, pat->value); - pat->name, - pat->value); } /* END for (pat) */ return; @@ -406,7 +407,17 @@ void addxmlnode( if (pat->value == NULL) continue; - MXMLCreateE(&AE, pat->name); + if (pat->resource != NULL && (strcmp(pat->resource,"") != 0)) + { + char *buffer = malloc(strlen(pat->name)+strlen(pat->resource)+2); + strcpy(buffer,pat->name); + strcat(buffer,"."); + strcat(buffer,pat->resource); + MXMLCreateE(&AE, buffer); + free(buffer); + } + else + MXMLCreateE(&AE, pat->name); MXMLSetVal(AE, pat->value, mdfString); diff --git a/src/include/attribute.h b/src/include/attribute.h index 069fa87..1016754 100644 --- a/src/include/attribute.h +++ b/src/include/attribute.h @@ -275,6 +275,7 @@ typedef struct attribute_def attribute_def; #define ATR_VFLAG_MODIFY 0x02 /* value has been modified */ #define ATR_VFLAG_DEFLT 0x04 /* value is default value */ #define ATR_VFLAG_SEND 0x08 /* value to be sent to server */ +#define ATR_VFLAG_FORCED 0x10 /* this value is forced by config */ #define ATR_TRUE "True" #define ATR_FALSE "False" @@ -451,6 +452,7 @@ extern int set_node_ntype A_((attribute*, attribute*, enum batch_op)); extern int set_node_props A_((attribute*, attribute*, enum batch_op)); extern int set_null A_((attribute*, attribute*, enum batch_op)); extern int node_state A_((attribute*, void*, int)); +extern int node_resources_action(attribute*, void*, int); extern int node_np_action A_((attribute*, void*, int)); extern int node_ntype A_((attribute*, void*, int)); extern int node_prop_list A_((attribute*, void*, int)); @@ -458,6 +460,7 @@ extern int node_status_list A_((attribute*, void*, int)); extern int node_note A_((attribute*, void*, int)); extern int set_note_str A_((attribute *attr, attribute *new, enum batch_op)); extern void replace_attr_string A_((attribute*, char*)); +extern int count_resc(attribute*); /* Token manipulation functions */ diff --git a/src/include/pbs_error_db.h b/src/include/pbs_error_db.h index 81c8c7c..7f249f5 100644 --- a/src/include/pbs_error_db.h +++ b/src/include/pbs_error_db.h @@ -193,6 +193,12 @@ PbsErrClient(PBSE_NOFAULTTOLERANT, "Queue does not allow fault tolerant jobs") /* only fault tolerant jobs allowed in queue */ PbsErrClient(PBSE_NOFAULTINTOLERANT, "Queue does not allow fault intolerant jobs") PbsErrClient(PBSE_NOJOBARRAYS, "Queue does not allow job arrays") +/* Routine preconditions test failed */ +PbsErrClient(PBSE_PRECONDITION, "Routine precondition failed.") +/* Routine postconditions test failed */ +PbsErrClient(PBSE_POSTCONDITION, "Routine postcondition failed.") +/* Routine consistency test failed */ +PbsErrClient(PBSE_CONSISTENCY, "Routine consistency check failed.") /* pbs client errors ceiling (max_client_err + 1) */ PbsErrClient(PBSE_CEILING, (char*)0) #endif diff --git a/src/include/pbs_ifl.h b/src/include/pbs_ifl.h index cd6d9d7..c056941 100644 --- a/src/include/pbs_ifl.h +++ b/src/include/pbs_ifl.h @@ -291,6 +291,8 @@ #define ATTR_npdefault "np_default" #define ATTR_jobstarttimeout "job_start_timeout" #define ATTR_jobforcecanceltime "job_force_cancel_time" +#define ATTR_ResourcesToStore "node_resources_to_store" +#define ATTR_ResourcesMappings "node_resources_mappings" /* additional node "attributes" names */ @@ -301,6 +303,8 @@ #define ATTR_NODE_jobs "jobs" #define ATTR_NODE_status "status" #define ATTR_NODE_note "note" +#define ATTR_NODE_resources_total "resources_total" +#define ATTR_NODE_resources_used "resources_used" /* notification email formating */ #define ATTR_mailsubjectfmt "mail_subject_fmt" diff --git a/src/include/pbs_job.h b/src/include/pbs_job.h index e8bcc9c..cdc3227 100644 --- a/src/include/pbs_job.h +++ b/src/include/pbs_job.h @@ -485,6 +485,8 @@ struct job int ji_isparent; /* set to TRUE if this is a "parent job"*/ #endif/* PBS_MOM */ /* END SERVER ONLY */ + char *ji_expanded_spec; /* pre-parsed nodespec */ + /* * fixed size internal data - maintained via "quick save" * some of the items are copies of attributes, if so this diff --git a/src/include/pbs_nodes.h b/src/include/pbs_nodes.h index 3723eb5..d45c665 100644 --- a/src/include/pbs_nodes.h +++ b/src/include/pbs_nodes.h @@ -85,6 +85,9 @@ /* NOTE: requires server_limits.h */ +#include "attribute.h" + + #define BM_ERROR -20 enum psit @@ -98,6 +101,7 @@ enum psit struct prop { char *name; + char *value; /* for resources */ short mark; struct prop *next; @@ -107,23 +111,21 @@ struct jobinfo { struct job *job; + int order; struct jobinfo *next; }; struct pbssubn { - struct pbsnode *host; - struct pbssubn *next; - - struct jobinfo *jobs; /* list of jobs allocating resources within subnode */ - /* does this include suspended jobs? */ + struct jobinfo *jobs; /* list of jobs allocating resources within subnode */ + /* does this include suspended jobs? */ resource_t allocto; - enum psit flag; /* XXX */ + enum psit flag; /* XXX */ unsigned short inuse; - short index; /* subnode index */ + short index; /* subnode index */ }; struct pbsnode @@ -158,6 +160,8 @@ struct pbsnode short nd_order; /* order of user's request */ time_t nd_warnbad; time_t nd_lastupdate; /* time of last update. */ + + struct attribute attributes[2]; /* resources_total, resources_used */ }; struct howl @@ -255,6 +259,8 @@ enum nodeattr ND_ATR_jobs, ND_ATR_status, ND_ATR_note, + ND_ATR_resources_total, + ND_ATR_resources_used, ND_ATR_LAST }; /* WARNING: Must be the highest valued enum */ @@ -287,7 +293,8 @@ extern void free_prop_list A_((struct prop*)); extern void free_prop_attr A_((attribute*)); extern void recompute_ntype_cnts A_(()); extern int create_pbs_node A_((char *, svrattrl *, int, int *)); -extern int mgr_set_node_attr A_((struct pbsnode *, attribute_def *, int, svrattrl *, int, int *, void *, int)); +extern int mgr_set_node_attr(struct pbsnode *, attribute_def *, int, svrattrl *, int, int *, void *, int); +extern int mgr_set_attr(attribute *pattr, attribute_def*, int, svrattrl*, int, int*, void*, int, int); struct prop *init_prop A_((char *pname)); #endif /* BATCH_REQUEST_H */ diff --git a/src/include/qmgr_node_public.h b/src/include/qmgr_node_public.h index 81a2abe..4086e8a 100644 --- a/src/include/qmgr_node_public.h +++ b/src/include/qmgr_node_public.h @@ -96,3 +96,5 @@ ATTR_NODE_np, ATTR_NODE_ntype, ATTR_NODE_status, ATTR_NODE_note, +ATTR_NODE_resources_total, + diff --git a/src/include/qmgr_node_readonly.h b/src/include/qmgr_node_readonly.h index 9ba0a0f..e32772b 100644 --- a/src/include/qmgr_node_readonly.h +++ b/src/include/qmgr_node_readonly.h @@ -94,3 +94,4 @@ */ ATTR_NODE_jobs, +ATTR_NODE_resources_used, diff --git a/src/include/qmgr_svr_public.h b/src/include/qmgr_svr_public.h index e8e596c..b6c30a1 100644 --- a/src/include/qmgr_svr_public.h +++ b/src/include/qmgr_svr_public.h @@ -157,3 +157,5 @@ ATTR_mailbodyfmt, ATTR_npdefault, ATTR_jobstarttimeout, ATTR_jobforcecanceltime, +ATTR_ResourcesToStore, +ATTR_ResourcesMappings, diff --git a/src/include/server.h b/src/include/server.h index 8c57615..6b01342 100644 --- a/src/include/server.h +++ b/src/include/server.h @@ -173,6 +173,8 @@ enum srv_atr SRV_ATR_NPDefault, SRV_ATR_JobStartTimeout, SRV_ATR_JobForceCancelTime, + SRV_ATR_ResourcesToStore, + SRV_ATR_ResourcesMappings, #include "site_svr_attr_enum.h" /* This must be last */ SRV_ATR_LAST diff --git a/src/lib/Libattr/attr_atomic.c b/src/lib/Libattr/attr_atomic.c index 49197ce..c665d44 100644 --- a/src/lib/Libattr/attr_atomic.c +++ b/src/lib/Libattr/attr_atomic.c @@ -152,7 +152,13 @@ int attr_atomic_set( } else { - index = unkn; /* if unknown attr are allowed */ + if (unkn != 0) + index = unkn; /* if unknown attr are allowed */ + else /* simply jump over unknown */ + { + plist = (struct svrattrl *)GET_NEXT(plist->al_link); + continue; + } } } @@ -291,6 +297,7 @@ attr_atomic_node_set( attribute temp; listidx = 0; + resc_access_perm = privil; /* set privilege for decode_resc() */ while (plist) { @@ -306,7 +313,12 @@ attr_atomic_node_set( break; } else - index = unkn; /*if unknown attr are allowed*/ + { + /*index = unkn;*/ /*if unknown attr are allowed*/ + /* if unknown enabled, then simply ignore it */ + plist = (struct svrattrl *)GET_NEXT(plist->al_link); + continue; + } } diff --git a/src/lib/Libattr/attr_fn_resc.c b/src/lib/Libattr/attr_fn_resc.c index 68bec25..5885823 100644 --- a/src/lib/Libattr/attr_fn_resc.c +++ b/src/lib/Libattr/attr_fn_resc.c @@ -199,6 +199,7 @@ int decode_resc( patr->at_flags |= ATR_VFLAG_SET | ATR_VFLAG_MODIFY; rv = prdef->rs_decode(&prsc->rs_value, name, rescn, val); + prsc->rs_value.at_flags |= ATR_VFLAG_FORCED; if (rv == 0) { @@ -363,7 +364,7 @@ int set_resc( { /* call resource type dependent set routine */ - + oldresc->rs_value.at_flags |= (newresc->rs_value.at_flags & ATR_VFLAG_FORCED); if ((rc = oldresc->rs_defin->rs_set(&oldresc->rs_value, &newresc->rs_value, local_op)) != 0) return (rc); @@ -383,6 +384,36 @@ int set_resc( +/* count resources in list */ +int count_resc(struct attribute *attr) + { + resource *wiresc; + int count = 0; + + if (attr == NULL) + { + /* FAILURE */ + + return(-1); + } + + wiresc = (resource *)GET_NEXT(attr->at_val.at_list); + + while (wiresc != NULL) + { + if ((wiresc->rs_value.at_flags & ATR_VFLAG_SET) && + ((wiresc->rs_value.at_flags & ATR_VFLAG_DEFLT) == 0)) + { + count++; + } + wiresc = (resource *)GET_NEXT(wiresc->rs_link); + } /* END while() */ + + return(count); + } /* END comp_resc() */ + + + /* * comp_resc - compare two attributes of type ATR_TYPE_RESR diff --git a/src/server/node_attr_def.c b/src/server/node_attr_def.c index 9af5008..262c7f9 100644 --- a/src/server/node_attr_def.c +++ b/src/server/node_attr_def.c @@ -211,4 +211,30 @@ attribute_def node_attr_def[] = PARENT_TYPE_NODE, }, + /* ND_ATR_resources_total */ + { ATTR_NODE_resources_total, + decode_resc, + encode_resc, + set_resc, + comp_resc, + free_resc, + NULL_FUNC, + MGR_ONLY_SET, + ATR_TYPE_RESC, + PARENT_TYPE_NODE, + }, + + /* ND_ATR_resources_used */ + { ATTR_NODE_resources_used, + decode_resc, + encode_resc, + set_resc, + comp_resc, + free_resc, + NULL_FUNC, + READ_ONLY, + ATR_TYPE_RESC, + PARENT_TYPE_NODE, + }, + }; diff --git a/src/server/node_func.c b/src/server/node_func.c index b11bd1f..c685e5e 100644 --- a/src/server/node_func.c +++ b/src/server/node_func.c @@ -431,6 +431,7 @@ static short old_ntype = (short)0xdead; /*node's ntype */ static int old_nprops = 0xdead; /*node's nprops */ static int old_nstatus = 0xdead; /*node's nstatus */ static char *old_note = NULL; /*node's note */ +static struct attribute *old_resources = (struct attribute*)0; @@ -472,6 +473,15 @@ void save_characteristic( old_note = strdup(pnode->nd_note); } + if (old_resources == NULL) + old_resources = malloc(sizeof(struct attribute)); + + if (old_resources == NULL) + return; /* XXX silent death */ + + clear_attr(old_resources,&node_attr_def[ND_ATR_resources_total]); + node_attr_def[ND_ATR_resources_total].at_set(old_resources,&pnode->attributes[0],SET); + return; } /* END save_characteristic() */ @@ -479,6 +489,8 @@ void save_characteristic( + + /* * chk_characteristic() - check the value of the characteristics against * that which was saved earlier. @@ -488,8 +500,6 @@ void save_characteristic( * bit(s) set depending on the results of the check. * The "returned" bits get used by the caller. */ - - int chk_characteristic( struct pbsnode *pnode, /* I */ @@ -498,6 +508,10 @@ int chk_characteristic( { short tmp; char tmpLine[1024]; +/* extern int comp_resc_eq;*/ + extern int comp_resc_gt; + extern int comp_resc_lt; + extern int comp_resc_nc; if ((pnode != old_address) || (pnode == NULL)) { @@ -575,6 +589,16 @@ int chk_characteristic( old_address = NULL; + + if (node_attr_def[ND_ATR_resources_total].at_comp(&pnode->attributes[0],old_resources) == 0) + { + if (count_resc(&pnode->attributes[0]) != count_resc(old_resources)) + *pneed_todo |= WRITE_NEW_NODESFILE; + + if (comp_resc_lt != 0 || comp_resc_gt != 0 || comp_resc_nc != 0) + *pneed_todo |= WRITE_NEW_NODESFILE; + } + return(0); } /* END chk_characteristic() */ @@ -631,7 +655,17 @@ int status_nodeattrib( else if (!strcmp((padef + i)->at_name, ATTR_NODE_np)) atemp[i].at_val.at_long = pnode->nd_nsn; else if (!strcmp((padef + i)->at_name, ATTR_NODE_note)) - atemp[i].at_val.at_str = pnode->nd_note; + atemp[i].at_val.at_str = pnode->nd_note; + else if (!strcmp((padef + i)->at_name, ATTR_NODE_resources_total)) + { + clear_attr(&atemp[i],(padef+i)); + (padef+i)->at_set(&atemp[i],&pnode->attributes[0],SET); + } + else if (!strcmp((padef + i)->at_name, ATTR_NODE_resources_used)) + { + clear_attr(&atemp[i],(padef+i)); + (padef+i)->at_set(&atemp[i],&pnode->attributes[1],SET); + } else { /*we don't ever expect this*/ @@ -788,6 +822,10 @@ static void initialize_pbsnode( tinsert(pul[i], pnode, &ipaddrs); } /* END for (i) */ + /* clear the resource atributes */ + clear_attr(&pnode->attributes[0], &node_attr_def[ND_ATR_resources_total]); + clear_attr(&pnode->attributes[1], &node_attr_def[ND_ATR_resources_used]); + return; } /* END initialize_pbsnode() */ @@ -886,13 +924,15 @@ void effective_node_delete( pnode->nd_nsn = 0; pnode->nd_nsnfree = 0; + /* free resource attributes */ + node_attr_def[ND_ATR_resources_total].at_free(&pnode->attributes[0]); + node_attr_def[ND_ATR_resources_used].at_free(&pnode->attributes[1]); + return; } /* END effective_node_delete() */ - - /** * NOTE: pul can return NULL even on SUCCESS of routine * @@ -1164,6 +1204,8 @@ update_nodes_file(void) #endif struct pbsnode *np; + tlist_head head; + resource *res; int i, j; FILE *nin; @@ -1222,6 +1264,25 @@ update_nodes_file(void) ATTR_NODE_np, np->nd_nsn); + /* write out resources */ + head = np->attributes[0].at_val.at_list; + while ((res = (resource*)GET_NEXT(head))) + { + if (res != 0 && (res->rs_value.at_flags & ATR_VFLAG_FORCED)) + { + tlist_head head; + svrattrl *patlist; + + CLEAR_HEAD(head); + res->rs_defin->rs_encode(&res->rs_value,&head,"resources_total", + res->rs_defin->rs_name,ATR_ENCODE_CLIENT); + patlist = (svrattrl *)GET_NEXT(head); + fprintf(nin," resources_total.%s=%s", patlist->al_atopl.resource, + patlist->al_atopl.value); + } + head = *head.ll_next; + } + /* write out properties */ for (j = 0;j < np->nd_nprops - 1;++j) @@ -1326,6 +1387,7 @@ struct prop *init_prop( if ((pp = (struct prop *)malloc(sizeof(struct prop))) != NULL) { pp->name = pname; + pp->value = 0; pp->mark = 0; pp->next = 0; } @@ -1415,8 +1477,10 @@ int create_pbs_node( int ntype; /* node type; time-shared, not */ char *pname; /* node name w/o any :ts */ u_long *pul; /* 0 terminated host adrs array*/ - int rc; + int rc, rc2; int iht; + tlist_head head; + resource *res; if ((rc = process_host_name_part( objname, /* I */ @@ -1535,16 +1599,29 @@ int create_pbs_node( } rc = mgr_set_node_attr( - pnode, node_attr_def, - ND_ATR_LAST, + ND_ATR_resources_total, plist, perms, bad, (void *)pnode, ATR_ACTION_ALTER); + if (rc == 0) + rc2 = mgr_set_attr( + pnode->attributes, + &node_attr_def[ND_ATR_LAST-2], + 2, + plist, + perms, + bad, + (void *)pnode, + ATR_ACTION_ALTER, + 1); + + if (rc == 0 && rc2 != 0) rc = rc2; + if (rc != 0) { effective_node_delete(pnode); @@ -1552,6 +1629,15 @@ int create_pbs_node( return(rc); } + /* for all set resources, mark the force flag ATR_VFLAG_FORCED */ + head = pnode->attributes[0].at_val.at_list; + while ((res = (resource*)GET_NEXT(head))) + { + if (res != 0) + res->rs_value.at_flags |= ATR_VFLAG_FORCED; + head = *head.ll_next; + } + recompute_ntype_cnts(); return(PBSE_NONE); /*create completely successful*/ @@ -1652,9 +1738,9 @@ int setup_nodes(void) char note[MAX_NOTE+1]; char *nodename; char propstr[256]; - char *token; + char *token, *token2; int bad, i, num, linenum; - int err; + int err, is_resource; struct pbsnode *np; char *val; @@ -1738,6 +1824,7 @@ int setup_nodes(void) /* now process remaining tokens (if any), they may be either */ /* attributes (keyword=value) or old style properties */ + /* or total resources (resources_total.res_name=value) */ while (1) { @@ -1758,7 +1845,25 @@ int setup_nodes(void) if ((val == NULL) || (err != 0) || (xchar == '=')) goto errtoken1; - pal = attrlist_create(token, 0, strlen(val) + 1); + is_resource = strncmp(token,ATTR_NODE_resources_total, + strlen(ATTR_NODE_resources_total)); + + if (is_resource == 0 || is_resource == 15) + is_resource = (strchr(token,'.')!=NULL)?1:0; + else + is_resource = 0; + + if (is_resource) + { + token[15] = '\0'; + token2 = token+strlen(ATTR_NODE_resources_total)+1; + } + else + { + token2 = 0; + } + + pal = attrlist_create(token, token2, strlen(val) + 1); if (pal == NULL) { @@ -2011,10 +2116,6 @@ static void delete_a_subnode( } /* END delete_a_subnode() */ - - - - /* * node_np_action - action routine for node's np attribute */ diff --git a/src/server/node_manager.c b/src/server/node_manager.c index bb42a1c..371a1b1 100644 --- a/src/server/node_manager.c +++ b/src/server/node_manager.c @@ -117,6 +117,8 @@ #include "mcom.h" #include "utils.h" +#include "assertions.h" + #define IS_VALID_STR(STR) (((STR) != NULL) && ((STR)[0] != '\0')) extern void DIS_rpp_reset A_((void)); @@ -180,6 +182,8 @@ int add_job_to_node(struct pbsnode *,struct pbssubn *,short,job *,int); int node_satisfies_request(struct pbsnode *,char *); int reserve_node(struct pbsnode *,short,job *,char *,struct howl **); int build_host_list(struct howl **,struct pbssubn *,struct pbsnode *); +void adjust_resources_use(struct pbsnode *pnode, struct jobinfo *jp, + enum batch_op op); /* @@ -1263,6 +1267,73 @@ int is_stat_get( } } + else + { + resource_def *def; + resource *res; + int store = 0; + char *target_name = ret_info, *c = strchr(ret_info,'='); + if (c != NULL) + *c = '\0'; + + /* check if the resource is in the list specified in ATTR_ResourcesToStore */ + if (server.sv_attr[SRV_ATR_ResourcesToStore].at_flags & ATR_VFLAG_SET) + { + int i; + struct array_strings *tmp = + server.sv_attr[SRV_ATR_ResourcesToStore].at_val.at_arst; + + for (i = 0; i < tmp->as_usedptr; i++) + { + if (strcmp(tmp->as_string[i],ret_info) == 0) + { + store = 1; + break; + } + } + } + + /* check if the resource is mapped to some other name */ + if (store && (server.sv_attr[SRV_ATR_ResourcesMappings].at_flags & ATR_VFLAG_SET)) + { + int i; + struct array_strings *tmp = + server.sv_attr[SRV_ATR_ResourcesMappings].at_val.at_arst; + + for (i = 0; i < tmp->as_usedptr; i++) + { + if (strncmp(tmp->as_string[i],ret_info,strlen(ret_info)) == 0) + { + char *new_name = strchr(tmp->as_string[i],'='); + + if (new_name == NULL) /* mallformed value */ + continue; + + target_name = ++new_name; + } + } + } + + if (store) + { + def = find_resc_def(svr_resc_def,target_name,svr_resc_size); + if (def != 0) + { + res = find_resc_entry(&np->attributes[0],def); + if (res != 0) + { + if ((res->rs_value.at_flags & ATR_VFLAG_FORCED) == 0) + def->rs_decode(&res->rs_value,0,0,c+1); + } + else + { + res = add_resource_entry(&np->attributes[0],def); + def->rs_decode(&res->rs_value,0,0,c+1); + res->rs_value.at_flags &= ~ATR_VFLAG_FORCED; + } + } + } + } free(ret_info); } /* END while (rc != DIS_EOD) */ @@ -2314,6 +2385,10 @@ static void free_prop( prop = pp->next; free(pp->name); + + if (pp->value) + free(pp->value); + free(pp); } /* END for (pp) */ @@ -2793,6 +2868,18 @@ static int proplist( return(1); } } + /* check if it is a known resource */ + else if (find_resc_def(svr_resc_def,pname,svr_resc_size) != NULL) + { + pequal++; + + pp = (struct prop *)malloc(sizeof(struct prop)); + pp->mark = 0; /* TODO for now resources are marked not to be checked */ + pp->name = strdup(pname); + pp->value = strdup(pequal); + pp->next = *plist; + *plist = pp; + } else { return(1); /* not recognized - error */ @@ -2804,6 +2891,7 @@ static int proplist( pp->mark = 1; pp->name = strdup(pname); + pp->value = NULL; pp->next = *plist; *plist = pp; @@ -2951,72 +3039,6 @@ done: } /* END listelem() */ - - - -/* -** Add the "global" spec to every sub-spec in "spec". -** RETURNS: allocated string buffer (must be freed externally) -*/ - -static char *mod_spec( - - char *spec, /* I */ - char *global) /* I */ - - { - char *line; - char *cp; - int len; - int nsubspec; - - nsubspec = 1; - - for (cp = spec;*cp != '\0';cp++) - { - if (*cp == '+') - { - nsubspec++; - } - } - - len = strlen(global); - - line = malloc(nsubspec * (len + 1) + strlen(spec) + 1); - - if (line == NULL) - { - /* FAILURE */ - - return(NULL); - } - - cp = line; - - while (*spec) - { - if (*spec == '+') - { - *cp++ = ':'; - - strcpy(cp, global); - - cp += len; - } - - *cp++ = *spec++; - } - - *cp++ = ':'; - - strcpy(cp, global); - - return(line); - } /* END mod_spec() */ - - - - /* cntjons - count jobs on (shared) nodes */ static int cntjons( @@ -3176,7 +3198,159 @@ int MSNPrintF( } /* END MSNPrintF() */ +/** Count the parts in a nodespec + * + * (Only works for local specs) + * + * @param spec Nodespec to parse + * @return Count of parts + */ +static int nodespec_part_count(const char *spec) + { + int result = 1; + + dbg_precondition(spec != NULL, "This function does not accept NULL"); + + while (*spec != '\0') + { + if (*spec == '+') + result++; + spec++; + } + + return result; + } + +/** Append requirements to each part of a spec + * + * @param spec the spec to be modified + * @param app requirements to be appended + * @return Modified nodespec + */ +static char *nodespec_app(const char *spec, const char *app) + { + char *cp; + char *result; + + result = malloc(nodespec_part_count(spec) * strlen(app+1) + strlen(spec) + 1); + if (result == NULL) /* alloc fail */ + return NULL; + + cp = result; + + while (*spec) + { + if (*spec == '+') /* add the requirements before each '+' */ + { + *cp++ = ':'; + + strcpy(cp, app); + + cp += strlen(app); + } + + *cp++ = *spec++; + } + + *cp++ = ':'; /* and also after the last part of the spec */ + + strcpy(cp, app); + + return(result); + } /* END nodespec_app() */ + +/** Expand nodespec + * + * Add the global nodespec part to local parts of nodespec and determine exclusivity. + * + * @param spec The spec to be parsed + * @param exclusive 0 if shared, 1 if exclusive, 2 if node exclusive + * @return NULL on failure or allocated modified spec + */ +static char *nodespec_expand(const char *spec, int *exclusive) + { + char *result, *globs, *cp, *tmp; + static char shared[] = "shared"; /* shared */ + static char excl[] = "excl"; /* node exclusive */ + + result = strdup(spec); + if (result == NULL) /* alloc failure */ + return NULL; + + if ((globs = strchr(result, '#')) != NULL) + /*find the first #, everything behind is global nodespec */ + { + *globs++ = '\0'; + + globs = strdup(globs); + if (globs == NULL) /* alloc failure */ + { + free(result); + return NULL; + } + + /* glob now stores the global part of the nodespec + * - go thru each part of the global spec and append + */ + while ((cp = strrchr(globs, '#')) != NULL) + { + *cp++ = '\0'; + + if (!strcmp(cp, shared)) /* #shared */ + { + *exclusive = 0; + continue; + } + if (!strcmp(cp, excl)) /* #excl */ + { + *exclusive = 1; + continue; + } + + tmp = nodespec_app(result, cp); + if (tmp == NULL) /* alloc failure */ + { + free(result); + free(globs); + return NULL; + } + + free(result); + result = tmp; + } + + /* now parse the first part of the global nodespec */ + if (!strcmp(globs, shared)) /* #shared */ + { + *exclusive = 0; + free(globs); + return result; + } + + if (!strcmp(globs, excl)) /* #excl */ + { + *exclusive = 1; + free(globs); + return result; + } + + tmp = nodespec_app(result, globs); + if (tmp == NULL) /* alloc failure */ + { + free(result); + free(globs); + return NULL; + } + + free(result); + result = tmp; + + free(globs); + } /* END if ((globs = strchr(spec,'#')) != NULL) */ + + return result; + } /* @@ -3195,6 +3369,7 @@ static int node_spec( int early, /* I (boolean) */ int exactmatch, /* I (boolean) - NOT USED */ char *ProcBMStr, /* I */ + job *pjob, /* O (optional) */ char *FailNode, /* O (optional,minsize=1024) */ char *EMsg) /* O (optional,minsize=1024) */ @@ -3204,10 +3379,9 @@ static int node_spec( struct pbsnode *pnode; struct pbssubn *snp; - char *str, *globs, *cp, *hold; + char *str; int i, num; int rv; - static char shared[] = "shared"; extern int PNodeStateToString(int, char *, int); @@ -3219,132 +3393,62 @@ static int node_spec( if (LOGLEVEL >= 6) { - sprintf(log_buffer, "entered spec=%.4000s", - spec); - - log_record( - PBSEVENT_SCHED, - PBS_EVENTCLASS_REQUEST, - id, - log_buffer); - - DBPRT(("%s\n", - log_buffer)); + sprintf(log_buffer, "entered spec=%.4000s", spec); + log_record(PBSEVENT_SCHED, PBS_EVENTCLASS_REQUEST, id, log_buffer); + DBPRT(("%s\n", log_buffer)); } exclusive = 1; /* by default, nodes (VPs) are requested exclusively */ + /* expand the global reqs into the local parts */ + spec = nodespec_expand(spec,&exclusive); - spec = strdup(spec); - - if (spec == NULL) + if (pjob != NULL) /* store the expanded nodespec */ { - /* FAILURE */ + if (pjob->ji_expanded_spec != NULL) + free(pjob->ji_expanded_spec); + pjob->ji_expanded_spec = strdup(spec); + } + if (spec == NULL) /* memory alloc fail */ + { sprintf(log_buffer,"cannot alloc memory"); - if (LOGLEVEL >= 1) - { - log_record( - PBSEVENT_SCHED, - PBS_EVENTCLASS_REQUEST, - id, - log_buffer); - } + log_record(PBSEVENT_SCHED, PBS_EVENTCLASS_REQUEST, id, log_buffer); if (EMsg != NULL) - { strncpy(EMsg,log_buffer,1024); - } return(-1); } - if ((globs = strchr(spec, '#')) != NULL) - { - *globs++ = '\0'; - - globs = strdup(globs); - - while ((cp = strrchr(globs, '#')) != NULL) - { - *cp++ = '\0'; - - if (strcmp(cp, shared) != 0) - { - hold = mod_spec(spec, cp); - - free(spec); - - spec = hold; - } - else - { - exclusive = 0; - } - } - - if (strcmp(globs, shared) != 0) - { - hold = mod_spec(spec, globs); - - free(spec); - - spec = hold; - } - else - { - exclusive = 0; - } - - free(globs); - } /* END if ((globs = strchr(spec,'#')) != NULL) */ - str = spec; - + /* count total nodes in the request */ num = ctnodes(str); - if (num > svr_clnodes) + if (num > svr_clnodes) /* the request is for more nodes then the server has */ { - /* FAILURE */ - free(spec); - sprintf(log_buffer, "job allocation request exceeds available cluster nodes, %d requested, %d available", - num, - svr_clnodes); + sprintf(log_buffer, "job allocation request exceeds available cluster" + " nodes, %d requested, %d available", num, svr_clnodes); if (LOGLEVEL >= 6) - { - log_record( - PBSEVENT_SCHED, - PBS_EVENTCLASS_REQUEST, - id, - log_buffer); - } + log_record(PBSEVENT_SCHED, PBS_EVENTCLASS_REQUEST, id, log_buffer); if (EMsg != NULL) - { strncpy(EMsg, log_buffer, 1024); - } return(-1); } if (LOGLEVEL >= 6) { - sprintf(log_buffer, "job allocation debug: %d requested, %d svr_clnodes, %d svr_totnodes", - num, - svr_clnodes, - svr_totnodes); + sprintf(log_buffer, "job allocation debug: %d requested, %d svr_clnodes," + " %d svr_totnodes", num, svr_clnodes, svr_totnodes); - log_record( - PBSEVENT_SCHED, - PBS_EVENTCLASS_REQUEST, - id, - log_buffer); + log_record(PBSEVENT_SCHED, PBS_EVENTCLASS_REQUEST, id, log_buffer); - DBPRT(("%s\n", - log_buffer)); + DBPRT(("%s\n", log_buffer)); } /* @@ -3882,8 +3986,6 @@ int reserve_node( #endif /* GEOMETRY_REQUESTS */ - - /** * adds this job to the node's list of jobs * checks to be sure not to add duplicates @@ -3940,10 +4042,13 @@ int add_job_to_node( jp->next = snp->jobs; snp->jobs = jp; jp->job = pjob; + jp->order = pnode->nd_order; + pnode->nd_nsnfree--; /* reduce free count */ + adjust_resources_use(pnode,jp,INCR); /* if no free VPs, set node state */ - if (pnode->nd_nsnfree <= 0) + if (pnode->nd_nsnfree <= 0) pnode->nd_state = newstate; if (snp->inuse == INUSE_FREE) @@ -4067,7 +4172,7 @@ int set_nodes( /* allocate nodes */ - if ((i = node_spec(spec, 1, 1, ProcBMStr, FailHost, EMsg)) == 0) /* check spec */ + if ((i = node_spec(spec, 1, 1, ProcBMStr, pjob, FailHost, EMsg)) == 0) /* check spec */ { /* no resources located, request failed */ @@ -4275,7 +4380,7 @@ int node_avail_complex( holdnum = svr_numnodes; - ret = node_spec(spec, 1, 0, NULL, NULL, NULL); + ret = node_spec(spec, 1, 0, NULL, NULL, NULL, NULL); svr_numnodes = holdnum; @@ -4463,7 +4568,7 @@ int node_reserve( return(-1); } - if ((ret_val = node_spec(nspec, 0, 0, NULL, NULL, NULL)) >= 0) + if ((ret_val = node_spec(nspec, 0, 0, NULL, NULL, NULL, NULL)) >= 0) { /* ** Zero or more of the needed Nodes are available to be @@ -4591,8 +4696,114 @@ find_ts_node(void) return(NULL); } /* END find_ts_node() */ +/** Adjust the resources use on a node + * + * @param pnode Node with the resources + * @param jp Job info + * @param op Operation to do (increment, decrement) + */ +void adjust_resources_use(struct pbsnode *pnode, struct jobinfo *jp, + enum batch_op op) + { + struct prop *prop = NULL, *iter = NULL; + char *str, *spec, *token; + int i,count,num; + + if (jp->job->ji_expanded_spec == NULL) + return; + + spec = strdup(jp->job->ji_expanded_spec); + token = spec; + /* determine the count of nodespec parts */ + for (i = 1; token != NULL; i++) + { + token = strchr(token,'+'); + if (token != NULL) + token++; + } + count = i; + + token = spec; + + /* record the starts of the node specs */ + for (i = 1; token != NULL; i++) + { + if (i == jp->order) + { + str = token; + } + + token = strchr(token,'+'); + if (token != NULL) + { + *token = '\0'; + token++; + } + } + + if ((i = number(&str, &num)) == -1) /* get number */ + return; + + if (i == 0) + { + /* number exists */ + if (*str == ':') + { + /* there are properties */ + (str)++; + + if (proplist(&str, &prop, &num)) + return; + } + } + else + { + /* no number */ + if (proplist(&str, &prop, &num)) + return; + } + + iter = prop; + while (iter != NULL) + { + resource_def *defin; + resource *val; + resource decoded; + int ret; + + if (iter->value != NULL) + /* it is a resource */ + if ((defin = find_resc_def(svr_resc_def,iter->name,svr_resc_size))) + /* it is a known resource */ + { + ret = defin->rs_decode(&decoded.rs_value,0,iter->name,iter->value); + if (ret != 0) + continue; /* ignore if cannot decode */ + if ((val = find_resc_entry(&pnode->attributes[1],defin))) + /* some value already present */ + { + ret = defin->rs_set(&val->rs_value,&decoded.rs_value,op); + if (ret != 0) + continue; /* ignore if cannot set */ + } + else + { + if (op == INCR) /* add new record only if increasing */ + { + if ((val = add_resource_entry(&pnode->attributes[1],defin))) + { + ret = defin->rs_set(&val->rs_value,&decoded.rs_value,SET); + if (ret != 0) + continue; /* ignore if cannot set */ + } + } + } + } + iter = iter->next; + } + } /* @@ -4665,6 +4876,8 @@ void free_nodes( else prev->next = jp->next; + adjust_resources_use(pnode,jp,DECR); + free(jp); pnode->nd_nsnfree++; /* up count of free */ diff --git a/src/server/req_manager.c b/src/server/req_manager.c index b35da50..434f3c6 100644 --- a/src/server/req_manager.c +++ b/src/server/req_manager.c @@ -361,7 +361,7 @@ mgr_log_attr( * attributes must be successfully set, or none are modified. */ -static int mgr_set_attr( +int mgr_set_attr( attribute *pattr, /* current attributes */ attribute_def *pdef, @@ -370,7 +370,8 @@ static int mgr_set_attr( int privil, int *bad, void *parent, - int mode) + int mode, + int skip_unknown) { int index; @@ -397,7 +398,7 @@ static int mgr_set_attr( * and update it with the newly decoded value */ - if ((rc = attr_atomic_set(plist, pattr, new, pdef, limit, -1, privil, bad)) != 0) + if ((rc = attr_atomic_set(plist, pattr, new, pdef, limit, skip_unknown?0:-1, privil, bad)) != 0) { attr_atomic_kill(new, pdef, limit); @@ -732,7 +733,7 @@ int mgr_set_node_attr( * return code (rc) shapes caller's reply */ - if ((rc = attr_atomic_node_set(plist, unused, new, pdef, limit, -1, privil, bad)) != 0) + if ((rc = attr_atomic_node_set(plist, unused, new, pdef, limit, 0, privil, bad)) != 0) { attr_atomic_kill(new, pdef, limit); @@ -967,7 +968,8 @@ void mgr_queue_create( preq->rq_perm, &bad, (void *)pque, - ATR_ACTION_NEW); + ATR_ACTION_NEW, + 0); if (rc != 0) { @@ -1106,7 +1108,8 @@ void mgr_server_set( preq->rq_perm, &bad_attr, (void *) & server, - ATR_ACTION_ALTER); + ATR_ACTION_ALTER, + 0); /* PBSE_BADACLHOST - lets show the user the first bad host in the ACL */ @@ -1376,7 +1379,8 @@ void mgr_queue_set( preq->rq_perm, &bad, (void *)pque, - ATR_ACTION_ALTER); + ATR_ACTION_ALTER, + 0); if (rc != 0) @@ -1520,7 +1524,96 @@ void mgr_queue_unset( } +/* + * mgr_node_unset - Unset (clear) Node Attribute Values + * + * Finds the node, clears the requested attributes and returns a reply + */ + +void mgr_node_unset( + + struct batch_request *preq) + + { + int allnodes; + int bad_attr = 0; + svrattrl *plist; + struct pbsnode **pnode; + char *nname; + int rc; + int total_count; + int position; + + if ((*preq->rq_ind.rq_manager.rq_objname == '\0') || + (*preq->rq_ind.rq_manager.rq_objname == '@')) + { + allnodes = TRUE; + nname = "all"; + + pnode = pbsndlist; + total_count = svr_totnodes; + } + else + { + allnodes = FALSE; + nname = preq->rq_ind.rq_manager.rq_objname; + + pnode = malloc(sizeof(struct pbsnode*)*1); + pnode[0] = find_nodebyname(nname); + total_count = 1; + } + + if (pnode == NULL) + { + req_reject(PBSE_UNKQUE, 0, preq, NULL, NULL); + + return; + } + + sprintf(log_buffer, msg_manager, + + msg_man_uns, + preq->rq_user, + preq->rq_host); + + log_event( + PBSEVENT_ADMIN, + PBS_EVENTCLASS_QUEUE, + nname, + log_buffer); + + plist = (svrattrl *)GET_NEXT(preq->rq_ind.rq_manager.rq_attr); + + for (position = 0; position < total_count; position++) + { + rc = mgr_unset_attr( + pnode[0]->attributes, + &node_attr_def[ND_ATR_LAST-2], + 2, + plist, + preq->rq_perm, + &bad_attr); + + if (rc != 0) + { + reply_badattr(rc, bad_attr, plist, preq); + + return; + } + + update_nodes_file(); + + mgr_log_attr(msg_man_uns, plist, PBS_EVENTCLASS_NODE, pnode[0]->nd_name); + } + + if (total_count == 1) + free(pnode); + + reply_ack(preq); + + return; + } /* @@ -1544,7 +1637,7 @@ void mgr_node_set( struct pbsnode *pnode; char *nodename = NULL; - int rc; + int rc, rc2; int i, len; int problem_cnt = 0; @@ -1572,6 +1665,7 @@ void mgr_node_set( propnodes = 1; nodename = preq->rq_ind.rq_manager.rq_objname; props.name = nodename + 1; + props.value = 0; props.mark = 1; props.next = NULL; } @@ -1631,13 +1725,28 @@ void mgr_node_set( rc = mgr_set_node_attr( pnode, node_attr_def, - ND_ATR_LAST, + ND_ATR_resources_total, plist, preq->rq_perm, &bad, (void *)pnode, ATR_ACTION_ALTER); + if (rc == 0) + rc2 = mgr_set_attr( + pnode->attributes, + &node_attr_def[ND_ATR_LAST-2], + 2, + plist, + preq->rq_perm, + &bad, + (void*)pnode, + ATR_ACTION_ALTER, + 1); + + if (rc == 0 && rc2 != 0) + rc = rc2; + if (rc != 0) { if (allnodes || propnodes) @@ -2215,18 +2324,12 @@ void req_manager( break; -#if 0 - - /* "unsetting" nodes isn't currently supported */ - case MGR_OBJ_NODE: mgr_node_unset(preq); break; -#endif /* 0 */ - default: req_reject(PBSE_IVALREQ, 0, preq, NULL, NULL); diff --git a/src/server/req_stat.c b/src/server/req_stat.c index e70f6f7..71048ae 100644 --- a/src/server/req_stat.c +++ b/src/server/req_stat.c @@ -1195,6 +1195,7 @@ void req_stat_node( { type = 2; props.name = name + 1; + props.value = NULL; props.mark = 1; props.next = NULL; } diff --git a/src/server/svr_attr_def.c b/src/server/svr_attr_def.c index 2092c15..f20e924 100644 --- a/src/server/svr_attr_def.c +++ b/src/server/svr_attr_def.c @@ -1101,6 +1101,30 @@ attribute_def svr_attr_def[] = PARENT_TYPE_SERVER }, + /* SRV_ATR_ResourcesToStore */ + { ATTR_ResourcesToStore, /* "resources_to_store" */ + decode_arst, + encode_arst, + set_arst, + comp_arst, + free_arst, + NULL_FUNC, + MGR_ONLY_SET, + ATR_TYPE_ARST, + PARENT_TYPE_SERVER + }, + /* SRV_ATR_ResourcesMappings */ + { ATTR_ResourcesMappings, /* "resources_mappings" */ + decode_arst, + encode_arst, + set_arst, + comp_arst, + free_arst, + NULL_FUNC, + MGR_ONLY_SET, + ATR_TYPE_ARST, + PARENT_TYPE_SERVER + }, /* site supplied server attribute definitions if any, see site_svr_attr_*.h */ #include "site_svr_attr_def.h"