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,
                &timestamp,
                &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;
}
示例#3
0
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;
}