From 82a63e7f2f32db670a52bff1005bdb8cca615130 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 (cherry picked from commit e0898a23d44e946d67afb12fb472703b1ee6908c) --- 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 fc0644d87833a8c15cc705a3beb6943fe63834e8 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 (cherry picked from commit c278bcf081a0b67bdb08fa8eafc5d56c713a0833) --- 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 2583e4e499..063dd1fd38 100644 --- a/libpromises/eval_context.c +++ b/libpromises/eval_context.c @@ -3453,6 +3453,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 5775414c9c..3bc60b5e1a 100644 --- a/libpromises/eval_context.h +++ b/libpromises/eval_context.h @@ -246,7 +246,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 eeae7ce1bc..f81ef7766a 100644 --- a/libpromises/evalfunction.c +++ b/libpromises/evalfunction.c @@ -1275,6 +1275,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; @@ -1313,8 +1314,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; @@ -1331,7 +1331,6 @@ static FnCallResult FnCallClassesMatching(EvalContext *ctx, ARG_UNUSED const Pol } StringSetDestroy(global_matches); - ClassTableIteratorDestroy(iter); } if (check_only && count >= 1) @@ -1340,8 +1339,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; @@ -1358,7 +1356,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"; +}