Search code examples
rpmcfengine

cfEngine3 - class if package is installed


how can i set a class if a package is installed ?

Background : i want to trigger a file modification only if a package is installed (optional in a specific version).

My (example) code unfortunately doesn't work :

vars:
    "cfengine_rpm" data => packagesmatching("cfengine-nova", ".*", ".*", ".*");
    "cfengine_rpm_installed" slist => getindices(cfengine_rpm);

classes:
    "cfengine_installed" expression => some("cfengine", cfengine_rpm_installed);

reports:
    cfengine_installed::
        "cfEngine is installed ";
        # Bonus :-)
        "cfEngine Version : $(cfengine_rpm[$(cfengine_rpm_installed)][version])";

Addendum : this question is similar to CFEngine - set variable if a specific package version is installed but I would like to ask for coded hints or solutions :-)


Solution

  • I tweaked your policy a bit and provided comments in line. I think your main issue was that you were expecting the index of the returned packagesmatching() data to be indexed by package name, instead of a numeric id.

    bundle agent main
    {
    vars:
    
        # Return data from cfengines internal cache about any packages matching the
        # name cfengine-nova
        "p"
          data => packagesmatching("cfengine.*", ".*", ".*", ".*");
    
        # Get the index (list of keys) from this data structure for iteration
    
        # Each value in the list is a number which is the position of the JSON
        # object in the data returned from packagesmatching(). For example, if
        # cfengine-nova-hub is the only package found to be installed that matches
        # then the data structure returend to p will look like the following
        # snippet. Note it's the 0th element inside the array ([]).
        #
        # [
        #   {
        #      "arch":"x86_64",
        #      "method":"dpkg",
        #      "name":"cfenigne-nova-hub",
        #      "version":"3.10.1-1"
        #   }
        # ]
    
        "i" slist => getindices(p);
        "c" slist => classesmatching( ".*", "defined_from=$(this.bundle)");
    
    classes:
    
        # Iterate over the packages found, if one of their names matches
        # cfengine-nova.* then define the class cfengine_installed.
    
        "cfengine_installed"
          expression => regcmp( "cfengine.*", "$(p[$(i)][name])" ),
          meta => { "defined_from=$(this.bundle)" };
    
    reports:
    
        # Emit the version of cfengine from the internal sys var
        "CFEngine $(sys.cf_version)";
    
        # Iterate over the index (i) of the data returned from packagesmatching
        # cfengine-nova (p) and print the name of each package.
    
        "CFEngine cached knowledge of $(p[$(i)][name]) $(p[$(i)][version])";
    
        "Found the class '$(c)' defined from $(this.bundle)";
    
        cfengine_installed::
    
            "CFEngine is installed ";
    
            # Bonus :-)
    
            # In case you had multiuple packages returned, you might want to make
            # this more strict, or it will emit the version of each package found
            # by packagesmatching.
    
            "CFEngine Package Version : $(p[$(i)][version])"
              if => strcmp( "cfengine-nova-hub", "$(p[$(i)][name])" );
    }
    

    Results in this output:

    R: CFEngine 3.10.1
    R: CFEngine cached knowledge of cfengine-nova-hub 3.10.1-1
    R: Found the class 'cfengine_installed' defined from main
    R: CFEngine is installed 
    R: CFEngine Package Version : 3.10.1-1
    

    Does this answer your question?