/*___INFO__MARK_BEGIN__*/ /************************************************************************* * * The Contents of this file are made available subject to the terms of * the Sun Industry Standards Source License Version 1.2 * * Sun Microsystems Inc., March, 2001 * * * Sun Industry Standards Source License Version 1.2 * ================================================= * The contents of this file are subject to the Sun Industry Standards * Source License Version 1.2 (the "License"); You may not use this file * except in compliance with the License. You may obtain a copy of the * License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html * * Software provided under this License is provided on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. * See the License for the specific provisions governing your rights and * obligations concerning the Software. * * The Initial Developer of the Original Code is: Sun Microsystems, Inc. * * Copyright: 2001 by Sun Microsystems, Inc. * * All Rights Reserved. * ************************************************************************/ /*___INFO__MARK_END__*/ #include #include #include #include #include #include "rmon/sgermon.h" #include "uti/setup_path.h" #include "uti/sge_hostname.h" #include "uti/sge_prog.h" #include "uti/sge_bootstrap.h" #include "sched/sort_hosts.h" #include "sched/sge_select_queue.h" #include "sgeobj/parse.h" #include "sgeobj/sge_schedd_conf.h" #include "sgeobj/sge_conf.h" #include "sgeobj/sge_range.h" #include "sgeobj/sge_resource_quota.h" #include "sgeobj/sge_hgroup.h" #include "sgeobj/sge_userset.h" #include "sgeobj/sge_host.h" #include "sgeobj/sge_answer.h" #include "sgeobj/sge_qinstance.h" #include "sgeobj/sge_ulong.h" #include "sgeobj/sge_centry.h" #include "sgeobj/sge_feature.h" #include "sgeobj/sge_all_listsL.h" #include "gdi/sge_gdi.h" #include "gdi/sge_gdi_ctx.h" #include "basis_types.h" #include "sge_qstat.h" #include "sge_qquota.h" #include "sge.h" #include "msg_clients_common.h" #define HEAD_FORMAT "%-18s %-20.20s %s\n" typedef struct { const char* user; const char* project; const char* pe; const char* queue; const char* host; } qquota_filter_t; static bool get_all_lists(sge_gdi_ctx_class_t *ctx, lList **rqs_l, lList **centry_l, lList **userset_l, lList **hgroup_l, lList **exechost_l, lList *hostref_list, lList **alpp); static char *qquota_get_next_filter(stringT filter, const char *cp); static bool qquota_print_out_rule(lListElem *rule, dstring rule_name, const char *limit_name, const char *usage_value, const char *limit_value, qquota_filter_t filter, lListElem *centry, report_handler_t* report_handler, lList *printed_rules, lList **alpp); static bool qquota_print_out_filter(lListElem *filter, const char *name, const char *value, dstring *buffer, report_handler_t *report_handler, lList **alpp); /****** qquota_output/qquota_output() ******************************************** * NAME * qquota_output() -- qquota output function * * SYNOPSIS * bool qquota_output(void *ctx, lList *host_list, lList *resource_match_list, * lList *user_list, lList *pe_list, lList *project_list, lList * *cqueue_list, lList **alpp, report_handler_t* report_handler) * * FUNCTION * print resource quota rule and the limit * * INPUTS * void *ctx - gdi handler * lList *host_list - selected hosts * lList *resource_match_list - selected resources * lList *user_list - selected users * lList *pe_list - selecte pes * lList *project_list - selected projects * lList *cqueue_list - selected cluster queues * lList **alpp - answer list * report_handler_t* report_handler - report handler for xml output * * RESULT * bool - true on success * false on error * * NOTES * MT-NOTE: qquota_output() is MT safe * *******************************************************************************/ bool qquota_output(sge_gdi_ctx_class_t *ctx, lList *host_list, lList *resource_match_list, lList *user_list, lList *pe_list, lList *project_list, lList *cqueue_list, lList **alpp, report_handler_t* report_handler) { lList *rqs_list = NULL; lList *centry_list = NULL; lList *userset_list = NULL; lList *hgroup_list = NULL; lList *exechost_list = NULL; lListElem* global_host = NULL; lListElem* exec_host = NULL; lList* printed_rules = NULL; /* Hash list of already printed resource quota rules (possible with -u user1,user2,user3...) */ bool ret = true; int xml_ret = 0; qquota_filter_t qquota_filter = { "*", "*", "*", "*", "*" }; dstring rule_name = DSTRING_INIT; DENTER(TOP_LAYER, "qquota_output"); /* If no user is requested on command line we set the current user as default */ qquota_filter.user = ctx->get_username(ctx); ret = get_all_lists(ctx, &rqs_list, ¢ry_list, &userset_list, &hgroup_list, &exechost_list, host_list, alpp); if (ret == true) { lListElem *rqs = NULL; printed_rules = lCreateList("rule_hash", ST_Type); global_host = host_list_locate(exechost_list, SGE_GLOBAL_NAME); if (report_handler != NULL) { xml_ret = report_handler->report_started(report_handler, alpp); if (xml_ret != QQUOTA_SUCCESS) { ret = false; goto qquota_output_error; } } for_each(rqs, rqs_list) { lListElem *rule = NULL; int rule_count = 1; if (lGetBool(rqs, RQS_enabled) == false) { continue; } for_each(rule, lGetList(rqs, RQS_rule)) { lListElem *user_ep = lFirst(user_list); lListElem *project_ep = lFirst(project_list); lListElem *pe_ep = lFirst(pe_list); lListElem *queue_ep = lFirst(cqueue_list); lListElem *host_ep = lFirst(host_list); do { if (user_ep != NULL) { qquota_filter.user = lGetString(user_ep, ST_name); } do { if (project_ep != NULL) { qquota_filter.project = lGetString(project_ep, ST_name); } do { if (pe_ep != NULL) { qquota_filter.pe = lGetString(pe_ep, ST_name); } do { if (queue_ep != NULL) { qquota_filter.queue = lGetString(queue_ep, ST_name); } do { if (host_ep != NULL) { qquota_filter.host = lGetString(host_ep, ST_name); } if (rqs_is_matching_rule(rule, qquota_filter.user, NULL, qquota_filter.project, qquota_filter.pe, qquota_filter.host, qquota_filter.queue, userset_list, hgroup_list)) { lListElem *limit = NULL; for_each(limit, lGetList(rule, RQR_limit)) { const char *limit_name = lGetString(limit, RQRL_name); lList *rue_list = lGetList(limit, RQRL_usage); lListElem *raw_centry = centry_list_locate(centry_list, limit_name); lListElem *rue_elem = NULL; if (raw_centry == NULL) { /* undefined centries can be ignored */ DPRINTF(("centry %s not defined -> IGNORING\n", limit_name)); continue; } if ((resource_match_list != NULL) && ((centry_list_locate(resource_match_list, limit_name) == NULL) && (centry_list_locate(resource_match_list, lGetString(raw_centry, CE_shortcut)) == NULL))) { DPRINTF(("centry %s was not requested on CLI -> IGNORING\n", limit_name)); continue; } if (lGetString(rule, RQR_name)) { sge_dstring_sprintf(&rule_name, "%s/%s", lGetString(rqs, RQS_name), lGetString(rule, RQR_name)); } else { sge_dstring_sprintf(&rule_name, "%s/%d", lGetString(rqs, RQS_name), rule_count); } if (lGetUlong(raw_centry, CE_consumable)) { /* for consumables we need to walk through the utilization and search for matching values */ DPRINTF(("found centry %s - consumable\n", limit_name)); for_each(rue_elem, rue_list) { u_long32 dominant = 0; const char *rue_name = lGetString(rue_elem, RUE_name); char *cp = NULL; stringT user, project, pe, queue, host; dstring limit_str = DSTRING_INIT; dstring value_str = DSTRING_INIT; qquota_filter_t qf = { NULL, NULL, NULL, NULL, NULL }; /* check user name */ cp = qquota_get_next_filter(user, rue_name); /* usergroups have the same beginning character @ as host groups */ if (is_hgroup_name(qquota_filter.user)) { lListElem *ugroup = NULL; if ((ugroup = userset_list_locate(userset_list, &qquota_filter.user[1])) != NULL) { if (sge_contained_in_access_list(user, NULL, ugroup, NULL) == 0) { continue; } } } else { if ((strcmp(user, "-") != 0) && (strcmp(qquota_filter.user, "*") != 0) && (fnmatch(qquota_filter.user, user, 0) != 0)) { continue; } } /* check project */ cp = qquota_get_next_filter(project, cp); if ((strcmp(project, "-") != 0) && (strcmp(qquota_filter.project, "*") != 0) && (fnmatch(qquota_filter.project, project, 0) != 0)) { continue; } /* check parallel environment */ cp = qquota_get_next_filter(pe, cp); if ((strcmp(pe, "-") != 0) && (strcmp(qquota_filter.pe, "*") != 0) && (fnmatch(qquota_filter.pe, pe, 0) != 0) ) { continue; } /* check cluster queue */ cp = qquota_get_next_filter(queue, cp); if ((strcmp(queue, "-") != 0) && (strcmp(qquota_filter.queue, "*") != 0) && (fnmatch(qquota_filter.queue, queue, 0) != 0)) { continue; } /* check host name */ cp = qquota_get_next_filter(host, cp); if (is_hgroup_name(qquota_filter.host)) { lListElem *hgroup = NULL; if ((hgroup = hgroup_list_locate(hgroup_list, qquota_filter.host)) != NULL) { lList *host_list = NULL; hgroup_find_all_references(hgroup, NULL, hgroup_list, &host_list, NULL); if (host_list == NULL && lGetElemHost(host_list, HR_name, host) == NULL) { lFreeList(&host_list); continue; } lFreeList(&host_list); } } else { if ((strcmp(host, "-") != 0) && (strcmp(qquota_filter.host, "*") != 0) && (fnmatch(qquota_filter.host, host, 0) != 0) ) { continue; } } if (lGetBool(limit, RQRL_dynamic)) { exec_host = host_list_locate(exechost_list, host); sge_dstring_sprintf(&limit_str, "%d", (int)scaled_mixed_load(lGetString(limit, RQRL_value), global_host, exec_host, centry_list)); } else { lSetDouble(raw_centry, CE_pj_doubleval, lGetDouble(limit, RQRL_dvalue)); sge_get_dominant_stringval(raw_centry, &dominant, &limit_str); } lSetDouble(raw_centry,CE_pj_doubleval, lGetDouble(rue_elem, RUE_utilized_now)); sge_get_dominant_stringval(raw_centry, &dominant, &value_str); qf.user = user; qf.project = project; qf.pe = pe; qf.queue = queue; qf.host = host; ret = qquota_print_out_rule(rule, rule_name, limit_name, sge_dstring_get_string(&value_str), sge_dstring_get_string(&limit_str), qf, raw_centry, report_handler, printed_rules, alpp); sge_dstring_free(&limit_str); sge_dstring_free(&value_str); } } else { /* static values */ qquota_filter_t qf = { NULL, NULL, NULL, NULL, NULL }; DPRINTF(("found centry %s - static value\n", limit_name)); ret = qquota_print_out_rule(rule, rule_name, limit_name, NULL, lGetString(limit, RQRL_value), qf, raw_centry, report_handler, printed_rules, alpp); } } } } while ((host_ep = lNext(host_ep))); } while ((queue_ep = lNext(queue_ep))); } while ((pe_ep = lNext(pe_ep))); } while ((project_ep = lNext(project_ep))); } while ((user_ep = lNext(user_ep))); rule_count++; } } if (report_handler != NULL) { report_handler->report_finished(report_handler, alpp); } } qquota_output_error: sge_dstring_free(&rule_name); lFreeList(&rqs_list); lFreeList(¢ry_list); lFreeList(&userset_list); lFreeList(&hgroup_list); lFreeList(&exechost_list); lFreeList(&printed_rules); DRETURN(ret); } /****** qquota_output/get_all_lists() ****************************************** * NAME * get_all_lists() -- get all lists from qmaster * * SYNOPSIS * static bool get_all_lists(sge_gdi_ctx_class_t *ctx, lList **rqs_l, lList * **centry_l, lList **userset_l, lList **hgroup_l, lList **exechost_l, * lList *hostref_l, lList **alpp) * * FUNCTION * Gets copies of queue-, job-, complex-, exechost-list from qmaster. * The lists are stored in the .._l pointerpointer-parameters. * WARNING: Lists previously stored in this pointers are not destroyed!! * * INPUTS * void *context - gdi context * lList **rqs_l - resource quota set list (RQS_Type) * lList **centry_l - consumable resource list (CE_Type) * lList **userset_l - userset list (US_Type) * lList **hgroup_l - host group list (HG_Type) * lList **exechost_l - exechost list (EH_Type) * lList *hostref_l - selected hosts (ST_Type) * lList **alpp - answer list * * RESULT * static bool - true on success * false on error * * NOTES * MT-NOTE: get_all_lists() is MT safe * *******************************************************************************/ static bool get_all_lists(sge_gdi_ctx_class_t *ctx, lList **rqs_l, lList **centry_l, lList **userset_l, lList **hgroup_l, lList **exechost_l, lList *hostref_l, lList **alpp) { lListElem *ep = NULL; lEnumeration *what = NULL; lCondition *where = NULL, *nw = NULL; lList *mal = NULL; int rqs_id, ce_id, userset_id, hgroup_id, eh_id; state_gdi_multi state = STATE_GDI_MULTI_INIT; DENTER(TOP_LAYER, "get_all_lists"); /* ** resource quota sets */ what = lWhat("%T(ALL)", RQS_Type); rqs_id = ctx->gdi_multi(ctx, alpp, SGE_GDI_RECORD, SGE_RQS_LIST, SGE_GDI_GET, NULL, NULL, what, &state, true); lFreeWhat(&what); if (answer_list_has_error(alpp)) { DRETURN(false); } /* ** complexes */ what = lWhat("%T(ALL)", CE_Type); ce_id = ctx->gdi_multi(ctx, alpp, SGE_GDI_RECORD, SGE_CE_LIST, SGE_GDI_GET, NULL, NULL, what, &state, true); lFreeWhat(&what); if (answer_list_has_error(alpp)) { DRETURN(false); } /* ** usersets */ what = lWhat("%T(ALL)", US_Type); userset_id = ctx->gdi_multi(ctx, alpp, SGE_GDI_RECORD, SGE_US_LIST, SGE_GDI_GET, NULL, NULL, what, &state, true); lFreeWhat(&what); if (answer_list_has_error(alpp)) { DRETURN(false); } /* ** host groups */ what = lWhat("%T(ALL)", HGRP_Type); hgroup_id = ctx->gdi_multi(ctx, alpp, SGE_GDI_RECORD, SGE_HGRP_LIST, SGE_GDI_GET, NULL, NULL, what, &state, true); lFreeWhat(&what); /* ** exec hosts */ for_each(ep, hostref_l) { nw = lWhere("%T(%I h= %s)", EH_Type, EH_name, lGetString(ep, ST_name)); if (!where) where = nw; else where = lOrWhere(where, nw); } /* the global host has to be retrieved as well */ if (where != NULL) { nw = lWhere("%T(%I == %s)", EH_Type, EH_name, SGE_GLOBAL_NAME); where = lOrWhere(where, nw); } nw = lWhere("%T(%I != %s)", EH_Type, EH_name, SGE_TEMPLATE_NAME); if (where) where = lAndWhere(where, nw); else where = nw; what = lWhat("%T(%I %I %I %I)", EH_Type, EH_name, EH_load_list, EH_consumable_config_list, EH_resource_utilization); eh_id = ctx->gdi_multi(ctx, alpp, SGE_GDI_SEND, SGE_EH_LIST, SGE_GDI_GET, NULL, where, what, &state, true); ctx->gdi_wait(ctx, alpp, &mal, &state); lFreeWhat(&what); lFreeWhere(&where); if (answer_list_has_error(alpp)) { DRETURN(false); } /* --- resource quota sets */ lFreeList(alpp); sge_gdi_extract_answer(alpp, SGE_GDI_GET, SGE_RQS_LIST, rqs_id, mal, rqs_l); if (answer_list_has_error(alpp)) { lFreeList(&mal); DRETURN(false); } /* --- complex attribute */ lFreeList(alpp); sge_gdi_extract_answer(alpp, SGE_GDI_GET, SGE_CE_LIST, ce_id, mal, centry_l); if (answer_list_has_error(alpp)) { lFreeList(&mal); DRETURN(false); } /* --- usersets */ lFreeList(alpp); sge_gdi_extract_answer(alpp, SGE_GDI_GET, SGE_US_LIST, userset_id, mal, userset_l); if (answer_list_has_error(alpp)) { lFreeList(&mal); DRETURN(false); } /* --- hostgroups */ lFreeList(alpp); sge_gdi_extract_answer(alpp, SGE_GDI_GET, SGE_HGRP_LIST, hgroup_id, mal, hgroup_l); if (answer_list_has_error(alpp)) { lFreeList(&mal); DRETURN(false); } /* --- exec hosts*/ lFreeList(alpp); sge_gdi_extract_answer(alpp, SGE_GDI_GET, SGE_EH_LIST, eh_id, mal, exechost_l); lFreeList(&mal); if (answer_list_has_error(alpp)) { DRETURN(false); } DRETURN(true); } /****** qquota_output/qquota_get_next_filter() ********************************* * NAME * qquota_get_next_filter() -- tokenize rue_name of usage * * SYNOPSIS * static char* qquota_get_next_filter(char *filter, const char *cp) * * FUNCTION * The rue_name has the type /user_name/project_name/pe_name/queue_name/host_name. * This function tokenizes the rue_name and gives always one element back * * INPUTS * char *filter - store for the token * const char *cp - pointer to rue_name * * RESULT * static char* - pointer for the next token * * NOTES * MT-NOTE: qquota_get_next_filter() is not MT safe * *******************************************************************************/ static char *qquota_get_next_filter(stringT filter, const char *cp) { char *ret = NULL; ret = strchr(cp, '/')+1; if (ret - cp < MAX_STRING_SIZE && ret - cp > 1) { snprintf(filter, ret - cp, "%s", cp); } else { sprintf(filter, "-"); } return ret; } /****** qquota_output/qquota_print_out_rule() ********************************** * NAME * qquota_print_out_rule() -- print out rule * * SYNOPSIS * static bool qquota_print_out_rule(lListElem *rule, dstring rule_name, * const char *limit_name, const char *usage_value, const char *limit_value, * qquota_filter_t qfilter, lListElem *centry, report_handler_t* * report_handler, lList **alpp) * * FUNCTION * ??? * * INPUTS * lListElem *rule - resouce quota rule (RQR_Type) * dstring rule_name - rule name (eg. ruleset1/rule1) * const char *limit_name - limiation name (eg. slots) * const char *usage_value - debited usage * const char *limit_value - configured limitation * qquota_filter_t qfilter - filter touple * lListElem *centry - limitation centry element * report_handler_t* report_handler - handler for xml output * lList **alpp - answer list * * RESULT * static bool - true on success * false on error * * NOTES * MT-NOTE: qquota_print_out_rule() is not MT safe * *******************************************************************************/ static bool qquota_print_out_rule(lListElem *rule, dstring rule_name, const char *limit_name, const char *usage_value, const char *limit_value, qquota_filter_t qfilter, lListElem *centry, report_handler_t* report_handler, lList *printed_rules, lList **alpp) { static bool printheader = true; bool ret = true; dstring filter_str = DSTRING_INIT; dstring limitation = DSTRING_INIT; dstring token = DSTRING_INIT; sge_dstring_sprintf(&token, "%s,%s,%s,%s,%s,%s,%s", sge_dstring_get_string(&rule_name), limit_name, qfilter.user? qfilter.user: "", qfilter.project? qfilter.project: "", qfilter.pe? qfilter.pe: "", qfilter.queue? qfilter.queue: "", qfilter.host? qfilter.host: ""); if (lGetElemStr(printed_rules, ST_name, sge_dstring_get_string(&token)) != NULL) { sge_dstring_free(&token); sge_dstring_free(&filter_str); sge_dstring_free(&limitation); return ret; } lAddElemStr(&printed_rules, ST_name, sge_dstring_get_string(&token), ST_Type); if (report_handler != NULL) { report_handler->report_limit_rule_begin(report_handler, sge_dstring_get_string(&rule_name), alpp); } else { if (printheader == true) { printheader = false; printf(HEAD_FORMAT, MSG_HEADER_RULE, MSG_HEADER_LIMIT, MSG_HEADER_FILTER); printf("--------------------------------------------------------------------------------\n"); } } qquota_print_out_filter(lGetObject(rule, RQR_filter_users), "users", qfilter.user, &filter_str, report_handler, alpp); qquota_print_out_filter(lGetObject(rule, RQR_filter_projects), "projects", qfilter.project, &filter_str, report_handler, alpp); qquota_print_out_filter(lGetObject(rule, RQR_filter_pes), "pes", qfilter.pe, &filter_str, report_handler, alpp); qquota_print_out_filter(lGetObject(rule, RQR_filter_queues), "queues", qfilter.queue, &filter_str, report_handler, alpp); qquota_print_out_filter(lGetObject(rule, RQR_filter_hosts), "hosts", qfilter.host, &filter_str, report_handler, alpp); if (report_handler != NULL) { report_handler->report_resource_value(report_handler, limit_name, limit_value, usage_value, alpp); report_handler->report_limit_rule_finished(report_handler, sge_dstring_get_string(&rule_name), alpp); } else { if (usage_value == NULL) { sge_dstring_sprintf(&limitation, "%s=%s", limit_name, limit_value); } else { sge_dstring_sprintf(&limitation, "%s=%s/%s", limit_name, usage_value, limit_value); } if (sge_dstring_strlen(&filter_str) == 0) { sge_dstring_append(&filter_str, "-"); } printf(HEAD_FORMAT, sge_dstring_get_string(&rule_name), sge_dstring_get_string(&limitation), sge_dstring_get_string(&filter_str)); } sge_dstring_free(&token); sge_dstring_free(&filter_str); sge_dstring_free(&limitation); return ret; } /****** qquota_output/qquota_print_out_filter() ******************************** * NAME * qquota_print_out_filter() -- prints out filter element * * SYNOPSIS * static bool qquota_print_out_filter(lListElem *filter, const char *name, * const char *value, dstring *buffer, report_handler_t *report_handler, * lList **alpp) * * FUNCTION * this function prints out the filter configured in the rule * * INPUTS * lListElem *filter - filter element (RQRF_Type) * const char *name - filter type name * const char *value - filter value * dstring *buffer - buffer * report_handler_t *report_handler - handler for report handler * lList **alpp - answer list * * RESULT * static bool - true on success * false on error * * NOTES * MT-NOTE: qquota_print_out_filter() is MT safe * *******************************************************************************/ static bool qquota_print_out_filter(lListElem *filter, const char *name, const char *value, dstring *buffer, report_handler_t *report_handler, lList **alpp) { bool ret = true; lListElem *scope; if (filter != NULL) { if (!lGetBool(filter, RQRF_expand) || value == NULL) { if (report_handler != NULL) { for_each(scope, lGetList(filter, RQRF_scope)) { report_handler->report_limit_string_value(report_handler, name, lGetString(scope, ST_name), false, alpp); } for_each(scope, lGetList(filter, RQRF_xscope)) { report_handler->report_limit_string_value(report_handler, name, lGetString(scope, ST_name), true, alpp); } } else { if (sge_dstring_strlen(buffer) != 0) { sge_dstring_append(buffer, " "); } sge_dstring_append(buffer, name); sge_dstring_append(buffer, " "); rqs_append_filter_to_dstring(filter, buffer, alpp); } } else { if (report_handler != NULL) { report_handler->report_limit_string_value(report_handler, name, value, false, alpp); } else { if (sge_dstring_strlen(buffer) != 0) { sge_dstring_append(buffer, " "); } sge_dstring_append(buffer, name); sge_dstring_append(buffer, " "); sge_dstring_append(buffer, value); } } } return ret; }