static int globus_l_staging_replace_one_stream( globus_gram_jobmanager_request_t * request, char * parameter, char * cached_destination, globus_list_t * list, globus_bool_t single) { globus_rsl_value_t from_cached; globus_rsl_value_t *to = NULL; globus_rsl_value_t *tag = NULL; char *evaled_to = NULL; char *evaled_tag = NULL; char *fname = NULL; unsigned long timestamp = GLOBUS_GASS_CACHE_TIMESTAMP_UNKNOWN; int rc = GLOBUS_SUCCESS; static const char gass_cache_scheme[] = "x-gass-cache://"; from_cached.type = GLOBUS_RSL_VALUE_LITERAL; from_cached.value.literal.string = cached_destination; /* * First element of the list is the destination, the second is the * (optional) tag. Both (if present) must be something that * evaluates to a string and not a sequence. */ to = globus_list_first(list); list = globus_list_rest(list); if (!globus_list_empty(list)) { tag = globus_list_first(list); list = globus_list_rest(list); } if (globus_rsl_value_is_sequence(to) || ((tag != NULL) && globus_rsl_value_is_sequence(tag)) || list != NULL) { rc = GLOBUS_GRAM_PROTOCOL_ERROR_RSL_STDOUT; goto bad_value; } rc = globus_gram_job_manager_rsl_evaluate_value( &request->symbol_table, to, &evaled_to); if (rc != GLOBUS_SUCCESS) { goto bad_value; } /* If it evaluates to a string, and is not an x-gass-cache URL, * then tag must be NULL */ if (strncmp(evaled_to, gass_cache_scheme, sizeof(gass_cache_scheme)-1) != 0 && tag != NULL) { rc = GLOBUS_GRAM_PROTOCOL_ERROR_RSL_STDOUT; free(evaled_to); goto bad_value; } if (tag != NULL) { /* If there's a tag, evaluate it and add it to the cache file * so that the file won't get erased when the job terminates */ rc = globus_gram_job_manager_rsl_evaluate_value( &request->symbol_table, tag, &evaled_tag); if (rc != GLOBUS_SUCCESS) { goto bad_value; } rc = globus_gass_cache_add( request->cache_handle, evaled_to, evaled_tag, GLOBUS_TRUE, ×tamp, &fname); if (rc != GLOBUS_GASS_CACHE_ADD_NEW && rc != GLOBUS_GASS_CACHE_ADD_EXISTS) { rc = GLOBUS_GRAM_PROTOCOL_ERROR_OPENING_STDOUT; goto bad_value; } free(fname); rc = globus_gass_cache_add_done( request->cache_handle, evaled_to, evaled_tag, timestamp); if (rc != GLOBUS_SUCCESS) { rc = GLOBUS_GRAM_PROTOCOL_ERROR_OPENING_STDOUT; goto bad_value; } } /* If there is more than one output destination, or this one is * a non-local destination, then add it to the streamout list */ if ((!single) || (strstr(evaled_to, "://") != NULL && strncmp(evaled_to, gass_cache_scheme, sizeof(gass_cache_scheme)-1) != 0)) { rc = globus_l_gram_job_manager_staging_add_pair( request, &from_cached, to, "filestreamout"); free(evaled_to); evaled_to = NULL; if (rc != GLOBUS_SUCCESS) { goto bad_value; } } else if (strstr(evaled_to, "://") == NULL) { /* If it's a local file, check that it is writable */ int tmpfd; tmpfd = open(evaled_to, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR); if (tmpfd < 0) { rc = GLOBUS_GRAM_PROTOCOL_ERROR_OPENING_STDOUT; free(evaled_to); goto bad_value; } else { close(tmpfd); } } if (evaled_to) { free(evaled_to); } if (rc != GLOBUS_SUCCESS) { bad_value: /* Normalize error types to match the RSL attribute that we are * processing */ if (strcmp(parameter, GLOBUS_GRAM_PROTOCOL_STDERR_PARAM) == 0) { switch (rc) { case GLOBUS_GRAM_PROTOCOL_ERROR_RSL_STDOUT: rc = GLOBUS_GRAM_PROTOCOL_ERROR_RSL_STDERR; break; case GLOBUS_GRAM_PROTOCOL_ERROR_OPENING_STDOUT: rc = GLOBUS_GRAM_PROTOCOL_ERROR_OPENING_STDERR; break; default: break; } } } return rc; }
static int globus_l_staging_replace_stream( globus_gram_jobmanager_request_t * request, char * parameter, char * cached_destination) { globus_list_t * list; globus_rsl_value_t *to; globus_rsl_value_t from_cached; globus_bool_t single; int rc = GLOBUS_SUCCESS; list = globus_rsl_param_get_values( request->rsl, parameter); if (list == NULL) { /* Attempting to replace something that was never in the job * RSL---too bad */ return GLOBUS_SUCCESS; } from_cached.type = GLOBUS_RSL_VALUE_LITERAL; from_cached.value.literal.string = cached_destination; /* The stdout and stderr attributes can occur in two forms: * - stdout = destination [tag] * - stdout = (destination [tag])+ * That is, either as a sequence of 1 or 2 values, or as a sequence of * sequences. * * In either form, if there is only one destination, and it's a local file * or x-gass-cache URL, we can safely write directly to that file and don't * need it to be staged after the job completes. Otherwise, we'll have to * write to the stdout (stderr) file in the job directory and copy it * during the STAGE_OUT state. */ if (! globus_rsl_value_is_sequence(globus_list_first(list))) { rc = globus_l_staging_replace_one_stream( request, parameter, cached_destination, list, GLOBUS_TRUE); } else { single = (globus_list_size(list) == 1); while (!globus_list_empty(list)) { globus_list_t *sequence_list; to = globus_list_first(list); list = globus_list_rest(list); if (!globus_rsl_value_is_sequence(to)) { /* Bare value instead of a sequence */ rc = GLOBUS_GRAM_PROTOCOL_ERROR_RSL_STDOUT; goto bad_value; } sequence_list = globus_rsl_value_sequence_get_value_list(to); rc = globus_l_staging_replace_one_stream( request, parameter, cached_destination, sequence_list, single); if (rc != GLOBUS_SUCCESS) { goto bad_value; } } } if (rc != GLOBUS_SUCCESS) { bad_value: /* Normalize error types to match the RSL attribute that we are * processing */ if (strcmp(parameter, GLOBUS_GRAM_PROTOCOL_STDERR_PARAM) == 0) { switch (rc) { case GLOBUS_GRAM_PROTOCOL_ERROR_RSL_STDOUT: rc = GLOBUS_GRAM_PROTOCOL_ERROR_RSL_STDERR; break; case GLOBUS_GRAM_PROTOCOL_ERROR_OPENING_STDOUT: rc = GLOBUS_GRAM_PROTOCOL_ERROR_OPENING_STDERR; break; default: break; } } } return rc; }
static bool value_to_expr(globus_rsl_value_t * value, classad::ExprTree*& expr) { if (globus_rsl_value_is_literal(value)) { char * literal = globus_rsl_value_literal_get_string(value); if (!literal) { return false; } classad::Value val; try { val.SetIntegerValue(boost::lexical_cast<long long>(literal)); } catch (const boost::bad_lexical_cast &) { try { val.SetRealValue(boost::lexical_cast<double>(literal)); } catch (const boost::bad_lexical_cast &) { std::string lower = literal; boost::algorithm::to_lower(lower); if (lower == "true") { val.SetBooleanValue(true); } else if (lower == "false") { val.SetBooleanValue(false); } else { val.SetStringValue(literal); } } } expr = classad::Literal::MakeLiteral(val); if (!expr) { return false; } return true; } else if (globus_rsl_value_is_sequence(value)) { globus_list_t * value_list = globus_rsl_value_sequence_get_value_list(value); if (!value_list) { return false; } classad::ExprList expr_list; while (!globus_list_empty(value_list)) { globus_rsl_value_t *list_item = static_cast<globus_rsl_value_t*>(globus_list_first(value_list)); value_list = globus_list_rest(value_list); if (!list_item) { continue; } classad::ExprTree *expr_item = NULL; if (!value_to_expr(list_item, expr_item) || !expr_item) { continue; } expr_list.push_back(expr_item); } expr = expr_list.Copy(); return expr ? true : false; } else if (globus_rsl_value_is_concatenation(value)) { globus_rsl_value_t *left_value = globus_rsl_value_concatenation_get_left(value); globus_rsl_value_t *right_value = globus_rsl_value_concatenation_get_right(value); if (!left_value || !right_value) { return false; } classad::ExprTree *left_expr = NULL, *right_expr = NULL; if (!value_to_expr(left_value, left_expr) || !left_expr || !value_to_expr(right_value, right_expr) || !right_expr) { return false; } std::vector<classad::ExprTree*> argList; argList.push_back(left_expr); argList.push_back(right_expr); expr = classad::FunctionCall::MakeFunctionCall("strcat", argList); return expr ? true : false; } else if (globus_rsl_value_is_variable(value)) { char * char_variable_name = globus_rsl_value_variable_get_name(value); char * default_value = globus_rsl_value_variable_get_default(value); if (!char_variable_name) { return false; } // Canonical forms of Globus RSL strip out all underscores and makes the string // lowercase. As ClassAds are case-preserving (and underscores are significant), // we just do the former transform. std::string variable_name(char_variable_name); boost::algorithm::replace_all(variable_name, "_", ""); if (default_value) { // ifThenElse(isUndefined(variable_name), default_value, variable_name) std::vector<classad::ExprTree*> ifArgList; classad::ExprTree *attr1 = classad::AttributeReference::MakeAttributeReference(NULL, variable_name); if (!attr1) { return false; } std::vector<classad::ExprTree*> argList; argList.push_back(attr1); classad::ExprTree *isUndefined = classad::FunctionCall::MakeFunctionCall("isUndefined", argList); ifArgList.push_back(isUndefined); classad::Value val; val.SetStringValue(default_value); classad::ExprTree *lit = classad::Literal::MakeLiteral(val); if (!lit) { return false; } ifArgList.push_back(lit); classad::ExprTree *attr2 = classad::AttributeReference::MakeAttributeReference(NULL, variable_name); if (!attr2) { return false; } ifArgList.push_back(attr2); expr = classad::FunctionCall::MakeFunctionCall("ifThenElse", ifArgList); } else { expr = classad::AttributeReference::MakeAttributeReference(NULL, variable_name); } return expr ? true : false; } return false; }