/* * basil_request - issue BASIL request and parse response * @bp: method-dependent parse data to guide the parsing process * * Returns 0 if ok, a negative %basil_error otherwise. */ int basil_request(struct basil_parse_data *bp) { int to_child, from_child; int ec, rc = -BE_UNKNOWN; FILE *apbasil; pid_t pid; if (log_sel == -1) _init_log_config(); if (!cray_conf->apbasil) { error("No alps client defined"); return 0; } assert(bp->version < BV_MAX); assert(bp->method > BM_none && bp->method < BM_MAX); pid = popen2(cray_conf->apbasil, &to_child, &from_child, true); if (pid < 0) fatal("popen2(\"%s\", ...)", cray_conf->apbasil); /* write out request */ apbasil = fdopen(to_child, "w"); if (apbasil == NULL) fatal("fdopen(): %s", strerror(errno)); setlinebuf(apbasil); _write_xml(apbasil, "<?xml version=\"1.0\"?>\n" "<BasilRequest protocol=\"%s\" method=\"%s\" ", bv_names[bp->version], bm_names[bp->method]); switch (bp->method) { case BM_engine: _write_xml(apbasil, "type=\"ENGINE\"/>"); break; case BM_inventory: _write_xml(apbasil, "type=\"INVENTORY\"/>"); break; case BM_reserve: _write_xml(apbasil, ">\n"); _rsvn_write_reserve_xml(apbasil, bp->mdata.res); break; case BM_confirm: if (bp->version == BV_1_0 && *bp->mdata.res->batch_id != '\0') _write_xml(apbasil, "job_name=\"%s\" ", bp->mdata.res->batch_id); _write_xml(apbasil, "reservation_id=\"%u\" %s=\"%llu\"/>\n", bp->mdata.res->rsvn_id, bp->version >= BV_3_1 ? "pagg_id" : "admin_cookie", (unsigned long long)bp->mdata.res->pagg_id); break; case BM_release: _write_xml(apbasil, "reservation_id=\"%u\"/>\n", bp->mdata.res->rsvn_id); break; case BM_switch: { char *suspend = bp->mdata.res->suspended ? "OUT" : "IN"; _write_xml(apbasil, ">\n"); _write_xml(apbasil, " <ReservationArray>\n"); _write_xml(apbasil, " <Reservation reservation_id=\"%u\" " "action=\"%s\"/>\n", bp->mdata.res->rsvn_id, suspend); _write_xml(apbasil, " </ReservationArray>\n"); _write_xml(apbasil, "</BasilRequest>\n"); } break; default: /* ignore BM_none, BM_MAX, and BM_UNKNOWN covered above */ break; } if (fclose(apbasil) < 0) /* also closes to_child */ error("fclose(apbasil): %s", strerror(errno)); rc = parse_basil(bp, from_child); ec = wait_for_child(pid); if (ec) { error("%s child process for BASIL %s method exited with %d", cray_conf->apbasil, bm_names[bp->method], ec); } return rc; }
static void _rsvn_write_reserve_xml(FILE *fp, struct basil_reservation *r) { struct basil_rsvn_param *param; _write_xml(fp, " <ReserveParamArray user_name=\"%s\"", r->user_name); if (*r->batch_id != '\0') _write_xml(fp, " batch_id=\"%s\"", r->batch_id); if (*r->account_name != '\0') _write_xml(fp, " account_name=\"%s\"", r->account_name); _write_xml(fp, ">\n"); for (param = r->params; param; param = param->next) { _write_xml(fp, " <ReserveParam architecture=\"%s\" " "width=\"%ld\" depth=\"%ld\" nppn=\"%ld\"", nam_arch[param->arch], param->width, param->depth, param->nppn); if (param->memory || param->labels || param->nodes || param->accel) { _write_xml(fp, ">\n"); } else { _write_xml(fp, "/>\n"); continue; } if (param->memory) { struct basil_memory_param *mem; _write_xml(fp, " <MemoryParamArray>\n"); for (mem = param->memory; mem; mem = mem->next) { _write_xml(fp, " <MemoryParam type=\"%s\"" " size_mb=\"%u\"/>\n", nam_memtype[mem->type], mem->size_mb ? : 1); } _write_xml(fp, " </MemoryParamArray>\n"); } if (param->labels) { struct basil_label *label; _write_xml(fp, " <LabelParamArray>\n"); for (label = param->labels; label; label = label->next) _write_xml(fp, " <LabelParam name=\"%s\"" " type=\"%s\" disposition=\"%s\"/>\n", label->name, nam_labeltype[label->type], nam_ldisp[label->disp]); _write_xml(fp, " </LabelParamArray>\n"); } if (param->nodes && *param->nodes) { /* * The NodeParamArray is declared within ReserveParam. * If the list is spread out over multiple NodeParam * elements, an * "at least one command's user NID list is short" * error results. Hence more than 1 NodeParam element * is probably only meant to be used when suggesting * alternative node lists to ALPS. This was confirmed * by repeating an identical same NodeParam 20 times, * which had the same effect as supplying it once. * Hence the array expression is actually not needed. */ _write_xml(fp, " <NodeParamArray>\n" " <NodeParam>%s</NodeParam>\n" " </NodeParamArray>\n", param->nodes); } if (param->accel) { struct basil_accel_param *accel; _write_xml(fp, " <AccelParamArray>\n"); for (accel = param->accel; accel; accel = accel->next) { _write_xml(fp, " <AccelParam type=\"%s\"", nam_acceltype[accel->type]); if (accel->memory_mb) _write_xml(fp, " memory_mb=\"%u\"", accel->memory_mb); _write_xml(fp, "/>\n"); } _write_xml(fp, " </AccelParamArray>\n"); } _write_xml(fp, " </ReserveParam>\n"); } _write_xml(fp, " </ReserveParamArray>\n" "</BasilRequest>\n"); }
/* * basil_request - issue BASIL request and parse response * @bp: method-dependent parse data to guide the parsing process * * Returns 0 if ok, a negative %basil_error otherwise. */ int basil_request(struct basil_parse_data *bp) { int to_child, from_child; int ec, i, rc = -BE_UNKNOWN; FILE *apbasil; pid_t pid = -1; pthread_t thread; pthread_attr_t attr; int time_it_out = 1; DEF_TIMERS; if (log_sel == -1) _init_log_config(); if (!cray_conf->apbasil) { error("No alps client defined"); return 0; } if ((cray_conf->apbasil_timeout == 0) || (cray_conf->apbasil_timeout == (uint16_t) NO_VAL)) { debug2("No ApbasilTimeout configured (%u)", cray_conf->apbasil_timeout); time_it_out = 0; } else { slurm_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); } assert(bp->version < BV_MAX); assert(bp->method > BM_none && bp->method < BM_MAX); START_TIMER; for (i = 0; ((i < 10) && (pid < 0)); i++) { if (i) usleep(100000); pid = popen2(cray_conf->apbasil, &to_child, &from_child, true); } if (pid < 0) fatal("popen2(\"%s\", ...)", cray_conf->apbasil); if (time_it_out) { pthread_create(&thread, &attr, _timer_func, (void*)&pid); } /* write out request */ apbasil = fdopen(to_child, "w"); if (apbasil == NULL) fatal("fdopen(): %s", strerror(errno)); setlinebuf(apbasil); _write_xml(apbasil, "<?xml version=\"1.0\"?>\n" "<BasilRequest protocol=\"%s\" method=\"%s\" ", bv_names[bp->version], bm_names[bp->method]); switch (bp->method) { case BM_engine: _write_xml(apbasil, "type=\"ENGINE\"/>"); break; case BM_inventory: _write_xml(apbasil, "type=\"INVENTORY\"/>"); break; case BM_reserve: _write_xml(apbasil, ">\n"); _rsvn_write_reserve_xml(apbasil, bp->mdata.res, bp->version); break; case BM_confirm: if (bp->version == BV_1_0 && *bp->mdata.res->batch_id != '\0') _write_xml(apbasil, "job_name=\"%s\" ", bp->mdata.res->batch_id); _write_xml(apbasil, "reservation_id=\"%u\" %s=\"%llu\"/>\n", bp->mdata.res->rsvn_id, bp->version >= BV_3_1 ? "pagg_id" : "admin_cookie", (unsigned long long)bp->mdata.res->pagg_id); break; case BM_release: _write_xml(apbasil, "reservation_id=\"%u\"/>\n", bp->mdata.res->rsvn_id); break; case BM_switch: { char *suspend = bp->mdata.res->suspended ? "OUT" : "IN"; _write_xml(apbasil, ">\n"); _write_xml(apbasil, " <ReservationArray>\n"); _write_xml(apbasil, " <Reservation reservation_id=\"%u\" " "action=\"%s\"/>\n", bp->mdata.res->rsvn_id, suspend); _write_xml(apbasil, " </ReservationArray>\n"); _write_xml(apbasil, "</BasilRequest>\n"); } break; default: /* ignore BM_none, BM_MAX, and BM_UNKNOWN covered above */ break; } if (fclose(apbasil) < 0) /* also closes to_child */ error("fclose(apbasil): %s", strerror(errno)); rc = parse_basil(bp, from_child); ec = wait_for_child(pid); if (time_it_out) { slurm_attr_destroy(&attr); debug2("Killing the timer thread."); pthread_mutex_lock(&timer_lock); pthread_cond_broadcast(&timer_cond); pthread_mutex_unlock(&timer_lock); } END_TIMER; if (ec) { error("%s child process for BASIL %s method exited with %d", cray_conf->apbasil, bm_names[bp->method], ec); } else if (DELTA_TIMER > 5000000) { /* 5 seconds limit */ info("%s child process for BASIL %s method time %s", cray_conf->apbasil, bm_names[bp->method], TIME_STR); } return rc; }