コード例 #1
0
ファイル: variable_test.c プロジェクト: Sphonic/cfengine-core
static void test_iterate_indices(void)
{
    VariableTable *t = ReferenceTable();

    {
        VarRef *ref = VarRefParse("default:scope1.array");
        VariableTableIterator *iter = VariableTableIteratorNewFromVarRef(t, ref);
        
        unsigned short number_of_entries = 0;
        while (VariableTableIteratorNext(iter))
        {
            number_of_entries++;
        }
        assert_int_equal(4, number_of_entries);
        
        VariableTableIteratorDestroy(iter);
        VarRefDestroy(ref);
    }
    
    {
        VarRef *ref = VarRefParse("default:scope1.array[two]");
        VariableTableIterator *iter = VariableTableIteratorNewFromVarRef(t, ref);

        unsigned short number_of_entries = 0;
        while (VariableTableIteratorNext(iter))
        {
            number_of_entries++;
        }
        
        assert_int_equal(3, number_of_entries);
        
        VariableTableIteratorDestroy(iter);
        VarRefDestroy(ref);
    }
}
コード例 #2
0
ファイル: expand.c プロジェクト: kkaempf/core
static void RemoveRemotelyInjectedVars(const EvalContext *ctx, const Bundle *bundle)
{
    const Seq *remote_var_promises = EvalContextGetRemoteVarPromises(ctx, bundle->name);
    if ((remote_var_promises == NULL) || SeqLength(remote_var_promises) == 0)
    {
        /* nothing to do here */
        return;
    }

    size_t promises_length = SeqLength(remote_var_promises);
    Seq *remove_vars = SeqNew(promises_length, NULL);

    /* remove variables that have been attempted to be inserted into this
     * bundle */
    /* TODO: this is expensive and should be removed! */
    for (size_t i = 0; i < promises_length; i++)
    {
        const Promise *pp = (Promise *) SeqAt(remote_var_promises, i);

        VariableTableIterator *iter = EvalContextVariableTableIteratorNew(ctx, NULL, bundle->name, NULL);
        const Variable *var = VariableTableIteratorNext(iter);
        while (var != NULL)
        {
            /* variables are stored together with their original promises (org_pp) */
            if (var->promise && var->promise->org_pp == pp)
            {
                Log(LOG_LEVEL_ERR, "Ignoring remotely-injected variable '%s'",
                    var->ref->lval);
                /* avoid modifications of the variable table being iterated
                 * over and avoid trying to remove the same variable twice */
                SeqAppendOnce(remove_vars, (void *) var, PointerCmp);
            }
            var = VariableTableIteratorNext(iter);
        }
        VariableTableIteratorDestroy(iter);
    }

    /* iteration over the variable table done, time to remove the variables */
    size_t remove_vars_length = SeqLength(remove_vars);
    for (size_t i = 0; i < remove_vars_length; i++)
    {
        Variable *var = (Variable *) SeqAt(remove_vars, i);
        if (var->ref != NULL)
        {
            EvalContextVariableRemove(ctx, var->ref);
        }
    }
    SeqDestroy(remove_vars);
}
コード例 #3
0
static void GetReturnValue(EvalContext *ctx, const Bundle *callee, const Promise *caller)
{
    char *result = PromiseGetConstraintAsRval(caller, "useresult", RVAL_TYPE_SCALAR);

    if (result)
    {
        VarRef *ref = VarRefParseFromBundle("last-result", callee);
        VariableTableIterator *iter = EvalContextVariableTableIteratorNew(ctx, ref->ns, ref->scope, ref->lval);
        Variable *result_var = NULL;
        while ((result_var = VariableTableIteratorNext(iter)))
        {
            assert(result_var->ref->num_indices == 1);
            if (result_var->ref->num_indices != 1)
            {
                continue;
            }

            VarRef *new_ref = VarRefParseFromBundle(result, PromiseGetBundle(caller));
            VarRefAddIndex(new_ref, result_var->ref->indices[0]);

            EvalContextVariablePut(ctx, new_ref, result_var->rval.item, result_var->type, "source=bundle");

            VarRefDestroy(new_ref);
        }

        VarRefDestroy(ref);
        VariableTableIteratorDestroy(iter);
    }

}
コード例 #4
0
ファイル: cf-promises.c プロジェクト: cstroe/core
static void ShowVariablesFormatted(EvalContext *ctx)
{
    VariableTableIterator *iter = EvalContextVariableTableIteratorNew(ctx, NULL, NULL, NULL);
    Variable *v = NULL;

    Seq *seq = SeqNew(2000, free);

    while ((v = VariableTableIteratorNext(iter)))
    {
        char *varname = VarRefToString(v->ref, true);

        Writer *w = StringWriter();

        switch (DataTypeToRvalType(v->type))
        {
        case RVAL_TYPE_CONTAINER:
            JsonWriteCompact(w, RvalContainerValue(v->rval));
            break;

        default:
            RvalWrite(w, v->rval);
        }

        const char *var_value;
        if (StringIsPrintable(StringWriterData(w)))
        {
            var_value = StringWriterData(w);
        }
        else
        {
            var_value = "<non-printable>";
        }


        StringSet *tagset = EvalContextVariableTags(ctx, v->ref);
        Buffer *tagbuf = StringSetToBuffer(tagset, ',');

        char *line;
        xasprintf(&line, "%-40s %-60s %-40s", varname, var_value, BufferData(tagbuf));

        SeqAppend(seq, line);

        BufferDestroy(tagbuf);
        WriterClose(w);
        free(varname);
    }

    SeqSort(seq, (SeqItemComparator)strcmp, NULL);

    printf("%-40s %-60s %-40s\n", "Variable name", "Variable value", "Meta tags");

    for (size_t i = 0; i < SeqLength(seq); i++)
    {
        const char *variable = SeqAt(seq, i);
        printf("%s\n", variable);
    }

    SeqDestroy(seq);
    VariableTableIteratorDestroy(iter);
}
コード例 #5
0
ファイル: verify_files.c プロジェクト: cduclos/core
static JsonElement *DefaultTemplateData(const EvalContext *ctx)
{
    JsonElement *hash = JsonObjectCreate(10);

    {
        ClassTableIterator *it = EvalContextClassTableIteratorNewGlobal(ctx, NULL, true, true);
        Class *cls = NULL;
        while ((cls = ClassTableIteratorNext(it)))
        {
            char *key = ClassRefToString(cls->ns, cls->name);
            JsonObjectAppendBool(hash, key, true);
            free(key);
        }
        ClassTableIteratorDestroy(it);
    }

    {
        ClassTableIterator *it = EvalContextClassTableIteratorNewLocal(ctx);
        Class *cls = NULL;
        while ((cls = ClassTableIteratorNext(it)))
        {
            char *key = ClassRefToString(cls->ns, cls->name);
            JsonObjectAppendBool(hash, key, true);
            free(key);
        }
        ClassTableIteratorDestroy(it);
    }

    {
        VariableTableIterator *it = EvalContextVariableTableIteratorNew(ctx, NULL, NULL, NULL);
        Variable *var = NULL;
        while ((var = VariableTableIteratorNext(it)))
        {
            // TODO: need to get a CallRef, this is bad
            char *scope_key = ClassRefToString(var->ref->ns, var->ref->scope);
            JsonElement *scope_obj = JsonObjectGetAsObject(hash, scope_key);
            if (!scope_obj)
            {
                scope_obj = JsonObjectCreate(50);
                JsonObjectAppendObject(hash, scope_key, scope_obj);
            }
            free(scope_key);

            char *lval_key = VarRefToString(var->ref, false);
            JsonObjectAppendElement(scope_obj, lval_key, RvalToJson(var->rval));
            free(lval_key);
        }
        VariableTableIteratorDestroy(it);
    }

    return hash;
}
コード例 #6
0
ファイル: variable_test.c プロジェクト: Sphonic/cfengine-core
// Below test relies on the ordering items in RB tree which is strongly
// related to the hash function used.
static void test_iterate_indices_ordering_related(void)
{
    VariableTable *t = ReferenceTable();
    
    {    
        VarRef *ref = VarRefParse("default:scope1.array");
        VariableTableIterator *iter = VariableTableIteratorNewFromVarRef(t, ref);

        Variable *v = VariableTableIteratorNext(iter);
        assert_true(v != NULL);
        assert_int_equal(1, v->ref->num_indices);
        assert_string_equal("two", v->ref->indices[0]);

        v = VariableTableIteratorNext(iter);
        assert_true(v != NULL);
        assert_int_equal(2, v->ref->num_indices);
        assert_string_equal("two", v->ref->indices[0]);
        assert_string_equal("three", v->ref->indices[1]);
        
        v = VariableTableIteratorNext(iter);
        assert_true(v != NULL);
        assert_int_equal(2, v->ref->num_indices);
        assert_string_equal("two", v->ref->indices[0]);
        assert_string_equal("four", v->ref->indices[1]);

        v = VariableTableIteratorNext(iter);
        assert_true(v != NULL);
        assert_int_equal(1, v->ref->num_indices);
        assert_string_equal("one", v->ref->indices[0]);

        assert_false(VariableTableIteratorNext(iter) != NULL);

        VariableTableIteratorDestroy(iter);
        VarRefDestroy(ref);
    }

    {
        VarRef *ref = VarRefParse("default:scope1.array[two]");
        VariableTableIterator *iter = VariableTableIteratorNewFromVarRef(t, ref);

        Variable *v = VariableTableIteratorNext(iter);
        assert_true(v != NULL);
        assert_int_equal(1, v->ref->num_indices);
        assert_string_equal("two", v->ref->indices[0]);
        
        v = VariableTableIteratorNext(iter);
        assert_true(v != NULL);
        assert_int_equal(2, v->ref->num_indices);
        assert_string_equal("two", v->ref->indices[0]);
        assert_string_equal("three", v->ref->indices[1]);

        v = VariableTableIteratorNext(iter);
        assert_true(v != NULL);
        assert_int_equal(2, v->ref->num_indices);
        assert_string_equal("two", v->ref->indices[0]);
        assert_string_equal("four", v->ref->indices[1]);

        assert_false(VariableTableIteratorNext(iter) != NULL);

        VariableTableIteratorDestroy(iter);
        VarRefDestroy(ref);
    }

    VariableTableDestroy(t);
}
コード例 #7
0
PromiseResult VerifyMethod(EvalContext *ctx, const Rval call, Attributes a, const Promise *pp)
{
    const Rlist *args = NULL;
    Buffer *method_name = BufferNew();
    switch (call.type)
    {
    case RVAL_TYPE_FNCALL:
    {
        const FnCall *fp = RvalFnCallValue(call);
        ExpandScalar(ctx, PromiseGetBundle(pp)->ns, PromiseGetBundle(pp)->name, fp->name, method_name);
        args = fp->args;
        int arg_index = 0;
        while (args)
        {
           ++arg_index;
           if (strcmp(args->val.item, CF_NULL_VALUE) == 0)
           {
               Log(LOG_LEVEL_DEBUG, "Skipping invokation of method '%s' due to null-values in argument '%d'",
                   fp->name, arg_index);
               BufferDestroy(method_name);
               return PROMISE_RESULT_SKIPPED;
           }
           args = args->next;
        }
        args = fp->args;
        EvalContextSetBundleArgs(ctx, args);
    }
    break;

    case RVAL_TYPE_SCALAR:
    {
        ExpandScalar(ctx, PromiseGetBundle(pp)->ns, PromiseGetBundle(pp)->name,
                     RvalScalarValue(call), method_name);
        args = NULL;
    }
    break;

    default:
        BufferDestroy(method_name);
        return PROMISE_RESULT_NOOP;
    }

    char lockname[CF_BUFSIZE];
    GetLockName(lockname, "method", pp->promiser, args);

    CfLock thislock = AcquireLock(ctx, lockname, VUQNAME, CFSTARTTIME, a.transaction, pp, false);
    if (thislock.lock == NULL)
    {
        BufferDestroy(method_name);
        return PROMISE_RESULT_SKIPPED;
    }

    PromiseBanner(ctx, pp);

    const Bundle *bp = EvalContextResolveBundleExpression(ctx, PromiseGetPolicy(pp), BufferData(method_name), "agent");

    if (!bp)
    {
        bp = EvalContextResolveBundleExpression(ctx, PromiseGetPolicy(pp), BufferData(method_name), "common");
    }

    PromiseResult result = PROMISE_RESULT_NOOP;

    if (bp)
    {
        if (a.transaction.action == cfa_warn) // don't skip for dry-runs (ie ignore DONTDO)
        {
            result = PROMISE_RESULT_WARN;
            cfPS(ctx, LOG_LEVEL_WARNING, result, pp, a, "Bundle '%s' should be invoked, but only a warning was promised!", BufferData(method_name));
        }
        else
        {
            BundleBanner(bp, args);
            EvalContextStackPushBundleFrame(ctx, bp, args, a.inherit);

            /* Clear all array-variables that are already set in the sub-bundle.
               Otherwise, array-data accumulates between multiple bundle evaluations.
               Note: for bundles invoked multiple times via bundlesequence, array
               data *does* accumulate. */
            VariableTableIterator *iter = EvalContextVariableTableIteratorNew(ctx, bp->ns, bp->name, NULL);
            Variable *var;
            while ((var = VariableTableIteratorNext(iter)))
            {
                if (!var->ref->num_indices)
                {
                    continue;
                }
                EvalContextVariableRemove(ctx, var->ref);
            }
            VariableTableIteratorDestroy(iter);

            BundleResolve(ctx, bp);

            result = ScheduleAgentOperations(ctx, bp);

            GetReturnValue(ctx, bp, pp);

            EvalContextStackPopFrame(ctx);
            switch (result)
            {
            case PROMISE_RESULT_SKIPPED:
                // if a bundle returns 'skipped', meaning that all promises were locked in the bundle,
                // we explicitly consider the method 'kept'
                result = PROMISE_RESULT_NOOP;
                // intentional fallthru

            case PROMISE_RESULT_NOOP:
                cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "Method '%s' verified", bp->name);
                break;

            case PROMISE_RESULT_WARN:
                cfPS(ctx, LOG_LEVEL_WARNING, PROMISE_RESULT_WARN, pp, a, "Method '%s' invoked repairs, but only warnings promised", bp->name);
                break;

            case PROMISE_RESULT_CHANGE:
                cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_CHANGE, pp, a, "Method '%s' invoked repairs", bp->name);
                break;

            case PROMISE_RESULT_FAIL:
            case PROMISE_RESULT_DENIED:
                cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Method '%s' failed in some repairs", bp->name);
                break;

            default: // PROMISE_RESULT_INTERRUPTED, TIMEOUT
                cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_FAIL, pp, a, "Method '%s' aborted in some repairs", bp->name);
                break;
            }
        }

        for (const Rlist *rp = bp->args; rp; rp = rp->next)
        {
            const char *lval = RlistScalarValue(rp);
            VarRef *ref = VarRefParseFromBundle(lval, bp);
            EvalContextVariableRemove(ctx, ref);
            VarRefDestroy(ref);
        }
    }
    else
    {
        if (IsCf3VarString(BufferData(method_name)))
        {
            Log(LOG_LEVEL_ERR,
                "A variable seems to have been used for the name of the method. In this case, the promiser also needs to contain the unique name of the method");
        }

        cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a,
             "A method attempted to use a bundle '%s' that was apparently not defined",
             BufferData(method_name));
        result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
    }

    YieldCurrentLock(thislock);
    BufferDestroy(method_name);
    EndBundleBanner(bp);

    return result;
}