diff --git a/cf-agent/cf-agent.c b/cf-agent/cf-agent.c index a121fe2953..7a7ad905fc 100644 --- a/cf-agent/cf-agent.c +++ b/cf-agent/cf-agent.c @@ -1002,12 +1002,6 @@ static void KeepControlPromises(EvalContext *ctx, const Policy *policy, GenericA continue; } - if (CommonControlFromString(cp->lval) != COMMON_CONTROL_MAX) - { - /* Already handled in generic_agent */ - continue; - } - VarRef *ref = VarRefParseFromScope(cp->lval, "control_agent"); DataType value_type; const void *value = EvalContextVariableGet(ctx, ref, &value_type); @@ -1353,6 +1347,22 @@ static void KeepControlPromises(EvalContext *ctx, const Policy *policy, GenericA config->agent_specific.agent.report_class_log? "true" : "false"); continue; } + + if (StringEqual(cp->lval, CFA_CONTROLBODY[AGENT_CONTROL_EVALUATION_ORDER].lval)) + { + assert(value_type == CF_DATA_TYPE_STRING); + const char *evaluation_order = (char *) value; + Log(LOG_LEVEL_VERBOSE, "SET evaluation %s", evaluation_order); + + if (StringEqual(evaluation_order, "top_down")) + { + EvalContextSetAgentEvalOrder(ctx, EVAL_ORDER_TOP_DOWN); + } + else + { + EvalContextSetAgentEvalOrder(ctx, EVAL_ORDER_CLASSIC); + } + } } } @@ -1569,7 +1579,7 @@ static void AllClassesReport(const EvalContext *ctx) PromiseResult ScheduleAgentOperations(EvalContext *ctx, const Bundle *bp) // NB - this function can be called recursively through "methods" { - if (EvalContextGetEvalOption(ctx, EVAL_OPTION_CLASSIC_EVALUATION)) + if (EvalContextIsClassicOrder(ctx)) { return ScheduleAgentOperationsNormalOrder(ctx, bp); } diff --git a/libpromises/cf3.defs.h b/libpromises/cf3.defs.h index 72555d6a51..cea29e672b 100644 --- a/libpromises/cf3.defs.h +++ b/libpromises/cf3.defs.h @@ -495,6 +495,7 @@ typedef enum AGENT_CONTROL_REPORTCLASSLOG, AGENT_CONTROL_SELECT_END_MATCH_EOF, AGENT_CONTROL_COPYFROM_RESTRICT_KEYS, + AGENT_CONTROL_EVALUATION_ORDER, AGENT_CONTROL_NONE } AgentControl; diff --git a/libpromises/eval_context.c b/libpromises/eval_context.c index 3df59eae32..0558709e7e 100644 --- a/libpromises/eval_context.c +++ b/libpromises/eval_context.c @@ -206,6 +206,9 @@ struct EvalContext_ int64_t elapsed; Seq *events; } profiler; + + EvalContextEvalOrder common_eval_order; + EvalContextEvalOrder agent_eval_order; }; void EvalContextSetConfig(EvalContext *ctx, const GenericAgentConfig *config) @@ -1110,6 +1113,10 @@ EvalContext *EvalContextNew(void) ctx->profiler.events = SeqNew(20, EventFrameDestroy); ctx->profiler.elapsed = 0; + // evaluation order + ctx->common_eval_order = EVAL_ORDER_UNDEFINED; + ctx->agent_eval_order = EVAL_ORDER_UNDEFINED; + return ctx; } @@ -4047,3 +4054,39 @@ void EvalContextProfilingEnd(EvalContext *ctx, const Policy *policy) JsonDestroy(profiling); } + +// ############################################################## + +void EvalContextSetCommonEvalOrder(EvalContext *ctx, EvalContextEvalOrder eval_order) +{ + assert(ctx != NULL); + ctx->common_eval_order = eval_order; +} + +void EvalContextSetAgentEvalOrder(EvalContext *ctx, EvalContextEvalOrder eval_order) +{ + assert(ctx != NULL); + ctx->agent_eval_order = eval_order; +} + +bool EvalContextIsClassicOrder(EvalContext *ctx) +{ + assert(ctx != NULL); + + if (ctx->config->agent_type != AGENT_TYPE_AGENT) + { + // Not cf-agent, so we ignore body agent control + return (ctx->common_eval_order != EVAL_ORDER_TOP_DOWN); + } + + // cf-agent + if (ctx->agent_eval_order != EVAL_ORDER_UNDEFINED) + { + // evaluation_order from body agent control has priority, if defined + return (ctx->agent_eval_order == EVAL_ORDER_CLASSIC); + } + + // The fallback is to use what is defined in body common control, + // or if not defined there either, default to true (normal order) + return (ctx->common_eval_order != EVAL_ORDER_TOP_DOWN); +} diff --git a/libpromises/eval_context.h b/libpromises/eval_context.h index 9333884182..63b30e7611 100644 --- a/libpromises/eval_context.h +++ b/libpromises/eval_context.h @@ -120,11 +120,17 @@ typedef enum EVAL_OPTION_EVAL_FUNCTIONS = 1 << 0, EVAL_OPTION_CACHE_SYSTEM_FUNCTIONS = 1 << 1, - EVAL_OPTION_CLASSIC_EVALUATION = 1 << 2, EVAL_OPTION_FULL = 0xFFFFFFFF } EvalContextOption; +typedef enum +{ + EVAL_ORDER_UNDEFINED = 0, + EVAL_ORDER_CLASSIC, + EVAL_ORDER_TOP_DOWN +} EvalContextEvalOrder; + EvalContext *EvalContextNew(void); void EvalContextDestroy(EvalContext *ctx); @@ -453,4 +459,8 @@ void EvalContextSetProfiling(EvalContext *ctx, bool profiling); void EvalContextProfilingStart(EvalContext *ctx); void EvalContextProfilingEnd(EvalContext *ctx, const Policy *policy); +void EvalContextSetCommonEvalOrder(EvalContext *ctx, EvalContextEvalOrder eval_order); +void EvalContextSetAgentEvalOrder(EvalContext *ctx, EvalContextEvalOrder eval_order); +bool EvalContextIsClassicOrder(EvalContext *ctx); + #endif diff --git a/libpromises/expand.c b/libpromises/expand.c index abe27eaa98..4b28b60f42 100644 --- a/libpromises/expand.c +++ b/libpromises/expand.c @@ -1030,8 +1030,14 @@ static void ResolveControlBody(EvalContext *ctx, GenericAgentConfig *config, Log(LOG_LEVEL_VERBOSE, "SET evaluation %s", RvalScalarValue(evaluated_rval)); - bool is_classic = (StringEqual(RvalScalarValue(evaluated_rval), "classic")); - EvalContextSetEvalOption(ctx, EVAL_OPTION_CLASSIC_EVALUATION, is_classic); + if (StringEqual(RvalScalarValue(evaluated_rval), "top_down")) + { + EvalContextSetCommonEvalOrder(ctx, EVAL_ORDER_TOP_DOWN); + } + else + { + EvalContextSetCommonEvalOrder(ctx, EVAL_ORDER_CLASSIC); + } } RvalDestroy(evaluated_rval); diff --git a/libpromises/mod_common.c b/libpromises/mod_common.c index 16b68589b2..d017b8cca3 100644 --- a/libpromises/mod_common.c +++ b/libpromises/mod_common.c @@ -320,6 +320,7 @@ const ConstraintSyntax CFA_CONTROLBODY[] = ConstraintSyntaxNewBool("report_class_log", "true/false enables logging classes at the end of agent execution. Default value: false", SYNTAX_STATUS_NORMAL), ConstraintSyntaxNewBool("select_end_match_eof", "Set the default behavior of select_end_match_eof in edit_line promises. Default: false", SYNTAX_STATUS_NORMAL), ConstraintSyntaxNewStringList("copyfrom_restrict_keys", ".*", "A list of key hashes to restrict copy_from to", SYNTAX_STATUS_NORMAL), + ConstraintSyntaxNewString("evaluation_order", "(classic|top_down)", "Order of evaluation of promises of agent", SYNTAX_STATUS_NORMAL), ConstraintSyntaxNewNull() };