{"action":"created","comment":{"url":"https://api.github.com/repos/PBSPro/pbspro/pulls/comments/178459823","pull_request_review_id":108520160,"id":178459823,"diff_hunk":"@@ -6751,6 +6944,479 @@ get_hook_rescdef_checksum(void)\n \treturn (hook_rescdef_checksum);\n }\n \n+/**\n+ *\n+ * @brief\n+ *\tGet the results from 'output_file' of a previously run hook.\n+ *\n+ * @param[in] \t\tinput_file -  file to process.\n+ * @param[in,out] \taccept_flag -  return 1 if event accept flag is true.\n+ * @param[in,out] \treject_flag -  return 1 if event reject flag is true.\n+ * @param[in,out] \treject_msg -  the reject message if reject_flag is 1.\n+ * @param[in]\t\treject_msg_size -  size of reject_msg buffer.\n+ * @param[in,out] \tpjob -  job in question, where if present (not NULL),\n+ *\t\t\t        it gets filled in with the\n+ *\t\t\t\t\"pbs.event().job\" entries in 'input_file'.\n+ *\t\t\t\t'pjob' can be NULL in periodic hooks, since\n+ *\t\t\t\t periodic hooks are not tied to jobs.\n+ *\t\t\t\t Note that pbs.event().job_list[<jobid>] entries\n+ *\t\t\t\t in 'input_file' fill in the individual\n+ *\t\t\t\t <jobid>'s job struct entry in the system, and\n+ *\t\t\t\t not the passed 'pjob' structure.\n+ * @param[in]\t\tphook -  hook that executed of which we're getting the\n+ *\t\t\t\tresults. If non-NULL, then phook->user is\n+ *\t\t\t\tused to validate 'pbs.event().job.euser' line\n+ *\t\t\t\tin 'input_file'.\n+ *\t\t\t\tIf main Mom is reading a job related hook\n+ *\t\t\t\tresults file, phook will be null; an entry in\n+ *\t\t\t\tthe file should give us the hook name from which\n+ *\t\t\t\tphook is found.\n+ * @param[out]\t\thook_output - struct of parameters to fill in output.\n+ *\n+ * @return int\n+ * @retval\t0 for success\n+ * @retval\tnon-zero for failure;  the returned parameters (accept_flag,\n+ *\t\treject_flag and pjob) may be invalid and should be\n+ *\t\tignored.   The list svrvnalist could have mallocate space and\n+ *\t\tshould be freed by the calling program.\n+ */\n+int\n+get_server_hook_results(char *input_file, int *accept_flag, int *reject_flag, char *reject_msg,\n+\tint reject_msg_size, job *pjob, hook *phook, hook_output_param_t *hook_output)  {\n+\n+\tchar\t*name_str;\n+\tchar\t*resc_str;\n+\tchar\t*obj_name;\n+\tchar\t*data_value;\n+\tchar\t*vname_str;\n+\tint\trc = -1;\n+\tchar\t*pc, *pc1, *pc2, *pc3, *pc4;\n+\tchar\t*in_data = NULL;\n+\tsize_t\tll;\n+\tFILE\t*fp;\n+\tchar\t*p;\n+\tint\tvn_obj_len = strlen(EVENT_VNODELIST_OBJECT);\n+\tchar\thook_job_outfile[MAXPATHLEN + 1];\n+\tFILE\t*fp2 = NULL;\n+\tchar\t*line_data = NULL;\n+\tint\tline_data_sz;\n+\tlong int endpos;\n+\tchar\thook_euser[PBS_MAXUSER + 1] = {0};\n+\tint\targ_list_entries = 0;\n+\tint\tb_triple_quotes = 0;\n+\tint\te_triple_quotes = 0;\n+\tchar\tbuf_data[STRBUF];\n+\tint\tbuf_data_sz = STRBUF;\n+\tint\tvalln = 0;\n+\tsvrattrl *plist = NULL;\n+\tstruct pbsnode *pnode;\n+\tint\tbad = 0;\n+\tint\tndtype_flag = 0;\n+\tchar\t*pbse_err;\n+\tchar\traw_err[10];\n+\n+\t/* Preset hook_euser for later.  If we are reading a job related     */\n+\t/* copy of hook results, there will be one or more (one per hook)    */\n+\t/* pbs_event().hook_euser=<value> entries.  In that case, hook_euser */\n+\t/* is reset to the <value>.  A null string <value> means PBSADMIN.   */\n+\tif (phook && pjob &&  (phook->user == HOOK_PBSUSER)) {\n+\t\tstrncpy(hook_euser,\n+\t\t\tpjob->ji_wattr[(int)JOB_ATR_euser].at_val.at_str,\n+\t\t\tPBS_MAXUSER);\n+\t}\n+\n+\t/* input_file will have content of the format: */\n+\t/* pbs.event().accept=True */\n+\t/* pbs.event().reject=False */\n+\t/* pbs.event().vnode.pcpus=4 */\n+\t/* pbs.event().vnode_list[\"node_name\"].state=sleep */\n+\t/* pbs.event().vnode_list[\"node_name\"].resources_available[ncpus]=10 */\n+\tif ((input_file != NULL) && (*input_file != '\\0')) {\n+\t\tfp = fopen(input_file, \"r\");\n+\n+\t\tif (fp == NULL) {\n+\t\t\tsnprintf(log_buffer, sizeof(log_buffer),\n+\t\t\t\t\"failed to open input file %s\", input_file);\n+\t\t\tlog_err(errno, __func__, log_buffer);\n+\t\t\treturn (1);\n+\t\t}\n+\t} else {\n+\t\tlog_err(PBSE_INTERNAL, __func__, \"bad input_file parameter\");\n+\t\treturn (1);\n+\t}\n+\n+\tline_data_sz = STRBUF;\n+\tline_data = (char *)malloc(line_data_sz);\n+\tif (line_data == NULL) {\n+\t\tlog_err(errno, __func__, \"malloc failed\");\n+\t\trc = 1;\n+\t\tgoto get_hook_results_end;\n+\t}\n+\tline_data[0] = '\\0';\n+\n+\tif (fseek(fp, 0, SEEK_END) != 0) {\n+\t\tlog_err(errno, __func__, \"fseek to end failed\");\n+\t\trc = 1;\n+\t\tgoto get_hook_results_end;\n+\t}\n+\n+\tendpos = ftell(fp);\n+\tif (fseek(fp, 0, SEEK_SET) != 0) {\n+\t\tlog_err(errno, __func__, \"fseek to beginning failed\");\n+\t\trc = 1;\n+\t\tgoto get_hook_results_end;\n+\t}\n+\n+\twhile (fgets(buf_data, buf_data_sz, fp) != NULL) {\n+\t\tb_triple_quotes = 0;\n+\t\te_triple_quotes = 0;\n+\n+\t\tif (pbs_strcat(&line_data, &line_data_sz, buf_data) == NULL) {\n+\t\t\tgoto get_hook_results_end;\n+\t\t}\n+\t\tif (in_data != NULL) {\n+\t\t\tfree(in_data);\n+\t\t}\n+\t\tin_data = strdup(line_data); /* preserve line_data */\n+\t\tif (in_data == NULL) {\n+\t\t\tlog_err(errno, __func__, \"strdup failed\");\n+\t\t\trc = 1;\n+\t\t\tgoto get_hook_results_end;\n+\t\t}\n+\n+\t\tif ((p = strchr(in_data, '=')) != NULL) {\n+\t\t\t/* string begins with three consecutive double quotes */\n+\t\t\tb_triple_quotes = starts_with_triple_quotes(p+1);\n+\t\t}\n+\n+\t\tll = strlen(in_data);\n+\t\tif (in_data[ll-1] == '\\n') {\n+\t\t\t/* string ends with three consecutive double quotes */\n+\t\t\te_triple_quotes = ends_with_triple_quotes(in_data, 0);\n+\n+\t\t\tif (b_triple_quotes && !e_triple_quotes) {\n+\t\t\t\tint\tjj;\n+\n+\t\t\t\twhile (fgets(buf_data, buf_data_sz, fp) != NULL) {\n+\t\t\t\t\tif (pbs_strcat(&line_data, &line_data_sz,\n+\t\t\t\t\t\tbuf_data) == NULL) {\n+\t\t\t\t\t\tgoto get_hook_results_end;\n+\t\t\t\t\t}\n+\n+\t\t\t\t\tjj = strlen(line_data);\n+\t\t\t\t\tif ((line_data[jj - 1] != '\\n') &&\n+\t\t\t\t\t    (ftell(fp) != endpos)) {\n+\t\t\t\t\t\t/* get more input for\n+\t\t\t\t\t\t * current item.\n+\t\t\t\t\t\t */\n+\t\t\t\t\t\tcontinue;\n+\t\t\t\t\t}\n+\t\t\t\t\te_triple_quotes =\n+\t\t\t\t\t  ends_with_triple_quotes(line_data, 0);\n+\n+\t\t\t\t\tif (e_triple_quotes) {\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\n+\t\t\t\tif ((!b_triple_quotes && e_triple_quotes) ||\n+\t\t\t\t\t(b_triple_quotes && !e_triple_quotes)) {\n+\t\t\t\t\tsnprintf(log_buffer, sizeof(log_buffer),\n+\t\t\t\t\t\t\"unmatched triple quotes! Skipping  line %s\",\n+\t\t\t\t\t\tin_data);\n+\t\t\t\t\tlog_err(PBSE_INTERNAL, __func__, log_buffer);\n+\t\t\t\t\t/* process a new line */\n+\t\t\t\t\tline_data[0] = '\\0';\n+\t\t\t\t\tcontinue;\n+\t\t\t\t}\n+\n+\t\t\t\tif (in_data != NULL) {\n+\t\t\t\t\tfree(in_data);\n+\t\t\t\t}\n+\t\t\t\tin_data = strdup(line_data); /* preserve line_data */\n+\t\t\t\tif (in_data == NULL) {\n+\t\t\t\t\tlog_err(errno, __func__, \"strdup failed\");\n+\t\t\t\t\trc = 1;\n+\t\t\t\t\tgoto get_hook_results_end;\n+\t\t\t\t}\n+\t\t\t\t/* remove newline */\n+\t\t\t\tin_data[strlen(in_data)-1] = '\\0';\n+\t\t\t} else {\n+\t\t\t\t/* remove newline */\n+\t\t\t\tin_data[ll-1] = '\\0';\n+\t\t\t}\n+\n+\t\t} else if (ftell(fp) != endpos) { /* continued on next line */\n+\t\t\t/* get more input for current item.  */\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tdata_value = NULL;\n+\t\tif ((p=strchr(in_data, '=')) != NULL) {\n+\t\t\t*p = '\\0';\n+\t\t\tp++;\n+\t\t\twhile (isspace(*p))\n+\t\t\t\tp++;\n+\n+\t\t\tif (b_triple_quotes) {\n+\t\t\t\t/* strip triple quotes */\n+\t\t\t\tp+=3;\n+\t\t\t}\n+\t\t\tdata_value = p;\n+\t\t\tif (e_triple_quotes) {\n+\t\t\t\tends_with_triple_quotes(p, 1);\n+\t\t\t}\n+\t\t}\n+\n+\t\tobj_name = in_data;\n+\n+\t\tpc = strrchr(in_data, '.');\n+\t\tif (pc) {\n+\t\t\t*pc = '\\0';\n+\t\t\tpc++;\n+\t\t} else {\n+\t\t\tpc = in_data;\n+\t\t}\n+\t\tname_str = pc;\n+\n+\t\tpc1 = strchr(pc, '[');\n+\t\tpc2 = strchr(pc, ']');\n+\t\tresc_str = NULL;\n+\t\tif (pc1 && pc2 && (pc2 > pc1)) {\n+\t\t\t*pc1 = '\\0';\n+\t\t\tpc1++;\n+\t\t\t*pc2 = '\\0';\n+\t\t\tpc2++;\n+\n+\t\t\t/* now let's if there's anything quoted inside */\n+\t\t\tpc3 = strchr(pc1, '\"');\n+\t\t\tif (pc3 != NULL)\n+\t\t\t\tpc4 = strchr(pc3+1, '\"');\n+\t\t\telse\n+\t\t\t\tpc4 = NULL;\n+\n+\t\t\tif (pc3 && pc4 && (pc4 > pc3)) {\n+\t\t\t\tpc3++;\n+\t\t\t\t*pc4 = '\\0';\n+\t\t\t\tresc_str = pc3;\n+\t\t\t} else {\n+\t\t\t\tresc_str = pc1;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* at this point, we have */\n+\t\t/* Given:  pbs.event().<attribute>=<value> */\n+\t\t/* Given:  pbs.event().job.<attribute>=<value> */\n+\t\t/* Given:  pbs.event().job.<attribute>[<resc>]=<value> */\n+\t\t/* Given:  pbs.event().vnode_list[<vname>].<attribute>=<value> */\n+\t\t/* Given:  pbs.event().vnode_list[<vname>].<attribute>[<resc>]=<value> */\n+\t\t/* We get: */\n+\n+\t\t/* obj_name = pbs.event() or \"pbs.event().job\" or \"pbs.event().vnode_list[<vname>]\" */\n+\t\t/* name_str = <attribute> */\n+\t\t/* resc_str = <resc> */\n+\t\t/* data_value = <value> */\n+\n+\t\tif (data_value == NULL) {\n+\n+\t\t\tsnprintf(log_buffer, sizeof(log_buffer),\n+\t\t\t\t\"%s: no value given\", in_data);\n+\t\t\tlog_err(errno, __func__, log_buffer);\n+\t\t\trc = 1;\n+\t\t\tgoto get_hook_results_end;\n+\t\t}\n+\n+\t\tif (strcmp(obj_name, EVENT_OBJECT) == 0) {\n+\t\t\tif (strcmp(name_str, \"hook_euser\") == 0) {\n+\t\t\t\tstrncpy(hook_euser, data_value, PBS_MAXUSER);\n+\t\t\t} else if ((accept_flag != NULL) &&\n+\t\t\t\tstrcmp(name_str, \"accept\") == 0) {\n+\t\t\t\tif (strcmp(data_value, \"True\") == 0)\n+\t\t\t\t\t*accept_flag = 1;\n+\t\t\t\telse\n+\t\t\t\t\t*accept_flag = 0;\n+\t\t\t} else if ((reject_flag != NULL) &&\n+\t\t\t\tstrcmp(name_str, \"reject\") == 0) {\n+\n+\t\t\t\tif (strcmp(data_value, \"True\") == 0)\n+\t\t\t\t\t*reject_flag = 1;\n+\t\t\t\telse\n+\t\t\t\t\t*reject_flag = 0;\n+\t\t\t} else if ((reject_msg != NULL) &&\n+\t\t\t\t(strcmp(name_str, \"reject_msg\") == 0)) {\n+\t\t\t\tstrncpy(reject_msg, data_value,\n+\t\t\t\t\treject_msg_size-1);\n+\t\t\t} else if (strcmp(name_str, PY_EVENT_PARAM_PROGNAME) == 0) {\n+\t\t\t\tchar\t**prog;\n+\t\t\t\tif (hook_output != NULL) {\n+\t\t\t\t\t/* need to free up here previous value */\n+\t\t\t\t\t/* in case of multiple hooks! */\n+\t\t\t\t\tprog = hook_output->progname;\n+\t\t\t\t\tif (*prog != NULL) {\n+\t\t\t\t\t\tfree(*prog);\n+\t\t\t\t\t}\n+\t\t\t\t\t*prog = strdup(data_value);\n+\t\t\t\t}\n+\t\t\t} else if (strcmp(name_str, PY_EVENT_PARAM_ARGLIST) == 0) {\n+\t\t\t\tpbs_list_head *ar_list;\n+\n+\t\t\t\targ_list_entries++;\n+\t\t\t\tif (hook_output != NULL) {\n+\t\t\t\t\tar_list = hook_output->argv_list;\n+\t\t\t\t\t/* free previous values at start of new list */\n+\t\t\t\t\tif (arg_list_entries == 1) {\n+\t\t\t\t\t\tfree_attrlist(ar_list);\n+\t\t\t\t\t}\n+\t\t\t\t\tadd_to_svrattrl_list(ar_list, name_str, resc_str,\n+\t\t\t\t\t\t\t\t\tdata_value, 0, NULL);\n+\t\t\t\t}\n+\t\t\t} else if (strcmp(name_str, PY_EVENT_PARAM_ENV) == 0) {\n+\t\t\t\tchar\t**env;\n+\t\t\t\tif (hook_output != NULL) {\n+\t\t\t\t\tenv = hook_output->env;\n+\t\t\t\t\tif (*env != NULL) {\n+\t\t\t\t\t\tfree(*env);\n+\t\t\t\t\t}\n+\t\t\t\t\t*env = strdup(data_value);\n+\t\t\t\t}\n+\t\t\t}\n+\n+\t\t\t/* if the hook is rejected we can go out now */\n+\t\t\tif((*reject_flag == 1) && (reject_msg != NULL))\n+\t\t\t\tgoto get_hook_results_end;\n+\t\t} else if (strncmp(obj_name, EVENT_VNODELIST_OBJECT,\n+\t\t\tvn_obj_len) == 0) {\n+\n+\t\t\t/* NOTE: obj_name here is: pbs.event().vnode_list[<vname>] */\n+\n+\t\t\t/* important here to look for the leftmost '[' (using strchr)\n+\t\t\t * and the rightmost ']' (using strrchr)\n+\t\t\t * as we can have:\n+\t\t\t *\tpbs.event().vnode_list[\"altix[5]\"].<attr>=<val>\n+\t\t\t * \tand \"altix[5]\" is a valid vnode id.\n+\t\t\t */\n+\t\t\tif (((pc1=strchr(obj_name, '[')) != NULL) &&\n+\t\t\t\t((pc2=strrchr(obj_name, ']')) != NULL) &&\n+\t\t\t\t(pc2 > pc1)) {\n+\t\t\t\tpc1++; /*  pc1=<vname>] */\n+\t\t\t\t*pc2 = '\\0'; /* pc1=<vname>  */\n+\t\t\t\tpc2++;\n+\n+\t\t\t\t/* now let's if there's anything quoted inside */\n+\t\t\t\tpc3 = strchr(pc1, '\"');\n+\t\t\t\tif (pc3 != NULL)\n+\t\t\t\t\tpc4 = strchr(pc3+1, '\"');\n+\t\t\t\telse\n+\t\t\t\t\tpc4 = NULL;\n+\n+\t\t\t\tif (pc3 && pc4 && (pc4 > pc3)) {\n+\t\t\t\t\tpc3++;\n+\t\t\t\t\t*pc4 = '\\0';\n+\t\t\t\t\tvname_str = pc3;\n+\t\t\t\t} else {\n+\t\t\t\t\tvname_str = pc1;\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\tsnprintf(log_buffer, sizeof(log_buffer),\n+\t\t\t\t\t\"object '%s' does not have a vnode name!\",\n+\t\t\t\t\tobj_name);\n+\t\t\t\tlog_err(-1, __func__, log_buffer);\n+\t\t\t\t/* process a new line */\n+\t\t\t\tline_data[0] = '\\0';\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\t/* server periodic hook vnode objects */\n+\t\t\tvalln = (int)strlen(data_value) + 1;\n+\t\t\tplist = attrlist_create(name_str, resc_str, valln);\n+\t\t\tif (plist == NULL) {\n+\t\t\t\t(void)sprintf(log_buffer,\"failed to add svrattrl list %s.%s.%s:%s\",\n+\t\t\t\t\t\tvname_str,name_str,resc_str,data_value);\n+\t\t\t\tlog_event(PBSEVENT_SYSTEM | PBSEVENT_FORCE, PBS_EVENTCLASS_SERVER,\n+\t\t\t\t\tLOG_NOTICE, msg_daemonname, log_buffer);\n+\t\t\t} else {\n+\t\t\t\tstrcpy(plist->al_value, data_value);\n+\t\t\t\t(plist->al_link).ll_next->ll_struct = NULL;\n+\t\t\t\t/* there are vnode hook updates */\n+\t\t\t\t/* Push hook changes to server */\n+\t\t\t\tpnode = find_nodebyname(vname_str);\n+\t\t\t\tif (pnode == NULL) {\n+\t\t\t\t\tlog_event(PBSEVENT_DEBUG3, PBS_EVENTCLASS_HOOK,\n+\t\t\t\t\t\tLOG_INFO, phook->hook_name, \"node_name not found\");\n+\t\t\t\t} else if ((pnode->nd_state & INUSE_DELETED) == 0) {\n+\t\t\t\t\tsave_characteristic(pnode);\n+\n+\t\t\t\t\trc = mgr_set_attr(pnode->nd_attr, node_attr_def, ND_ATR_LAST,\n+\t\t\t\t\t\t\t\t  plist, ATR_DFLAG_WRACC, &bad, (void *)pnode, ATR_ACTION_ALTER);\n+\t\t\t\t\tif (rc != 0) {\n+\t\t\t\t\t\tpbse_err = pbse_to_txt(rc);\n+\t\t\t\t\t\tsnprintf(raw_err, sizeof(raw_err), \"%d\", rc);\n+\t\t\t\t\t\tsprintf(log_buffer, \"vnode %s: failed to set %s to %s: %s\",\n+\t\t\t\t\t\t\t\tpnode->nd_name, plist->al_name, plist->al_value ? plist->al_value : \"\",\n+\t\t\t\t\t\t\t\tpbse_err ? pbse_err : raw_err);\n+\t\t\t\t\t\tlog_err(PBSE_SYSTEM, __func__, log_buffer);\n+\t\t\t\t\t} else {\n+\t\t\t\t\t\t(void)chk_characteristic(pnode, &ndtype_flag);\n+\t\t\t\t\t\tmgr_log_attr(msg_man_set, plist,\n+\t\t\t\t\t\t\t\t PBS_EVENTCLASS_NODE, pnode->nd_name, NULL);\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t\tfree(plist);","path":"src/server/hook_func.c","position":768,"original_position":768,"commit_id":"439253f65e05b03d2088b4ec61a0cbf724f52eb3","original_commit_id":"439253f65e05b03d2088b4ec61a0cbf724f52eb3","user":{"login":"ashwathraop","id":17821341,"avatar_url":"https://avatars3.githubusercontent.com/u/17821341?v=4","gravatar_id":"","url":"https://api.github.com/users/ashwathraop","html_url":"https://github.com/ashwathraop","followers_url":"https://api.github.com/users/ashwathraop/followers","following_url":"https://api.github.com/users/ashwathraop/following{/other_user}","gists_url":"https://api.github.com/users/ashwathraop/gists{/gist_id}","starred_url":"https://api.github.com/users/ashwathraop/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ashwathraop/subscriptions","organizations_url":"https://api.github.com/users/ashwathraop/orgs","repos_url":"https://api.github.com/users/ashwathraop/repos","events_url":"https://api.github.com/users/ashwathraop/events{/privacy}","received_events_url":"https://api.github.com/users/ashwathraop/received_events","type":"User","site_admin":false},"body":"Did you mean free_svrattrl()? free_attrlist() is for (pbs_list_head *).","created_at":"2018-04-01T14:33:31Z","updated_at":"2018-04-01T14:33:31Z","html_url":"https://github.com/PBSPro/pbspro/pull/601#discussion_r178459823","pull_request_url":"https://api.github.com/repos/PBSPro/pbspro/pulls/601","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/PBSPro/pbspro/pulls/comments/178459823"},"html":{"href":"https://github.com/PBSPro/pbspro/pull/601#discussion_r178459823"},"pull_request":{"href":"https://api.github.com/repos/PBSPro/pbspro/pulls/601"}},"in_reply_to_id":178337427},"pull_request":{"url":"https://api.github.com/repos/PBSPro/pbspro/pulls/601","id":176223535,"html_url":"https://github.com/PBSPro/pbspro/pull/601","diff_url":"https://github.com/PBSPro/pbspro/pull/601.diff","patch_url":"https://github.com/PBSPro/pbspro/pull/601.patch","issue_url":"https://api.github.com/repos/PBSPro/pbspro/issues/601","number":601,"state":"open","locked":false,"title":"PP-824: Cray - on/off functionality","user":{"login":"ashwathraop","id":17821341,"avatar_url":"https://avatars3.githubusercontent.com/u/17821341?v=4","gravatar_id":"","url":"https://api.github.com/users/ashwathraop","html_url":"https://github.com/ashwathraop","followers_url":"https://api.github.com/users/ashwathraop/followers","following_url":"https://api.github.com/users/ashwathraop/following{/other_user}","gists_url":"https://api.github.com/users/ashwathraop/gists{/gist_id}","starred_url":"https://api.github.com/users/ashwathraop/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ashwathraop/subscriptions","organizations_url":"https://api.github.com/users/ashwathraop/orgs","repos_url":"https://api.github.com/users/ashwathraop/repos","events_url":"https://api.github.com/users/ashwathraop/events{/privacy}","received_events_url":"https://api.github.com/users/ashwathraop/received_events","type":"User","site_admin":false},"body":"<!--- Please review your changes in preview mode -->\r\n<!--- Provide a general summary of your changes in the Title above -->\r\n\r\n#### Feature Description\r\nThis feature allows PBS to power on and off Cray compute nodes based on the workload.\r\n* *[PP-824](https://pbspro.atlassian.net/browse/PP-824)*\r\n\r\n#### Affected Platform(s)\r\n* CLE 5.2 and above with capmc support.\r\n\r\n#### Cause / Analysis / Design\r\n* *External design for the feature **[project documentation area](https://pbspro.atlassian.net/wiki/spaces/PD/pages/70123530/External+Interface+Design+for+Ramp+Rate+Limiting+and+power+on+off+nodes.)***\r\n* *Discussion on the Forum,  **[pbspro community forum](http://community.pbspro.org/t/external-design-document-for-pp-824-cray-ramp-rate-limiting/693)***\r\n\r\n#### Solution Description\r\n1.\tA pbshook will control the feature and enabling the hook will enable the power feature (including power capping using eoe and energy reporting) across the cluster. \r\n2.\tThere will be a node level control as well so that admin can decide what nodes to power on/off.\r\n3.\tEvery time a job/reservation ends, node involved in the execution of job/reservation, gets updated with the time stamp to attribute named last_used_time. This attribute is independent of power feature and can be used to sort nodes by scheduler.\r\n4.\tAnother node attribute also gets updated with time stamp when node changes its status (ex: free to busy, free to sleep) and is named last_state_change_time. This attribute will be used to identify how long node was in powered down state. \r\n5.\tFeature introduces a new hook config file for server periodic hook with finer control options like:\r\n\ta.\tpower_on_off_enable, enable power on/off feature at cluster level.\r\n\tb.\tNode_idle_time limit to decide if the node can be considered to shut down. Default 30min.\r\n\tc.\tmin_node_down_delay, once shutdown node has to be down for this much amount of time. Default 30 min.\r\n\td.\tmax_concurrent_nodes, how many nodes to power up/down per hook execution. Default 10.\r\n6.\tA node should check conditions listed below to power down :\r\n\ta.\tAll the vnodes on the node should be free.\r\n\tb.\tNo reservation is running or being deleted or being altered.\r\n7.\tScheduler can consider down nodes or as we named it “sleep” state, but it’ll update the estimated start_time to time_now + 600 seconds. \r\n8.\tUsing qselect -tt and qstat -f, hook identifies jobs with estimates start time and exec_vnodes to figure out if there are any down nodes that it needs to bring up now.\r\n9.\tIf hook brings a node up, next run of alps inventory update hook will mark the node up and free.\r\n\r\n\r\n#### Checklist:\r\n<!--- Use the preview button to see the checkboxes/links properly. -->\r\n<!--- Go over the following points, and put an `x` (without spaces around it) in the boxes that apply. -->\r\n<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->\r\n- [x] I have joined the **[pbspro community forum](http://community.pbspro.org/)**.\r\n- [x] My pull request contains a **single, signed** commit. See **[setting up gpg signature](https://pbspro.atlassian.net/wiki/display/DG/Signing+Your+Git+Commits)**.\r\n- [x] My code follows the **[coding style](https://pbspro.atlassian.net/wiki/display/DG/Coding+Standards)** of this project.\r\n- [x ] My change requires project documentation. See **[required documentation checklist](https://pbspro.atlassian.net/wiki/display/DG/Checklist+for+Developing+Features+and+Bug+Fixes)** for details.\r\n   - [x ] I have added documentation in the **[project documentation area](https://pbspro.atlassian.net/wiki/display/PD)**.\r\n- [ ] I have added new **PTL test(s) to my commit**. (See **[using PTL for testing](https://pbspro.atlassian.net/wiki/display/DG/Using+PTL+for+Testing)**) *(or)*\r\n   - [ ] I have added  **manual test(s) to this pull request and explained why PTL is not appropriate** for this case.\r\n- [ ] All new and existing automated tests have passed. (See **[running automated PTL tests](https://pbspro.atlassian.net/wiki/display/DG/PTL+Quick+Start+Guide)**).\r\n- [ ] I have attached **test logs to this pull request** as evidence of testing/verification.\r\n\r\n\r\n__***For further information please visit the [Developer Guide Home](https://pbspro.atlassian.net/wiki/display/DG/Developer+Guide+Home).***__\r\n","created_at":"2018-03-20T15:12:22Z","updated_at":"2018-04-01T14:33:31Z","closed_at":null,"merged_at":null,"merge_commit_sha":"697d1c1b5049ef3d05ec529f4bc299df32e6956d","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/PBSPro/pbspro/pulls/601/commits","review_comments_url":"https://api.github.com/repos/PBSPro/pbspro/pulls/601/comments","review_comment_url":"https://api.github.com/repos/PBSPro/pbspro/pulls/comments{/number}","comments_url":"https://api.github.com/repos/PBSPro/pbspro/issues/601/comments","statuses_url":"https://api.github.com/repos/PBSPro/pbspro/statuses/439253f65e05b03d2088b4ec61a0cbf724f52eb3","head":{"label":"ashwathraop:PP-824","ref":"PP-824","sha":"439253f65e05b03d2088b4ec61a0cbf724f52eb3","user":{"login":"ashwathraop","id":17821341,"avatar_url":"https://avatars3.githubusercontent.com/u/17821341?v=4","gravatar_id":"","url":"https://api.github.com/users/ashwathraop","html_url":"https://github.com/ashwathraop","followers_url":"https://api.github.com/users/ashwathraop/followers","following_url":"https://api.github.com/users/ashwathraop/following{/other_user}","gists_url":"https://api.github.com/users/ashwathraop/gists{/gist_id}","starred_url":"https://api.github.com/users/ashwathraop/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ashwathraop/subscriptions","organizations_url":"https://api.github.com/users/ashwathraop/orgs","repos_url":"https://api.github.com/users/ashwathraop/repos","events_url":"https://api.github.com/users/ashwathraop/events{/privacy}","received_events_url":"https://api.github.com/users/ashwathraop/received_events","type":"User","site_admin":false},"repo":{"id":62328625,"name":"pbspro","full_name":"ashwathraop/pbspro","owner":{"login":"ashwathraop","id":17821341,"avatar_url":"https://avatars3.githubusercontent.com/u/17821341?v=4","gravatar_id":"","url":"https://api.github.com/users/ashwathraop","html_url":"https://github.com/ashwathraop","followers_url":"https://api.github.com/users/ashwathraop/followers","following_url":"https://api.github.com/users/ashwathraop/following{/other_user}","gists_url":"https://api.github.com/users/ashwathraop/gists{/gist_id}","starred_url":"https://api.github.com/users/ashwathraop/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ashwathraop/subscriptions","organizations_url":"https://api.github.com/users/ashwathraop/orgs","repos_url":"https://api.github.com/users/ashwathraop/repos","events_url":"https://api.github.com/users/ashwathraop/events{/privacy}","received_events_url":"https://api.github.com/users/ashwathraop/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ashwathraop/pbspro","description":"An HPC workload manager and job scheduler for desktops, clusters, and clouds.","fork":true,"url":"https://api.github.com/repos/ashwathraop/pbspro","forks_url":"https://api.github.com/repos/ashwathraop/pbspro/forks","keys_url":"https://api.github.com/repos/ashwathraop/pbspro/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ashwathraop/pbspro/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ashwathraop/pbspro/teams","hooks_url":"https://api.github.com/repos/ashwathraop/pbspro/hooks","issue_events_url":"https://api.github.com/repos/ashwathraop/pbspro/issues/events{/number}","events_url":"https://api.github.com/repos/ashwathraop/pbspro/events","assignees_url":"https://api.github.com/repos/ashwathraop/pbspro/assignees{/user}","branches_url":"https://api.github.com/repos/ashwathraop/pbspro/branches{/branch}","tags_url":"https://api.github.com/repos/ashwathraop/pbspro/tags","blobs_url":"https://api.github.com/repos/ashwathraop/pbspro/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ashwathraop/pbspro/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ashwathraop/pbspro/git/refs{/sha}","trees_url":"https://api.github.com/repos/ashwathraop/pbspro/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ashwathraop/pbspro/statuses/{sha}","languages_url":"https://api.github.com/repos/ashwathraop/pbspro/languages","stargazers_url":"https://api.github.com/repos/ashwathraop/pbspro/stargazers","contributors_url":"https://api.github.com/repos/ashwathraop/pbspro/contributors","subscribers_url":"https://api.github.com/repos/ashwathraop/pbspro/subscribers","subscription_url":"https://api.github.com/repos/ashwathraop/pbspro/subscription","commits_url":"https://api.github.com/repos/ashwathraop/pbspro/commits{/sha}","git_commits_url":"https://api.github.com/repos/ashwathraop/pbspro/git/commits{/sha}","comments_url":"https://api.github.com/repos/ashwathraop/pbspro/comments{/number}","issue_comment_url":"https://api.github.com/repos/ashwathraop/pbspro/issues/comments{/number}","contents_url":"https://api.github.com/repos/ashwathraop/pbspro/contents/{+path}","compare_url":"https://api.github.com/repos/ashwathraop/pbspro/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ashwathraop/pbspro/merges","archive_url":"https://api.github.com/repos/ashwathraop/pbspro/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ashwathraop/pbspro/downloads","issues_url":"https://api.github.com/repos/ashwathraop/pbspro/issues{/number}","pulls_url":"https://api.github.com/repos/ashwathraop/pbspro/pulls{/number}","milestones_url":"https://api.github.com/repos/ashwathraop/pbspro/milestones{/number}","notifications_url":"https://api.github.com/repos/ashwathraop/pbspro/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ashwathraop/pbspro/labels{/name}","releases_url":"https://api.github.com/repos/ashwathraop/pbspro/releases{/id}","deployments_url":"https://api.github.com/repos/ashwathraop/pbspro/deployments","created_at":"2016-06-30T17:06:59Z","updated_at":"2016-06-30T17:07:05Z","pushed_at":"2018-03-30T17:28:11Z","git_url":"git://github.com/ashwathraop/pbspro.git","ssh_url":"git@github.com:ashwathraop/pbspro.git","clone_url":"https://github.com/ashwathraop/pbspro.git","svn_url":"https://github.com/ashwathraop/pbspro","homepage":"www.pbspro.org","size":14636,"stargazers_count":0,"watchers_count":0,"language":"C","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"other","name":"Other","spdx_id":null,"url":null},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"PBSPro:master","ref":"master","sha":"16deb6dc902ab75c610ee5ce268cf4c005caaae8","user":{"login":"PBSPro","id":19280436,"avatar_url":"https://avatars2.githubusercontent.com/u/19280436?v=4","gravatar_id":"","url":"https://api.github.com/users/PBSPro","html_url":"https://github.com/PBSPro","followers_url":"https://api.github.com/users/PBSPro/followers","following_url":"https://api.github.com/users/PBSPro/following{/other_user}","gists_url":"https://api.github.com/users/PBSPro/gists{/gist_id}","starred_url":"https://api.github.com/users/PBSPro/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/PBSPro/subscriptions","organizations_url":"https://api.github.com/users/PBSPro/orgs","repos_url":"https://api.github.com/users/PBSPro/repos","events_url":"https://api.github.com/users/PBSPro/events{/privacy}","received_events_url":"https://api.github.com/users/PBSPro/received_events","type":"Organization","site_admin":false},"repo":{"id":59082072,"name":"pbspro","full_name":"PBSPro/pbspro","owner":{"login":"PBSPro","id":19280436,"avatar_url":"https://avatars2.githubusercontent.com/u/19280436?v=4","gravatar_id":"","url":"https://api.github.com/users/PBSPro","html_url":"https://github.com/PBSPro","followers_url":"https://api.github.com/users/PBSPro/followers","following_url":"https://api.github.com/users/PBSPro/following{/other_user}","gists_url":"https://api.github.com/users/PBSPro/gists{/gist_id}","starred_url":"https://api.github.com/users/PBSPro/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/PBSPro/subscriptions","organizations_url":"https://api.github.com/users/PBSPro/orgs","repos_url":"https://api.github.com/users/PBSPro/repos","events_url":"https://api.github.com/users/PBSPro/events{/privacy}","received_events_url":"https://api.github.com/users/PBSPro/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/PBSPro/pbspro","description":"An HPC workload manager and job scheduler for desktops, clusters, and clouds.","fork":false,"url":"https://api.github.com/repos/PBSPro/pbspro","forks_url":"https://api.github.com/repos/PBSPro/pbspro/forks","keys_url":"https://api.github.com/repos/PBSPro/pbspro/keys{/key_id}","collaborators_url":"https://api.github.com/repos/PBSPro/pbspro/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/PBSPro/pbspro/teams","hooks_url":"https://api.github.com/repos/PBSPro/pbspro/hooks","issue_events_url":"https://api.github.com/repos/PBSPro/pbspro/issues/events{/number}","events_url":"https://api.github.com/repos/PBSPro/pbspro/events","assignees_url":"https://api.github.com/repos/PBSPro/pbspro/assignees{/user}","branches_url":"https://api.github.com/repos/PBSPro/pbspro/branches{/branch}","tags_url":"https://api.github.com/repos/PBSPro/pbspro/tags","blobs_url":"https://api.github.com/repos/PBSPro/pbspro/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/PBSPro/pbspro/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/PBSPro/pbspro/git/refs{/sha}","trees_url":"https://api.github.com/repos/PBSPro/pbspro/git/trees{/sha}","statuses_url":"https://api.github.com/repos/PBSPro/pbspro/statuses/{sha}","languages_url":"https://api.github.com/repos/PBSPro/pbspro/languages","stargazers_url":"https://api.github.com/repos/PBSPro/pbspro/stargazers","contributors_url":"https://api.github.com/repos/PBSPro/pbspro/contributors","subscribers_url":"https://api.github.com/repos/PBSPro/pbspro/subscribers","subscription_url":"https://api.github.com/repos/PBSPro/pbspro/subscription","commits_url":"https://api.github.com/repos/PBSPro/pbspro/commits{/sha}","git_commits_url":"https://api.github.com/repos/PBSPro/pbspro/git/commits{/sha}","comments_url":"https://api.github.com/repos/PBSPro/pbspro/comments{/number}","issue_comment_url":"https://api.github.com/repos/PBSPro/pbspro/issues/comments{/number}","contents_url":"https://api.github.com/repos/PBSPro/pbspro/contents/{+path}","compare_url":"https://api.github.com/repos/PBSPro/pbspro/compare/{base}...{head}","merges_url":"https://api.github.com/repos/PBSPro/pbspro/merges","archive_url":"https://api.github.com/repos/PBSPro/pbspro/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/PBSPro/pbspro/downloads","issues_url":"https://api.github.com/repos/PBSPro/pbspro/issues{/number}","pulls_url":"https://api.github.com/repos/PBSPro/pbspro/pulls{/number}","milestones_url":"https://api.github.com/repos/PBSPro/pbspro/milestones{/number}","notifications_url":"https://api.github.com/repos/PBSPro/pbspro/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/PBSPro/pbspro/labels{/name}","releases_url":"https://api.github.com/repos/PBSPro/pbspro/releases{/id}","deployments_url":"https://api.github.com/repos/PBSPro/pbspro/deployments","created_at":"2016-05-18T04:31:29Z","updated_at":"2018-04-01T14:22:51Z","pushed_at":"2018-04-01T14:22:47Z","git_url":"git://github.com/PBSPro/pbspro.git","ssh_url":"git@github.com:PBSPro/pbspro.git","clone_url":"https://github.com/PBSPro/pbspro.git","svn_url":"https://github.com/PBSPro/pbspro","homepage":"www.pbspro.org","size":14547,"stargazers_count":152,"watchers_count":152,"language":"C","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":129,"mirror_url":null,"archived":false,"open_issues_count":12,"license":{"key":"other","name":"Other","spdx_id":null,"url":null},"forks":129,"open_issues":12,"watchers":152,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/PBSPro/pbspro/pulls/601"},"html":{"href":"https://github.com/PBSPro/pbspro/pull/601"},"issue":{"href":"https://api.github.com/repos/PBSPro/pbspro/issues/601"},"comments":{"href":"https://api.github.com/repos/PBSPro/pbspro/issues/601/comments"},"review_comments":{"href":"https://api.github.com/repos/PBSPro/pbspro/pulls/601/comments"},"review_comment":{"href":"https://api.github.com/repos/PBSPro/pbspro/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/PBSPro/pbspro/pulls/601/commits"},"statuses":{"href":"https://api.github.com/repos/PBSPro/pbspro/statuses/439253f65e05b03d2088b4ec61a0cbf724f52eb3"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"ashwathraop"}}