2
Copyright (C) 2003 by Sean David Fleming
6
This program is free software; you can redistribute it and/or
7
modify it under the terms of the GNU General Public License
8
as published by the Free Software Foundation; either version 2
9
of the License, or (at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
The GNU GPL can also be found at http://www.gnu.org
27
#include <sys/types.h>
40
#include "grisu_client.h"
41
#include "interface.h"
43
extern struct sysenv_pak sysenv;
45
/* CURRENT - register apps for a GRID destination */
46
/* NULL -> not on grid */
47
/* TODO - consider storing structs containing more info */
48
/* ie site, app details etc - for faster job building */
50
GHashTable *grid_table=NULL;
51
/* CURRENT - assume credential already uploaded for the time being */
52
gint grid_authenticated=FALSE;
53
gchar *myproxy_init=NULL;
55
void grid_application_set(const gchar *name, const gchar *value)
59
g_hash_table_replace(grid_table, g_strdup(name), g_strdup(value));
65
gchar *grid_application_get(const gchar *name)
69
return(g_hash_table_lookup(grid_table, name));
77
void grid_application_remove(const gchar *name)
81
g_hash_table_remove(grid_table, name);
87
GList *grid_application_all(void)
90
return(g_hash_table_get_keys(grid_table));
96
GSList *grid_search_by_name(const gchar *name)
99
return(grisu_submit_find(name));
105
/*********************************************/
106
/* allocate and initialize a grid job object */
107
/*********************************************/
108
gpointer grid_new(void)
110
struct grid_pak *grid;
112
grid = g_malloc(sizeof(struct grid_pak));
114
grid->user_vo = NULL;
115
grid->jobname = NULL;
116
grid->exename = NULL;
117
grid->exe_version = NULL;
118
grid->jobcode = JOB_UNKNOWN;
120
grid->remote_q = NULL;
121
grid->remote_root = NULL;
122
grid->remote_exe = NULL;
123
grid->remote_exe_module = NULL;
124
grid->remote_site = NULL;
126
grid->remote_exe_type=-1;
127
grid->remote_exe_np=1;
129
grid->local_cwd = NULL;
130
grid->local_input = NULL;
131
grid->local_output = NULL;
136
/**************************/
137
/* free a grid job object */
138
/**************************/
139
void grid_free(gpointer data)
141
struct grid_pak *grid=data;
143
g_assert(grid != NULL);
145
g_free(grid->user_vo);
146
g_free(grid->jobname);
147
g_free(grid->exename);
148
g_free(grid->exe_version);
150
g_free(grid->remote_q);
151
g_free(grid->remote_root);
152
g_free(grid->remote_exe);
153
g_free(grid->remote_exe_module);
154
g_free(grid->remote_site);
156
g_free(grid->local_cwd);
157
g_free(grid->local_input);
158
g_free(grid->local_output);
163
/***************************************/
164
/* get the DN from an x509 certificate */
165
/***************************************/
166
// openssl x509 -noout -in usercert.pem -subject
167
gchar *grid_get_DN(gchar *certificate_fullpath)
170
gchar *cmd, *out, *err, *subject=NULL;
173
cmd = g_strdup_printf("openssl x509 -noout -in %s -subject", certificate_fullpath);
175
/* TODO - get the output */
176
if (g_spawn_command_line_sync(cmd, &out, &err, &status, &error))
178
for (i=0 ; i<8000 ; i++)
182
/* not sure why but plain g_strdup adds a crappy char (null?) */
183
/* to the string, so scan for the end and use strndup instead */
184
for (j=i ; j<9000 ; j++)
189
subject = g_strndup(&out[i], j-i-1);
199
gboolean grid_credential_get()
204
/*******************************************************/
205
/* set valid auth in case of external means (eg) grisu */
206
/*******************************************************/
207
/* TODO - could chuck into sysenv eventually */
208
void grid_auth_set(gint value)
210
grid_authenticated=value;
213
/*********************************************/
214
/* verify current authentication information */
215
/*********************************************/
216
gint grid_auth_check(void)
221
/* perform a grisu operation that requires authentication */
222
/* NB: use anything fast (as long as auth info is in the header) */
223
//list = grisu_fqans_get();
224
list = grisu_site_list();
228
grid_authenticated = TRUE;
233
grid_authenticated = FALSE;
238
/****************************************************/
239
/* upload a temporary credential to a remote server */
240
/****************************************************/
241
/* TODO - if grid_passwd is NULL -> use stdin */
242
#define DEBUG_GRID_CREDENTIAL_INIT 0
243
void grid_credential_init(const gchar *grid_password)
247
gchar **argv, **envp;
248
const gchar *username, *password, *server, *port;
251
FILE *fpi, *fpo, *fpe;
253
/* TODO - informative user error messages */
256
if (grid_authenticated)
261
username = grisu_username_get();
262
password = grisu_password_get();
263
server = grisu_myproxy_get();
264
port = grisu_myproxyport_get();
266
#if DEBUG_GRID_CREDENTIAL_INIT
267
printf("Credential for: ");
268
printf("%s : %s -> %s : %s\n", username, password, server, port);
271
/* FIXME - authentication issues with myproxy/myproxy2 */
272
/* solution is to point at myproxy2 and set */
273
/* MYPROXY_SERVER_DN /C=AU/O=APACGrid/OU=VPAC/CN=myproxy2.arcs.org.au */
275
/* FIXME - need to ensure enviroment has GT_PROXY_MODE set to "old" */
276
/* unless markus fixes grisu's credential retrieval */
277
/* build argument vector */
279
/* FIXME - implement this */
280
envp = g_malloc(3 * sizeof(gchar *));
281
*(envp) = g_strdup("GT_PROXYMODE=old");
282
*(envp+1) = g_strdup("MYPROXY_SERVER_DN=/C=AU/O=APACGrid/OU=VPAC/CN=myproxy2.arcs.org.au");
286
argv = g_malloc(10 * sizeof(gchar *));
287
/* NB: need full path to executable */
288
*(argv) = g_strdup(myproxy_init);
290
*(argv+1) = g_strdup("-l");
291
*(argv+2) = g_strdup(username);
293
/* small lifetime while we debug */
294
*(argv+3) = g_strdup("-c");
295
*(argv+4) = g_strdup("1");
297
*(argv+5) = g_strdup("-a");
299
*(argv+6) = g_strdup("-S");
301
*(argv+7) = g_strdup("-s");
302
*(argv+8) = g_strdup(server);
307
if (g_spawn_async_with_pipes(NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
308
NULL, NULL, &pid, &inp, &out, &err, &error))
313
/* parent - wait until child is done */
314
//printf("parent: waiting for child...\n");
316
fpi = fdopen(inp, "a");
317
fpo = fdopen(out, "r");
318
fpe = fdopen(err, "r");
320
/* NB: -S will make myproxy prompt for grid passphrase */
321
/* and then the credential password once only */
322
/* CURRENT - not sure why this isnt working - it seems */
323
/* to work if run manually from the command line */
325
fprintf(fpi, "%s\n", grid_password);
328
/* CURRENT - this seems to fix the problem! */
329
/* obviously a delay is needed while myproxy-init processes the */
330
/* grid_password to generate a local proxy */
331
/* the problem is - how to we poll stdout to know when to send the */
332
/* passphrase ... which is probably better than an arbitrary sleep */
338
/* test if process has terminated */
339
/* note that if it has - child is reaped and we cant call waitpid() again */
342
if (waitpid(pid, NULL, WNOHANG) > 0)
344
printf("Bad password.\n");
346
g_spawn_close_pid(pid);
347
grid_authenticated = FALSE;
353
//printf("waitpid 4: %d\n", waitpid(pid, NULL, WEXITED | WNOHANG));
356
fprintf(fpi, "%s\n", password);
360
#if DEBUG_GRID_CREDENTIAL_INIT
364
line = file_read_line(fpo);
365
printf("FORK, stdout: %s\n", line);
371
line = file_read_line(fpe);
372
printf("FORK, stderr : %s\n", line);
387
waitpid(pid, NULL, WEXITED);
390
g_spawn_close_pid(pid);
392
grid_authenticated = TRUE;
395
/* sleep - give the uploaded proxy some time to "stick" to the server */
396
/* FIXME - better to poll (myproxy-logon?) for the credential */
397
printf("Uploading Credential, please wait ...\n");
409
printf("Failed to upload credential, myproxy-init not found or bad connectivity?\n");
419
/****************************************************/
420
/* get short text message describing current status */
421
/****************************************************/
422
const gchar *grid_get_status()
424
if (grid_authenticated)
425
return("Authenticated");
427
return("Not authenticated");
430
/***********************************************************/
431
/* generate a random alphabetical string of specified size */
432
/***********************************************************/
433
gchar *grid_random_alpha(gint length)
440
text = g_string_new(NULL);
442
for (i=length ; i-- ; )
444
g_string_sprintfa(text, "%c", g_rand_int_range(r, 'a', 'z'));
449
return(g_string_free(text, FALSE));
452
/************************************************************/
453
/* generate a random alpha-numeric string of specified size */
454
/************************************************************/
455
gchar *grid_random_alphanum(gint length)
462
text = g_string_new(NULL);
464
/* NB: some systems require an alphabetical character first */
465
g_string_sprintfa(text, "%c", g_rand_int_range(r, 'a', 'z'));
469
decide = g_rand_int_range(r, 0, 99);
471
g_string_sprintfa(text, "%c", g_rand_int_range(r, 'a', 'z'));
473
g_string_sprintfa(text, "%c", g_rand_int_range(r, '0', '9'));
479
return(g_string_free(text, FALSE));
482
/**********************************/
483
/* attempt to upload a credential */
484
/**********************************/
485
gint grid_connect(gint method)
494
case GRID_LOCALPROXY:
495
/* if successful, send info to grisu client for soap header */
496
/* CURRENT - myproxy-init fed with grid_passwd */
497
grid_credential_init(grisu_password_get());
501
grisu_auth_set(TRUE);
513
void grid_setup(void)
521
myproxy_init = g_find_program_in_path("myproxy-init");
523
printf("grid_setup() Warning. Failed to locate: myproxy-init\n");
527
grid_table = g_hash_table_new(g_str_hash, g_str_equal);
534
void grid_cleanup(void)
536
g_hash_table_destroy(grid_table);
539
/*****************************************/
540
/* process completed jobs after download */
541
/*****************************************/
542
/* this could be generic, since we assume output is on local filestore */
543
void grid_process_job(const gchar *job_name, GSList *file_list)
548
gchar *input=NULL, *output=NULL;
550
struct model_pak *model;
552
type = grisu_job_type(job_name);
557
printf("processing GULP job ... \n");
559
for (item=file_list ; item ; item=g_slist_next(item))
563
/* skip if no extension */
564
ext = file_extension_get(name);
568
/* load results file as preference for coords */
569
if (g_strncasecmp(ext, "res", 3) == 0)
571
/* only load original input file if no results file found */
572
if (g_strncasecmp(ext, "gin", 3) == 0)
577
/* output file containing energies etc */
578
if (g_strncasecmp(ext, "go", 2) == 0)
584
printf("No GULP output file found. Failed job?\n");
589
printf("No GULP input file found. Failed authentication?\n");
593
/* create new model for the results */
595
/* read main data from the res file (correct charges etc.) */
596
read_gulp(input, model);
597
/* graft to the model tree, so subsequent GULP read doesn't replace coords */
599
/* CURRENT - give the loaded model the same name as the job ... better method? */
602
g_free(model->basename);
603
// model->basename = g_strdup(job_name);
604
// model->basename = g_strdup(input);
606
model->basename = parse_strip(input);
609
sysenv.active_model = model;
611
tree_model_add(model);
612
/* get the output energy/phonons etc. */
613
read_gulp_output(output, model);
615
/* FIXME - if the GULP job fails - model_prep() isnt called, and the */
616
/* model camera isnt initialized => error trap when gdis tries to visualize */
619
printf("WARNING: GULP calculation has possibly failed.\n");
622
/* TODO - return model - so gui part decides whether to force a select/display or not */
623
//gui_model_select(model);
628
printf("processsing GAMESS job ... \n");
630
for (item=file_list ; item ; item=g_slist_next(item))
633
ext = file_extension_get(name);
634
/* skip if no extension */
638
if (g_strncasecmp(ext, "gmot", 4) == 0)
644
/* create new model for the results */
646
/* read main data from the res file (correct charges etc.) */
647
read_gms_out(output, model);
651
g_free(model->basename);
652
model->basename = g_strdup(job_name);
655
sysenv.active_model = model;
657
tree_model_add(model);
659
/* FIXME - if the job fails - model_prep() isnt called, and the */
660
/* model camera isnt initialized => error trap when gdis tries to visualize */
663
printf("WARNING: GAMESS calculation has possibly failed.\n");
667
/* TODO - return model - so gui part decides whether to force a select/display or not */
668
//gui_model_select(model);
669
//sysenv.active_model = model;
674
printf("No GAMESS output file found. Failed job?\n");
680
printf("Error, unknown job\n");
686
/***************************/
687
/* download completed jobs */
688
/***************************/
689
GSList *grid_download_job(const gchar *name)
692
gchar *remote_cwd, *local, *remote;
693
GSList *item, *list, *results=NULL;
695
printf("Getting result files for: %s\n", name);
697
remote_cwd = grisu_job_cwd(name);
699
/* TODO - get job type (GULP etc) from name (eg grisu_job_type()) and filter */
700
//printf("Working directory = %s\n", cwd);
704
list = grisu_file_list(remote_cwd);
706
for (item=list ; item ; item=g_slist_next(item))
708
gchar *file = item->data;
709
printf("[%s]\n", file);
710
// TODO - strictly - should be the job's local_output destination here */
711
local = g_build_filename(sysenv.cwd, file, NULL);
712
remote = g_build_filename(remote_cwd, file, NULL);
714
//printf("Transferring [%s] -> [%s]\n", remote, local);
716
/* if download is successful add to results list for post-processing */
717
if (grisu_file_download(remote, local))
718
results = g_slist_prepend(results, local);
731
/**********************************/
732
/* background task job submission */
733
/**********************************/
734
void grid_job_start(gpointer data)
738
gchar *jobxml, *value, *tmp;
739
gchar *fs_absolute, *fs_relative;
740
gchar *local, *remote;
743
struct grid_pak *grid=data;
745
g_assert(grid != NULL);
746
g_assert(grid->exename != NULL);
747
g_assert(grid->remote_q != NULL);
749
grid->jobcode = grisu_job_type(grid->exename);
750
grid->user_vo = g_strdup(grisu_vo_get());
752
grid->remote_site = grisu_site_name(grid->remote_q);
753
if (!grid->remote_site)
755
printf("Could not determine submission site.\n");
759
list = grisu_application_versions(grid->exename, grid->remote_site);
762
/* CURRENT - just use the first entry */
763
if (grid->exe_version)
764
g_free(grid->exe_version);
765
grid->exe_version = g_strdup(list->data);
769
/* strictly, not all programs would require a version */
770
/* eg gamess does, but gulp doesnt */
771
printf("Warning: could not determine executable version of [%s] at [%s]\n", grid->exename, grid->remote_site);
774
details = grisu_application_details(grid->exename, grid->remote_site);
777
tmp = g_hash_table_lookup(details, "Executables");
780
printf("Failed to locate executable on remote site.\n");
783
grid->remote_exe = g_strdup(tmp);
785
tmp = g_hash_table_lookup(details, "Module");
787
grid->remote_exe_module = g_strdup(tmp);
789
//printf("Requiring module [%s]\n", grid->remote_exe_module);
791
/* CURRENT - prefer serial over parallel */
792
value = g_hash_table_lookup(details, "ParallelAvail");
793
if (g_strncasecmp(value, "true", 4) == 0)
795
grid->remote_exe_type = GRID_MPI;
796
/* CURRENT - hack to force // ie mpi */
797
grid->remote_exe_np = 2;
800
/* CURRENT - prefer serial over parallel */
801
value = g_hash_table_lookup(details, "SerialAvail");
802
if (g_strncasecmp(value, "true", 4) == 0)
804
grid->remote_exe_type = GRID_SERIAL;
805
grid->remote_exe_np = 1;
808
if (grid->remote_exe_type == -1)
810
printf("Failed to determine serial/parallel invocation method on remote site.\n");
816
printf("Failed to get application details from MDS.\n");
822
grid->jobname = grisu_jobname_request(grid->jobcode);
825
printf("Failed to create job, not authenticated?\n");
829
/* calculate mount point */
830
fs_absolute = grisu_absolute_job_dir(grid->jobname, grid->remote_q, grid->user_vo);
833
printf("Failed to locate a valid remote filesystem for VO [%s] at [%s]\n", grid->user_vo, grid->remote_site);
837
fs_relative = grisu_relative_job_dir(grid->jobname);
838
g_assert(fs_relative != NULL);
840
alen = strlen(fs_absolute);
841
rlen = strlen(fs_relative);
843
grid->remote_root = g_strndup(fs_absolute, alen-rlen);
846
printf("Bad filesystem returned by grisu.\n");
847
// cope as best we can
848
grid->remote_root = g_strdup(fs_absolute);
851
//printf("Remote root: %s\n", grid->remote_root);
855
/* TODO - stat the file to ensure it was written */
856
if (!grid->local_input || !grid->local_cwd)
858
printf("Error, job input file not correctly written.\n");
862
/* TODO - could do this earlier as well ... */
863
switch (grid->jobcode)
866
grid->local_output = parse_extension_set(grid->local_input, "gmot");
869
grid->local_output = parse_extension_set(grid->local_input, "got");
873
local = g_build_filename(grid->local_cwd, grid->local_input, NULL);
874
remote = g_build_filename(fs_absolute, grid->local_input, NULL);
876
//printf("upload [%s] -> [%s]\n", local, remote);
878
grisu_file_upload(local, remote);
884
jobxml = grisu_xml_create(grid);
886
//printf(" *** XML:\n%s\n", jobxml);
888
grisu_job_configure(grid->jobname, jobxml);
889
grisu_job_submit(grid->jobname, grid->user_vo);
898
/*******************/
899
/* completion task */
900
/*******************/
901
void grid_job_stop(gpointer data)
903
struct grid_pak *grid=data;
905
/* TODO - free the grid structre */
912
/* refresh all jobs */
913
/* FIXME - too expensive to keep doing all the time */
914
/* FIXME - do this at start (eg when connecting ... and only add/del subsequently) */
915
//gui_job_refresh_all();
918
/*******************************************************/
919
/* submit a grid job (potentially from setup a dialog) */
920
/*******************************************************/
921
/* name = application name (eg "gulp") */
922
gint grid_job_submit(const gchar *name, gpointer data)
926
struct grid_pak *grid=data;
929
g_assert(grid != NULL);
931
/* test we have a valid grid destination */
932
remote_q = grid_application_get(name);
935
printf("No valid destination queue registered for: %s\n", name);
940
if (!grid_task_start())
944
grid->exename = g_strdup(name);
945
grid->remote_q = g_strdup(remote_q);
947
/* submit and lock model */
948
task_new("grid", grid_job_start, grid, grid_job_stop, grid, NULL);
952
printf("No grid support installed.\n");