From e0898a23d44e946d67afb12fb472703b1ee6908c Mon Sep 17 00:00:00 2001 From: Craig Comstock Date: Tue, 25 Jul 2023 13:19:06 -0500 Subject: [PATCH 1/2] Added details about running in-source-directory and debugging with libtool Ticket: none Changelog: none --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index b356c99bfd..deefb86546 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,13 @@ stated otherwise in the copyright notice inside the particular file. ## Example Usage +In order to use the built cf-agent in the source tree you must add a $HOME/.cfagent/bin/cf-promises file: + +$ pwd +/core +$ echo "cd $(pwd); cf-promises/cf-promises \"\$@\"" > ~/.cfagent/bin/cf-promises + + ### Hello World The following code demonstrates simple CFEngine output through a reports promise. @@ -63,6 +70,13 @@ The following policy code may be executed with cf-agent (the main CFEngine binar $ cf-agent/cf-agent hello.cf R: Hello, world + +## Debugging + +As this project uses autotools you must use libtool to run gdb/lldb/debuggers + +./libtool --mode=execute ./cf-agent/cf-agent + ## Contributing Please see the [CONTRIBUTING.md](https://github.com/cfengine/core/blob/master/CONTRIBUTING.md) file. From c278bcf081a0b67bdb08fa8eafc5d56c713a0833 Mon Sep 17 00:00:00 2001 From: Craig Comstock Date: Tue, 25 Jul 2023 13:19:53 -0500 Subject: [PATCH 2/2] Modified classesmatching() function to search parent bundles with inherit => true Ticket: ENT-5850 Changelog: title --- libpromises/eval_context.c | 59 +++++++++++++++++ libpromises/eval_context.h | 3 +- libpromises/evalfunction.c | 9 +-- .../02_functions/classesmatching_inherit.cf | 38 +++++++++++ .../02_functions/classesmatching_inherit_2.cf | 65 +++++++++++++++++++ 5 files changed, 167 insertions(+), 7 deletions(-) create mode 100644 tests/acceptance/02_classes/02_functions/classesmatching_inherit.cf create mode 100644 tests/acceptance/02_classes/02_functions/classesmatching_inherit_2.cf diff --git a/libpromises/eval_context.c b/libpromises/eval_context.c index d9ec0d55da..7f56480f97 100644 --- a/libpromises/eval_context.c +++ b/libpromises/eval_context.c @@ -3484,6 +3484,65 @@ bool EvalContextIsIgnoringLocks(const EvalContext *ctx) return ctx->ignore_locks; } +StringSet *ClassesMatchingLocalRecursive( + const EvalContext *ctx, + const char *regex, + const Rlist *tags, + bool first_only, + size_t stack_index) +{ + assert(ctx != NULL); + StackFrame *frame = SeqAt(ctx->stack, stack_index); + StringSet *matches; + if (frame->type == STACK_FRAME_TYPE_BUNDLE) + { + ClassTableIterator *iter = ClassTableIteratorNew( + frame->data.bundle.classes, + frame->data.bundle.owner->ns, + false, + true); // from EvalContextClassTableIteratorNewLocal() + matches = ClassesMatching(ctx, iter, regex, tags, first_only); + ClassTableIteratorDestroy(iter); + } + else + { + matches = StringSetNew(); // empty for passing up the recursion chain + } + + if (stack_index > 0 && frame->inherits_previous) + { + StringSet *parent_matches = ClassesMatchingLocalRecursive( + ctx, regex, tags, first_only, stack_index - 1); + StringSetJoin(matches, parent_matches, xstrdup); + StringSetDestroy(parent_matches); + } + + return matches; +} + +StringSet *ClassesMatchingLocal( + const EvalContext *ctx, + const char *regex, + const Rlist *tags, + bool first_only) +{ + assert(ctx != NULL); + return ClassesMatchingLocalRecursive( + ctx, regex, tags, first_only, SeqLength(ctx->stack) - 1); +} + +StringSet *ClassesMatchingGlobal( + const EvalContext *ctx, + const char *regex, + const Rlist *tags, + bool first_only) +{ + ClassTableIterator *iter = + EvalContextClassTableIteratorNewGlobal(ctx, NULL, true, true); + StringSet *matches = ClassesMatching(ctx, iter, regex, tags, first_only); + ClassTableIteratorDestroy(iter); + return matches; +} StringSet *ClassesMatching(const EvalContext *ctx, ClassTableIterator *iter, const char* regex, const Rlist *tags, bool first_only) { StringSet *matching = StringSetNew(); diff --git a/libpromises/eval_context.h b/libpromises/eval_context.h index be50f59202..0bf3096a13 100644 --- a/libpromises/eval_context.h +++ b/libpromises/eval_context.h @@ -249,7 +249,8 @@ static inline bool IsDefinedClass(const EvalContext *ctx, const char *context) return (CheckClassExpression(ctx, context) == EXPRESSION_VALUE_TRUE); } StringSet *ClassesMatching(const EvalContext *ctx, ClassTableIterator *iter, const char* regex, const Rlist *tags, bool first_only); - +StringSet *ClassesMatchingGlobal(const EvalContext *ctx, const char* regex, const Rlist *tags, bool first_only); +StringSet *ClassesMatchingLocal(const EvalContext *ctx, const char* regex, const Rlist *tags, bool first_only); bool EvalProcessResult(const char *process_result, StringSet *proc_attr); bool EvalFileResult(const char *file_result, StringSet *leaf_attr); diff --git a/libpromises/evalfunction.c b/libpromises/evalfunction.c index 39a5202971..94838b70ac 100644 --- a/libpromises/evalfunction.c +++ b/libpromises/evalfunction.c @@ -1331,6 +1331,7 @@ static FnCallResult FnCallIfElse(EvalContext *ctx, static FnCallResult FnCallClassesMatching(EvalContext *ctx, ARG_UNUSED const Policy *policy, const FnCall *fp, const Rlist *finalargs) { + assert(finalargs != NULL); bool count_only = false; bool check_only = false; unsigned count = 0; @@ -1369,8 +1370,7 @@ static FnCallResult FnCallClassesMatching(EvalContext *ctx, ARG_UNUSED const Pol Rlist *matches = NULL; { - ClassTableIterator *iter = EvalContextClassTableIteratorNewGlobal(ctx, NULL, true, true); - StringSet *global_matches = ClassesMatching(ctx, iter, RlistScalarValue(finalargs), finalargs->next, check_only); + StringSet *global_matches = ClassesMatchingGlobal(ctx, RlistScalarValue(finalargs), finalargs->next, check_only); StringSetIterator it = StringSetIteratorInit(global_matches); const char *element = NULL; @@ -1387,7 +1387,6 @@ static FnCallResult FnCallClassesMatching(EvalContext *ctx, ARG_UNUSED const Pol } StringSetDestroy(global_matches); - ClassTableIteratorDestroy(iter); } if (check_only && count >= 1) @@ -1396,8 +1395,7 @@ static FnCallResult FnCallClassesMatching(EvalContext *ctx, ARG_UNUSED const Pol } { - ClassTableIterator *iter = EvalContextClassTableIteratorNewLocal(ctx); - StringSet *local_matches = ClassesMatching(ctx, iter, RlistScalarValue(finalargs), finalargs->next, check_only); + StringSet *local_matches = ClassesMatchingLocal(ctx, RlistScalarValue(finalargs), finalargs->next, check_only); StringSetIterator it = StringSetIteratorInit(local_matches); const char *element = NULL; @@ -1414,7 +1412,6 @@ static FnCallResult FnCallClassesMatching(EvalContext *ctx, ARG_UNUSED const Pol } StringSetDestroy(local_matches); - ClassTableIteratorDestroy(iter); } if (check_only) diff --git a/tests/acceptance/02_classes/02_functions/classesmatching_inherit.cf b/tests/acceptance/02_classes/02_functions/classesmatching_inherit.cf new file mode 100644 index 0000000000..add7db3e85 --- /dev/null +++ b/tests/acceptance/02_classes/02_functions/classesmatching_inherit.cf @@ -0,0 +1,38 @@ +bundle agent __main__ +{ + classes: + "defined_in_parent" expression => "cfengine"; + + methods: + "ENT-5850" + usebundle => ENT_5850, + inherit => "true"; +} + +bundle agent ENT_5850 +{ + vars: + "c_matching" + slist => classesmatching(".*"); + "c_matching_defined_in_parent" + slist => classesmatching("defined_in_parent"); + + classes: + "defined_here" expression => "cfengine"; + + reports: + "$(this.promise_filename) Pass" + if => some( "defined_in_parent", c_matching); + + "$(this.promise_filename) FAIL $(this.promise_filename)$(const.n)Could not find class 'defined_in_parent' in classesmatching() but it's defined" + if => and( not( some( "defined_in_parent", c_matching) ), + defined_in_parent + ); + + "Classes found by classesmatching() starting with 'defined' $(with)" + with => join( ", ", classesmatching("defined.*") ); + + "'defined_here' is defined" if => "defined_here"; + "'defined_in_parent' is defined" if => "defined_in_parent"; + "Running CFEngine: $(sys.cf_version)"; +} diff --git a/tests/acceptance/02_classes/02_functions/classesmatching_inherit_2.cf b/tests/acceptance/02_classes/02_functions/classesmatching_inherit_2.cf new file mode 100644 index 0000000000..a493934021 --- /dev/null +++ b/tests/acceptance/02_classes/02_functions/classesmatching_inherit_2.cf @@ -0,0 +1,65 @@ +bundle agent common +{ + vars: + "logfile" string => "$(this.promise_dirname)$(const.dirsep)defined_classes.log"; +} + +bundle agent __main__ +{ + classes: "defined_in_main"; + methods: + "init"; + "first" inherit => "true"; + "check"; +} + +bundle agent init +{ + files: + "$(common.logfile)" + delete => tidy; +} + +bundle agent first +{ + classes: "defined_in_first"; + methods: "second" inherit => "true"; +} + +bundle agent second +{ + classes: "defined_in_second"; + methods: "third" inherit => "true"; +} + +bundle agent third +{ + vars: + "defined_classes" slist => classesmatching("defined.*"); + + reports: + "defined_classes: $(defined_classes)" + report_to_file => "$(common.logfile)"; +} + +bundle agent check +{ + vars: + "expected" string => concat("defined_classes: defined_in_main$(const.n)", + "defined_classes: defined_in_first$(const.n)", + "defined_classes: defined_in_second$(const.n)"); + "actual" string => readfile("$(common.logfile)", inf); + + reports: + "$(this.promise_filename) Pass" + if => strcmp($(expected), $(actual)); + + "$(this.promise_filename) FAIL" + if => not(strcmp($(expected), $(actual))); +} + +body delete tidy +{ + dirlinks => "delete"; + rmdirs => "true"; +}