1 /*****************************************************************************\
2  *  node_info.c - Functions related to node display mode of sview.
3  *****************************************************************************
4  *  Copyright (C) 2004-2007 The Regents of the University of California.
5  *  Copyright (C) 2008-2010 Lawrence Livermore National Security.
6  *  Portions Copyright (C) 2010-2015 SchedMD LLC.
7  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
8  *  Written by Danny Auble <da@llnl.gov>
9  *
10  *  CODE-OCEC-09-009. All rights reserved.
11  *
12  *  This file is part of Slurm, a resource management program.
13  *  For details, see <https://slurm.schedmd.com/>.
14  *  Please also read the included file: DISCLAIMER.
15  *
16  *  Slurm is free software; you can redistribute it and/or modify it under
17  *  the terms of the GNU General Public License as published by the Free
18  *  Software Foundation; either version 2 of the License, or (at your option)
19  *  any later version.
20  *
21  *  Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
22  *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
23  *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
24  *  details.
25  *
26  *  You should have received a copy of the GNU General Public License along
27  *  with Slurm; if not, write to the Free Software Foundation, Inc.,
28  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
29 \*****************************************************************************/
30 
31 #include "src/sview/sview.h"
32 
33 #define _DEBUG 0
34 #define ECLIPSE_RT 0
35 
36 //static int _l_topo_color_ndx = MAKE_TOPO_1;
37 //static int _l_sw_color_ndx = 0;
38 
39 /* These need to be in alpha order (except POS and CNT) */
40 enum {
41 	SORTID_POS = POS_LOC,
42 	SORTID_ACTIVE_FEATURES,
43 	SORTID_ARCH,
44 	SORTID_AVAIL_FEATURES,
45 	SORTID_AVE_WATTS,
46 	SORTID_BOARDS,
47 	SORTID_BOOT_TIME,
48 	SORTID_CAP_WATTS,
49 	SORTID_CLUSTER_NAME,
50 	SORTID_COLOR,
51 	SORTID_CPUS,
52 	SORTID_CPU_LOAD,
53 	SORTID_CORES,
54 	SORTID_CURRENT_WATTS,
55 	SORTID_ERR_CPUS,
56 	SORTID_FREE_MEM,
57 	SORTID_GRES,
58 	SORTID_IDLE_CPUS,
59 	SORTID_MCS_LABEL,
60 	SORTID_NAME,
61 	SORTID_NODE_ADDR,
62 	SORTID_NODE_HOSTNAME,
63 	SORTID_OWNER,
64 	SORTID_PORT,
65 	SORTID_REAL_MEMORY,
66 	SORTID_REASON,
67 	SORTID_SLURMD_START_TIME,
68 	SORTID_SOCKETS,
69 	SORTID_STATE,
70 	SORTID_STATE_NUM,
71 	SORTID_THREADS,
72 	SORTID_TMP_DISK,
73 	SORTID_TRES_ALLOC,
74 	SORTID_TRES_CONFIG,
75 	SORTID_UPDATED,
76 	SORTID_USED_CPUS,
77 	SORTID_USED_MEMORY,
78 	SORTID_VERSION,
79 	SORTID_WEIGHT,
80 	SORTID_CNT
81 };
82 
83 typedef struct {
84 	int node_col;
85 	char *nodelist;
86 } process_node_t;
87 
88 /*these are the settings to apply for the user
89  * on the first startup after a fresh slurm install.*/
90 static char *_initial_page_opts = "Name,RackMidplane,State,CPU_Count,"
91 	"Used_CPU_Count,Error_CPU_Count,CoresPerSocket,Sockets,ThreadsPerCore,"
92 	"Real_Memory,Tmp_Disk";
93 
94 static display_data_t display_data_node[] = {
95 	{G_TYPE_INT, SORTID_POS, NULL, false, EDIT_NONE, refresh_node,
96 	 create_model_node, admin_edit_node},
97 	{G_TYPE_STRING, SORTID_CLUSTER_NAME, "ClusterName", false, EDIT_NONE,
98 	 refresh_node, create_model_node, admin_edit_node},
99 	{G_TYPE_STRING, SORTID_NAME, "Name", false, EDIT_NONE, refresh_node,
100 	 create_model_node, admin_edit_node},
101 	{G_TYPE_STRING, SORTID_COLOR, NULL, true, EDIT_COLOR, refresh_node,
102 	 create_model_node, admin_edit_node},
103 	{G_TYPE_STRING, SORTID_NODE_ADDR, "NodeAddr", false, EDIT_NONE,
104 	 refresh_node, create_model_node, admin_edit_node},
105 	{G_TYPE_STRING, SORTID_NODE_HOSTNAME, "NodeHostName", false, EDIT_NONE,
106 	 refresh_node, create_model_node, admin_edit_node},
107 	{G_TYPE_STRING, SORTID_OWNER, "Owner", false, EDIT_NONE,
108 	 refresh_node, create_model_node, admin_edit_node},
109 	{G_TYPE_STRING, SORTID_MCS_LABEL, "MCS_Label", false, EDIT_NONE,
110 	 refresh_node, create_model_node, admin_edit_node},
111 	{G_TYPE_STRING, SORTID_STATE, "State", false, EDIT_MODEL, refresh_node,
112 	 create_model_node, admin_edit_node},
113 	{G_TYPE_INT, SORTID_STATE_NUM, NULL, false, EDIT_NONE, refresh_node,
114 	 create_model_node, admin_edit_node},
115 	{G_TYPE_STRING, SORTID_CPUS, "CPU Count", false,
116 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
117 	{G_TYPE_STRING, SORTID_USED_CPUS, "Used CPU Count", false,
118 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
119 	{G_TYPE_STRING, SORTID_ERR_CPUS, "Error CPU Count", false,
120 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
121 	{G_TYPE_STRING, SORTID_IDLE_CPUS, "Idle CPU Count", false,
122 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
123 	{G_TYPE_STRING, SORTID_TRES_CONFIG, "Config TRES", false,
124 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
125 	{G_TYPE_STRING, SORTID_TRES_ALLOC, "Alloc TRES", false,
126 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
127 	{G_TYPE_INT, SORTID_BOARDS, "Boards", false,
128 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
129 	{G_TYPE_INT, SORTID_SOCKETS, "Sockets", false,
130 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
131 	{G_TYPE_INT, SORTID_CORES, "CoresPerSocket", false,
132 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
133 	{G_TYPE_INT, SORTID_THREADS, "ThreadsPerCore", false,
134 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
135 	{G_TYPE_STRING, SORTID_REAL_MEMORY, "Real Memory", false,
136 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
137 	{G_TYPE_STRING, SORTID_USED_MEMORY, "Used Memory", false,
138 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
139 	{G_TYPE_STRING, SORTID_FREE_MEM, "Free Memory", false, EDIT_NONE,
140 	 refresh_node, create_model_node, admin_edit_node},
141 	{G_TYPE_STRING, SORTID_PORT, "Port", false, EDIT_NONE,
142 	 refresh_node, create_model_node, admin_edit_node},
143 	{G_TYPE_STRING, SORTID_TMP_DISK, "Tmp Disk", false, EDIT_NONE,
144 	 refresh_node, create_model_node, admin_edit_node},
145 	{G_TYPE_STRING, SORTID_ACTIVE_FEATURES, "Active Features", false,
146 	 EDIT_TEXTBOX, refresh_node, create_model_node, admin_edit_node},
147 	{G_TYPE_STRING, SORTID_ARCH, "Arch", false,
148 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
149 	{G_TYPE_STRING, SORTID_AVAIL_FEATURES, "Available Features", false,
150 	 EDIT_TEXTBOX, refresh_node, create_model_node, admin_edit_node},
151 	{G_TYPE_STRING, SORTID_BOOT_TIME, "BootTime", false,
152 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
153 	{G_TYPE_STRING, SORTID_CPU_LOAD, "CPU Load", false, EDIT_NONE,
154 	 refresh_node, create_model_node, admin_edit_node},
155 	{G_TYPE_STRING, SORTID_GRES, "Gres", false,
156 	 EDIT_TEXTBOX, refresh_node, create_model_node, admin_edit_node},
157 	{G_TYPE_STRING, SORTID_REASON, "Reason", false,
158 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
159 	{G_TYPE_STRING, SORTID_SLURMD_START_TIME, "SlurmdStartTime", false,
160 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
161 	{G_TYPE_STRING, SORTID_CURRENT_WATTS, "Current Watts", false,
162 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
163 	{G_TYPE_STRING, SORTID_AVE_WATTS, "Average Watts", false,
164 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
165 	{G_TYPE_STRING, SORTID_CAP_WATTS,"Cap Watts", false,
166 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
167 	{G_TYPE_STRING, SORTID_VERSION, "Version", false,
168 	 EDIT_NONE, refresh_node, create_model_node, admin_edit_node},
169 	{G_TYPE_INT, SORTID_WEIGHT,"Weight", false, EDIT_NONE, refresh_node,
170 	 create_model_node, admin_edit_node},
171 	{G_TYPE_INT, SORTID_UPDATED, NULL, false, EDIT_NONE, refresh_node,
172 	 create_model_node, admin_edit_node},
173 	{G_TYPE_NONE, -1, NULL, false, EDIT_NONE}
174 };
175 
176 static display_data_t options_data_node[] = {
177 	{G_TYPE_INT, SORTID_POS, NULL, false, EDIT_NONE},
178 	{G_TYPE_STRING, INFO_PAGE, "Full Info", true, NODE_PAGE},
179 	{G_TYPE_STRING, NODE_PAGE, "Drain Node", true, ADMIN_PAGE},
180 	{G_TYPE_STRING, NODE_PAGE, "Undrain Node", true, ADMIN_PAGE},
181 	{G_TYPE_STRING, NODE_PAGE, "Resume Node", true, ADMIN_PAGE},
182 	{G_TYPE_STRING, NODE_PAGE, "Set Node(s) Down", true, ADMIN_PAGE},
183 	{G_TYPE_STRING, NODE_PAGE, "Make Node(s) Idle", true, ADMIN_PAGE},
184 	{G_TYPE_STRING, NODE_PAGE, "Update Active Features", true, ADMIN_PAGE},
185 	{G_TYPE_STRING, NODE_PAGE, "Update Available Features", true, ADMIN_PAGE},
186 	{G_TYPE_STRING, NODE_PAGE, "Update Gres", true, ADMIN_PAGE},
187 	{G_TYPE_STRING, JOB_PAGE,  "Jobs", true, NODE_PAGE},
188 	{G_TYPE_STRING, PART_PAGE, "Partitions", true, NODE_PAGE},
189 	{G_TYPE_STRING, RESV_PAGE, "Reservations", true, NODE_PAGE},
190 	//{G_TYPE_STRING, SUBMIT_PAGE, "Job Submit", false, NODE_PAGE},
191 	{G_TYPE_NONE, -1, NULL, false, EDIT_NONE}
192 };
193 
194 static display_data_t *local_display_data = NULL;
195 static GtkTreeModel *last_model = NULL;
196 
_layout_node_record(GtkTreeView * treeview,sview_node_info_t * sview_node_info_ptr,int update)197 static void _layout_node_record(GtkTreeView *treeview,
198 				sview_node_info_t *sview_node_info_ptr,
199 				int update)
200 {
201 	char tmp_cnt[50];
202 	char tmp_current_watts[50];
203 	char tmp_ave_watts[50];
204 	char tmp_cap_watts[50], tmp_owner[32];
205 	char tmp_version[50];
206 	char *upper = NULL, *lower = NULL;
207 	GtkTreeIter iter;
208 	uint16_t alloc_cpus = 0;
209 	uint64_t alloc_memory = 0;
210 	node_info_t *node_ptr = sview_node_info_ptr->node_ptr;
211 	int idle_cpus = node_ptr->cpus;
212 	char *node_alloc_tres = NULL;
213 	GtkTreeStore *treestore =
214 		GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
215 	if (!treestore)
216 		return;
217 
218 	add_display_treestore_line(update, treestore, &iter,
219 				   find_col_name(display_data_node,
220 						 SORTID_CLUSTER_NAME),
221 				   node_ptr->cluster_name);
222 
223 	add_display_treestore_line(update, treestore, &iter,
224 				   find_col_name(display_data_node,
225 						 SORTID_NAME),
226 				   node_ptr->name);
227 
228 	add_display_treestore_line(update, treestore, &iter,
229 				   find_col_name(display_data_node,
230 						 SORTID_NODE_ADDR),
231 				   node_ptr->node_addr);
232 
233 	add_display_treestore_line(update, treestore, &iter,
234 				   find_col_name(display_data_node,
235 						 SORTID_NODE_HOSTNAME),
236 				   node_ptr->node_hostname);
237 
238 	if (node_ptr->owner == NO_VAL) {
239 		snprintf(tmp_owner, sizeof(tmp_owner), "N/A");
240 	} else {
241 		char *user_name;
242 		user_name = uid_to_string((uid_t) node_ptr->owner);
243 		snprintf(tmp_owner, sizeof(tmp_owner), "%s(%u)",
244 			 user_name, node_ptr->owner);
245 		xfree(user_name);
246 	}
247 	add_display_treestore_line(update, treestore, &iter,
248 				   find_col_name(display_data_node,
249 						 SORTID_OWNER), tmp_owner);
250 
251 	add_display_treestore_line(update, treestore, &iter,
252 				   find_col_name(display_data_node,
253 						 SORTID_MCS_LABEL),
254 				   (node_ptr->mcs_label == NULL) ? "N/A" :
255 						 node_ptr->mcs_label),
256 
257 	convert_num_unit((float)node_ptr->cpus, tmp_cnt, sizeof(tmp_cnt),
258 			 UNIT_NONE, NO_VAL, working_sview_config.convert_flags);
259 	add_display_treestore_line(update, treestore, &iter,
260 				   find_col_name(display_data_node,
261 						 SORTID_CPUS),
262 				   tmp_cnt);
263 
264 	if (node_ptr->cpu_load == NO_VAL) {
265 		snprintf(tmp_cnt, sizeof(tmp_cnt), "N/A");
266 	} else {
267 		snprintf(tmp_cnt, sizeof(tmp_cnt), "%.2f",
268 			 (node_ptr->cpu_load / 100.0));
269 	}
270 	add_display_treestore_line(update, treestore, &iter,
271 				   find_col_name(display_data_node,
272 						 SORTID_CPU_LOAD),
273 				   tmp_cnt);
274 
275 	if (node_ptr->free_mem == NO_VAL64) {
276 		snprintf(tmp_cnt, sizeof(tmp_cnt), "N/A");
277 	} else {
278 		snprintf(tmp_cnt, sizeof(tmp_cnt), "%"PRIu64"M",
279 		         node_ptr->free_mem);
280 	}
281 	add_display_treestore_line(update, treestore, &iter,
282 				   find_col_name(display_data_node,
283 						 SORTID_FREE_MEM),
284 				   tmp_cnt);
285 
286 	select_g_select_nodeinfo_get(node_ptr->select_nodeinfo,
287 				     SELECT_NODEDATA_SUBCNT,
288 				     NODE_STATE_ALLOCATED,
289 				     &alloc_cpus);
290 	idle_cpus -= alloc_cpus;
291 	convert_num_unit((float)alloc_cpus, tmp_cnt,
292 			 sizeof(tmp_cnt), UNIT_NONE, NO_VAL,
293 			 working_sview_config.convert_flags);
294 	add_display_treestore_line(update, treestore, &iter,
295 				   find_col_name(display_data_node,
296 						 SORTID_USED_CPUS),
297 				   tmp_cnt);
298 
299 	convert_num_unit((float)idle_cpus, tmp_cnt, sizeof(tmp_cnt), UNIT_NONE,
300 			 NO_VAL, working_sview_config.convert_flags);
301 	add_display_treestore_line(update, treestore, &iter,
302 				   find_col_name(display_data_node,
303 						 SORTID_IDLE_CPUS),
304 				   tmp_cnt);
305 
306 	add_display_treestore_line(update, treestore, &iter,
307 				   find_col_name(display_data_node,
308 						 SORTID_TRES_CONFIG),
309 				   node_ptr->tres_fmt_str);
310 
311 	select_g_select_nodeinfo_get(node_ptr->select_nodeinfo,
312 				     SELECT_NODEDATA_TRES_ALLOC_FMT_STR,
313 				     NODE_STATE_ALLOCATED, &node_alloc_tres);
314 
315 	add_display_treestore_line(update, treestore, &iter,
316 				   find_col_name(display_data_node,
317 						 SORTID_TRES_ALLOC),
318 				   node_alloc_tres ? node_alloc_tres : "");
319 	xfree(node_alloc_tres);
320 
321 	upper = node_state_string(node_ptr->node_state);
322 	lower = str_tolower(upper);
323 
324 	add_display_treestore_line(update, treestore, &iter,
325 				   find_col_name(display_data_node,
326 						 SORTID_STATE),
327 				   lower);
328 	xfree(lower);
329 
330 	convert_num_unit((float)node_ptr->boards, tmp_cnt, sizeof(tmp_cnt),
331 			 UNIT_NONE, NO_VAL, working_sview_config.convert_flags);
332 	add_display_treestore_line(update, treestore, &iter,
333 				   find_col_name(display_data_node,
334 						 SORTID_BOARDS),
335 				   tmp_cnt);
336 
337 	convert_num_unit((float)node_ptr->sockets, tmp_cnt, sizeof(tmp_cnt),
338 			 UNIT_NONE, NO_VAL, working_sview_config.convert_flags);
339 	add_display_treestore_line(update, treestore, &iter,
340 				   find_col_name(display_data_node,
341 						 SORTID_SOCKETS),
342 				   tmp_cnt);
343 
344 	convert_num_unit((float)node_ptr->cores, tmp_cnt, sizeof(tmp_cnt),
345 			 UNIT_NONE, NO_VAL, working_sview_config.convert_flags);
346 	add_display_treestore_line(update, treestore, &iter,
347 				   find_col_name(display_data_node,
348 						 SORTID_CORES),
349 				   tmp_cnt);
350 
351 	convert_num_unit((float)node_ptr->port, tmp_cnt, sizeof(tmp_cnt),
352 			 UNIT_NONE, NO_VAL, working_sview_config.convert_flags);
353 	add_display_treestore_line(update, treestore, &iter,
354 				   find_col_name(display_data_node,
355 						 SORTID_PORT),
356 				   tmp_cnt);
357 
358 	convert_num_unit((float)node_ptr->threads, tmp_cnt, sizeof(tmp_cnt),
359 			 UNIT_NONE, NO_VAL, working_sview_config.convert_flags);
360 	add_display_treestore_line(update, treestore, &iter,
361 				   find_col_name(display_data_node,
362 						 SORTID_THREADS),
363 				   tmp_cnt);
364 
365 	convert_num_unit((float)node_ptr->real_memory, tmp_cnt, sizeof(tmp_cnt),
366 			 UNIT_MEGA, NO_VAL, working_sview_config.convert_flags);
367 	add_display_treestore_line(update, treestore, &iter,
368 				   find_col_name(display_data_node,
369 						 SORTID_REAL_MEMORY),
370 				   tmp_cnt);
371 
372 	select_g_select_nodeinfo_get(node_ptr->select_nodeinfo,
373 				     SELECT_NODEDATA_MEM_ALLOC,
374 				     NODE_STATE_ALLOCATED,
375 				     &alloc_memory);
376 	snprintf(tmp_cnt, sizeof(tmp_cnt), "%"PRIu64"M", alloc_memory);
377 	add_display_treestore_line(update, treestore, &iter,
378 				   find_col_name(display_data_node,
379 						 SORTID_USED_MEMORY),
380 				   tmp_cnt);
381 
382 	convert_num_unit((float)node_ptr->tmp_disk, tmp_cnt, sizeof(tmp_cnt),
383 			 UNIT_MEGA, NO_VAL, working_sview_config.convert_flags);
384 	add_display_treestore_line(update, treestore, &iter,
385 				   find_col_name(display_data_node,
386 						 SORTID_TMP_DISK),
387 				   tmp_cnt);
388 	snprintf(tmp_cnt, sizeof(tmp_cnt), "%u", node_ptr->weight);
389 	add_display_treestore_line(update, treestore, &iter,
390 				   find_col_name(display_data_node,
391 						 SORTID_WEIGHT),
392 				   tmp_cnt);
393 	add_display_treestore_line(update, treestore, &iter,
394 				   find_col_name(display_data_node,
395 						 SORTID_ARCH),
396 				   node_ptr->arch);
397 	add_display_treestore_line(update, treestore, &iter,
398 				   find_col_name(display_data_node,
399 						 SORTID_AVAIL_FEATURES),
400 				   node_ptr->features);
401 	add_display_treestore_line(update, treestore, &iter,
402 				   find_col_name(display_data_node,
403 						 SORTID_ACTIVE_FEATURES),
404 				   node_ptr->features_act);
405 	add_display_treestore_line(update, treestore, &iter,
406 				   find_col_name(display_data_node,
407 						 SORTID_GRES),
408 				   node_ptr->gres);
409 	add_display_treestore_line(update, treestore, &iter,
410 				   find_col_name(display_data_node,
411 						 SORTID_BOOT_TIME),
412 				   sview_node_info_ptr->boot_time);
413 	add_display_treestore_line(update, treestore, &iter,
414 				   find_col_name(display_data_node,
415 						 SORTID_SLURMD_START_TIME),
416 				   sview_node_info_ptr->slurmd_start_time);
417 	add_display_treestore_line(update, treestore, &iter,
418 				   find_col_name(display_data_node,
419 						 SORTID_REASON),
420 				   sview_node_info_ptr->reason);
421 
422 	if (node_ptr->energy->current_watts == NO_VAL) {
423 		snprintf(tmp_current_watts, sizeof(tmp_current_watts),
424 			 "N/A");
425 		snprintf(tmp_ave_watts, sizeof(tmp_ave_watts),
426 			 "N/A");
427 	} else {
428 		snprintf(tmp_current_watts, sizeof(tmp_current_watts),
429 			 "%u", node_ptr->energy->current_watts);
430 		snprintf(tmp_ave_watts, sizeof(tmp_ave_watts),
431 			 "%u", node_ptr->energy->ave_watts);
432 	}
433 
434 	add_display_treestore_line(update, treestore, &iter,
435 				   find_col_name(display_data_node,
436 						 SORTID_CURRENT_WATTS),
437 				   tmp_current_watts);
438 
439 	add_display_treestore_line(update, treestore, &iter,
440 				   find_col_name(display_data_node,
441 						 SORTID_AVE_WATTS),
442 				   tmp_ave_watts);
443 
444 	if (!node_ptr->power || (node_ptr->power->cap_watts == NO_VAL)) {
445 		snprintf(tmp_cap_watts, sizeof(tmp_cap_watts), "N/A");
446 	} else {
447 		snprintf(tmp_cap_watts, sizeof(tmp_cap_watts), "%u",
448 			 node_ptr->power->cap_watts);
449 	}
450 	add_display_treestore_line(update, treestore, &iter,
451 				   find_col_name(display_data_node,
452 						 SORTID_CAP_WATTS),
453 				   tmp_cap_watts);
454 
455 	if (node_ptr->version == NULL) {
456 		snprintf(tmp_version, sizeof(tmp_version), "N/A");
457 	} else {
458 		snprintf(tmp_version, sizeof(tmp_version), "%s",
459 			 node_ptr->version);
460 	}
461 	add_display_treestore_line(update, treestore, &iter,
462 				   find_col_name(display_data_node,
463 						 SORTID_VERSION),
464 				   tmp_version);
465 	return;
466 }
467 
_update_node_record(sview_node_info_t * sview_node_info_ptr,GtkTreeStore * treestore)468 static void _update_node_record(sview_node_info_t *sview_node_info_ptr,
469 				GtkTreeStore *treestore)
470 {
471 	uint16_t alloc_cpus = 0, idle_cpus;
472 	uint64_t alloc_memory;
473 	node_info_t *node_ptr = sview_node_info_ptr->node_ptr;
474 	char tmp_disk[20], tmp_cpus[20], tmp_idle_cpus[20];
475 	char tmp_mem[20], tmp_used_memory[20];
476 	char tmp_used_cpus[20], tmp_cpu_load[20], tmp_free_mem[20], tmp_owner[32];
477 	char tmp_current_watts[50], tmp_ave_watts[50];
478 	char tmp_cap_watts[50], tmp_version[50];
479 	char *tmp_state_lower, *tmp_state_upper;
480 	char *node_alloc_tres = NULL;
481 
482 	if (node_ptr->energy->current_watts == NO_VAL) {
483 		snprintf(tmp_current_watts, sizeof(tmp_current_watts),
484 			 "N/A");
485 		snprintf(tmp_ave_watts, sizeof(tmp_ave_watts),
486 			 "N/A");
487 	} else {
488 		snprintf(tmp_current_watts, sizeof(tmp_current_watts),
489 			 "%u ", node_ptr->energy->current_watts);
490 		snprintf(tmp_ave_watts, sizeof(tmp_ave_watts),
491 			 "%u", node_ptr->energy->ave_watts);
492 	}
493 
494 	if (!node_ptr->power || (node_ptr->power->cap_watts == NO_VAL)) {
495 		snprintf(tmp_cap_watts, sizeof(tmp_cap_watts), "N/A");
496 	} else {
497 		snprintf(tmp_cap_watts, sizeof(tmp_cap_watts), "%u",
498 			 node_ptr->power->cap_watts);
499 	}
500 
501 	if (node_ptr->cpu_load == NO_VAL) {
502 		strlcpy(tmp_cpu_load, "N/A", sizeof(tmp_cpu_load));
503 	} else {
504 		snprintf(tmp_cpu_load, sizeof(tmp_cpu_load),
505 			 "%.2f", (node_ptr->cpu_load / 100.0));
506 	}
507 
508 	if (node_ptr->free_mem == NO_VAL64) {
509 		strlcpy(tmp_free_mem, "N/A", sizeof(tmp_free_mem));
510 	} else {
511 		snprintf(tmp_free_mem, sizeof(tmp_free_mem),
512 		         "%"PRIu64"M", node_ptr->free_mem);
513 	}
514 
515 	convert_num_unit((float)node_ptr->cpus, tmp_cpus,
516 			 sizeof(tmp_cpus), UNIT_NONE, NO_VAL,
517 			 working_sview_config.convert_flags);
518 
519 	select_g_select_nodeinfo_get(node_ptr->select_nodeinfo,
520 				     SELECT_NODEDATA_SUBCNT,
521 				     NODE_STATE_ALLOCATED,
522 				     &alloc_cpus);
523 
524 	idle_cpus = node_ptr->cpus - alloc_cpus;
525 	convert_num_unit((float)alloc_cpus, tmp_used_cpus,
526 			 sizeof(tmp_used_cpus), UNIT_NONE, NO_VAL,
527 			 working_sview_config.convert_flags);
528 
529 	select_g_select_nodeinfo_get(node_ptr->select_nodeinfo,
530 				     SELECT_NODEDATA_MEM_ALLOC,
531 				     NODE_STATE_ALLOCATED,
532 				     &alloc_memory);
533 	snprintf(tmp_used_memory, sizeof(tmp_used_memory), "%"PRIu64"M", alloc_memory);
534 
535 	convert_num_unit((float)alloc_cpus, tmp_used_cpus,
536 			 sizeof(tmp_used_cpus), UNIT_NONE, NO_VAL,
537 			 working_sview_config.convert_flags);
538 
539 	convert_num_unit((float)idle_cpus, tmp_idle_cpus, sizeof(tmp_idle_cpus),
540 			 UNIT_NONE, NO_VAL, working_sview_config.convert_flags);
541 
542 	if (IS_NODE_DRAIN(node_ptr)) {
543 		/* don't worry about mixed since the
544 		 * whole node is being drained. */
545 	} else if (idle_cpus && (idle_cpus != node_ptr->cpus)) {
546 		node_ptr->node_state &= NODE_STATE_FLAGS;
547 		node_ptr->node_state |= NODE_STATE_MIXED;
548 	}
549 	tmp_state_upper = node_state_string(node_ptr->node_state);
550 	tmp_state_lower = str_tolower(tmp_state_upper);
551 
552 	convert_num_unit((float)node_ptr->real_memory, tmp_mem, sizeof(tmp_mem),
553 			 UNIT_MEGA, NO_VAL, working_sview_config.convert_flags);
554 
555 	convert_num_unit((float)node_ptr->tmp_disk, tmp_disk, sizeof(tmp_disk),
556 			 UNIT_MEGA, NO_VAL, working_sview_config.convert_flags);
557 
558 	if (node_ptr->version == NULL) {
559 		snprintf(tmp_version, sizeof(tmp_version), "N/A");
560 	} else {
561 		snprintf(tmp_version, sizeof(tmp_version), "%s",
562 			 node_ptr->version);
563 	}
564 
565 	if (node_ptr->owner == NO_VAL) {
566 		snprintf(tmp_owner, sizeof(tmp_owner), "N/A");
567 	} else {
568 		char *user_name;
569 		user_name = uid_to_string((uid_t) node_ptr->owner);
570 		snprintf(tmp_owner, sizeof(tmp_owner), "%s(%u)",
571 			 user_name, node_ptr->owner);
572 		xfree(user_name);
573 	}
574 
575 	select_g_select_nodeinfo_get(node_ptr->select_nodeinfo,
576 				     SELECT_NODEDATA_TRES_ALLOC_FMT_STR,
577 				     NODE_STATE_ALLOCATED, &node_alloc_tres);
578 
579 	/* Combining these records provides a slight performance improvement */
580 	gtk_tree_store_set(treestore, &sview_node_info_ptr->iter_ptr,
581 			   SORTID_ACTIVE_FEATURES, node_ptr->features_act,
582 			   SORTID_ARCH,      node_ptr->arch,
583 			   SORTID_AVAIL_FEATURES,  node_ptr->features,
584 			   SORTID_AVE_WATTS, tmp_ave_watts,
585 			   SORTID_BOARDS,    node_ptr->boards,
586 			   SORTID_BOOT_TIME, sview_node_info_ptr->boot_time,
587 			   SORTID_CLUSTER_NAME, node_ptr->cluster_name,
588 			   SORTID_CAP_WATTS, tmp_cap_watts,
589 			   SORTID_COLOR,
590 				sview_colors[sview_node_info_ptr->pos
591 				% sview_colors_cnt],
592 			   SORTID_CORES,     node_ptr->cores,
593 			   SORTID_CPUS,      tmp_cpus,
594 			   SORTID_CURRENT_WATTS, tmp_current_watts,
595 			   SORTID_CPU_LOAD,  tmp_cpu_load,
596 			   SORTID_FREE_MEM,  tmp_free_mem,
597 			   SORTID_TMP_DISK,  tmp_disk,
598 			   SORTID_IDLE_CPUS, tmp_idle_cpus,
599 			   SORTID_GRES,      node_ptr->gres,
600 			   SORTID_MCS_LABEL, (node_ptr->mcs_label == NULL) ?
601 				"N/A" : node_ptr->mcs_label,
602 			   SORTID_REAL_MEMORY, tmp_mem,
603 			   SORTID_NAME,      node_ptr->name,
604 			   SORTID_NODE_ADDR, node_ptr->node_addr,
605 			   SORTID_NODE_HOSTNAME, node_ptr->node_hostname,
606 			   SORTID_OWNER,     tmp_owner,
607 			   SORTID_REASON,    sview_node_info_ptr->reason,
608 			   SORTID_SLURMD_START_TIME,
609 				sview_node_info_ptr->slurmd_start_time,
610 			   SORTID_SOCKETS,   node_ptr->sockets,
611 			   SORTID_STATE,     tmp_state_lower,
612 			   SORTID_STATE_NUM, node_ptr->node_state,
613 			   SORTID_THREADS,   node_ptr->threads,
614 			   SORTID_TRES_ALLOC, node_alloc_tres ?
615 			   node_alloc_tres : "",
616 			   SORTID_TRES_CONFIG, node_ptr->tres_fmt_str,
617 			   SORTID_USED_CPUS, tmp_used_cpus,
618 			   SORTID_USED_MEMORY, tmp_used_memory,
619 			   SORTID_VERSION,   tmp_version,
620 			   SORTID_WEIGHT,    node_ptr->weight,
621 			   SORTID_UPDATED,   1,
622 			  -1);
623 
624 	xfree(tmp_state_lower);
625 	xfree(node_alloc_tres);
626 	return;
627 }
628 
_append_node_record(sview_node_info_t * sview_node_info,GtkTreeStore * treestore)629 static void _append_node_record(sview_node_info_t *sview_node_info,
630 				GtkTreeStore *treestore)
631 {
632 	gtk_tree_store_append(treestore, &sview_node_info->iter_ptr, NULL);
633 	gtk_tree_store_set(treestore, &sview_node_info->iter_ptr, SORTID_POS,
634 			   sview_node_info->pos, -1);
635 	_update_node_record(sview_node_info, treestore);
636 }
637 
_update_info_node(List info_list,GtkTreeView * tree_view)638 static void _update_info_node(List info_list, GtkTreeView *tree_view)
639 {
640 	GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
641 	char *name = NULL;
642 	ListIterator itr = NULL;
643 	sview_node_info_t *sview_node_info = NULL;
644 
645 	set_for_update(model, SORTID_UPDATED);
646 
647 	itr = list_iterator_create(info_list);
648 	while ((sview_node_info = list_next(itr))) {
649 		/* This means the tree_store changed (added new column
650 		 * or something). */
651 		if (last_model != model)
652 			sview_node_info->iter_set = false;
653 
654 		if (sview_node_info->iter_set) {
655 			gtk_tree_model_get(model, &sview_node_info->iter_ptr,
656 					   SORTID_NAME, &name, -1);
657 			if (xstrcmp(name, sview_node_info->node_name)) {
658 				/* Bad pointer */
659 				sview_node_info->iter_set = false;
660 				//g_print("bad node iter pointer\n");
661 			}
662 			g_free(name);
663 		}
664 		if (sview_node_info->iter_set)
665 			_update_node_record(sview_node_info,
666 					    GTK_TREE_STORE(model));
667 		else {
668 			_append_node_record(sview_node_info,
669 					    GTK_TREE_STORE(model));
670 			sview_node_info->iter_set = true;
671 		}
672 	}
673 	list_iterator_destroy(itr);
674 
675 	/* remove all old nodes */
676 	remove_old(model, SORTID_UPDATED);
677 	last_model = model;
678 }
679 
_node_info_free(sview_node_info_t * sview_node_info)680 static void _node_info_free(sview_node_info_t *sview_node_info)
681 {
682 	if (sview_node_info) {
683 		xfree(sview_node_info->slurmd_start_time);
684 		xfree(sview_node_info->boot_time);
685 		xfree(sview_node_info->node_name);
686 		xfree(sview_node_info->rack_mp);
687 		xfree(sview_node_info->reason);
688 	}
689 }
690 
_node_info_list_del(void * object)691 static void _node_info_list_del(void *object)
692 {
693 	sview_node_info_t *sview_node_info = (sview_node_info_t *)object;
694 
695 	if (sview_node_info) {
696 		_node_info_free(sview_node_info);
697 		xfree(sview_node_info);
698 	}
699 }
700 
_display_info_node(List info_list,popup_info_t * popup_win)701 static void _display_info_node(List info_list,	popup_info_t *popup_win)
702 {
703 	specific_info_t *spec_info = popup_win->spec_info;
704 	char *name = (char *)spec_info->search_info->gchar_data;
705 	int found = 0;
706 	node_info_t *node_ptr = NULL;
707 	GtkTreeView *treeview = NULL;
708 	int update = 0;
709 	ListIterator itr = NULL;
710 	sview_node_info_t *sview_node_info = NULL;
711 	int i = -1;
712 
713 	if (!spec_info->search_info->gchar_data) {
714 		goto finished;
715 	}
716 need_refresh:
717 	if (!spec_info->display_widget) {
718 		treeview = create_treeview_2cols_attach_to_table(
719 			popup_win->table);
720 		spec_info->display_widget =
721 			g_object_ref(GTK_WIDGET(treeview));
722 	} else {
723 		treeview = GTK_TREE_VIEW(spec_info->display_widget);
724 		update = 1;
725 	}
726 
727 	itr = list_iterator_create(info_list);
728 	while ((sview_node_info = list_next(itr))) {
729 		node_ptr = sview_node_info->node_ptr;
730 		i++;
731 		if (!xstrcmp(node_ptr->name, name)) {
732 			change_grid_color(popup_win->grid_button_list,
733 					  i, i, i, true, 0);
734 			_layout_node_record(treeview, sview_node_info, update);
735 			found = 1;
736 			break;
737 		}
738 	}
739 	list_iterator_destroy(itr);
740 	if (!found) {
741 		if (!popup_win->not_found) {
742 			char *temp;
743 			GtkTreeIter iter;
744 			GtkTreeModel *model = NULL;
745 
746 			temp = "NODE NOT FOUND\n";
747 			/* only time this will be run so no update */
748 			model = gtk_tree_view_get_model(treeview);
749 			add_display_treestore_line(0,
750 						   GTK_TREE_STORE(model),
751 						   &iter,
752 						   temp, "");
753 		}
754 		popup_win->not_found = true;
755 	} else {
756 		if (popup_win->not_found) {
757 			popup_win->not_found = false;
758 			gtk_widget_destroy(spec_info->display_widget);
759 
760 			goto need_refresh;
761 		}
762 	}
763 	gtk_widget_show(spec_info->display_widget);
764 
765 finished:
766 	return;
767 }
768 
_selected_page(GtkMenuItem * menuitem,display_data_t * display_data)769 static void _selected_page(GtkMenuItem *menuitem,
770 			   display_data_t *display_data)
771 {
772 	switch(display_data->extra) {
773 	case NODE_PAGE:
774 		popup_all_node_name(display_data->user_data, display_data->id,
775 				    NULL);
776 		break;
777 	case ADMIN_PAGE:
778 		admin_node_name(display_data->user_data,
779 				NULL, display_data->name);
780 		break;
781 	default:
782 		g_print("node got %d %d\n", display_data->extra,
783 			display_data->id);
784 	}
785 
786 }
787 
_process_each_node(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer userdata)788 static void _process_each_node(GtkTreeModel *model, GtkTreePath *path,
789 			       GtkTreeIter *iter, gpointer userdata)
790 {
791 	char *name = NULL;
792 	process_node_t *process_node = userdata;
793 
794 	gtk_tree_model_get(model, iter, process_node->node_col, &name, -1);
795 	if (process_node->nodelist)
796 		xstrfmtcat(process_node->nodelist, ",%s", name);
797 	else
798 		process_node->nodelist = xstrdup(name);
799 	g_free(name);
800 }
801 /*process_each_node ^^^*/
802 
803 
804 
refresh_node(GtkAction * action,gpointer user_data)805 extern void refresh_node(GtkAction *action, gpointer user_data)
806 {
807 	popup_info_t *popup_win = (popup_info_t *)user_data;
808 	xassert(popup_win);
809 	xassert(popup_win->spec_info);
810 	xassert(popup_win->spec_info->title);
811 	popup_win->force_refresh = 1;
812 	specific_info_node(popup_win);
813 }
814 
815 /* don't destroy the list from this function */
create_node_info_list(node_info_msg_t * node_info_ptr,bool by_partition)816 extern List create_node_info_list(node_info_msg_t *node_info_ptr,
817 				  bool by_partition)
818 {
819 	static List info_list = NULL;
820 	static node_info_msg_t *last_node_info_ptr = NULL;
821 	List last_list = NULL;
822 	ListIterator last_list_itr = NULL;
823 	int i = 0;
824 	sview_node_info_t *sview_node_info_ptr = NULL;
825 	node_info_t *node_ptr = NULL;
826 	char user[32], time_str[32];
827 
828 	if (!by_partition) {
829 		if (!node_info_ptr
830 		    || (info_list && (node_info_ptr == last_node_info_ptr)))
831 			goto update_color;
832 	}
833 
834 	last_node_info_ptr = node_info_ptr;
835 
836 	if (info_list)
837 		last_list = info_list;
838 
839 	info_list = list_create(_node_info_list_del);
840 
841 	if (last_list)
842 		last_list_itr = list_iterator_create(last_list);
843 	for (i=0; i<node_info_ptr->record_count; i++) {
844 		node_ptr = &(node_info_ptr->node_array[i]);
845 
846 		if (!node_ptr->name || (node_ptr->name[0] == '\0'))
847 			continue;
848 
849 		sview_node_info_ptr = NULL;
850 
851 		if (last_list_itr) {
852 			while ((sview_node_info_ptr =
853 				list_next(last_list_itr))) {
854 				if (!xstrcmp(sview_node_info_ptr->node_name,
855 					     node_ptr->name)) {
856 					list_remove(last_list_itr);
857 					_node_info_free(sview_node_info_ptr);
858 					break;
859 				}
860 			}
861 			list_iterator_reset(last_list_itr);
862 		}
863 
864 		/* constrain list to included partitions' nodes */
865 		/* and there are excluded values to process */
866 		/* and user has not requested to show hidden */
867 		/* if (by_partition && apply_partition_check */
868 		/*     && !working_sview_config.show_hidden */
869 		/*     && !check_part_includes_node(i)) */
870 		/* 	continue; */
871 
872 		if (!sview_node_info_ptr)
873 			sview_node_info_ptr =
874 				xmalloc(sizeof(sview_node_info_t));
875 		list_append(info_list, sview_node_info_ptr);
876 		sview_node_info_ptr->node_name = xstrdup(node_ptr->name);
877 		sview_node_info_ptr->node_ptr = node_ptr;
878 		sview_node_info_ptr->pos = i;
879 
880 		if (node_ptr->reason &&
881 		    (node_ptr->reason_uid != NO_VAL) && node_ptr->reason_time) {
882 			struct passwd *pw = NULL;
883 
884 			if ((pw=getpwuid(node_ptr->reason_uid)))
885 				snprintf(user, sizeof(user), "%s", pw->pw_name);
886 			else
887 				snprintf(user, sizeof(user), "Unk(%u)",
888 					 node_ptr->reason_uid);
889 			slurm_make_time_str(&node_ptr->reason_time,
890 					    time_str, sizeof(time_str));
891 			sview_node_info_ptr->reason = xstrdup_printf(
892 				"%s [%s@%s]", node_ptr->reason, user, time_str);
893 		} else if (node_ptr->reason)
894 			sview_node_info_ptr->reason = xstrdup(node_ptr->reason);
895 
896 		if (node_ptr->boot_time) {
897 			slurm_make_time_str(&node_ptr->boot_time,
898 					    time_str, sizeof(time_str));
899 			sview_node_info_ptr->boot_time = xstrdup(time_str);
900 		}
901 		if (node_ptr->slurmd_start_time) {
902 			slurm_make_time_str(&node_ptr->slurmd_start_time,
903 					    time_str, sizeof(time_str));
904 			sview_node_info_ptr->slurmd_start_time =
905 				xstrdup(time_str);
906 		}
907 	}
908 
909 	if (last_list) {
910 		list_iterator_destroy(last_list_itr);
911 		FREE_NULL_LIST(last_list);
912 	}
913 
914 update_color:
915 
916 	return info_list;
917 }
918 
get_new_info_node(node_info_msg_t ** info_ptr,int force)919 extern int get_new_info_node(node_info_msg_t **info_ptr, int force)
920 {
921 	node_info_msg_t *new_node_ptr = NULL;
922 	uint16_t show_flags = 0;
923 	int error_code = SLURM_NO_CHANGE_IN_DATA;
924 	time_t now = time(NULL), delay;
925 	static time_t last;
926 	static bool changed = 0;
927 	static uint16_t last_flags = 0;
928 
929 	delay = now - last;
930 	if (delay < 2) {
931 		/* Avoid re-loading node information within 2 secs as the data
932 		 * may still be in use. If we load new node data and free the
933 		 * old data while it it still in use, the result is likely
934 		 * invalid memory references. */
935 		force = 0;
936 		/* FIXME: Add an "in use" flag, copy the data, or otherwise
937 		 * permit the timely loading of new node information. */
938 	}
939 
940 	if (g_node_info_ptr && !force &&
941 	    (delay < working_sview_config.refresh_delay)) {
942 		if (*info_ptr != g_node_info_ptr)
943 			error_code = SLURM_SUCCESS;
944 		*info_ptr = g_node_info_ptr;
945 		return error_code;
946 	}
947 	last = now;
948 
949 	if (cluster_flags & CLUSTER_FLAG_FED)
950 		show_flags |= SHOW_FEDERATION;
951 	//if (working_sview_config.show_hidden)
952 	show_flags |= SHOW_ALL;
953 	if (g_node_info_ptr) {
954 		if (show_flags != last_flags)
955 			g_node_info_ptr->last_update = 0;
956 		error_code = slurm_load_node(g_node_info_ptr->last_update,
957 					     &new_node_ptr, show_flags);
958 		if (error_code == SLURM_SUCCESS) {
959 			slurm_free_node_info_msg(g_node_info_ptr);
960 			changed = 1;
961 		} else if (slurm_get_errno() == SLURM_NO_CHANGE_IN_DATA) {
962 			error_code = SLURM_NO_CHANGE_IN_DATA;
963 			new_node_ptr = g_node_info_ptr;
964 			changed = 0;
965 		}
966 	} else {
967 		new_node_ptr = NULL;
968 		error_code = slurm_load_node((time_t) NULL, &new_node_ptr,
969 					     show_flags);
970 		changed = 1;
971 	}
972 
973 	last_flags = show_flags;
974 	g_node_info_ptr = new_node_ptr;
975 
976 	if (g_node_info_ptr && (*info_ptr != g_node_info_ptr))
977 		error_code = SLURM_SUCCESS;
978 
979  	if (new_node_ptr && new_node_ptr->node_array && changed) {
980 		int i;
981 		node_info_t *node_ptr = NULL;
982 		uint16_t alloc_cpus = 0;
983 		int idle_cpus;
984 
985 		for (i=0; i<g_node_info_ptr->record_count; i++) {
986 			node_ptr = &(g_node_info_ptr->node_array[i]);
987 			if (!node_ptr->name || (node_ptr->name[0] == '\0'))
988 				continue;	/* bad node */
989 			idle_cpus = node_ptr->cpus;
990 
991 			slurm_get_select_nodeinfo(
992 				node_ptr->select_nodeinfo,
993 				SELECT_NODEDATA_SUBCNT,
994 				NODE_STATE_ALLOCATED,
995 				&alloc_cpus);
996 			idle_cpus -= alloc_cpus;
997 
998 			if (IS_NODE_DRAIN(node_ptr)) {
999 				/* don't worry about mixed since the
1000 				   whole node is being drained. */
1001 			} else if (idle_cpus &&
1002 				   (idle_cpus != node_ptr->cpus)) {
1003 				node_ptr->node_state &= NODE_STATE_FLAGS;
1004 				node_ptr->node_state |= NODE_STATE_MIXED;
1005 			}
1006 		}
1007 	}
1008 
1009 	*info_ptr = g_node_info_ptr;
1010 
1011 	if (!g_topo_info_msg_ptr &&
1012 	    default_sview_config.grid_topological) {
1013 		get_topo_conf(); /* pull in topology NOW */
1014 	}
1015 
1016 	return error_code;
1017 }
1018 
update_active_features_node(GtkDialog * dialog,const char * nodelist,const char * old_features)1019 extern int update_active_features_node(GtkDialog *dialog, const char *nodelist,
1020 				       const char *old_features)
1021 {
1022 	char tmp_char[100];
1023 	char *edit = NULL;
1024 	GtkWidget *entry = NULL;
1025 	GtkWidget *label = NULL;
1026 	update_node_msg_t *node_msg = xmalloc(sizeof(update_node_msg_t));
1027 	int response = 0;
1028 	int no_dialog = 0;
1029 	int rc = SLURM_SUCCESS;
1030 
1031 
1032 	if (_DEBUG)
1033 		g_print("update_active_features_node:global_row_count: %d "
1034 			"node_names %s\n",
1035 			global_row_count, nodelist);
1036 	if (!dialog) {
1037 		snprintf(tmp_char, sizeof(tmp_char),
1038 			 "Update Acitve Features for Node(s) %s?",
1039 			 nodelist);
1040 
1041 		dialog = GTK_DIALOG(
1042 			gtk_dialog_new_with_buttons(
1043 				tmp_char,
1044 				GTK_WINDOW(main_window),
1045 				GTK_DIALOG_MODAL
1046 				| GTK_DIALOG_DESTROY_WITH_PARENT,
1047 				NULL));
1048 		no_dialog = 1;
1049 	}
1050 	label = gtk_dialog_add_button(dialog,
1051 				      GTK_STOCK_YES, GTK_RESPONSE_OK);
1052 	gtk_window_set_type_hint(GTK_WINDOW(dialog),
1053 				 GDK_WINDOW_TYPE_HINT_NORMAL);
1054 	gtk_window_set_default(GTK_WINDOW(dialog), label);
1055 	gtk_dialog_add_button(dialog,
1056 			      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1057 
1058 	slurm_init_update_node_msg(node_msg);
1059 	node_msg->node_names = xstrdup(nodelist);
1060 
1061 	snprintf(tmp_char, sizeof(tmp_char),
1062 		 "Active Features for Node(s) %s?", nodelist);
1063 	label = gtk_label_new(tmp_char);
1064 	gtk_box_pack_start(GTK_BOX(dialog->vbox),
1065 			   label, false, false, 0);
1066 
1067 	entry = create_entry();
1068 	if (!entry)
1069 		goto end_it;
1070 
1071 	if (old_features)
1072 		gtk_entry_set_text(GTK_ENTRY(entry), old_features);
1073 
1074 	gtk_box_pack_start(GTK_BOX(dialog->vbox), entry, true, true, 0);
1075 	gtk_widget_show_all(GTK_WIDGET(dialog));
1076 
1077 	response = gtk_dialog_run(dialog);
1078 	if (response == GTK_RESPONSE_OK) {
1079 		node_msg->features_act =
1080 			xstrdup(gtk_entry_get_text(GTK_ENTRY(entry)));
1081 		if (!node_msg->features_act) {
1082 			edit = g_strdup_printf("No features given.");
1083 			display_edit_note(edit);
1084 			g_free(edit);
1085 			goto end_it;
1086 		}
1087 		if ((rc = slurm_update_node(node_msg)) == SLURM_SUCCESS) {
1088 			edit = g_strdup_printf(
1089 				"Node(s) %s updated successfully.",
1090 				nodelist);
1091 			display_edit_note(edit);
1092 			g_free(edit);
1093 
1094 		} else {
1095 			edit = g_strdup_printf(
1096 				"Problem updating node(s) %s: %s",
1097 				nodelist, slurm_strerror(rc));
1098 			display_edit_note(edit);
1099 			g_free(edit);
1100 		}
1101 	}
1102 
1103 end_it:
1104 	slurm_free_update_node_msg(node_msg);
1105 	if (no_dialog)
1106 		gtk_widget_destroy(GTK_WIDGET(dialog));
1107 
1108 	return rc;
1109 }
1110 
update_avail_features_node(GtkDialog * dialog,const char * nodelist,const char * old_features)1111 extern int update_avail_features_node(GtkDialog *dialog, const char *nodelist,
1112 				      const char *old_features)
1113 {
1114 	char tmp_char[100];
1115 	char *edit = NULL;
1116 	GtkWidget *entry = NULL;
1117 	GtkWidget *label = NULL;
1118 	update_node_msg_t *node_msg = xmalloc(sizeof(update_node_msg_t));
1119 	int response = 0;
1120 	int no_dialog = 0;
1121 	int rc = SLURM_SUCCESS;
1122 
1123 
1124 	if (_DEBUG)
1125 		g_print("update_avail_features_node:global_row_count: %d "
1126 			"node_names %s\n",
1127 			global_row_count, nodelist);
1128 	if (!dialog) {
1129 		snprintf(tmp_char, sizeof(tmp_char),
1130 			 "Update Available Features for Node(s) %s?",
1131 			 nodelist);
1132 
1133 		dialog = GTK_DIALOG(
1134 			gtk_dialog_new_with_buttons(
1135 				tmp_char,
1136 				GTK_WINDOW(main_window),
1137 				GTK_DIALOG_MODAL
1138 				| GTK_DIALOG_DESTROY_WITH_PARENT,
1139 				NULL));
1140 		no_dialog = 1;
1141 	}
1142 	label = gtk_dialog_add_button(dialog,
1143 				      GTK_STOCK_YES, GTK_RESPONSE_OK);
1144 	gtk_window_set_type_hint(GTK_WINDOW(dialog),
1145 				 GDK_WINDOW_TYPE_HINT_NORMAL);
1146 	gtk_window_set_default(GTK_WINDOW(dialog), label);
1147 	gtk_dialog_add_button(dialog,
1148 			      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1149 
1150 	slurm_init_update_node_msg(node_msg);
1151 	node_msg->node_names = xstrdup(nodelist);
1152 
1153 	snprintf(tmp_char, sizeof(tmp_char),
1154 		 "Available Features for Node(s) %s?", nodelist);
1155 	label = gtk_label_new(tmp_char);
1156 	gtk_box_pack_start(GTK_BOX(dialog->vbox),
1157 			   label, false, false, 0);
1158 
1159 	entry = create_entry();
1160 	if (!entry)
1161 		goto end_it;
1162 
1163 	if (old_features)
1164 		gtk_entry_set_text(GTK_ENTRY(entry), old_features);
1165 
1166 	gtk_box_pack_start(GTK_BOX(dialog->vbox), entry, true, true, 0);
1167 	gtk_widget_show_all(GTK_WIDGET(dialog));
1168 
1169 	response = gtk_dialog_run(dialog);
1170 	if (response == GTK_RESPONSE_OK) {
1171 		node_msg->features =
1172 			xstrdup(gtk_entry_get_text(GTK_ENTRY(entry)));
1173 		if (!node_msg->features) {
1174 			edit = g_strdup_printf("No features given.");
1175 			display_edit_note(edit);
1176 			g_free(edit);
1177 			goto end_it;
1178 		}
1179 		if ((rc = slurm_update_node(node_msg)) == SLURM_SUCCESS) {
1180 			edit = g_strdup_printf(
1181 				"Node(s) %s updated successfully.",
1182 				nodelist);
1183 			display_edit_note(edit);
1184 			g_free(edit);
1185 
1186 		} else {
1187 			edit = g_strdup_printf(
1188 				"Problem updating node(s) %s: %s",
1189 				nodelist, slurm_strerror(rc));
1190 			display_edit_note(edit);
1191 			g_free(edit);
1192 		}
1193 	}
1194 
1195 end_it:
1196 	slurm_free_update_node_msg(node_msg);
1197 	if (no_dialog)
1198 		gtk_widget_destroy(GTK_WIDGET(dialog));
1199 
1200 	return rc;
1201 }
1202 
update_gres_node(GtkDialog * dialog,const char * nodelist,const char * old_gres)1203 extern int update_gres_node(GtkDialog *dialog, const char *nodelist,
1204 			    const char *old_gres)
1205 {
1206 	char tmp_char[100];
1207 	char *edit = NULL;
1208 	GtkWidget *entry = NULL;
1209 	GtkWidget *label = NULL;
1210 	update_node_msg_t *node_msg = xmalloc(sizeof(update_node_msg_t));
1211 	int response = 0;
1212 	int no_dialog = 0;
1213 	int rc = SLURM_SUCCESS;
1214 
1215 	if (_DEBUG)
1216 		g_print("update_gres_node:global_row_count:"
1217 			" %d node_names %s\n",
1218 			global_row_count, nodelist);
1219 	if (!dialog) {
1220 		snprintf(tmp_char, sizeof(tmp_char),
1221 			 "Update Gres for Node(s) %s?",
1222 			 nodelist);
1223 
1224 		dialog = GTK_DIALOG(
1225 			gtk_dialog_new_with_buttons(
1226 				tmp_char,
1227 				GTK_WINDOW(main_window),
1228 				GTK_DIALOG_MODAL
1229 				| GTK_DIALOG_DESTROY_WITH_PARENT,
1230 				NULL));
1231 		no_dialog = 1;
1232 	}
1233 	label = gtk_dialog_add_button(dialog, GTK_STOCK_YES, GTK_RESPONSE_OK);
1234 	gtk_window_set_type_hint(GTK_WINDOW(dialog),
1235 				 GDK_WINDOW_TYPE_HINT_NORMAL);
1236 	gtk_window_set_default(GTK_WINDOW(dialog), label);
1237 	gtk_dialog_add_button(dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1238 
1239 	slurm_init_update_node_msg(node_msg);
1240 	node_msg->node_names = xstrdup(nodelist);
1241 
1242 	snprintf(tmp_char, sizeof(tmp_char), "Gres for Node(s) %s?", nodelist);
1243 
1244 	label = gtk_label_new(tmp_char);
1245 	gtk_box_pack_start(GTK_BOX(dialog->vbox), label, false, false, 0);
1246 
1247 	entry = create_entry();
1248 	if (!entry)
1249 		goto end_it;
1250 
1251 	if (old_gres)
1252 		gtk_entry_set_text(GTK_ENTRY(entry), old_gres);
1253 
1254 	gtk_box_pack_start(GTK_BOX(dialog->vbox), entry, true, true, 0);
1255 	gtk_widget_show_all(GTK_WIDGET(dialog));
1256 
1257 	response = gtk_dialog_run(dialog);
1258 	if (response == GTK_RESPONSE_OK) {
1259 		node_msg->gres = xstrdup(gtk_entry_get_text(GTK_ENTRY(entry)));
1260 		if (!node_msg->gres) {
1261 			edit = g_strdup_printf("No gres given.");
1262 			display_edit_note(edit);
1263 			g_free(edit);
1264 			goto end_it;
1265 		}
1266 		if ((rc = slurm_update_node(node_msg)) == SLURM_SUCCESS) {
1267 			edit = g_strdup_printf(
1268 				"Nodes %s updated successfully.",
1269 				nodelist);
1270 			display_edit_note(edit);
1271 			g_free(edit);
1272 		} else {
1273 			edit = g_strdup_printf(
1274 				"Problem updating nodes %s: %s",
1275 				nodelist, slurm_strerror(rc));
1276 			display_edit_note(edit);
1277 			g_free(edit);
1278 		}
1279 	}
1280 
1281 end_it:
1282 	slurm_free_update_node_msg(node_msg);
1283 	if (no_dialog)
1284 		gtk_widget_destroy(GTK_WIDGET(dialog));
1285 
1286 	return rc;
1287 }
1288 
update_state_node(GtkDialog * dialog,const char * nodelist,const char * type)1289 extern int update_state_node(GtkDialog *dialog,
1290 			     const char *nodelist, const char *type)
1291 {
1292 	uint16_t state = NO_VAL16;
1293 	char *upper = NULL, *lower = NULL;
1294 	int i = 0;
1295 	int rc = SLURM_SUCCESS;
1296 	char tmp_char[100];
1297 	update_node_msg_t *node_msg = xmalloc(sizeof(update_node_msg_t));
1298 	GtkWidget *label = NULL;
1299 	GtkWidget *entry = NULL;
1300 	int no_dialog = 0;
1301 
1302 	if (!dialog) {
1303 		dialog = GTK_DIALOG(
1304 			gtk_dialog_new_with_buttons(
1305 				type,
1306 				GTK_WINDOW(main_window),
1307 				GTK_DIALOG_MODAL
1308 				| GTK_DIALOG_DESTROY_WITH_PARENT,
1309 				NULL));
1310 		no_dialog = 1;
1311 	}
1312 	label = gtk_dialog_add_button(dialog, GTK_STOCK_YES, GTK_RESPONSE_OK);
1313 	gtk_window_set_type_hint(GTK_WINDOW(dialog),
1314 				 GDK_WINDOW_TYPE_HINT_NORMAL);
1315 	gtk_window_set_default(GTK_WINDOW(dialog), label);
1316 	gtk_dialog_add_button(dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1317 
1318 	slurm_init_update_node_msg(node_msg);
1319 	node_msg->node_names = xstrdup(nodelist);
1320 
1321 	if (!xstrncasecmp("drain", type, 5)) {
1322 		snprintf(tmp_char, sizeof(tmp_char),
1323 			 "Are you sure you want to drain node(s) %s?\n\n"
1324 			 "Please put reason.",
1325 			 nodelist);
1326 		entry = create_entry();
1327 		label = gtk_label_new(tmp_char);
1328 		state = NODE_STATE_DRAIN;
1329 	} else if (!xstrncasecmp("resume", type, 5)) {
1330 		snprintf(tmp_char, sizeof(tmp_char),
1331 			 "Are you sure you want to resume node(s) %s?",
1332 			 nodelist);
1333 		label = gtk_label_new(tmp_char);
1334 		state = NODE_RESUME;
1335 	} else if (!xstrncasecmp("set", type, 3)) {
1336 		snprintf(tmp_char, sizeof(tmp_char),
1337 			 "Are you sure you want to down node(s) %s?\n\n"
1338 			 "Please put reason.",
1339 			 nodelist);
1340 		entry = create_entry();
1341 		label = gtk_label_new(tmp_char);
1342 		state = NODE_STATE_DOWN;
1343 	} else if (!xstrncasecmp("undrain", type, 5)) {
1344 		snprintf(tmp_char, sizeof(tmp_char),
1345 			 "Are you sure you want to undrain node(s) %s?",
1346 			 nodelist);
1347 		label = gtk_label_new(tmp_char);
1348 		state = NODE_STATE_UNDRAIN;
1349 	} else {
1350 
1351 		if (!xstrncasecmp("make", type, 4))
1352 			type = "idle";
1353 		for(i = 0; i < NODE_STATE_END; i++) {
1354 			upper = node_state_string(i);
1355 			lower = str_tolower(upper);
1356 			if (!xstrcmp(lower, type)) {
1357 				snprintf(tmp_char, sizeof(tmp_char),
1358 					 "Are you sure you want to set "
1359 					 "node(s) %s to %s?",
1360 					 nodelist, lower);
1361 				label = gtk_label_new(tmp_char);
1362 				state = i;
1363 				xfree(lower);
1364 				break;
1365 			}
1366 			xfree(lower);
1367 		}
1368 	}
1369 	if (!label)
1370 		goto end_it;
1371 	node_msg->node_state = (uint16_t)state;
1372 	gtk_box_pack_start(GTK_BOX(dialog->vbox), label, false, false, 0);
1373 	if (entry)
1374 		gtk_box_pack_start(GTK_BOX(dialog->vbox), entry, true, true, 0);
1375 	gtk_widget_show_all(GTK_WIDGET(dialog));
1376 	i = gtk_dialog_run(dialog);
1377 	if (i == GTK_RESPONSE_OK) {
1378 		if (entry) {
1379 			node_msg->reason = xstrdup(
1380 				gtk_entry_get_text(GTK_ENTRY(entry)));
1381 			if (!node_msg->reason || !strlen(node_msg->reason)) {
1382 				lower = g_strdup_printf(
1383 					"You need a reason to do that.");
1384 				display_edit_note(lower);
1385 				g_free(lower);
1386 				goto end_it;
1387 			}
1388 			if (uid_from_string(getlogin(),
1389 					    &node_msg->reason_uid) < 0)
1390 				node_msg->reason_uid = getuid();
1391 
1392 		}
1393 		if ((rc = slurm_update_node(node_msg)) == SLURM_SUCCESS) {
1394 			lower = g_strdup_printf(
1395 				"Nodes %s updated successfully.",
1396 				nodelist);
1397 			display_edit_note(lower);
1398 			g_free(lower);
1399 		} else {
1400 			lower = g_strdup_printf(
1401 				"Problem updating nodes %s: %s",
1402 				nodelist, slurm_strerror(rc));
1403 			display_edit_note(lower);
1404 			g_free(lower);
1405 		}
1406 	}
1407 end_it:
1408 	slurm_free_update_node_msg(node_msg);
1409 	if (no_dialog)
1410 		gtk_widget_destroy(GTK_WIDGET(dialog));
1411 
1412 	return rc;
1413 }
1414 
create_model_node(int type)1415 extern GtkListStore *create_model_node(int type)
1416 {
1417 	GtkListStore *model = NULL;
1418 	GtkTreeIter iter;
1419 	char *upper = NULL, *lower = NULL;
1420 	int i=0;
1421 
1422 	last_model = NULL;	/* Reformat display */
1423 	switch(type) {
1424 	case SORTID_STATE:
1425 		model = gtk_list_store_new(2, G_TYPE_STRING,
1426 					   G_TYPE_INT);
1427 		gtk_list_store_append(model, &iter);
1428 		gtk_list_store_set(model, &iter,
1429 				   0, "drain",
1430 				   1, i,
1431 				   -1);
1432 		gtk_list_store_append(model, &iter);
1433 		gtk_list_store_set(model, &iter,
1434 				   0, "NoResp",
1435 				   1, i,
1436 				   -1);
1437 		gtk_list_store_append(model, &iter);
1438 		gtk_list_store_set(model, &iter,
1439 				   0, "resume",
1440 				   1, i,
1441 				   -1);
1442 		gtk_list_store_append(model, &iter);
1443 		gtk_list_store_set(model, &iter,
1444 				   0, "undrain",
1445 				   1, i,
1446 				   -1);
1447 		for(i = 0; i < NODE_STATE_END; i++) {
1448 			upper = node_state_string(i);
1449 			gtk_list_store_append(model, &iter);
1450 			lower = str_tolower(upper);
1451 			gtk_list_store_set(model, &iter,
1452 					   0, lower,
1453 					   1, i,
1454 					   -1);
1455 			xfree(lower);
1456 		}
1457 
1458 		break;
1459 
1460 	}
1461 	return model;
1462 }
1463 
admin_edit_node(GtkCellRendererText * cell,const char * path_string,const char * new_text,gpointer data)1464 extern void admin_edit_node(GtkCellRendererText *cell,
1465 			    const char *path_string,
1466 			    const char *new_text,
1467 			    gpointer data)
1468 {
1469 	GtkTreeStore *treestore = NULL;
1470 	GtkTreePath *path = NULL;
1471 	GtkTreeIter iter;
1472 	char *nodelist = NULL;
1473 	int column;
1474 
1475 	if (!new_text || !xstrcmp(new_text, ""))
1476 		goto no_input;
1477 
1478 	if (cluster_flags & CLUSTER_FLAG_FED) {
1479 		display_fed_disabled_popup(new_text);
1480 		goto no_input;
1481 	}
1482 
1483 	treestore = GTK_TREE_STORE(data);
1484 	path = gtk_tree_path_new_from_string(path_string);
1485 	gtk_tree_model_get_iter(GTK_TREE_MODEL(treestore), &iter, path);
1486 
1487 	column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column"));
1488 	switch(column) {
1489 	case SORTID_STATE:
1490 		gtk_tree_model_get(GTK_TREE_MODEL(treestore), &iter,
1491 				   SORTID_NAME,
1492 				   &nodelist, -1);
1493 
1494 		update_state_node(NULL, nodelist, new_text);
1495 
1496 		g_free(nodelist);
1497 	default:
1498 		break;
1499 	}
1500 
1501 	gtk_tree_path_free(path);
1502 no_input:
1503 	g_mutex_unlock(sview_mutex);
1504 }
1505 
get_info_node(GtkTable * table,display_data_t * display_data)1506 extern void get_info_node(GtkTable *table, display_data_t *display_data)
1507 {
1508 	int error_code = SLURM_SUCCESS;
1509 	static int view = -1;
1510 	static node_info_msg_t *node_info_ptr = NULL;
1511 	char error_char[100];
1512 	GtkWidget *label = NULL;
1513 	GtkTreeView *tree_view = NULL;
1514 	static GtkWidget *display_widget = NULL;
1515 	List info_list = NULL;
1516 	int i = 0, sort_key;
1517 	sview_node_info_t *sview_node_info_ptr = NULL;
1518 	ListIterator itr = NULL;
1519 	GtkTreePath *path = NULL;
1520 	static bool set_opts = false;
1521 
1522 	if (!set_opts)
1523 		set_page_opts(NODE_PAGE, display_data_node,
1524 			      SORTID_CNT, _initial_page_opts);
1525 	set_opts = true;
1526 
1527 	/* reset */
1528 	if (!table && !display_data) {
1529 		if (display_widget)
1530 			gtk_widget_destroy(display_widget);
1531 		display_widget = NULL;
1532 		goto reset_curs;
1533 	}
1534 
1535 	if (display_data)
1536 		local_display_data = display_data;
1537 	if (!table) {
1538 		display_data_node->set_menu = local_display_data->set_menu;
1539 		goto reset_curs;
1540 	}
1541 
1542 	if (display_widget && toggled) {
1543 		gtk_widget_destroy(display_widget);
1544 		display_widget = NULL;
1545 		/* Since the node_info_ptr could change out from under
1546 		 * us we always need to check if it is new or not.
1547 		 */
1548 		/* goto display_it; */
1549 	}
1550 	if ((error_code = get_new_info_node(&node_info_ptr, force_refresh))
1551 	    == SLURM_NO_CHANGE_IN_DATA) {
1552 		if (!display_widget || view == ERROR_VIEW)
1553 			goto display_it;
1554 	} else if (error_code != SLURM_SUCCESS) {
1555 		if (view == ERROR_VIEW)
1556 			goto end_it;
1557 		view = ERROR_VIEW;
1558 		if (display_widget)
1559 			gtk_widget_destroy(display_widget);
1560 		sprintf(error_char, "slurm_load_node: %s",
1561 			slurm_strerror(slurm_get_errno()));
1562 		label = gtk_label_new(error_char);
1563 		display_widget = g_object_ref(label);
1564 		gtk_table_attach_defaults(table, label, 0, 1, 0, 1);
1565 		gtk_widget_show(label);
1566 		goto end_it;
1567 	}
1568 
1569 display_it:
1570 	info_list = create_node_info_list(node_info_ptr, false);
1571 	if (!info_list)
1572 		goto reset_curs;
1573 	i = 0;
1574 	/* set up the grid */
1575 	if (display_widget && GTK_IS_TREE_VIEW(display_widget) &&
1576 	    gtk_tree_selection_count_selected_rows(
1577 		    gtk_tree_view_get_selection(
1578 			    GTK_TREE_VIEW(display_widget)))) {
1579 		GtkTreeViewColumn *focus_column = NULL;
1580 		/* highlight the correct nodes from the last selection */
1581 		gtk_tree_view_get_cursor(GTK_TREE_VIEW(display_widget),
1582 					 &path, &focus_column);
1583 	}
1584 	if (!path) {
1585 		int array_size = node_info_ptr->record_count;
1586 		int  *color_inx = xmalloc(sizeof(int) * array_size);
1587 		bool *color_set_flag = xmalloc(sizeof(bool) * array_size);
1588 		itr = list_iterator_create(info_list);
1589 		while ((sview_node_info_ptr = list_next(itr))) {
1590 			color_set_flag[i] = true;
1591 			color_inx[i] = i;
1592 			i++;
1593 		}
1594 		list_iterator_destroy(itr);
1595 		change_grid_color_array(grid_button_list, array_size,
1596 					color_inx, color_set_flag, true, 0);
1597 		xfree(color_inx);
1598 		xfree(color_set_flag);
1599 	} else {
1600 		highlight_grid(GTK_TREE_VIEW(display_widget),
1601 			       SORTID_POS, (int)NO_VAL, grid_button_list);
1602 		gtk_tree_path_free(path);
1603 	}
1604 
1605 	if (view == ERROR_VIEW && display_widget) {
1606 		gtk_widget_destroy(display_widget);
1607 		display_widget = NULL;
1608 	}
1609 	if (!display_widget) {
1610 		tree_view = create_treeview(local_display_data,
1611 					    &grid_button_list);
1612 		/*set multiple capability here*/
1613 		gtk_tree_selection_set_mode(
1614 			gtk_tree_view_get_selection(tree_view),
1615 			GTK_SELECTION_MULTIPLE);
1616 		display_widget = g_object_ref(GTK_WIDGET(tree_view));
1617 		gtk_table_attach_defaults(GTK_TABLE(table),
1618 					  GTK_WIDGET(tree_view),
1619 					  0, 1, 0, 1);
1620 		/* Since this function sets the model of the tree_view to the
1621 		 * treestore we don't really care about the return value
1622 		 * On large clusters, sorting on the node name slows GTK down
1623 		 * by a large margin. */
1624 		if (node_info_ptr->record_count > 1000)
1625 			sort_key = -1;
1626 		else
1627 			sort_key = SORTID_NAME;
1628 		create_treestore(tree_view, display_data_node,
1629 				 SORTID_CNT, sort_key, SORTID_COLOR);
1630 	}
1631 
1632 	view = INFO_VIEW;
1633 	/* If the system has a large number of nodes then not all lines
1634 	 * will be displayed. You can try different values for the third
1635 	 * argument of gtk_widget_set_size_request() in an attempt to
1636 	 * maximumize the data displayed in your environment. These are my
1637 	 * results: Y=1000 good for 43 lines, Y=-1 good for 1151 lines,
1638 	 *  Y=64000 good for 2781 lines, Y=99000 good for 1453 lines */
1639 	/* gtk_widget_set_size_request(display_widget, -1, -1); */
1640 	_update_info_node(info_list, GTK_TREE_VIEW(display_widget));
1641 end_it:
1642 	toggled = false;
1643 	force_refresh = 1;
1644 reset_curs:
1645 	if (main_window && main_window->window)
1646 		gdk_window_set_cursor(main_window->window, NULL);
1647 	return;
1648 
1649 }
1650 
specific_info_node(popup_info_t * popup_win)1651 extern void specific_info_node(popup_info_t *popup_win)
1652 {
1653 	int error_code = SLURM_SUCCESS;
1654 	static node_info_msg_t *node_info_ptr = NULL;
1655 	specific_info_t *spec_info = popup_win->spec_info;
1656 	char error_char[100];
1657 	GtkWidget *label = NULL;
1658 	GtkTreeView *tree_view = NULL;
1659 	List info_list = NULL;
1660 	List send_info_list = NULL;
1661 	ListIterator itr = NULL;
1662 	sview_node_info_t *sview_node_info_ptr = NULL;
1663 	node_info_t *node_ptr = NULL;
1664 	hostlist_t hostlist = NULL;
1665 	hostlist_iterator_t host_itr = NULL;
1666 	int i = -1, sort_key;
1667 	sview_search_info_t *search_info = spec_info->search_info;
1668 
1669 	if (!spec_info->display_widget)
1670 		setup_popup_info(popup_win, display_data_node, SORTID_CNT);
1671 
1672 	if (node_info_ptr && popup_win->toggled) {
1673 		gtk_widget_destroy(spec_info->display_widget);
1674 		spec_info->display_widget = NULL;
1675 		/* Since the node_info_ptr could change out from under
1676 		 * us we always need to check if it is new or not.
1677 		 */
1678 		/* goto display_it; */
1679 	}
1680 
1681 	if ((error_code = get_new_info_node(&node_info_ptr,
1682 					    popup_win->force_refresh))
1683 	    == SLURM_NO_CHANGE_IN_DATA) {
1684 		if (!spec_info->display_widget || spec_info->view == ERROR_VIEW)
1685 			goto display_it;
1686 	} else if (error_code != SLURM_SUCCESS) {
1687 		if (spec_info->view == ERROR_VIEW)
1688 			goto end_it;
1689 		spec_info->view = ERROR_VIEW;
1690 		if (spec_info->display_widget)
1691 			gtk_widget_destroy(spec_info->display_widget);
1692 		sprintf(error_char, "slurm_load_node: %s",
1693 			slurm_strerror(slurm_get_errno()));
1694 		label = gtk_label_new(error_char);
1695 		gtk_table_attach_defaults(popup_win->table,
1696 					  label,
1697 					  0, 1, 0, 1);
1698 		gtk_widget_show(label);
1699 		spec_info->display_widget = g_object_ref(label);
1700 		return;
1701 	}
1702 display_it:
1703 
1704 	info_list = create_node_info_list(node_info_ptr, false);
1705 
1706 	if (!info_list)
1707 		return;
1708 
1709 	if (spec_info->view == ERROR_VIEW && spec_info->display_widget) {
1710 		gtk_widget_destroy(spec_info->display_widget);
1711 		spec_info->display_widget = NULL;
1712 	}
1713 	if (spec_info->type != INFO_PAGE && !spec_info->display_widget) {
1714 		tree_view = create_treeview(local_display_data,
1715 					    &popup_win->grid_button_list);
1716 		/*set multiple capability here*/
1717 		gtk_tree_selection_set_mode(
1718 			gtk_tree_view_get_selection(tree_view),
1719 			GTK_SELECTION_MULTIPLE);
1720 		spec_info->display_widget =
1721 			g_object_ref(GTK_WIDGET(tree_view));
1722 		gtk_table_attach_defaults(popup_win->table,
1723 					  GTK_WIDGET(tree_view),
1724 					  0, 1, 0, 1);
1725 		/* Since this function sets the model of the tree_view to the
1726 		 * treestore we don't really care about the return value
1727 		 * On large clusters, sorting on the node name slows GTK down
1728 		 * by a large margin. */
1729 		if (node_info_ptr->record_count > 1000)
1730 			sort_key = -1;
1731 		else
1732 			sort_key = SORTID_NAME;
1733 		create_treestore(tree_view, popup_win->display_data,
1734 				 SORTID_CNT, sort_key, SORTID_COLOR);
1735 	}
1736 
1737 	setup_popup_grid_list(popup_win);
1738 
1739 	spec_info->view = INFO_VIEW;
1740 	if (spec_info->type == INFO_PAGE) {
1741 		_display_info_node(info_list, popup_win);
1742 		goto end_it;
1743 	}
1744 
1745 	setup_popup_grid_list(popup_win);
1746 
1747 	/* just linking to another list, don't free the inside, just
1748 	   the list */
1749 	send_info_list = list_create(NULL);
1750 	if (search_info->gchar_data) {
1751 		hostlist = hostlist_create(search_info->gchar_data);
1752 		host_itr = hostlist_iterator_create(hostlist);
1753 	}
1754 
1755 	i = -1;
1756 
1757 	itr = list_iterator_create(info_list);
1758 	while ((sview_node_info_ptr = list_next(itr))) {
1759 		int found = 0;
1760 		char *host = NULL;
1761 		i++;
1762 		node_ptr = sview_node_info_ptr->node_ptr;
1763 
1764 		switch(search_info->search_type) {
1765 		case SEARCH_NODE_STATE:
1766 			if (search_info->int_data == NO_VAL)
1767 				continue;
1768 			else if (search_info->int_data
1769 				 != node_ptr->node_state) {
1770 				if (IS_NODE_MIXED(node_ptr)) {
1771 					uint16_t alloc_cnt = 0;
1772 					uint16_t idle_cnt = node_ptr->cpus;
1773 					select_g_select_nodeinfo_get(
1774 						node_ptr->select_nodeinfo,
1775 						SELECT_NODEDATA_SUBCNT,
1776 						NODE_STATE_ALLOCATED,
1777 						&alloc_cnt);
1778 					idle_cnt -= alloc_cnt;
1779 					if ((search_info->int_data
1780 					     & NODE_STATE_BASE)
1781 					    == NODE_STATE_ALLOCATED) {
1782 						if (alloc_cnt)
1783 							break;
1784 					} else if ((search_info->int_data
1785 						    & NODE_STATE_BASE)
1786 						   == NODE_STATE_IDLE) {
1787 						if (idle_cnt)
1788 							break;
1789 					}
1790 				}
1791 				continue;
1792 			}
1793 			break;
1794 		case SEARCH_NODE_NAME:
1795 		default:
1796 			if (!search_info->gchar_data)
1797 				continue;
1798 			while ((host = hostlist_next(host_itr))) {
1799 				if (!xstrcmp(host, node_ptr->name)) {
1800 					free(host);
1801 					found = 1;
1802 					break;
1803 				}
1804 				free(host);
1805 			}
1806 			hostlist_iterator_reset(host_itr);
1807 
1808 			if (!found)
1809 				continue;
1810 			break;
1811 		}
1812 		list_push(send_info_list, sview_node_info_ptr);
1813 		change_grid_color(popup_win->grid_button_list,
1814 				  i, i, 0, true, 0);
1815 	}
1816 	list_iterator_destroy(itr);
1817 	post_setup_popup_grid_list(popup_win);
1818 
1819 	if (search_info->gchar_data) {
1820 		hostlist_iterator_destroy(host_itr);
1821 		hostlist_destroy(hostlist);
1822 	}
1823 
1824 	_update_info_node(send_info_list,
1825 			  GTK_TREE_VIEW(spec_info->display_widget));
1826 	FREE_NULL_LIST(send_info_list);
1827 end_it:
1828 	popup_win->toggled = 0;
1829 	popup_win->force_refresh = 0;
1830 
1831 	return;
1832 
1833 }
1834 
set_menus_node(void * arg,void * arg2,GtkTreePath * path,int type)1835 extern void set_menus_node(void *arg, void *arg2, GtkTreePath *path, int type)
1836 {
1837 	GtkTreeView *tree_view = (GtkTreeView *)arg;
1838 	popup_info_t *popup_win = (popup_info_t *)arg;
1839 	GtkMenu *menu = (GtkMenu *)arg2;
1840 	List button_list = (List)arg2;
1841 
1842 	switch(type) {
1843 	case TAB_CLICKED:
1844 		make_fields_menu(NULL, menu, display_data_node, SORTID_CNT);
1845 		break;
1846 	case ROW_CLICKED:
1847 		make_options_menu(tree_view, path, menu, options_data_node);
1848 		break;
1849 	case ROW_LEFT_CLICKED:
1850 	{
1851 		GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
1852 		GtkTreeIter iter;
1853 		if (!gtk_tree_model_get_iter(model, &iter, path)) {
1854 			g_error("error getting iter from model\n");
1855 			break;
1856 		}
1857 		highlight_grid(tree_view, SORTID_POS, (int)NO_VAL, button_list);
1858 		break;
1859 	}
1860 	case FULL_CLICKED:
1861 	{
1862 		GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
1863 		GtkTreeIter iter;
1864 		if (!gtk_tree_model_get_iter(model, &iter, path)) {
1865 			g_error("error getting iter from model\n");
1866 			break;
1867 		}
1868 
1869 		popup_all_node(model, &iter, INFO_PAGE);
1870 
1871 		break;
1872 	}
1873 	case POPUP_CLICKED:
1874 		make_fields_menu(popup_win, menu,
1875 				 popup_win->display_data, SORTID_CNT);
1876 		break;
1877 	default:
1878 		g_error("UNKNOWN type %d given to set_fields\n", type);
1879 	}
1880 }
1881 
popup_all_node(GtkTreeModel * model,GtkTreeIter * iter,int id)1882 extern void popup_all_node(GtkTreeModel *model, GtkTreeIter *iter, int id)
1883 {
1884 	char *name = NULL, *cluster_name = NULL;
1885 
1886 	gtk_tree_model_get(model, iter, SORTID_NAME, &name, -1);
1887 	gtk_tree_model_get(model, iter, SORTID_CLUSTER_NAME, &cluster_name, -1);
1888 	if (_DEBUG)
1889 		g_print("popup_all_node: name = %s\n", name);
1890 	popup_all_node_name(name, id, cluster_name);
1891 	/* this name gets g_strdup'ed in the previous function */
1892 	g_free(name);
1893 	g_free(cluster_name);
1894 }
1895 
popup_all_node_name(char * name,int id,char * cluster_name)1896 extern void popup_all_node_name(char *name, int id, char *cluster_name)
1897 {
1898 	char title[100] = {0};
1899 	ListIterator itr = NULL;
1900 	popup_info_t *popup_win = NULL;
1901 	GError *error = NULL;
1902 
1903 	switch(id) {
1904 	case JOB_PAGE:
1905 		snprintf(title, 100, "Job(s) with Node %s", name);
1906 		break;
1907 	case PART_PAGE:
1908 		snprintf(title, 100, "Partition(s) with Node %s", name);
1909 		break;
1910 	case RESV_PAGE:
1911 		snprintf(title, 100, "Reservation(s) with Node %s", name);
1912 		break;
1913 	case SUBMIT_PAGE:
1914 		snprintf(title, 100, "Submit job on Node %s", name);
1915 		break;
1916 	case INFO_PAGE:
1917 		snprintf(title, 100, "Full Info for Node %s", name);
1918 		break;
1919 	default:
1920 		g_print("Node got %d\n", id);
1921 	}
1922 
1923 	if (cluster_name && federation_name &&
1924 	    (cluster_flags & CLUSTER_FLAG_FED)) {
1925 		char *tmp_cname =
1926 			xstrdup_printf(" (%s:%s)",
1927 				       federation_name, cluster_name);
1928 		strncat(title, tmp_cname, sizeof(title) - strlen(title) - 1);
1929 		xfree(tmp_cname);
1930 	}
1931 
1932 	itr = list_iterator_create(popup_list);
1933 	while ((popup_win = list_next(itr))) {
1934 		if (popup_win->spec_info)
1935 			if (!xstrcmp(popup_win->spec_info->title, title)) {
1936 				break;
1937 			}
1938 	}
1939 	list_iterator_destroy(itr);
1940 
1941 	if (!popup_win) {
1942 		if (id == INFO_PAGE)
1943 			popup_win = create_popup_info(id, NODE_PAGE, title);
1944 		else
1945 			popup_win = create_popup_info(NODE_PAGE, id, title);
1946 		popup_win->spec_info->search_info->gchar_data = g_strdup(name);
1947 
1948 		if (cluster_flags & CLUSTER_FLAG_FED)
1949 			popup_win->spec_info->search_info->cluster_name =
1950 				g_strdup(cluster_name);
1951 		if (!sview_thread_new((gpointer)popup_thr, popup_win,
1952 				      false, &error)) {
1953 			g_printerr ("Failed to create node popup thread: "
1954 				    "%s\n",
1955 				    error->message);
1956 			return;
1957 		}
1958 	} else
1959 		gtk_window_present(GTK_WINDOW(popup_win->popup));
1960 }
1961 
admin_menu_node_name(char * name,GdkEventButton * event)1962 extern void admin_menu_node_name(char *name, GdkEventButton *event)
1963 {
1964 	GtkMenu *menu = GTK_MENU(gtk_menu_new());
1965 	display_data_t *display_data = options_data_node;
1966 	GtkWidget *menuitem;
1967 
1968 	while (display_data++) {
1969 		if (display_data->id == -1)
1970 			break;
1971 		if (!display_data->name)
1972 			continue;
1973 
1974 		display_data->user_data = name;
1975 		menuitem = gtk_menu_item_new_with_label(display_data->name);
1976 		g_signal_connect(menuitem, "activate",
1977 				 G_CALLBACK(_selected_page),
1978 				 display_data);
1979 		gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1980 	}
1981 	gtk_widget_show_all(GTK_WIDGET(menu));
1982 	gtk_menu_popup(menu, NULL, NULL, NULL, NULL,
1983 		       event ? event->button : 0,
1984 		       gdk_event_get_time((GdkEvent*)event));
1985 }
1986 
select_admin_nodes(GtkTreeModel * model,GtkTreeIter * iter,display_data_t * display_data,uint32_t node_col,GtkTreeView * treeview)1987 extern void select_admin_nodes(GtkTreeModel *model,
1988 			       GtkTreeIter *iter,
1989 			       display_data_t *display_data,
1990 			       uint32_t node_col,
1991 			       GtkTreeView *treeview)
1992 {
1993 	if (treeview) {
1994 		char *old_value = NULL;
1995 		hostlist_t hl = NULL;
1996 		process_node_t process_node;
1997 		memset(&process_node, 0, sizeof(process_node_t));
1998 		if (node_col == NO_VAL)
1999 			process_node.node_col = SORTID_NAME;
2000 		else
2001 			process_node.node_col = node_col;
2002 
2003 		gtk_tree_selection_selected_foreach(
2004 			gtk_tree_view_get_selection(treeview),
2005 			_process_each_node, &process_node);
2006 		hl = hostlist_create(process_node.nodelist);
2007 		hostlist_uniq(hl);
2008 		hostlist_sort(hl);
2009 		xfree(process_node.nodelist);
2010 		process_node.nodelist = hostlist_ranged_string_xmalloc(hl);
2011 		hostlist_destroy(hl);
2012 
2013 		if (!xstrcasecmp("Update Features", display_data->name)) {
2014 			/* get old features */
2015 			gtk_tree_model_get(model, iter, SORTID_AVAIL_FEATURES,
2016 					   &old_value, -1);
2017 		} else if (!xstrcasecmp("Update Gres", display_data->name)) {
2018 			/* get old gres */
2019 			gtk_tree_model_get(model, iter, SORTID_GRES,
2020 					   &old_value, -1);
2021 		}
2022 		admin_node_name(process_node.nodelist, old_value,
2023 				display_data->name);
2024 		xfree(process_node.nodelist);
2025 		if (old_value)
2026 			g_free(old_value);
2027 
2028 
2029 	}
2030 } /*select_admin_nodes ^^^*/
2031 
admin_node_name(char * name,char * old_value,char * type)2032 extern void admin_node_name(char *name, char *old_value, char *type)
2033 {
2034 	GtkWidget *popup = NULL;
2035 
2036 	if (cluster_flags & CLUSTER_FLAG_FED) {
2037 		display_fed_disabled_popup(type);
2038 		return;
2039 	}
2040 
2041 	popup = gtk_dialog_new_with_buttons(
2042 		type,
2043 		GTK_WINDOW(main_window),
2044 		GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
2045 		NULL);
2046 	gtk_window_set_type_hint(GTK_WINDOW(popup),
2047 				 GDK_WINDOW_TYPE_HINT_NORMAL);
2048 	gtk_window_set_transient_for(GTK_WINDOW(popup), NULL);
2049 
2050 	if (!xstrcasecmp("Update Available Features", type)
2051 	    || !xstrcasecmp("Update Node Features", type)
2052 	    || !xstrcasecmp("Update Midplane Features",
2053 			   type)) { /* update features */
2054 		update_avail_features_node(GTK_DIALOG(popup), name, old_value);
2055 	} else if (!xstrcasecmp("Update Active Features", type)) {
2056 		update_active_features_node(GTK_DIALOG(popup), name, old_value);
2057 	} else if (!xstrcasecmp("Update Gres", type)) { /* update gres */
2058 		update_gres_node(GTK_DIALOG(popup), name, old_value);
2059 	} else /* something that has to deal with a node state change */
2060 		update_state_node(GTK_DIALOG(popup), name, type);
2061 
2062 	gtk_widget_destroy(popup);
2063 
2064 	return;
2065 }
2066 
cluster_change_node(void)2067 extern void cluster_change_node(void)
2068 {
2069 	display_data_t *display_data = display_data_node;
2070 	while (display_data++) {
2071 		if (display_data->id == -1)
2072 			break;
2073 		if (cluster_flags & CLUSTER_FLAG_FED) {
2074 			switch(display_data->id) {
2075 			case SORTID_CLUSTER_NAME:
2076 				display_data->show = true;
2077 				break;
2078 			}
2079 		} else {
2080 			switch(display_data->id) {
2081 			case SORTID_CLUSTER_NAME:
2082 				display_data->show = false;
2083 				break;
2084 			}
2085 		}
2086 	}
2087 
2088 	get_info_node(NULL, NULL);
2089 }
2090