Re: Newbie questions

"'Nick Anderson' via help-cfengine" <[email protected]> Fri, 08 Aug 2025 17:54:50 -0500
Newsgroups gmane.comp.sysutils.cfengine.general
Message-ID <[email protected]>
--=-=-=
Content-Type: multipart/alternative; boundary="==-=-="

--==-=-=
Content-Type: text/plain; charset="UTF-8"

IN_PROGRESS Respond to Jakub Wardyn <[email protected]>: Re: [help-cfengine] Newbie questions :email:
============================================================================================

  Hi Jakub,

  Welcome to CFEngine. I will jump around a bit in my response.

        - Is there any "practical" guide for CFEngine which is
          reasonably recent, and can guide me through building
          small-scale stuff from the grounds up. I'd appreciate a
          link.

  I don't think there is a single guide that works for everyone. If I
  had to provide but a single link it would have to be
  <https://docs.cfengine.com>.

        Right now I have a couple of servers, on which I want to
        deploy some services (some in Docker, some as regular
        processes), I want a solution where I can describe that
        declaratively, and have a e.g. git repository with
        "current state of everything that's running on my
        servers", I also want to automate stuff like setting up
        backups, updating the system, etc. It's all Linux for now,
        and I expect the number of servers to grow in the future.

  This sounds like stuff that CFEngine can help you with. You might find
  `promise-type-docker-compose' useful or a source of inspirational
  (<https://build.cfengine.com/modules/promise-type-docker-compose/>).

        - And honestly, is CFEngine even the right tool for use
          cases like mine? I don't mind tinkering a bit and
          working in low-level stuff, but I hate fighting with the
          complexity of my tools. I want a simple low-level tool
          with which I build my own automation, not an
          "out-of-the-box" corporate solution for thousands of
          servers.

  So, you have some servers running Linux and you want a tool that can
  help you manage configuration files, processes and help you adjust and
  maintain the state of the running systems over time. You want
  something simple and low level to build your own system with and not
  an out of the box solution.

  I am bias, but I think CFEngine sounds like a natural fit.

  I think that CFEngine is simple, but I guess it's subjective. I am at
  least quite familiar with how it operates. If you find yourself
  "fighting" with CFEngine maybe take a step back and see if you can
  approach from a different perspective. I remember when starting with
  CFEngine that it changed the way I thought about things.

        - How to deal with the differences between paths in
          different distros? Should I just roll out CFEngine
          manually? I thought I can just install CFEngine in
          anyway, and then bootstrap and it will figure everything
          out from there, seems like that's not the case. I hope
          the "hub" can tell the agents where to look for the
          policies? Or is the files structure just coupled
          together everywhere?

  I think it's important to remember the agency of the agents, no one
  tells an agent anything. Perhaps imagine yourself as the agent rather
  than hollering at the hub in the sky ask where you should look for
  your policy think what in my environment can I clue in on to figure
  out where to get policy.

  Installing and bootstrapping to a hub and then figuring things out is
  totally possible. That's I think what most people do. By default the
  MPF doesn't really do much of anything.

  I am not sure what you mean by "is the file structure just coupled
  together everywhere".

  How to deal with the difference in paths between different distros?
  There are fundamental lower level answers to this but perhaps that
  leads well into your question if you need the MPF.

        - Do I need MPF? If I have a git repo do I just copy MPF
          into it? What does MPF do for me? The very reason that I
          wanted to learn CFEngine is the simplicity and
          transparency of what it does, MPF seems to contradict
          that.

  Categorically, I can tell you that you do not *need* the MPF. However,
  it does offer something to build off of and the policy is instrumented
  in the most common places so that you can tweak behavior without
  having to modify the vendored policy. Plus, there is often an
  assumption of use so if you are not using it it's good to highlight
  that fact. You can build a much leaner policy set, that covers just
  what you need. This goes back to dealing with differences in paths
  between repos and binaries.

  The MPF didn't always exist. In the early versions of 3.x up to maybe
  3.5 there wasn't much to graft on to
  (<https://github.com/cfengine/core/tree/3.0.0/inputs>). So, the
  questions from that period of time led to the structure of the
  Masterfiles Policy Framework MPF forming.

        - Is there any "practical" guide for CFEngine which is
          reasonably recent, and can guide me through building
          small-scale stuff from the grounds up. I'd appreciate a
          link.

  I think the all time best way of learning CFEngine is live in person
  training.

  The best book is Diegos Learning CFEngine (<https://cf-learn.info/>).
  It's not current, but all the basics are in there and I recall when
  the book came out wishing I had that book when I started learning
  CFEngine. I referred to things in it for many years.

  Aleksey Tslalokhin published the content that he used for CFEngine
  training. You can use it as a self guided tutorial.
  <https://www.softcover.io/read/72be7d4f/cf3/_single-page>

  I think that modern practical guides focus on leveraging the newer
  higher level tools that are available
  (<https://docs.cfengine.com/docs/3.24/getting-started.html>).

  If you do choose to write your own policy, I will say that you might
  find `cf-locate'
  (<https://github.com/cfengine/core/tree/master/contrib/cf-locate>)
  useful. You could use it to lift out specific body and bundles from
  the standard library to keep your own policy set extremely minimal.

  The follow-up from [2025-08-04 Mon] :

        Got quick two questions: Can strings in CFEngine be split
        up into multiline without defining additional variables,
        and without adding unintended whitespaces? E.g. In C++ I'd
        do something like this: ``` const char* string = "This is
        my first line," " this is another line"; ``` Which
        evaluates to "This is my first line, this is another line"


  Yep, you can.

  ,----
  | bundle agent __main__
  | {
  |   vars:
  |       "s1" string => "Here
  | is
  | a
  | multiline string \
  | where I \
  | have escaped some \
  | but not other newlines.
  | ";
  |
  |       # Sometimes there is preference to use concat()
  |       "s2" string => concat("Here we",
  |                             " bring some strings",
  |                             ' together and show',
  |                             ` various quoting of`,
  |                             ` strings which contain quoteing chars "'"'`,
  |                             " handy tricks indeed to avoid escapes" );
  |
  |
  |   reports:
  |       "$(s1)";
  |       "$(s2)";
  | }
  `----

  ,----
  | R: Here
  | is
  | a
  | multiline string where I have escaped some but not other newlines.
  |
  | R: Here we bring some strings together and show various quoting of strings which contain quoteing chars "'"' handy tricks indeed to avoid escapes
  `----


        Can I build my own bundles/functions which return values?
        I've seen that bundles can modify variables and define
        class in the parent scope, but that seems quite horrible.
        I mean something like this: ``` vars: "my_value" string =>
        do_http_request("some arguments here"); ``` where
        "do_http_request" is some wrapper around Curl that I can
        write on my own, can't use url_get, because the binary on
        Alpine is compiled without curl support, and I would
        rather not bother with that, and instead do what I would
        do in other languages: abstract the mundane task of
        calling curl into something less repetitive.

  Yes, it's possible to define your own bundles and bodies (it's quite
  expected that you will).

  I recommend reading through the language concepts section of the
  reference manual
  (<https://docs.cfengine.com/docs/3.24/reference-language-concepts.html>).
  You can even define your own promise types
  (<https://cfengine.com/blog/2020/introducing-cfengine-custom-promise-types/>)
  but there is not currently any ability to define custom /functions/.

  I think it's important to remember that bundles are not functions
  (<https://docs.cfengine.com/docs/3.24/reference-language-concepts-bundles.html>).
  Though you can use them in that way and they have the ability to
  return data into the calling bundle via /reports/ promises using
  `bundle_return_value_index'
  (<https://docs.cfengine.com/docs/3.26/reference-promise-types-reports.html#bundle_return_value_index>)
  and `useresult'
  (<https://docs.cfengine.com/docs/3.26/reference-promise-types-methods.html#useresult>)

  Here is an example:

  ,----
  | bundle agent __main__
  | {
  |   methods:
  |       "Call my bundle with params and define a variable with returned data"
  |         usebundle => myBundle("KEY", "VALUE"),
  |         useresult => "returned_from_myBundle";
  |
  |       "More ...."
  |         usebundle => myBundle("CFEngine", "Awesome"),
  |         useresult => "returned_from_myBundle";
  |
  |       "Calculator"
  |         usebundle => add("5266", "42", "value"),
  |         useresult => "sum";
  |
  |   reports:
  |       "CFEngine version: $(sys.cf_version)";
  |       "$(with)"
  |         with => storejson( returned_from_myBundle );
  |
  |       "Calculated $(sum[value])";
  | }
  | bundle agent myBundle(key, value)
  | {
  |   reports:
  |       "$(value)"
  |         bundle_return_value_index => "$(key)";
  | }
  | bundle agent add(int1, int2, key)
  | {
  |   reports:
  |       "$(with)"
  |         with => int( eval( "$(int1)+$(int2)", "math", "infix" ) ),
  |         bundle_return_value_index => "$(key)";
  | }
  `----

  ,----
  | R: CFEngine version: 3.27.0a.5553c81fe
  | R: {
  |   "CFEngine": "Awesome",
  |   "KEY": "VALUE"
  | }
  | R: Calculated 5308
  `----


  Modules are another thing to know about
  (<https://docs.cfengine.com/docs/3.26/reference-language-concepts-modules.html#top>).
  There are a lot of different kinds of modules in CFEngine. There are
  the traditional variables and classes modules which allow you to
  define variables and classes from external programs via a simple line
  based protocol. You can use modules in different ways but primarily
  via `usemodule()'
  (<https://docs.cfengine.com/docs/3.26/reference-functions-usemodule.html#top>)
  or via commands with `module => true'
  (<https://docs.cfengine.com/docs/3.26/reference-promise-types-commands.html#module>).
  Then there are package modules which are external programs that
  communicate with CFEngine to implement packages promises, promise
  modules which are for defining custom promise types and CFEngine Build
  Modules (<https://build.cfengine.com/>) which are collections of
  policy or other CFEngine related content.

-- 
You received this message because you are subscribed to the Google Groups "help-cfengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/help-cfengine/87ikix8lvm.fsf%40northern.tech.

--==-=-=
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<p>
Hi Jakub,
</p>

<p>
Welcome to CFEngine. I will jump around a bit in my response.
</p>

<blockquote style=3D"border-left: 2px solid gray; padding-left: 4px;">
<ul class=3D"org-ul">
<li>Is there any "practical" guide for CFEngine which is reasonably recent,=
 and
can guide me through building small-scale stuff from the grounds up. I'd
appreciate a link.</li>
</ul>
</blockquote>

<p>
I don't think there is a single guide that works for everyone. If I had to =
provide but a single link it would have to be <a href=3D"https://docs.cfeng=
ine.com">https://docs.cfengine.com</a>.
</p>

<blockquote style=3D"border-left: 2px solid gray; padding-left: 4px;">
<p>
Right now I have a couple of servers, on which I want to deploy some servic=
es
(some in Docker, some as regular processes), I want a solution where I can
describe that declaratively, and have a e.g. git repository with "current s=
tate
of everything that's running on my servers", I also want to automate stuff =
like
setting up backups, updating the system, etc. It's all Linux for now, and I
expect the number of servers to grow in the future.
</p>
</blockquote>

<p>
This sounds like stuff that CFEngine can help you with.
You might find <code>promise-type-docker-compose</code> useful or a source =
of inspirational (<a href=3D"https://build.cfengine.com/modules/promise-typ=
e-docker-compose/">https://build.cfengine.com/modules/promise-type-docker-c=
ompose/</a>).
</p>

<blockquote style=3D"border-left: 2px solid gray; padding-left: 4px;">
<ul class=3D"org-ul">
<li>And honestly, is CFEngine even the right tool for use cases like mine? =
I don't
mind tinkering a bit and working in low-level stuff, but I hate fighting wi=
th
the complexity of my tools. I want a simple low-level tool with which I bui=
ld
my own automation, not an "out-of-the-box" corporate solution for thousands=
 of
servers.</li>
</ul>
</blockquote>

<p>
So, you have some servers running Linux and you want a tool that can help y=
ou
manage configuration files, processes and help you adjust and maintain the =
state
of the running systems over time. You want something simple and low level t=
o
build your own system with and not an out of the box solution.
</p>

<p>
I am bias, but I think CFEngine sounds like a natural fit.
</p>

<p>
I think that CFEngine is simple, but I guess it's subjective. I am at least
quite familiar with how it operates. If you find yourself "fighting" with
CFEngine maybe take a step back and see if you can approach from a differen=
t
perspective. I remember when starting with CFEngine that it changed the way=
 I
thought about things.
</p>

<blockquote style=3D"border-left: 2px solid gray; padding-left: 4px;">
<ul class=3D"org-ul">
<li>How to deal with the differences between paths in different distros? Sh=
ould I
just roll out CFEngine manually? I thought I can just install CFEngine in
anyway, and then bootstrap and it will figure everything out from there, se=
ems
like that's not the case. I hope the "hub" can tell the agents where to loo=
k
for the policies? Or is the files structure just coupled together everywher=
e?</li>
</ul>
</blockquote>

<p>
I think it's important to remember the agency of the agents, no one tells a=
n
agent anything. Perhaps imagine yourself as the agent rather than hollering=
 at
the hub in the sky ask where you should look for your policy think what in =
my
environment can I clue in on to figure out where to get policy.
</p>

<p>
Installing and bootstrapping to a hub and then figuring things out is total=
ly
possible. That's I think what most people do. By default the MPF doesn't re=
ally
do much of anything.
</p>

<p>
I am not sure what you mean by "is the file structure just coupled together=
 everywhere".
</p>

<p>
How to deal with the difference in paths between different distros? There a=
re
fundamental lower level answers to this but perhaps that leads well into yo=
ur
question if you need the MPF.
</p>

<blockquote style=3D"border-left: 2px solid gray; padding-left: 4px;">
<ul class=3D"org-ul">
<li>Do I need MPF? If I have a git repo do I just copy MPF into it? What do=
es MPF
do for me? The very reason that I wanted to learn CFEngine is the simplicit=
y
and transparency of what it does, MPF seems to contradict that.</li>
</ul>
</blockquote>

<p>
Categorically, I can tell you that you do not <b>need</b> the MPF. However,=
 it does
offer something to build off of and the policy is instrumented in the most
common places so that you can tweak behavior without having to modify the
vendored policy. Plus, there is often an assumption of use so if you are no=
t
using it it's good to highlight that fact. You can build a much leaner poli=
cy
set, that covers just what you need. This goes back to dealing with differe=
nces
in paths between repos and binaries.
</p>

<p>
The MPF didn't always exist. In the early versions of 3.x up to maybe 3.5 t=
here
wasn't much to graft on to (<a href=3D"https://github.com/cfengine/core/tre=
e/3.0.0/inputs">https://github.com/cfengine/core/tree/3.0.0/inputs</a>). So=
, the
questions from that period of time led to the structure of the Masterfiles
Policy Framework MPF forming.
</p>

<blockquote style=3D"border-left: 2px solid gray; padding-left: 4px;">
<ul class=3D"org-ul">
<li>Is there any "practical" guide for CFEngine which is reasonably recent,=
 and
can guide me through building small-scale stuff from the grounds up. I'd
appreciate a link.</li>
</ul>
</blockquote>

<p>
I think the all time best way of learning CFEngine is live in person traini=
ng.
</p>

<p>
The best book is Diegos Learning CFEngine (<a href=3D"https://cf-learn.info=
/">https://cf-learn.info/</a>). It's not current, but all the basics are in=
 there and I recall when the book came out wishing I had that book when I s=
tarted learning CFEngine. I referred to things in it for many years.
</p>

<p>
Aleksey Tslalokhin published the content that he used for CFEngine training=
. You can use it as a self guided tutorial. <a href=3D"https://www.softcove=
r.io/read/72be7d4f/cf3/_single-page">https://www.softcover.io/read/72be7d4f=
/cf3/_single-page</a>
</p>

<p>
I think that modern practical guides focus on leveraging the newer higher l=
evel
tools that are available (<a href=3D"https://docs.cfengine.com/docs/3.24/ge=
tting-started.html">https://docs.cfengine.com/docs/3.24/getting-started.htm=
l</a>).
</p>

<p>
If you do choose to write your own policy, I will say that you might find <=
code>cf-locate</code> (<a href=3D"https://github.com/cfengine/core/tree/mas=
ter/contrib/cf-locate">https://github.com/cfengine/core/tree/master/contrib=
/cf-locate</a>) useful. You could use it to lift out specific body and bund=
les from the standard library to keep your own policy set extremely minimal=
.
</p>

<p>
The follow-up from <span class=3D"timestamp-wrapper"><span class=3D"timesta=
mp">[2025-08-04 Mon] </span></span> :
</p>

<blockquote style=3D"border-left: 2px solid gray; padding-left: 4px;">
<p>
Got quick two questions:
Can strings in CFEngine be split up into multiline without defining additio=
nal variables, and without adding unintended
whitespaces?
E.g. In C++ I'd do something like this:
```
const char* string =3D "This is my first line,"
" this is another line";
```
Which evaluates to "This is my first line, this is another line"
</p>
</blockquote>


<p>
Yep, you can.
</p>

<div class=3D"org-src-container">
<pre class=3D"src src-cfengine3"><span style=3D"color: #a89984; font-weight=
: bold;">bundle</span> <span style=3D"color: #458588; font-weight: bold;">a=
gent</span> <span style=3D"color: #458588;">__main__</span>
<span style=3D"color: #689d6a;">{</span>
  <span style=3D"color: #a89984; font-weight: bold;">vars</span>:
      <span style=3D"color: #689d6a;">"s1"</span> <span style=3D"color: #d7=
9921;">string</span> =3D&gt; <span style=3D"color: #689d6a;">"Here
is
a
multiline string \
where I \
have escaped some \
but not other newlines.
"</span>;

      <span style=3D"color: #7c6f64;"># Sometimes there is preference to us=
e concat()
</span>      <span style=3D"color: #689d6a;">"s2"</span> <span style=3D"col=
or: #d79921;">string</span> =3D&gt; concat<span style=3D"color: #d79921;">(=
</span><span style=3D"color: #689d6a;">"Here we"</span>,
                            <span style=3D"color: #689d6a;">" bring some st=
rings"</span>,
                            <span style=3D"color: #689d6a;">' together and =
show'</span>,
                            ` various quoting of`,
                            ` strings which contain quoteing chars <span st=
yle=3D"color: #689d6a;">"'"'`,
                            " handy tricks indeed to avoid escapes" );


  reports:
      "$(s1)";
      "$(s2)";
}</span>
</pre>
</div>

<pre class=3D"example">
R: Here
is
a
multiline string where I have escaped some but not other newlines.

R: Here we bring some strings together and show various quoting of strings =
which contain quoteing chars "'"' handy tricks indeed to avoid escapes
</pre>


<blockquote style=3D"border-left: 2px solid gray; padding-left: 4px;">
<p>
Can I build my own bundles/functions which return values? I've seen that bu=
ndles can modify variables and define
class in the parent scope, but that seems quite horrible. I mean something =
like this:
```
vars:
    "my_value" string =3D&gt; do_http_request("some arguments here");
```
where "do_http_request" is some wrapper around Curl that I can write on my =
own,
can't use url_get, because the binary on Alpine is compiled without curl su=
pport, and I would rather not bother with that,
and instead do what I would do in other languages: abstract the mundane tas=
k of calling curl into something less
repetitive.
</p>
</blockquote>

<p>
Yes, it's possible to define your own bundles and bodies (it's quite expect=
ed that you will).
</p>

<p>
I recommend reading through the language concepts section of the reference =
manual (<a href=3D"https://docs.cfengine.com/docs/3.24/reference-language-c=
oncepts.html">https://docs.cfengine.com/docs/3.24/reference-language-concep=
ts.html</a>). You can even define your own promise types (<a href=3D"https:=
//cfengine.com/blog/2020/introducing-cfengine-custom-promise-types/">https:=
//cfengine.com/blog/2020/introducing-cfengine-custom-promise-types/</a>) bu=
t there is not currently any ability to define custom <i>functions</i>.
</p>

<p>
I think it's important to remember that bundles are not functions (<a href=
=3D"https://docs.cfengine.com/docs/3.24/reference-language-concepts-bundles=
.html">https://docs.cfengine.com/docs/3.24/reference-language-concepts-bund=
les.html</a>). Though you can use them in that way and they have the abilit=
y to return data into the calling bundle via <i>reports</i> promises using =
<code>bundle_return_value_index</code> (<a href=3D"https://docs.cfengine.co=
m/docs/3.26/reference-promise-types-reports.html#bundle_return_value_index"=
>https://docs.cfengine.com/docs/3.26/reference-promise-types-reports.html#b=
undle_return_value_index</a>) and <code>useresult</code> (<a href=3D"https:=
//docs.cfengine.com/docs/3.26/reference-promise-types-methods.html#useresul=
t">https://docs.cfengine.com/docs/3.26/reference-promise-types-methods.html=
#useresult</a>)
</p>

<p>
Here is an example:
</p>

<div class=3D"org-src-container">
<pre class=3D"src src-cfengine3"><span style=3D"color: #a89984; font-weight=
: bold;">bundle</span> <span style=3D"color: #458588; font-weight: bold;">a=
gent</span> <span style=3D"color: #458588;">__main__</span>
<span style=3D"color: #689d6a;">{</span>
  <span style=3D"color: #a89984; font-weight: bold;">methods</span>:
      <span style=3D"color: #689d6a;">"Call my bundle with params and defin=
e a variable with returned data"</span>
        usebundle =3D&gt; myBundle<span style=3D"color: #d79921;">(</span><=
span style=3D"color: #689d6a;">"KEY"</span>, <span style=3D"color: #689d6a;=
">"VALUE"</span><span style=3D"color: #d79921;">)</span>,
        useresult =3D&gt; <span style=3D"color: #689d6a;">"returned_from_my=
Bundle"</span>;

      <span style=3D"color: #689d6a;">"More ...."</span>
        usebundle =3D&gt; myBundle<span style=3D"color: #d79921;">(</span><=
span style=3D"color: #689d6a;">"CFEngine"</span>, <span style=3D"color: #68=
9d6a;">"Awesome"</span><span style=3D"color: #d79921;">)</span>,
        useresult =3D&gt; <span style=3D"color: #689d6a;">"returned_from_my=
Bundle"</span>;

      <span style=3D"color: #689d6a;">"Calculator"</span>
        usebundle =3D&gt; add<span style=3D"color: #d79921;">(</span><span =
style=3D"color: #689d6a;">"5266"</span>, <span style=3D"color: #689d6a;">"4=
2"</span>, <span style=3D"color: #689d6a;">"value"</span><span style=3D"col=
or: #d79921;">)</span>,
        useresult =3D&gt; <span style=3D"color: #689d6a;">"sum"</span>;

  <span style=3D"color: #a89984; font-weight: bold;">reports</span>:
      <span style=3D"color: #689d6a;">"CFEngine version: $(sys.cf_version)"=
</span>;
      <span style=3D"color: #689d6a;">"$(with)"</span>
        with =3D&gt; storejson<span style=3D"color: #d79921;">(</span> retu=
rned_from_myBundle <span style=3D"color: #d79921;">)</span>;

      <span style=3D"color: #689d6a;">"Calculated $(sum[value])"</span>;
<span style=3D"color: #689d6a;">}</span>
<span style=3D"color: #a89984; font-weight: bold;">bundle</span> <span styl=
e=3D"color: #458588; font-weight: bold;">agent</span> <span style=3D"color:=
 #458588;">myBundle</span><span style=3D"color: #689d6a;">(</span><span sty=
le=3D"color: #458588;">key, value</span><span style=3D"color: #689d6a;">)</=
span>
<span style=3D"color: #689d6a;">{</span>
  <span style=3D"color: #a89984; font-weight: bold;">reports</span>:
      <span style=3D"color: #689d6a;">"$(value)"</span>
        bundle_return_value_index =3D&gt; <span style=3D"color: #689d6a;">"=
$(key)"</span>;
<span style=3D"color: #689d6a;">}</span>
<span style=3D"color: #a89984; font-weight: bold;">bundle</span> <span styl=
e=3D"color: #458588; font-weight: bold;">agent</span> <span style=3D"color:=
 #458588;">add</span><span style=3D"color: #689d6a;">(</span><span style=3D=
"color: #458588;">int1, int2, key</span><span style=3D"color: #689d6a;">)</=
span>
<span style=3D"color: #689d6a;">{</span>
  <span style=3D"color: #a89984; font-weight: bold;">reports</span>:
      <span style=3D"color: #689d6a;">"$(with)"</span>
        with =3D&gt; <span style=3D"color: #d79921;">int</span><span style=
=3D"color: #d79921;">(</span> eval<span style=3D"color: #458588;">(</span> =
<span style=3D"color: #689d6a;">"$(int1)+$(int2)"</span>, <span style=3D"co=
lor: #689d6a;">"math"</span>, <span style=3D"color: #689d6a;">"infix"</span=
> <span style=3D"color: #458588;">)</span> <span style=3D"color: #d79921;">=
)</span>,
        bundle_return_value_index =3D&gt; <span style=3D"color: #689d6a;">"=
$(key)"</span>;
<span style=3D"color: #689d6a;">}</span>
</pre>
</div>

<pre class=3D"example">
R: CFEngine version: 3.27.0a.5553c81fe
R: {
  "CFEngine": "Awesome",
  "KEY": "VALUE"
}
R: Calculated 5308
</pre>


<p>
Modules are another thing to know about (<a href=3D"https://docs.cfengine.c=
om/docs/3.26/reference-language-concepts-modules.html#top">https://docs.cfe=
ngine.com/docs/3.26/reference-language-concepts-modules.html#top</a>). Ther=
e are a lot of different kinds of modules in CFEngine. There are the tradit=
ional variables and classes modules which allow you to define variables and=
 classes from external programs via a simple line based protocol. You can u=
se modules in different ways but primarily via <code>usemodule()</code> (<a=
 href=3D"https://docs.cfengine.com/docs/3.26/reference-functions-usemodule.=
html#top">https://docs.cfengine.com/docs/3.26/reference-functions-usemodule=
.html#top</a>) or via commands with <code>module =3D&gt; true</code> (<a hr=
ef=3D"https://docs.cfengine.com/docs/3.26/reference-promise-types-commands.=
html#module">https://docs.cfengine.com/docs/3.26/reference-promise-types-co=
mmands.html#module</a>). Then there are package modules which are external =
programs that communicate with CFEngine to implement packages promises, pro=
mise modules which are for defining custom promise types and CFEngine Build=
 Modules (<a href=3D"https://build.cfengine.com/">https://build.cfengine.co=
m/</a>) which are collections of policy or other CFEngine related content.
</p>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;help-cfengine&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:[email protected]">help-=
[email protected]</a>.<br />
To view this discussion visit <a href=3D"https://groups.google.com/d/msgid/=
help-cfengine/87ikix8lvm.fsf%40northern.tech?utm_medium=3Demail&utm_source=
=3Dfooter">https://groups.google.com/d/msgid/help-cfengine/87ikix8lvm.fsf%4=
0northern.tech</a>.<br />

--==-=-=--

--=-=-=
Content-Type: text/plain; charset="UTF-8"




--
Nick Anderson | Doer of Things | (+1) 785-550-1767 | https://northern.tech

-- 
You received this message because you are subscribed to the Google Groups "help-cfengine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/help-cfengine/87ikix8lvm.fsf%40northern.tech.

--=-=-=--