Skip to content

Commit 08f01da

Browse files
committed
Added getbundlemetatags policy function
Changelog: Added a new policy function to get the list of metatags of a bundle, in the same manner as getclassmetatags and getvariablemetatags. Ticket: CFE-4019 Signed-off-by: Victor Moene <victor.moene@northern.tech>
1 parent 824bd0c commit 08f01da

File tree

4 files changed

+154
-4
lines changed

4 files changed

+154
-4
lines changed

examples/getbundlemetatags.cf

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#+begin_src cfengine3
2+
body common control
3+
{
4+
bundlesequence => { "example" };
5+
}
6+
7+
bundle agent example
8+
{
9+
meta:
10+
"tags" slist => { "autorun", "myOtherTag", "contact=Some Person <some.person@northern.tech>"};
11+
12+
vars:
13+
"bundle_tags" slist => getbundlemetatags("default:example");
14+
"contact_tag" slist => getbundlemetatags("default:example", "contact");
15+
16+
reports:
17+
"Found tags: $(bundle_tags)";
18+
"Contact tag: $(contact_tag)";
19+
}
20+
#+end_src
21+
###############################################################################
22+
#+begin_src example_output
23+
#@ ```
24+
#@ R: Found tags: autorun
25+
#@ R: Found tags: myOtherTag
26+
#@ R: Found tags: contact=Some Person <some.person@northern.tech>
27+
#@ R: Contact tag: Some Person <some.person@northern.tech>
28+
#@ ```
29+
#+end_src

libpromises/evalfunction.c

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,9 +1563,48 @@ static FnCallResult FnCallVariablesMatching(EvalContext *ctx, ARG_UNUSED const P
15631563
}
15641564

15651565
/*********************************************************************/
1566+
static Bundle *GetBundleFromPolicy(const Policy *policy, const char *namespace, const char *bundlename)
1567+
{
1568+
assert(policy != NULL);
1569+
const size_t bundles_length = SeqLength(policy->bundles);
15661570

1567-
static FnCallResult FnCallGetMetaTags(EvalContext *ctx, ARG_UNUSED const Policy *policy, const FnCall *fp, const Rlist *finalargs)
1571+
for (size_t i = 0; i < bundles_length; i++)
1572+
{
1573+
Bundle *bp = SeqAt(policy->bundles, i);
1574+
if (StringEqual(bp->name, bundlename) && StringEqual(bp->ns, namespace))
1575+
{
1576+
return bp;
1577+
}
1578+
}
1579+
return NULL;
1580+
}
1581+
1582+
static Promise *GetPromiseFromBundle(const Bundle *bundle, const char *promise_type, const char *promiser)
15681583
{
1584+
assert(bundle != NULL);
1585+
const size_t sections_length = SeqLength(bundle->sections);
1586+
for (size_t i = 0; i < sections_length; i++)
1587+
{
1588+
BundleSection *bsection = SeqAt(bundle->sections, i);
1589+
if (StringEqual(bsection->promise_type, promise_type))
1590+
{
1591+
const size_t promises_length = SeqLength(bsection->promises);
1592+
for (size_t i = 0; i < promises_length; i++)
1593+
{
1594+
Promise *promise = SeqAt(bsection->promises, i);
1595+
if (StringEqual(promise->promiser, promiser))
1596+
{
1597+
return promise;
1598+
}
1599+
}
1600+
}
1601+
}
1602+
return NULL;
1603+
}
1604+
1605+
static FnCallResult FnCallGetMetaTags(EvalContext *ctx, const Policy *policy, const FnCall *fp, const Rlist *finalargs)
1606+
{
1607+
assert(fp != NULL);
15691608
if (!finalargs)
15701609
{
15711610
FatalError(ctx, "Function '%s' requires at least one argument", fp->name);
@@ -1574,18 +1613,63 @@ static FnCallResult FnCallGetMetaTags(EvalContext *ctx, ARG_UNUSED const Policy
15741613
Rlist *tags = NULL;
15751614
StringSet *tagset = NULL;
15761615

1577-
if (strcmp(fp->name, "getvariablemetatags") == 0)
1616+
if (StringEqual(fp->name, "getvariablemetatags"))
15781617
{
15791618
VarRef *ref = VarRefParse(RlistScalarValue(finalargs));
15801619
tagset = EvalContextVariableTags(ctx, ref);
15811620
VarRefDestroy(ref);
15821621
}
1583-
else if (strcmp(fp->name, "getclassmetatags") == 0)
1622+
else if (StringEqual(fp->name, "getclassmetatags"))
15841623
{
15851624
ClassRef ref = ClassRefParse(RlistScalarValue(finalargs));
15861625
tagset = EvalContextClassTags(ctx, ref.ns, ref.name);
15871626
ClassRefDestroy(ref);
15881627
}
1628+
else if (StringEqual(fp->name, "getbundlemetatags"))
1629+
{
1630+
const char *bundleref = RlistScalarValue(finalargs);
1631+
assert(bundleref != NULL);
1632+
const Rlist *args = RlistFromSplitString(bundleref, ':');
1633+
const char *namespace = (args->next == NULL) ? "default" : RlistScalarValue(args);
1634+
const char *name = RlistScalarValue((args->next == NULL) ? args : args->next);
1635+
1636+
const Bundle *bundle = GetBundleFromPolicy(policy, namespace, name);
1637+
if (bundle == NULL)
1638+
{
1639+
Log(LOG_LEVEL_ERR,
1640+
"Function %s couldn't find bundle '%s' with namespace '%s'",
1641+
fp->name,
1642+
name,
1643+
namespace);
1644+
return FnFailure();
1645+
}
1646+
const Promise *promise = GetPromiseFromBundle(bundle, "meta", "tags");
1647+
if (bundle == NULL)
1648+
{
1649+
Log(LOG_LEVEL_ERR,
1650+
"Function %s couldn't find meta tags in '%s:%s'",
1651+
fp->name,
1652+
namespace,
1653+
name);
1654+
return FnFailure();
1655+
}
1656+
Rlist *start = PromiseGetConstraintAsList(ctx, "slist", promise);
1657+
if (start == NULL)
1658+
{
1659+
Log(LOG_LEVEL_ERR,
1660+
"Function %s couldn't find meta tags constraint string list",
1661+
fp->name);
1662+
return FnFailure();
1663+
}
1664+
1665+
tagset = StringSetNew();
1666+
Rlist *temp = start;
1667+
while (temp != NULL)
1668+
{
1669+
StringSetAdd(tagset, temp->val.item);
1670+
temp = temp->next;
1671+
}
1672+
}
15891673
else
15901674
{
15911675
FatalError(ctx, "FnCallGetMetaTags: got unknown function name '%s', aborting", fp->name);
@@ -10483,6 +10567,8 @@ const FnCallType CF_FNCALL_TYPES[] =
1048310567
FNCALL_OPTION_COLLECTING, FNCALL_CATEGORY_DATA, SYNTAX_STATUS_NORMAL),
1048410568
FnCallTypeNew("getvariablemetatags", CF_DATA_TYPE_STRING_LIST, GETVARIABLEMETATAGS_ARGS, &FnCallGetMetaTags, "Collect the variable arg1's meta tags into an slist, optionally collecting only tag key arg2",
1048510569
FNCALL_OPTION_VARARG, FNCALL_CATEGORY_UTILS, SYNTAX_STATUS_NORMAL),
10570+
FnCallTypeNew("getbundlemetatags", CF_DATA_TYPE_STRING_LIST, GETVARIABLEMETATAGS_ARGS, &FnCallGetMetaTags, "Collect the bundle arg1's meta tags into an slist, optionally collecting only tag key arg2",
10571+
FNCALL_OPTION_VARARG, FNCALL_CATEGORY_UTILS, SYNTAX_STATUS_NORMAL),
1048610572
FnCallTypeNew("grep", CF_DATA_TYPE_STRING_LIST, GREP_ARGS, &FnCallGrep, "Extract the sub-list if items matching the regular expression in arg1 of the list or array or data container arg2",
1048710573
FNCALL_OPTION_COLLECTING, FNCALL_CATEGORY_DATA, SYNTAX_STATUS_NORMAL),
1048810574
FnCallTypeNew("groupexists", CF_DATA_TYPE_CONTEXT, GROUPEXISTS_ARGS, &FnCallGroupExists, "True if group or numerical id exists on this host",

tests/acceptance/01_vars/02_functions/gettags.cf

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ body common control
88

99
bundle common init
1010
{
11+
meta:
12+
"tags" slist => { "bundletag1", "foo=bar" };
1113
classes:
1214
"myclass" expression => "any", meta => { "mytag1" };
1315
"myotherclass" expression => "any", meta => { "mytag5", "mytag51" };
@@ -37,6 +39,10 @@ bundle agent test
3739
"tags9" slist => getclassmetatags("keyclass2", "foo");
3840
"tagsa" slist => getvariablemetatags("init.keyvar", "foo");
3941
"tagsb" slist => getvariablemetatags("init.keyvar2", "foo");
42+
"tagsc" slist => getbundlemetatags("default:init");
43+
"tagsd" slist => getbundlemetatags("init", "foo");
44+
"tagse" slist => getbundlemetatags("something:dummy");
45+
"tagsf" slist => getbundlemetatags("something:dummy", "foo");
4046
}
4147

4248

@@ -47,3 +53,15 @@ bundle agent check
4753
"$(this.promise_filename).expected.json",
4854
$(this.promise_filename));
4955
}
56+
57+
body file control
58+
{
59+
namespace => "something";
60+
}
61+
62+
bundle common dummy
63+
{
64+
meta:
65+
"tags" slist => { "dummytag1", "dummytag2", "foo=bar", "foo=hello" };
66+
}
67+

tests/acceptance/01_vars/02_functions/gettags.cf.expected.json

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,22 @@
2727
"1",
2828
"2"
2929
],
30-
"tagsb": []
30+
"tagsb": [],
31+
"tagsc": [
32+
"bundletag1",
33+
"foo=bar"
34+
],
35+
"tagsd": [
36+
"bar"
37+
],
38+
"tagse": [
39+
"dummytag1",
40+
"dummytag2",
41+
"foo=bar",
42+
"foo=hello"
43+
],
44+
"tagsf": [
45+
"bar",
46+
"hello"
47+
]
3148
}

0 commit comments

Comments
 (0)