/*****************************************************************************\ * front_end_info.c - Functions related to front end node display * mode of sview. ***************************************************************************** * Copyright (C) 2004-2007 The Regents of the University of California. * Copyright (C) 2008-2011 Lawrence Livermore National Security. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). * Written by Morris Jette * CODE-OCEC-09-009. All rights reserved. * * This file is part of Slurm, a resource management program. * For details, see . * Please also read the included file: DISCLAIMER. * * Slurm is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along * with Slurm; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. \*****************************************************************************/ #include "src/common/uid.h" #include "src/sview/sview.h" #include "src/common/parse_time.h" #define _DEBUG 0 /* Collection of data for printing reports. Like data is combined here */ typedef struct { int color_inx; char *front_end_name; front_end_info_t *front_end_ptr; GtkTreeIter iter_ptr; bool iter_set; char *boot_time; int node_inx[3]; int pos; char *reason; char *slurmd_start_time; char *state; } sview_front_end_info_t; typedef struct { char *node_list; } front_end_user_data_t; enum { EDIT_REMOVE = 1, EDIT_EDIT }; /* These need to be in alpha order (except POS and CNT) */ enum { SORTID_POS = POS_LOC, SORTID_ALLOW_GROUPS, SORTID_ALLOW_USERS, SORTID_BOOT_TIME, SORTID_COLOR, SORTID_COLOR_INX, SORTID_DENY_GROUPS, SORTID_DENY_USERS, SORTID_NAME, SORTID_NODE_INX, SORTID_REASON, SORTID_SLURMD_START_TIME, SORTID_STATE, SORTID_UPDATED, SORTID_VERSION, SORTID_CNT }; /* extra field here is for choosing the type of edit you that will * take place. If you choose EDIT_MODEL (means only display a set of * known options) create it in function create_model_*. */ /*these are the settings to apply for the user * on the first startup after a fresh slurm install. * s/b a const probably*/ static char *_initial_page_opts = "Name,State"; static display_data_t display_data_front_end[] = { {G_TYPE_INT, SORTID_POS, NULL, false, EDIT_NONE, refresh_front_end, create_model_front_end, admin_edit_front_end}, {G_TYPE_STRING, SORTID_NAME, "Name", false, EDIT_NONE, refresh_front_end, create_model_front_end, admin_edit_front_end}, {G_TYPE_STRING, SORTID_COLOR, NULL, true, EDIT_COLOR, refresh_front_end, create_model_front_end, admin_edit_front_end}, {G_TYPE_STRING, SORTID_STATE, "State", false, EDIT_MODEL, refresh_front_end, create_model_front_end, admin_edit_front_end}, {G_TYPE_STRING, SORTID_BOOT_TIME, "BootTime", false, EDIT_NONE, refresh_front_end, create_model_front_end, admin_edit_front_end}, {G_TYPE_STRING, SORTID_SLURMD_START_TIME, "SlurmdStartTime", false, EDIT_NONE, refresh_front_end, create_model_front_end, admin_edit_front_end}, {G_TYPE_STRING, SORTID_REASON, "Reason", false, EDIT_NONE, refresh_front_end, create_model_front_end, admin_edit_front_end}, {G_TYPE_STRING, SORTID_ALLOW_GROUPS, "Allow Groups", false, EDIT_NONE, refresh_front_end, create_model_front_end, admin_edit_front_end}, {G_TYPE_STRING, SORTID_ALLOW_USERS, "Allow Users", false, EDIT_NONE, refresh_front_end, create_model_front_end, admin_edit_front_end}, {G_TYPE_STRING, SORTID_DENY_GROUPS, "Deny Groups", false, EDIT_NONE, refresh_front_end, create_model_front_end, admin_edit_front_end}, {G_TYPE_STRING, SORTID_DENY_USERS, "Deny Users", false, EDIT_NONE, refresh_front_end, create_model_front_end, admin_edit_front_end}, {G_TYPE_STRING, SORTID_VERSION, "Version", false, EDIT_NONE, refresh_front_end, create_model_front_end, admin_edit_front_end}, {G_TYPE_INT, SORTID_COLOR_INX, NULL, false, EDIT_NONE, refresh_front_end, create_model_front_end, admin_edit_front_end}, {G_TYPE_POINTER, SORTID_NODE_INX, NULL, false, EDIT_NONE, refresh_front_end, create_model_front_end, admin_edit_front_end}, {G_TYPE_INT, SORTID_UPDATED, NULL, false, EDIT_NONE, refresh_resv, create_model_resv, admin_edit_resv}, {G_TYPE_NONE, -1, NULL, false, EDIT_NONE} }; static display_data_t options_data_front_end[] = { {G_TYPE_INT, SORTID_POS, NULL, false, EDIT_NONE}, {G_TYPE_STRING, INFO_PAGE, "Full Info", true, FRONT_END_PAGE}, {G_TYPE_STRING, FRONT_END_PAGE, "Drain Front End Node", true, ADMIN_PAGE}, {G_TYPE_STRING, FRONT_END_PAGE, "Resume Front End Node", true, ADMIN_PAGE}, {G_TYPE_NONE, -1, NULL, false, EDIT_NONE} }; static display_data_t *local_display_data = NULL; static char *got_edit_signal = NULL; static GtkTreeModel *last_model = NULL; static void _admin_front_end(GtkTreeModel *model, GtkTreeIter *iter, char *type, char *node_list); static void _process_each_front_end(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter*iter, gpointer userdata); static void _front_end_info_free(sview_front_end_info_t *sview_front_end_info) { if (sview_front_end_info) { xfree(sview_front_end_info->boot_time); xfree(sview_front_end_info->reason); xfree(sview_front_end_info->slurmd_start_time); xfree(sview_front_end_info->state); } } static void _front_end_info_list_del(void *object) { sview_front_end_info_t *sview_front_end_info; sview_front_end_info = (sview_front_end_info_t *)object; if (sview_front_end_info) { _front_end_info_free(sview_front_end_info); xfree(sview_front_end_info); } } static void _layout_front_end_record(GtkTreeView *treeview, sview_front_end_info_t * sview_front_end_info, int update) { GtkTreeIter iter; front_end_info_t *front_end_ptr = sview_front_end_info->front_end_ptr; GtkTreeStore *treestore = GTK_TREE_STORE(gtk_tree_view_get_model(treeview)); if (!treestore) return; add_display_treestore_line(update, treestore, &iter, find_col_name(display_data_front_end, SORTID_NAME), front_end_ptr->name); add_display_treestore_line(update, treestore, &iter, find_col_name(display_data_front_end, SORTID_STATE), sview_front_end_info->state); add_display_treestore_line(update, treestore, &iter, find_col_name(display_data_front_end, SORTID_BOOT_TIME), sview_front_end_info->boot_time); add_display_treestore_line(update, treestore, &iter, find_col_name(display_data_front_end, SORTID_SLURMD_START_TIME), sview_front_end_info->slurmd_start_time); add_display_treestore_line(update, treestore, &iter, find_col_name(display_data_front_end, SORTID_REASON), sview_front_end_info->reason); add_display_treestore_line(update, treestore, &iter, find_col_name(display_data_front_end, SORTID_ALLOW_GROUPS), front_end_ptr->allow_groups); add_display_treestore_line(update, treestore, &iter, find_col_name(display_data_front_end, SORTID_ALLOW_USERS), front_end_ptr->allow_users); add_display_treestore_line(update, treestore, &iter, find_col_name(display_data_front_end, SORTID_DENY_GROUPS), front_end_ptr->deny_groups); add_display_treestore_line(update, treestore, &iter, find_col_name(display_data_front_end, SORTID_DENY_USERS), front_end_ptr->deny_users); add_display_treestore_line(update, treestore, &iter, find_col_name(display_data_front_end, SORTID_VERSION), front_end_ptr->version); } static void _update_front_end_record( sview_front_end_info_t *sview_front_end_info_ptr, GtkTreeStore *treestore) { front_end_info_t *front_end_ptr; front_end_ptr = sview_front_end_info_ptr->front_end_ptr; /* Combining these records provides a slight performance improvement */ gtk_tree_store_set(treestore, &sview_front_end_info_ptr->iter_ptr, SORTID_ALLOW_GROUPS, front_end_ptr->allow_groups, SORTID_ALLOW_USERS, front_end_ptr->allow_users, SORTID_BOOT_TIME, sview_front_end_info_ptr->boot_time, SORTID_COLOR, sview_colors[ sview_front_end_info_ptr->color_inx], SORTID_COLOR_INX, sview_front_end_info_ptr->color_inx, SORTID_DENY_GROUPS, front_end_ptr->deny_groups, SORTID_DENY_USERS, front_end_ptr->deny_users, SORTID_NODE_INX, sview_front_end_info_ptr->node_inx, SORTID_NAME, front_end_ptr->name, SORTID_REASON, sview_front_end_info_ptr->reason, SORTID_SLURMD_START_TIME, sview_front_end_info_ptr->slurmd_start_time, SORTID_STATE, sview_front_end_info_ptr->state, SORTID_UPDATED, 1, SORTID_VERSION, front_end_ptr->version, -1); return; } static void _append_front_end_record( sview_front_end_info_t *sview_front_end_info_ptr, GtkTreeStore *treestore) { gtk_tree_store_append(treestore, &sview_front_end_info_ptr->iter_ptr, NULL); gtk_tree_store_set(treestore, &sview_front_end_info_ptr->iter_ptr, SORTID_POS, sview_front_end_info_ptr->pos, -1); _update_front_end_record(sview_front_end_info_ptr, treestore); } static void _update_info_front_end(List info_list, GtkTreeView *tree_view) { GtkTreeModel *model = gtk_tree_view_get_model(tree_view); char *name; ListIterator itr = NULL; sview_front_end_info_t *sview_front_end_info = NULL; set_for_update(model, SORTID_UPDATED); itr = list_iterator_create(info_list); while ((sview_front_end_info = list_next(itr))) { /* This means the tree_store changed (added new column or something). */ if (last_model != model) sview_front_end_info->iter_set = false; if (sview_front_end_info->iter_set) { gtk_tree_model_get(model, &sview_front_end_info->iter_ptr, SORTID_NAME, &name, -1); if (xstrcmp(name, sview_front_end_info->front_end_name)) { /* Bad pointer */ sview_front_end_info->iter_set = false; //g_print("bad front_end iter pointer\n"); } g_free(name); } if (sview_front_end_info->iter_set) _update_front_end_record(sview_front_end_info, GTK_TREE_STORE(model)); else { _append_front_end_record(sview_front_end_info, GTK_TREE_STORE(model)); sview_front_end_info->iter_set = true; } } list_iterator_destroy(itr); /* remove all old front_ends */ remove_old(model, SORTID_UPDATED); last_model = model; } static List _create_front_end_info_list( front_end_info_msg_t *front_end_info_ptr, int changed) { char *upper = NULL; char user[32], time_str[32]; static List info_list = NULL; List last_list = NULL; ListIterator last_list_itr = NULL; int i = 0; sview_front_end_info_t *sview_front_end_info_ptr = NULL; front_end_info_t *front_end_ptr = NULL; if (!changed && info_list) goto update_color; if (info_list) last_list = info_list; info_list = list_create(_front_end_info_list_del); if (last_list) last_list_itr = list_iterator_create(last_list); for (i = 0; i < front_end_info_ptr->record_count; i++) { front_end_ptr = &(front_end_info_ptr->front_end_array[i]); sview_front_end_info_ptr = NULL; if (last_list_itr) { while ((sview_front_end_info_ptr = list_next(last_list_itr))) { if (!xstrcmp(sview_front_end_info_ptr-> front_end_name, front_end_ptr->name)) { list_remove(last_list_itr); _front_end_info_free( sview_front_end_info_ptr); break; } } list_iterator_reset(last_list_itr); } if (!sview_front_end_info_ptr) sview_front_end_info_ptr = xmalloc(sizeof(sview_front_end_info_t)); sview_front_end_info_ptr->pos = i; sview_front_end_info_ptr->front_end_name = front_end_ptr->name; sview_front_end_info_ptr->front_end_ptr = front_end_ptr; sview_front_end_info_ptr->color_inx = i % sview_colors_cnt; if (g_node_info_ptr) { sview_front_end_info_ptr->node_inx[0] = 0; sview_front_end_info_ptr->node_inx[1] = g_node_info_ptr->record_count - 1; sview_front_end_info_ptr->node_inx[2] = -1; } else sview_front_end_info_ptr->node_inx[0] = -1; if (front_end_ptr->boot_time) { slurm_make_time_str(&front_end_ptr->boot_time, time_str, sizeof(time_str)); sview_front_end_info_ptr->boot_time = xstrdup(time_str); } if (front_end_ptr->slurmd_start_time) { slurm_make_time_str(&front_end_ptr->slurmd_start_time, time_str, sizeof(time_str)); sview_front_end_info_ptr->slurmd_start_time = xstrdup(time_str); } upper = node_state_string(front_end_ptr->node_state); sview_front_end_info_ptr->state = str_tolower(upper); if (front_end_ptr->reason && front_end_ptr->reason_time && (front_end_ptr->reason_uid != NO_VAL)) { struct passwd *pw = NULL; if ((pw=getpwuid(front_end_ptr->reason_uid))) snprintf(user, sizeof(user), "%s", pw->pw_name); else snprintf(user, sizeof(user), "Unk(%u)", front_end_ptr->reason_uid); slurm_make_time_str(&front_end_ptr->reason_time, time_str, sizeof(time_str)); sview_front_end_info_ptr->reason = xstrdup_printf("%s [%s@%s]", front_end_ptr->reason, user, time_str); } else { sview_front_end_info_ptr->reason = xstrdup(front_end_ptr->reason); } list_append(info_list, sview_front_end_info_ptr); } if (last_list) { list_iterator_destroy(last_list_itr); FREE_NULL_LIST(last_list); } update_color: return info_list; } static void _display_info_front_end(List info_list, popup_info_t *popup_win) { specific_info_t *spec_info = popup_win->spec_info; char *name = (char *)spec_info->search_info->gchar_data; int found = 0, j; front_end_info_t *front_end_ptr = NULL; GtkTreeView *treeview = NULL; ListIterator itr = NULL; sview_front_end_info_t *sview_fe_info = NULL; int update = 0; if (!spec_info->search_info->gchar_data) { //info = xstrdup("No pointer given!"); goto finished; } need_refresh: if (!spec_info->display_widget) { treeview = create_treeview_2cols_attach_to_table( popup_win->table); spec_info->display_widget = g_object_ref(GTK_WIDGET(treeview)); } else { treeview = GTK_TREE_VIEW(spec_info->display_widget); update = 1; } itr = list_iterator_create(info_list); while ((sview_fe_info = list_next(itr))) { front_end_ptr = sview_fe_info->front_end_ptr; if (xstrcmp(front_end_ptr->name, name) == 0) { j = 0; while (sview_fe_info->node_inx[j] >= 0) { change_grid_color(popup_win->grid_button_list, sview_fe_info->node_inx[j], sview_fe_info->node_inx[j+1], sview_fe_info->color_inx, true, 0); j += 2; } _layout_front_end_record(treeview, sview_fe_info, update); found = 1; break; } } list_iterator_destroy(itr); post_setup_popup_grid_list(popup_win); if (!found) { if (!popup_win->not_found) { char *temp = "FRONT END DOESN'T EXSIST\n"; GtkTreeIter iter; GtkTreeModel *model = NULL; /* only time this will be run so no update */ model = gtk_tree_view_get_model(treeview); add_display_treestore_line(0, GTK_TREE_STORE(model), &iter, temp, ""); } popup_win->not_found = true; } else { if (popup_win->not_found) { popup_win->not_found = false; gtk_widget_destroy(spec_info->display_widget); goto need_refresh; } } gtk_widget_show(spec_info->display_widget); finished: return; } extern void refresh_front_end(GtkAction *action, gpointer user_data) { popup_info_t *popup_win = (popup_info_t *)user_data; xassert(popup_win); xassert(popup_win->spec_info); xassert(popup_win->spec_info->title); popup_win->force_refresh = 1; specific_info_front_end(popup_win); } extern int get_new_info_front_end(front_end_info_msg_t **info_ptr, int force) { static front_end_info_msg_t *new_front_end_ptr = NULL; int error_code = SLURM_NO_CHANGE_IN_DATA; time_t now = time(NULL); static time_t last; static bool changed = 0; if (g_front_end_info_ptr && !force && ((now - last) < working_sview_config.refresh_delay)) { if (*info_ptr != g_front_end_info_ptr) error_code = SLURM_SUCCESS; *info_ptr = g_front_end_info_ptr; if (changed) error_code = SLURM_SUCCESS; goto end_it; } last = now; if (g_front_end_info_ptr) { error_code = slurm_load_front_end( g_front_end_info_ptr->last_update, &new_front_end_ptr); if (error_code == SLURM_SUCCESS) { slurm_free_front_end_info_msg(g_front_end_info_ptr); changed = 1; } else if (slurm_get_errno() == SLURM_NO_CHANGE_IN_DATA) { error_code = SLURM_NO_CHANGE_IN_DATA; new_front_end_ptr = g_front_end_info_ptr; changed = 0; } } else { new_front_end_ptr = NULL; error_code = slurm_load_front_end((time_t) NULL, &new_front_end_ptr); changed = 1; } g_front_end_info_ptr = new_front_end_ptr; if (g_front_end_info_ptr && (*info_ptr != g_front_end_info_ptr)) error_code = SLURM_SUCCESS; *info_ptr = g_front_end_info_ptr; end_it: return error_code; } extern GtkListStore *create_model_front_end(int type) { GtkListStore *model = NULL; GtkTreeIter iter; int i = 0; last_model = NULL; /* Reformat display */ switch(type) { case SORTID_STATE: model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT); gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, 0, "Drain", 1, i, -1); gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, 0, "Resume", 1, i, -1); break; } return model; } extern void admin_edit_front_end(GtkCellRendererText *cell, const char *path_string, const char *new_text, gpointer data) { GtkTreeStore *treestore = GTK_TREE_STORE(data); GtkTreePath *path = gtk_tree_path_new_from_string(path_string); GtkTreeIter iter; char *node_list = NULL; int column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column")); if (!new_text || !xstrcmp(new_text, "")) goto no_input; gtk_tree_model_get_iter(GTK_TREE_MODEL(treestore), &iter, path); switch(column) { case SORTID_STATE: gtk_tree_model_get(GTK_TREE_MODEL(treestore), &iter, SORTID_NAME, &node_list, -1); _admin_front_end(GTK_TREE_MODEL(treestore), &iter, (char *)new_text, node_list); g_free(node_list); default: break; } no_input: gtk_tree_path_free(path); g_mutex_unlock(sview_mutex); } extern void get_info_front_end(GtkTable *table, display_data_t *display_data) { int error_code = SLURM_SUCCESS; List info_list = NULL; static int view = -1; static front_end_info_msg_t *front_end_info_ptr = NULL; char error_char[100]; GtkWidget *label = NULL; GtkTreeView *tree_view = NULL; static GtkWidget *display_widget = NULL; int changed = 1, j; ListIterator itr = NULL; GtkTreePath *path = NULL; static bool set_opts = false; if (!set_opts) set_page_opts(FRONT_END_PAGE, display_data_front_end, SORTID_CNT, _initial_page_opts); set_opts = true; /* reset */ if (!table && !display_data) { if (display_widget) gtk_widget_destroy(display_widget); display_widget = NULL; front_end_info_ptr = NULL; goto reset_curs; } if (display_data) local_display_data = display_data; if (!table) { display_data_front_end->set_menu = local_display_data->set_menu; goto reset_curs; } if (cluster_flags & CLUSTER_FLAG_FED) { view = ERROR_VIEW; if (display_widget) gtk_widget_destroy(display_widget); label = gtk_label_new("Not available in a federated view"); gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); gtk_widget_show(label); display_widget = g_object_ref(label); goto end_it; } if (display_widget && toggled) { gtk_widget_destroy(display_widget); display_widget = NULL; goto display_it; } error_code = get_new_info_front_end(&front_end_info_ptr, force_refresh); if (error_code == SLURM_NO_CHANGE_IN_DATA) { changed = 0; } else if (error_code != SLURM_SUCCESS) { if (view == ERROR_VIEW) goto end_it; if (display_widget) gtk_widget_destroy(display_widget); view = ERROR_VIEW; sprintf(error_char, "slurm_load_front_end: %s", slurm_strerror(slurm_get_errno())); label = gtk_label_new(error_char); gtk_table_attach_defaults(table, label, 0, 1, 0, 1); gtk_widget_show(label); display_widget = g_object_ref(GTK_WIDGET(label)); goto end_it; } display_it: info_list = _create_front_end_info_list(front_end_info_ptr, changed); if (!info_list) goto reset_curs; /* set up the grid */ if (display_widget && GTK_IS_TREE_VIEW(display_widget) && gtk_tree_selection_count_selected_rows( gtk_tree_view_get_selection( GTK_TREE_VIEW(display_widget)))) { GtkTreeViewColumn *focus_column = NULL; /* highlight the correct nodes from the last selection */ gtk_tree_view_get_cursor(GTK_TREE_VIEW(display_widget), &path, &focus_column); } if (!path) { sview_front_end_info_t *fe_ptr; itr = list_iterator_create(info_list); while ((fe_ptr = list_next(itr))) { j = 0; while (fe_ptr->node_inx[j] >= 0) { change_grid_color(grid_button_list, fe_ptr->node_inx[j], fe_ptr->node_inx[j+1], fe_ptr->color_inx, true, 0); j += 2; } } list_iterator_destroy(itr); change_grid_color(grid_button_list, -1, -1, MAKE_WHITE, true, 0); } else { highlight_grid(GTK_TREE_VIEW(display_widget), SORTID_NODE_INX, SORTID_COLOR_INX, grid_button_list); gtk_tree_path_free(path); } if (view == ERROR_VIEW && display_widget) { gtk_widget_destroy(display_widget); display_widget = NULL; } if (!display_widget) { tree_view = create_treeview(local_display_data, &grid_button_list); gtk_tree_selection_set_mode( gtk_tree_view_get_selection(tree_view), GTK_SELECTION_MULTIPLE); display_widget = g_object_ref(GTK_WIDGET(tree_view)); gtk_table_attach_defaults(table, GTK_WIDGET(tree_view), 0, 1, 0, 1); /* since this function sets the model of the tree_view to the treestore we don't really care about the return value */ create_treestore(tree_view, display_data_front_end, SORTID_CNT, SORTID_NAME, SORTID_COLOR); } view = INFO_VIEW; _update_info_front_end(info_list, GTK_TREE_VIEW(display_widget)); end_it: toggled = false; force_refresh = false; reset_curs: if (main_window && main_window->window) gdk_window_set_cursor(main_window->window, NULL); return; } extern void specific_info_front_end(popup_info_t *popup_win) { int resv_error_code = SLURM_SUCCESS; static front_end_info_msg_t *front_end_info_ptr = NULL; static front_end_info_t *front_end_ptr = NULL; specific_info_t *spec_info = popup_win->spec_info; sview_search_info_t *search_info = spec_info->search_info; char error_char[100]; GtkWidget *label = NULL; GtkTreeView *tree_view = NULL; List resv_list = NULL; List send_resv_list = NULL; int changed = 1; sview_front_end_info_t *sview_front_end_info_ptr = NULL; int i = -1; ListIterator itr = NULL; if (!spec_info->display_widget) { setup_popup_info(popup_win, display_data_front_end, SORTID_CNT); } if (spec_info->display_widget && popup_win->toggled) { gtk_widget_destroy(spec_info->display_widget); spec_info->display_widget = NULL; goto display_it; } resv_error_code = get_new_info_front_end(&front_end_info_ptr, popup_win->force_refresh); if (resv_error_code == SLURM_NO_CHANGE_IN_DATA) { if (!spec_info->display_widget || spec_info->view == ERROR_VIEW) goto display_it; changed = 0; } else if (resv_error_code != SLURM_SUCCESS) { if (spec_info->view == ERROR_VIEW) goto end_it; spec_info->view = ERROR_VIEW; if (spec_info->display_widget) gtk_widget_destroy(spec_info->display_widget); sprintf(error_char, "get_new_info_front_end: %s", slurm_strerror(slurm_get_errno())); label = gtk_label_new(error_char); gtk_table_attach_defaults(popup_win->table, label, 0, 1, 0, 1); gtk_widget_show(label); spec_info->display_widget = g_object_ref(label); goto end_it; } display_it: resv_list = _create_front_end_info_list(front_end_info_ptr, changed); if (!resv_list) return; if (spec_info->view == ERROR_VIEW && spec_info->display_widget) { gtk_widget_destroy(spec_info->display_widget); spec_info->display_widget = NULL; } if (spec_info->type != INFO_PAGE && !spec_info->display_widget) { tree_view = create_treeview(local_display_data, &popup_win->grid_button_list); gtk_tree_selection_set_mode( gtk_tree_view_get_selection(tree_view), GTK_SELECTION_MULTIPLE); spec_info->display_widget = g_object_ref(GTK_WIDGET(tree_view)); gtk_table_attach_defaults(popup_win->table, GTK_WIDGET(tree_view), 0, 1, 0, 1); /* since this function sets the model of the tree_view to the treestore we don't really care about the return value */ create_treestore(tree_view, popup_win->display_data, SORTID_CNT, SORTID_NAME, SORTID_COLOR); } setup_popup_grid_list(popup_win); spec_info->view = INFO_VIEW; if (spec_info->type == INFO_PAGE) { _display_info_front_end(resv_list, popup_win); goto end_it; } /* just linking to another list, don't free the inside, just the list */ send_resv_list = list_create(NULL); itr = list_iterator_create(resv_list); i = -1; while ((sview_front_end_info_ptr = list_next(itr))) { i++; front_end_ptr = sview_front_end_info_ptr->front_end_ptr; switch (spec_info->type) { case PART_PAGE: case NODE_PAGE: break; case JOB_PAGE: if (xstrcmp(front_end_ptr->name, search_info->gchar_data)) continue; break; case RESV_PAGE: switch (search_info->search_type) { case SEARCH_RESERVATION_NAME: if (!search_info->gchar_data) continue; if (xstrcmp(front_end_ptr->name, search_info->gchar_data)) continue; break; default: continue; } break; default: g_print("Unknown type %d\n", spec_info->type); continue; } list_push(send_resv_list, sview_front_end_info_ptr); } list_iterator_destroy(itr); post_setup_popup_grid_list(popup_win); _update_info_front_end(send_resv_list, GTK_TREE_VIEW(spec_info->display_widget)); FREE_NULL_LIST(send_resv_list); end_it: popup_win->toggled = 0; popup_win->force_refresh = 0; return; } extern void set_menus_front_end(void *arg, void *arg2, GtkTreePath *path, int type) { GtkTreeView *tree_view = (GtkTreeView *)arg; popup_info_t *popup_win = (popup_info_t *)arg; GtkMenu *menu = (GtkMenu *)arg2; List button_list = (List)arg2; switch (type) { case TAB_CLICKED: make_fields_menu(NULL, menu, display_data_front_end, SORTID_CNT); break; case ROW_CLICKED: make_options_menu(tree_view, path, menu, options_data_front_end); break; case ROW_LEFT_CLICKED: highlight_grid(tree_view, SORTID_NODE_INX, SORTID_COLOR_INX, button_list); break; case FULL_CLICKED: { GtkTreeModel *model = gtk_tree_view_get_model(tree_view); GtkTreeIter iter; if (!gtk_tree_model_get_iter(model, &iter, path)) { g_error("error getting iter from model\n"); break; } popup_all_front_end(model, &iter, INFO_PAGE); break; } case POPUP_CLICKED: make_fields_menu(popup_win, menu, popup_win->display_data, SORTID_CNT); break; default: g_error("UNKNOWN type %d given to set_fields\n", type); } } extern void popup_all_front_end(GtkTreeModel *model, GtkTreeIter *iter, int id) { char *name = NULL; char title[100] = {0}; ListIterator itr = NULL; popup_info_t *popup_win = NULL; GError *error = NULL; gtk_tree_model_get(model, iter, SORTID_NAME, &name, -1); switch (id) { case INFO_PAGE: snprintf(title, 100, "Full info for front end node %s", name); break; default: g_print("front end got %d\n", id); } itr = list_iterator_create(popup_list); while ((popup_win = list_next(itr))) { if (popup_win->spec_info) if (!xstrcmp(popup_win->spec_info->title, title)) { break; } } list_iterator_destroy(itr); if (!popup_win) { if (id == INFO_PAGE) popup_win = create_popup_info(id, FRONT_END_PAGE, title); else { popup_win = create_popup_info(FRONT_END_PAGE, id, title); } } else { g_free(name); gtk_window_present(GTK_WINDOW(popup_win->popup)); return; } /* Pass the model and the structs from the iter so we can always get * the current node_inx. */ popup_win->model = model; popup_win->iter = *iter; popup_win->node_inx_id = SORTID_NODE_INX; switch (id) { case INFO_PAGE: popup_win->spec_info->search_info->gchar_data = name; break; default: g_print("resv got unknown type %d\n", id); } if (!sview_thread_new((gpointer)popup_thr, popup_win, false, &error)) { g_printerr ("Failed to create resv popup thread: %s\n", error->message); return; } } static void _process_each_front_end(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter*iter, gpointer user_data) { char *name = NULL; front_end_user_data_t *fe_data = user_data; gtk_tree_model_get(model, iter, SORTID_NAME, &name, -1); if (fe_data->node_list) xstrfmtcat(fe_data->node_list, ",%s", name); else fe_data->node_list = xstrdup(name); g_free(name); } extern void select_admin_front_end(GtkTreeModel *model, GtkTreeIter *iter, display_data_t *display_data, GtkTreeView *treeview) { if (treeview) { char *node_list; hostlist_t hl = NULL; front_end_user_data_t user_data; memset(&user_data, 0, sizeof(front_end_user_data_t)); gtk_tree_selection_selected_foreach( gtk_tree_view_get_selection(treeview), _process_each_front_end, &user_data); hl = hostlist_create(user_data.node_list); hostlist_uniq(hl); hostlist_sort(hl); xfree(user_data.node_list); node_list = hostlist_ranged_string_xmalloc(hl); hostlist_destroy(hl); _admin_front_end(model, iter, display_data->name, node_list); xfree(node_list); } } static void _admin_front_end(GtkTreeModel *model, GtkTreeIter *iter, char *type, char *node_list) { uint16_t state = NO_VAL16; update_front_end_msg_t front_end_update_msg; char *new_type = NULL, *reason = NULL; char tmp_char[100]; char *lower; int rc; GtkWidget *label = NULL; GtkWidget *entry = NULL; GtkWidget *popup = NULL; if (cluster_flags & CLUSTER_FLAG_FED) { display_fed_disabled_popup(type); global_entry_changed = 0; return; } popup = gtk_dialog_new_with_buttons( type, GTK_WINDOW(main_window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, NULL); gtk_window_set_type_hint(GTK_WINDOW(popup), GDK_WINDOW_TYPE_HINT_NORMAL); gtk_window_set_transient_for(GTK_WINDOW(popup), NULL); label = gtk_dialog_add_button(GTK_DIALOG(popup), GTK_STOCK_YES, GTK_RESPONSE_OK); gtk_window_set_default(GTK_WINDOW(popup), label); gtk_dialog_add_button(GTK_DIALOG(popup), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); if (!xstrncasecmp("Drain", type, 5)) { new_type = "DRAIN"; reason = "\n\nPlease enter reason."; state = NODE_STATE_DRAIN; entry = create_entry(); } else if (!xstrncasecmp("Resume", type, 6)) { new_type = "RESUME"; reason = ""; state = NODE_RESUME; } snprintf(tmp_char, sizeof(tmp_char), "Are you sure you want to set state of front end node %s " "to %s?%s", node_list, new_type, reason); label = gtk_label_new(tmp_char); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(popup)->vbox), label, false, false, 0); if (entry) gtk_box_pack_start(GTK_BOX(GTK_DIALOG(popup)->vbox), entry, true, true, 0); gtk_widget_show_all(popup); rc = gtk_dialog_run (GTK_DIALOG(popup)); slurm_init_update_front_end_msg(&front_end_update_msg); if (rc == GTK_RESPONSE_OK) { front_end_update_msg.name = node_list; front_end_update_msg.node_state = state; if (entry) { front_end_update_msg.reason = xstrdup( gtk_entry_get_text(GTK_ENTRY(entry))); if (!front_end_update_msg.reason || !strlen(front_end_update_msg.reason)) { lower = g_strdup_printf( "You need a reason to do that."); display_edit_note(lower); g_free(lower); goto end_it; } rc = uid_from_string(getlogin(), &front_end_update_msg.reason_uid); if (rc < 0) front_end_update_msg.reason_uid = getuid(); } rc = slurm_update_front_end(&front_end_update_msg); if (rc == SLURM_SUCCESS) { lower = g_strdup_printf( "Nodes %s updated successfully.", node_list); display_edit_note(lower); g_free(lower); } else { lower = g_strdup_printf( "Problem updating nodes %s: %s", node_list, slurm_strerror(rc)); display_edit_note(lower); g_free(lower); } } end_it: global_entry_changed = 0; xfree(front_end_update_msg.reason); gtk_widget_destroy(popup); if (got_edit_signal) { type = got_edit_signal; got_edit_signal = NULL; _admin_front_end(model, iter, type, node_list); xfree(type); } return; } extern void cluster_change_front_end(void) { get_info_front_end(NULL, NULL); }