static void test_class_ref(void) { { ClassRef ref = ClassRefParse("class"); assert_true(ref.ns == NULL); assert_string_equal("class", ref.name); char *expr = ClassRefToString(ref.ns, ref.name); assert_string_equal("class", expr); free(expr); ClassRefDestroy(ref); } { ClassRef ref = ClassRefParse("default:class"); assert_string_equal("default", ref.ns); assert_string_equal("class", ref.name); char *expr = ClassRefToString(ref.ns, ref.name); assert_string_equal("class", expr); free(expr); ClassRefDestroy(ref); } { ClassRef ref = ClassRefParse("ns:class"); assert_string_equal("ns", ref.ns); assert_string_equal("class", ref.name); char *expr = ClassRefToString(ref.ns, ref.name); assert_string_equal("ns:class", expr); free(expr); ClassRefDestroy(ref); } }
static bool MethodsParseTreeCheck(const Promise *pp, Seq *errors) { bool success = true; for (size_t i = 0; i < SeqLength(pp->conlist); i++) { const Constraint *cp = SeqAt(pp->conlist, i); // ensure: if call and callee are resolved, then they have matching arity if (StringSafeEqual(cp->lval, "usebundle")) { if (cp->rval.type == RVAL_TYPE_FNCALL) { // HACK: exploiting the fact that class-references and call-references are similar FnCall *call = RvalFnCallValue(cp->rval); ClassRef ref = ClassRefParse(call->name); if (!ClassRefIsQualified(ref)) { ClassRefQualify(&ref, PromiseGetNamespace(pp)); } const Bundle *callee = PolicyGetBundle(PolicyFromPromise(pp), ref.ns, "agent", ref.name); if (!callee) { callee = PolicyGetBundle(PolicyFromPromise(pp), ref.ns, "common", ref.name); } ClassRefDestroy(ref); if (callee) { if (RlistLen(call->args) != RlistLen(callee->args)) { SeqAppend(errors, PolicyErrorNew(POLICY_ELEMENT_TYPE_CONSTRAINT, cp, POLICY_ERROR_METHODS_BUNDLE_ARITY, call->name, RlistLen(callee->args), RlistLen(call->args))); success = false; } } } } } return success; }
static PromiseResult VerifyProcessOp(EvalContext *ctx, Item *procdata, Attributes a, const Promise *pp) { bool do_signals = true; int out_of_range; int killed = 0; bool need_to_restart = true; Item *killlist = NULL; int matches = FindPidMatches(procdata, &killlist, a, pp->promiser); /* promise based on number of matches */ PromiseResult result = PROMISE_RESULT_NOOP; if (a.process_count.min_range != CF_NOINT) /* if a range is specified */ { if ((matches < a.process_count.min_range) || (matches > a.process_count.max_range)) { cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_CHANGE, pp, a, "Process count for '%s' was out of promised range (%d found)", pp->promiser, matches); result = PromiseResultUpdate(result, PROMISE_RESULT_CHANGE); for (const Rlist *rp = a.process_count.out_of_range_define; rp != NULL; rp = rp->next) { ClassRef ref = ClassRefParse(RlistScalarValue(rp)); EvalContextClassPutSoft(ctx, RlistScalarValue(rp), CONTEXT_SCOPE_NAMESPACE, "source=promise"); ClassRefDestroy(ref); } out_of_range = true; } else { for (const Rlist *rp = a.process_count.in_range_define; rp != NULL; rp = rp->next) { ClassRef ref = ClassRefParse(RlistScalarValue(rp)); EvalContextClassPutSoft(ctx, RlistScalarValue(rp), CONTEXT_SCOPE_NAMESPACE, "source=promise"); ClassRefDestroy(ref); } cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "Process promise for '%s' is kept", pp->promiser); out_of_range = false; } } else { out_of_range = true; } if (!out_of_range) { DeleteItemList(killlist); return result; } if (a.transaction.action == cfa_warn) { do_signals = false; result = PromiseResultUpdate(result, PROMISE_RESULT_WARN); } else { do_signals = true; } /* signal/kill promises for existing matches */ if (do_signals && (matches > 0)) { if (a.process_stop != NULL) { if (DONTDO) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_WARN, pp, a, "Need to keep process-stop promise for '%s', but only a warning is promised", pp->promiser); result = PromiseResultUpdate(result, PROMISE_RESULT_WARN); } else { if (IsExecutable(CommandArg0(a.process_stop))) { ShellCommandReturnsZero(a.process_stop, SHELL_TYPE_NONE); } else { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Process promise to stop '%s' could not be kept because '%s' the stop operator failed", pp->promiser, a.process_stop); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); DeleteItemList(killlist); return result; } } } killed = DoAllSignals(ctx, killlist, a, pp, &result); } /* delegated promise to restart killed or non-existent entries */ need_to_restart = (a.restart_class != NULL) && (killed || (matches == 0)); DeleteItemList(killlist); if (!need_to_restart) { cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "No restart promised for %s", pp->promiser); return result; } else { if (a.transaction.action == cfa_warn) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_WARN, pp, a, "Need to keep restart promise for '%s', but only a warning is promised", pp->promiser); result = PromiseResultUpdate(result, PROMISE_RESULT_WARN); } else { cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a, "Making a one-time restart promise for '%s'", pp->promiser); result = PromiseResultUpdate(result, PROMISE_RESULT_CHANGE); EvalContextClassPutSoft(ctx, a.restart_class, CONTEXT_SCOPE_NAMESPACE, "source=promise"); } } return result; }
static PromiseResult VerifyEnvironments(EvalContext *ctx, Attributes a, const Promise *pp) { char hyper_uri[CF_MAXVARSIZE]; enum cfhypervisors envtype = cfv_none; switch (Str2Hypervisors(a.env.type)) { case cfv_virt_xen: case cfv_virt_xen_net: snprintf(hyper_uri, CF_MAXVARSIZE - 1, "xen:///"); envtype = cfv_virt_xen; break; case cfv_virt_kvm: case cfv_virt_kvm_net: snprintf(hyper_uri, CF_MAXVARSIZE - 1, "qemu:///session"); envtype = cfv_virt_kvm; break; case cfv_virt_esx: case cfv_virt_esx_net: snprintf(hyper_uri, CF_MAXVARSIZE - 1, "esx://127.0.0.1"); envtype = cfv_virt_esx; break; case cfv_virt_test: case cfv_virt_test_net: snprintf(hyper_uri, CF_MAXVARSIZE - 1, "test:///default"); envtype = cfv_virt_test; break; case cfv_virt_vbox: snprintf(hyper_uri, CF_MAXVARSIZE - 1, "vbox:///session"); envtype = cfv_virt_vbox; break; case cfv_zone: snprintf(hyper_uri, CF_MAXVARSIZE - 1, "solaris_zone"); envtype = cfv_zone; break; default: Log(LOG_LEVEL_ERR, "Environment type '%s' not currently supported", a.env.type); return PROMISE_RESULT_NOOP; break; } Log(LOG_LEVEL_VERBOSE, "Selecting environment type '%s' '%s'", a.env.type, hyper_uri); ClassRef environment_host_ref = ClassRefParse(a.env.host); if (!EvalContextClassGet(ctx, environment_host_ref.ns, environment_host_ref.name)) { switch (a.env.state) { case ENVIRONMENT_STATE_CREATE: case ENVIRONMENT_STATE_RUNNING: Log(LOG_LEVEL_VERBOSE, "This host ''%s' is not the promised host for the environment '%s', so setting its intended state to 'down'", VFQNAME, a.env.host); a.env.state = ENVIRONMENT_STATE_DOWN; break; default: Log(LOG_LEVEL_VERBOSE, "This is not the promised host for the environment, but it does not promise a run state, so take promise as valid"); } } ClassRefDestroy(environment_host_ref); virInitialize(); PromiseResult result = PROMISE_RESULT_NOOP; #if defined(__linux__) switch (Str2Hypervisors(a.env.type)) { case cfv_virt_xen: case cfv_virt_kvm: case cfv_virt_esx: case cfv_virt_vbox: case cfv_virt_test: result = PromiseResultUpdate(result, VerifyVirtDomain(ctx, hyper_uri, envtype, a, pp)); break; case cfv_virt_xen_net: case cfv_virt_kvm_net: case cfv_virt_esx_net: case cfv_virt_test_net: result = PromiseResultUpdate(result, VerifyVirtNetwork(ctx, hyper_uri, envtype, a, pp)); break; case cfv_ec2: break; case cfv_eucalyptus: break; default: break; } #elif defined(__APPLE__) switch (Str2Hypervisors(a.env.type)) { case cfv_virt_vbox: case cfv_virt_test: result = PromiseResultUpdate(result, VerifyVirtDomain(ctx, hyper_uri, envtype, a, pp)); break; case cfv_virt_xen_net: case cfv_virt_kvm_net: case cfv_virt_esx_net: case cfv_virt_test_net: result = PromiseResultUpdate(result, VerifyVirtNetwork(ctx, hyper_uri, envtype, a, pp)); break; default: break; } #elif defined(__sun) switch (Str2Hypervisors(a.env.type)) { case cfv_zone: result = PromiseResultUpdate(result, VerifyZone(a, pp)); break; default: break; } #else Log(LOG_LEVEL_VERBOSE, "Unable to resolve an environment supervisor/monitor for this platform, aborting"); #endif return result; }