Search code examples
linuxcfengine

CFENGINE: policy to perform bunch of commands on bunch of packages


I have to create one CFENGINE 3 Policy which should take input from defined input list and then want to perform some bunch of commands on that set one by one.

For Eg:

For only one Package here I have the example:

bundle agent test_tester_install

{

commands:

    "/usr/bin/wget  http://something.example.com/perl-modules/Test-Tester-0.104.tar.gz;
    /usr/bin/gunzip Test-Tester-0.104.tar.gz;
    tar -xf Test-Tester-0.104.tar;
    cd Test-Tester-0.104;
    /usr/bin/perl Makefile.PL;
    /usr/bin/make;
    /usr/bin/make install"


    contain =>  standard,
            classes => satisfied("Test-Tester Installed");
     }
body contain standard

{

    useshell => "true";
    exec_owner => "root";
}

body classes satisfied(new_class)


{

    promise_repaired => { "$(new_class)" };
}

But I am not sure that how to do it if I want to do the same for 100 packages. I think "slist would do this but how exactly i need to draft that policy i am not sure"

This is very similar to applying "for" loop in bash shell where we iterate input one by one and perform some operations

Experts Please help


Solution

  • The way to do something like this is to use CFEngine's implicit looping. You store the values in a list, and then iterate over them in the promises. For your example, it would be something like this:

    bundle agent install
    
    {
    vars:
        "packages" slist => { "Test-Tester-0.104", "Foo-Bar-1.001" }; # etc.
    commands:
        "/usr/bin/wget  http://something.example.com/perl-modules/$(packages).tar.gz;
        /usr/bin/gunzip $(packages).tar.gz;
        tar -xf $(packages).tar;
        cd $(packages);
        /usr/bin/perl Makefile.PL;
        /usr/bin/make;
        /usr/bin/make install"
                contain =>  standard,
                classes => satisfied(canonify("$(packages)-installed"));
         }
    

    Note that I'm using $(package) whenever you previously had Test-Tester-0.104. Of course this only works if all the names are consistent in this respect. To add more, you'd only need to add the names to the packages variable. Not also that I used canonify() to make the string that gets passed to the satisfied() body a valid class name.

    Now, if you are going to be doing a lot of installs like this, what I would suggest is defining a new package_method definition, which takes care of following the right steps internally, so that in your policy you can have something much cleaner, like this:

    vars:
        "packages" slist => { "Test-Tester-0.104", "Foo-Bar-1.001" }; # etc.
    packages:
        "$(packages)"
           package_policy => "add",
           package_method => perlsrcpkg;  # or whatever you call your new package_method
    

    You can find the documentation for packages promises here: http://cfengine.com/docs/3.5/reference-promise-types-packages.html#packages, and a bunch of package_method definition examples in the CFEngine Standard Library: https://github.com/cfengine/masterfiles/blob/master/lib/3.5/packages.cf

    Finally, if the packages you are installing are from CPAN, you could just use the Packages::Installed::cpanm sketch from the Design Center: https://cfengine.com/cfengine-design-center/sketches/packages-cpan-cpanm