static VersionCmpResult RunCmpCommand(EvalContext *ctx, const char *command, const char *v1, const char *v2, Attributes a, const Promise *pp, PromiseResult *result) { Buffer *expanded_command = BufferNew(); { VarRef *ref_v1 = VarRefParseFromScope("v1", PACKAGES_CONTEXT); EvalContextVariablePut(ctx, ref_v1, v1, CF_DATA_TYPE_STRING, "source=promise"); VarRef *ref_v2 = VarRefParseFromScope("v2", PACKAGES_CONTEXT); EvalContextVariablePut(ctx, ref_v2, v2, CF_DATA_TYPE_STRING, "source=promise"); ExpandScalar(ctx, NULL, PACKAGES_CONTEXT, command, expanded_command); EvalContextVariableRemove(ctx, ref_v1); VarRefDestroy(ref_v1); EvalContextVariableRemove(ctx, ref_v2); VarRefDestroy(ref_v2); } FILE *pfp = a.packages.package_commands_useshell ? cf_popen_sh(BufferData(expanded_command), "w") : cf_popen(BufferData(expanded_command), "w", true); if (pfp == NULL) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Can not start package version comparison command '%s'. (cf_popen: %s)", BufferData(expanded_command), GetErrorStr()); *result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL); BufferDestroy(expanded_command); return VERCMP_ERROR; } Log(LOG_LEVEL_VERBOSE, "Executing '%s'", BufferData(expanded_command)); int retcode = cf_pclose(pfp); if (retcode == -1) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Error during package version comparison command execution '%s'. (cf_pclose: %s)", BufferData(expanded_command), GetErrorStr()); *result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL); BufferDestroy(expanded_command); return VERCMP_ERROR; } BufferDestroy(expanded_command); return retcode == 0; }
static VersionCmpResult RunCmpCommand(EvalContext *ctx, const char *command, const char *v1, const char *v2, Attributes a, Promise *pp) { char expanded_command[CF_EXPANDSIZE]; { VarRef *ref_v1 = VarRefParseFromScope("v1", "cf_pack_context"); EvalContextVariablePut(ctx, ref_v1, (Rval) { v1, RVAL_TYPE_SCALAR }, DATA_TYPE_STRING); VarRef *ref_v2 = VarRefParseFromScope("v2", "cf_pack_context"); EvalContextVariablePut(ctx, ref_v2, (Rval) { v2, RVAL_TYPE_SCALAR }, DATA_TYPE_STRING); ExpandScalar(ctx, NULL, "cf_pack_context", command, expanded_command); EvalContextVariableRemove(ctx, ref_v1); VarRefDestroy(ref_v1); EvalContextVariableRemove(ctx, ref_v2); VarRefDestroy(ref_v2); } FILE *pfp = a.packages.package_commands_useshell ? cf_popen_sh(expanded_command, "w") : cf_popen(expanded_command, "w", true); if (pfp == NULL) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Can not start package version comparison command '%s'. (cf_popen: %s)", expanded_command, GetErrorStr()); return VERCMP_ERROR; } Log(LOG_LEVEL_VERBOSE, "Executing '%s'", expanded_command); int retcode = cf_pclose(pfp); if (retcode == -1) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Error during package version comparison command execution '%s'. (cf_pclose: %s)", expanded_command, GetErrorStr()); return VERCMP_ERROR; } return retcode == 0; }
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); }
static void ResolveControlBody(EvalContext *ctx, GenericAgentConfig *config, const Body *control_body) { const ConstraintSyntax *body_syntax = NULL; Rval returnval; assert(strcmp(control_body->name, "control") == 0); for (int i = 0; CONTROL_BODIES[i].constraints != NULL; i++) { body_syntax = CONTROL_BODIES[i].constraints; if (strcmp(control_body->type, CONTROL_BODIES[i].body_type) == 0) { break; } } if (body_syntax == NULL) { FatalError(ctx, "Unknown agent"); } char scope[CF_BUFSIZE]; snprintf(scope, CF_BUFSIZE, "%s_%s", control_body->name, control_body->type); Log(LOG_LEVEL_DEBUG, "Initiate control variable convergence for scope '%s'", scope); EvalContextStackPushBodyFrame(ctx, NULL, control_body, NULL); for (size_t i = 0; i < SeqLength(control_body->conlist); i++) { Constraint *cp = SeqAt(control_body->conlist, i); if (!IsDefinedClass(ctx, cp->classes)) { continue; } if (strcmp(cp->lval, CFG_CONTROLBODY[COMMON_CONTROL_BUNDLESEQUENCE].lval) == 0) { returnval = ExpandPrivateRval(ctx, NULL, scope, cp->rval.item, cp->rval.type); } else { returnval = EvaluateFinalRval(ctx, control_body->parent_policy, NULL, scope, cp->rval, true, NULL); } VarRef *ref = VarRefParseFromScope(cp->lval, scope); EvalContextVariableRemove(ctx, ref); if (!EvalContextVariablePut(ctx, ref, returnval.item, ConstraintSyntaxGetDataType(body_syntax, cp->lval), "source=promise")) { Log(LOG_LEVEL_ERR, "Rule from %s at/before line %zu", control_body->source_path, cp->offset.line); } VarRefDestroy(ref); if (strcmp(cp->lval, CFG_CONTROLBODY[COMMON_CONTROL_OUTPUT_PREFIX].lval) == 0) { strncpy(VPREFIX, returnval.item, CF_MAXVARSIZE); } if (strcmp(cp->lval, CFG_CONTROLBODY[COMMON_CONTROL_DOMAIN].lval) == 0) { strcpy(VDOMAIN, cp->rval.item); Log(LOG_LEVEL_VERBOSE, "SET domain = %s", VDOMAIN); EvalContextVariableRemoveSpecial(ctx, SPECIAL_SCOPE_SYS, "domain"); EvalContextVariableRemoveSpecial(ctx, SPECIAL_SCOPE_SYS, "fqhost"); snprintf(VFQNAME, CF_MAXVARSIZE, "%s.%s", VUQNAME, VDOMAIN); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "fqhost", VFQNAME, DATA_TYPE_STRING, "inventory,source=agent,group=Host name"); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "domain", VDOMAIN, DATA_TYPE_STRING, "source=agent"); EvalContextClassPutHard(ctx, VDOMAIN, "source=agent"); } if (strcmp(cp->lval, CFG_CONTROLBODY[COMMON_CONTROL_IGNORE_MISSING_INPUTS].lval) == 0) { Log(LOG_LEVEL_VERBOSE, "SET ignore_missing_inputs %s", RvalScalarValue(cp->rval)); config->ignore_missing_inputs = BooleanFromString(cp->rval.item); } if (strcmp(cp->lval, CFG_CONTROLBODY[COMMON_CONTROL_IGNORE_MISSING_BUNDLES].lval) == 0) { Log(LOG_LEVEL_VERBOSE, "SET ignore_missing_bundles %s", RvalScalarValue(cp->rval)); config->ignore_missing_bundles = BooleanFromString(cp->rval.item); } if (strcmp(cp->lval, CFG_CONTROLBODY[COMMON_CONTROL_CACHE_SYSTEM_FUNCTIONS].lval) == 0) { Log(LOG_LEVEL_VERBOSE, "SET cache_system_functions %s", RvalScalarValue(cp->rval)); bool cache_system_functions = BooleanFromString(RvalScalarValue(cp->rval)); EvalContextSetEvalOption(ctx, EVAL_OPTION_CACHE_SYSTEM_FUNCTIONS, cache_system_functions); } if (strcmp(cp->lval, CFG_CONTROLBODY[COMMON_CONTROL_GOALPATTERNS].lval) == 0) { /* Ignored */ continue; } RvalDestroy(returnval); } EvalContextStackPopFrame(ctx); }
/** * Evaluate the relevant control body, and set the * relevant fields in #ctx and #config. */ static void ResolveControlBody(EvalContext *ctx, GenericAgentConfig *config, const Body *control_body) { const char *filename = control_body->source_path; assert(CFG_CONTROLBODY[COMMON_CONTROL_MAX].lval == NULL); const ConstraintSyntax *body_syntax = NULL; for (int i = 0; CONTROL_BODIES[i].constraints != NULL; i++) { body_syntax = CONTROL_BODIES[i].constraints; if (strcmp(control_body->type, CONTROL_BODIES[i].body_type) == 0) { break; } } if (body_syntax == NULL) { FatalError(ctx, "Unknown control body: %s", control_body->type); } char *scope; assert(strcmp(control_body->name, "control") == 0); xasprintf(&scope, "control_%s", control_body->type); Log(LOG_LEVEL_DEBUG, "Initiate control variable convergence for scope '%s'", scope); EvalContextStackPushBodyFrame(ctx, NULL, control_body, NULL); for (size_t i = 0; i < SeqLength(control_body->conlist); i++) { const char *lval; Rval evaluated_rval; size_t lineno; /* Use nested scope to constrain cp. */ { Constraint *cp = SeqAt(control_body->conlist, i); lval = cp->lval; lineno = cp->offset.line; if (!IsDefinedClass(ctx, cp->classes)) { continue; } if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_BUNDLESEQUENCE].lval) == 0) { evaluated_rval = ExpandPrivateRval(ctx, NULL, scope, cp->rval.item, cp->rval.type); } else { evaluated_rval = EvaluateFinalRval(ctx, control_body->parent_policy, NULL, scope, cp->rval, true, NULL); } } /* Close scope: assert we only use evaluated_rval, not cp->rval. */ VarRef *ref = VarRefParseFromScope(lval, scope); EvalContextVariableRemove(ctx, ref); DataType rval_proper_datatype = ConstraintSyntaxGetDataType(body_syntax, lval); if (evaluated_rval.type != DataTypeToRvalType(rval_proper_datatype)) { Log(LOG_LEVEL_ERR, "Attribute '%s' in %s:%zu is of wrong type, skipping", lval, filename, lineno); VarRefDestroy(ref); RvalDestroy(evaluated_rval); continue; } bool success = EvalContextVariablePut( ctx, ref, evaluated_rval.item, rval_proper_datatype, "source=promise"); if (!success) { Log(LOG_LEVEL_ERR, "Attribute '%s' in %s:%zu can't be added, skipping", lval, filename, lineno); VarRefDestroy(ref); RvalDestroy(evaluated_rval); continue; } VarRefDestroy(ref); if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_OUTPUT_PREFIX].lval) == 0) { strlcpy(VPREFIX, RvalScalarValue(evaluated_rval), sizeof(VPREFIX)); } if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_DOMAIN].lval) == 0) { strlcpy(VDOMAIN, RvalScalarValue(evaluated_rval), sizeof(VDOMAIN)); Log(LOG_LEVEL_VERBOSE, "SET domain = %s", VDOMAIN); EvalContextVariableRemoveSpecial(ctx, SPECIAL_SCOPE_SYS, "domain"); EvalContextVariableRemoveSpecial(ctx, SPECIAL_SCOPE_SYS, "fqhost"); snprintf(VFQNAME, CF_MAXVARSIZE, "%s.%s", VUQNAME, VDOMAIN); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "fqhost", VFQNAME, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=Host name"); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "domain", VDOMAIN, CF_DATA_TYPE_STRING, "source=agent"); EvalContextClassPutHard(ctx, VDOMAIN, "source=agent"); } if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_IGNORE_MISSING_INPUTS].lval) == 0) { Log(LOG_LEVEL_VERBOSE, "SET ignore_missing_inputs %s", RvalScalarValue(evaluated_rval)); config->ignore_missing_inputs = BooleanFromString( RvalScalarValue(evaluated_rval)); } if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_IGNORE_MISSING_BUNDLES].lval) == 0) { Log(LOG_LEVEL_VERBOSE, "SET ignore_missing_bundles %s", RvalScalarValue(evaluated_rval)); config->ignore_missing_bundles = BooleanFromString( RvalScalarValue(evaluated_rval)); } if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_CACHE_SYSTEM_FUNCTIONS].lval) == 0) { Log(LOG_LEVEL_VERBOSE, "SET cache_system_functions %s", RvalScalarValue(evaluated_rval)); bool cache_system_functions = BooleanFromString( RvalScalarValue(evaluated_rval)); EvalContextSetEvalOption(ctx, EVAL_OPTION_CACHE_SYSTEM_FUNCTIONS, cache_system_functions); } if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_PROTOCOL_VERSION].lval) == 0) { config->protocol_version = ProtocolVersionParse( RvalScalarValue(evaluated_rval)); Log(LOG_LEVEL_VERBOSE, "SET common protocol_version: %s", PROTOCOL_VERSION_STRING[config->protocol_version]); } /* Those are package_inventory and package_module common control body options */ if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_PACKAGE_INVENTORY].lval) == 0) { AddDefaultInventoryToContext(ctx, RvalRlistValue(evaluated_rval)); Log(LOG_LEVEL_VERBOSE, "SET common package_inventory list"); } if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_PACKAGE_MODULE].lval) == 0) { AddDefaultPackageModuleToContext(ctx, RvalScalarValue(evaluated_rval)); Log(LOG_LEVEL_VERBOSE, "SET common package_module: %s", RvalScalarValue(evaluated_rval)); } if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_GOALPATTERNS].lval) == 0) { /* Ignored */ } RvalDestroy(evaluated_rval); } EvalContextStackPopFrame(ctx); free(scope); }
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; }
PromiseResult VerifyMethod(EvalContext *ctx, const Rval call, Attributes a, const Promise *pp) { assert(a.havebundle); 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; } 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(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_ERR, result, pp, a, "Bundle '%s' should be invoked, but only a warning was promised!", BufferData(method_name)); } else { BannerSubBundle(bp, args); EvalContextStackPushBundleFrame(ctx, bp, args, a.inherit); 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); return result; }
PromiseResult VerifyMethod(EvalContext *ctx, char *attrname, Attributes a, const Promise *pp) { Bundle *bp; void *vp; FnCall *fp; char method_name[CF_EXPANDSIZE]; Rlist *args = NULL; CfLock thislock; char lockname[CF_BUFSIZE]; if (a.havebundle) { if ((vp = PromiseGetConstraintAsRval(pp, attrname, RVAL_TYPE_FNCALL))) { fp = (FnCall *) vp; ExpandScalar(ctx, PromiseGetBundle(pp)->ns, PromiseGetBundle(pp)->name, fp->name, method_name); args = fp->args; } else if ((vp = PromiseGetConstraintAsRval(pp, attrname, RVAL_TYPE_SCALAR))) { ExpandScalar(ctx, PromiseGetBundle(pp)->ns, PromiseGetBundle(pp)->name, (char *) vp, method_name); args = NULL; } else { return PROMISE_RESULT_NOOP; } } GetLockName(lockname, "method", pp->promiser, args); thislock = AcquireLock(ctx, lockname, VUQNAME, CFSTARTTIME, a.transaction, pp, false); if (thislock.lock == NULL) { return PROMISE_RESULT_SKIPPED; } PromiseBanner(pp); char ns[CF_MAXVARSIZE] = ""; char bundle_name[CF_MAXVARSIZE] = ""; SplitScopeName(method_name, ns, bundle_name); bp = PolicyGetBundle(PolicyFromPromise(pp), EmptyString(ns) ? NULL : ns, "agent", bundle_name); if (!bp) { bp = PolicyGetBundle(PolicyFromPromise(pp), EmptyString(ns) ? NULL : ns, "common", bundle_name); } PromiseResult result = PROMISE_RESULT_NOOP; if (bp) { BannerSubBundle(bp, args); EvalContextStackPushBundleFrame(ctx, bp, args, a.inherit); BundleResolve(ctx, bp); result = ScheduleAgentOperations(ctx, bp); GetReturnValue(ctx, bp, pp); EvalContextStackPopFrame(ctx); switch (result) { case PROMISE_RESULT_FAIL: cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_FAIL, pp, a, "Method '%s' failed in some repairs or aborted", bp->name); break; case PROMISE_RESULT_CHANGE: cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_CHANGE, pp, a, "Method '%s' invoked repairs", bp->name); break; default: cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "Method '%s' verified", 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(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"); } if (bp && (bp->name)) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Method '%s' was used but was not defined", bp->name); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } else { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "A method attempted to use a bundle '%s' that was apparently not defined", method_name); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } } YieldCurrentLock(thislock); return result; }