Uploaded image for project: 'CFEngine Community'
  1. CFEngine Community
  2. CFE-2346

As a policy writer I would like to be able to easily define a class if a package is installed or if there is a package update available for a specific package

    XMLWordPrintable

    Details

    • Type: Story
    • Status: Open
    • Priority: Low
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: None
    • Labels:

      Description

      Currently we can use `packagesmatching()` to find packages that are currently installed based on name, version, architecture, and the `package_module` or `package_method` used to collect the data.

      In order to define a class that indicates a package is installed we can check the length of the returned data container and see if its greater than 0.

      bundle agent main
      {
        vars:
            "pkg" string => "vim";
            "p" data => packagesmatching( $(pkg), ".*", ".*", ".*" );
      
            "l" int => length(p);
      
        classes:
            "have_vim_installed" expression => isgreaterthan( $(l), 0);
      
        reports:
            "I $(l) packages matching $(pkg) installed which is more than 0."
              if => "have_vim_installed";
      
            "I have $(l) packages matching $(pkg) installed."
              unless => isgreaterthan( $(l), 0 );
      }
      

      It would be convenient to not have to step through these intermediary variables when I am only concerned with a class.

      Syntax suggestions:

      bundle agent example
      {
        classes:
          "at_least_one_package_installed_matching"
            expression => package_installed_matching( name_reg, version_reg, arch_reg, method_reg);
      
          "at_least_one_package_update_matching"
            expression => package_update_available( name_reg, version_reg, arch_reg, method_reg)
      }
      

      Policy Examples

      Class for each package found via packagesmatching()

      This example defines classes for each package found by packagesmatching(). You don't have to worry about explicitly canonifying the names, cfengine will do it for you automatically (only when you are defining a class, not when you are checking a class).

      bundle agent main
      {
        vars:
            "pkgs_installed_d" data => packagesmatching( "e.*", ".*", ".*", ".*" );
            "i" slist => getindices( pkgs_installed_d );
      
        classes:
            "pkg_installed_$(pkgs_installed_d[$(i)][name])" expression => isvariable( "pkgs_installed_d[$(i)][name]" );
      
        vars:
            "c" slist => classesmatching("pkg_installed_.*");
        reports:
            "$(c)";
      }
      
      

      On my workstation all of these packages starting with e are installed:

      R: pkg_installed_evolution_data_server_online_accounts
      R: pkg_installed_exo_utils
      R: pkg_installed_enfuse
      R: pkg_installed_enblend
      R: pkg_installed_evolution_data_server
      R: pkg_installed_empathy_common
      R: pkg_installed_emacs24
      R: pkg_installed_e2fslibs
      R: pkg_installed_enigmail
      R: pkg_installed_e2fsprogs
      R: pkg_installed_eog
      R: pkg_installed_enchant
      R: pkg_installed_emacsen_common
      R: pkg_installed_emacs
      R: pkg_installed_example_content
      R: pkg_installed_evince
      R: pkg_installed_emacs24_common
      R: pkg_installed_elinks
      R: pkg_installed_efibootmgr
      R: pkg_installed_evolution_data_server_common
      R: pkg_installed_espeak_data
      R: pkg_installed_ethtool
      R: pkg_installed_ed
      R: pkg_installed_emacs24_bin_common
      R: pkg_installed_evince_common
      R: pkg_installed_elinks_data
      R: pkg_installed_eject
      R: pkg_installed_emacs24_common_non_dfsg
      

      Class for each package name and version found by packagesmatching()

      bundle agent main
      {
        vars:
            "pkgs_installed_d" data => packagesmatching( "e.*", ".*", ".*", ".*" );
            "i" slist => getindices( pkgs_installed_d );
      
        classes:
            "pkg_installed_$(pkgs_installed_d[$(i)][name])"
              expression => isvariable( "pkgs_installed_d[$(i)][name]" ),
              meta => { "identifies=package_name_present" };
      
            "pkg_installed_$(pkgs_installed_d[$(i)][name])_$(pkgs_installed_d[$(i)][version])"
              expression => isvariable( "pkgs_installed_d[$(i)][version]" ),
              meta => { "identifies=package_version_present" };
      
        vars:
            "c_pkg_name_installed" slist => classesmatching(".*", "identifies=package_name_present");
            "c_pkg_name_version_installed" slist => classesmatching(".*", "identifies=package_version_present");
      
        reports:
            "Classes for package names that are installed:";
            "  $(c_pkg_name_installed)";
            "Classes for package names and versions that are installed:";
            "  $(c_pkg_name_version_installed)";
      }
      
      

      Here you can see the classes that were defined by the package name, followed by the classes defined for the package name and version.

      R: Classes for package names that are installed:
      R:   pkg_installed_evolution_data_server_online_accounts
      R:   pkg_installed_exo_utils
      R:   pkg_installed_enfuse
      R:   pkg_installed_enblend
      R:   pkg_installed_evolution_data_server
      R:   pkg_installed_empathy_common
      R:   pkg_installed_emacs24
      R:   pkg_installed_e2fslibs
      R:   pkg_installed_enigmail
      R:   pkg_installed_e2fsprogs
      R:   pkg_installed_eog
      R:   pkg_installed_enchant
      R:   pkg_installed_emacsen_common
      R:   pkg_installed_emacs
      R:   pkg_installed_example_content
      R:   pkg_installed_evince
      R:   pkg_installed_emacs24_common
      R:   pkg_installed_elinks
      R:   pkg_installed_efibootmgr
      R:   pkg_installed_evolution_data_server_common
      R:   pkg_installed_espeak_data
      R:   pkg_installed_ethtool
      R:   pkg_installed_ed
      R:   pkg_installed_emacs24_bin_common
      R:   pkg_installed_evince_common
      R:   pkg_installed_elinks_data
      R:   pkg_installed_eject
      R:   pkg_installed_emacs24_common_non_dfsg
      R: Classes for package names and versions that are installed:
      R:   pkg_installed_eog_3_16_3_1ubuntu2_1
      R:   pkg_installed_emacs24_bin_common_24_5_1_1ubuntu2
      R:   pkg_installed_efibootmgr_0_12_4
      R:   pkg_installed_emacs_46_1
      R:   pkg_installed_eject_2_1_5_deb1_cvs20081104_13_1
      R:   pkg_installed_elinks_data_0_12_pre6_10
      R:   pkg_installed_enigmail_2_1_8_2_0ubuntu1
      R:   pkg_installed_evince_common_3_16_1_0ubuntu1
      R:   pkg_installed_emacs24_common_24_5_1_1ubuntu2
      R:   pkg_installed_elinks_0_12_pre6_10
      R:   pkg_installed_evince_3_16_1_0ubuntu1
      R:   pkg_installed_evolution_data_server_3_16_5_1ubuntu3
      R:   pkg_installed_enfuse_4_1_3_dfsg_2build1
      R:   pkg_installed_emacs24_24_5_1_1ubuntu2
      R:   pkg_installed_emacsen_common_2_0_8
      R:   pkg_installed_emacs24_common_non_dfsg_24_4_1_2
      R:   pkg_installed_ethtool_1_3_16_1
      R:   pkg_installed_evolution_data_server_common_3_16_5_1ubuntu3
      R:   pkg_installed_empathy_common_3_12_10_0ubuntu2
      R:   pkg_installed_exo_utils_0_10_7_1
      R:   pkg_installed_espeak_data_1_48_04_dfsg_1
      R:   pkg_installed_enblend_4_1_3_dfsg_2build1
      R:   pkg_installed_enchant_1_6_0_10_1build1
      R:   pkg_installed_e2fsprogs_1_42_12_1ubuntu2
      R:   pkg_installed_evolution_data_server_online_accounts_3_16_5_1ubuntu3
      R:   pkg_installed_ed_1_10_2
      R:   pkg_installed_e2fslibs_1_42_12_1ubuntu2
      R:   pkg_installed_example_content_48
      

      Parameterized bundle to deifne namespace scoped class if packagesmatching() finds matches on package name.

      Here is a parameterized bundle that can be used to define a class if any package on the system is found by packagesmatching():

      bundle agent main
      {
          methods:
            "Define class if any packages installed matching emacs"
              usebundle => package_exists( "emacs" );
      
          vars:
            "p" slist => classesmatching( ".*", "package_exists" );
      
          reports:
            "Found class $(p)";
      
      }
      bundle agent package_exists(pkg)
      # This code is based on the example code in https://tracker.mender.io/browse/CFE-2346
      {
        vars:
            "p" data => packagesmatching( $(pkg), ".*", ".*", ".*" );
            "l" int => length(p);
      
        classes:
            "package_exists_$(pkg)"
              expression => isgreaterthan( $(l), 0),
              meta => { "package_exists" },
              scope => "namespace";
      }
      
      R: Found class package_exists_emacs
      

      Beware your search may match more than you want.

      bundle agent main
      {
          methods:
            "Define class if any packages installed starting with e"
              usebundle => package_exists( "e.*" );
      
          vars:
            "p" slist => classesmatching( ".*", "package_exists" );
      
          reports:
            "Found class $(p)";
      
      }
      bundle agent package_exists(pkg)
      # This code is based on the example code in https://tracker.mender.io/browse/CFE-2346
      {
        vars:
            "p" data => packagesmatching( $(pkg), ".*", ".*", ".*" );
            "l" int => length(p);
      
        classes:
            "package_exists_$(pkg)"
              expression => isgreaterthan( $(l), 0),
              meta => { "package_exists" },
              scope => "namespace";
      }
      

      Because I have at least one package installed that starts with e I get the class package_exists_e__.

      R: Found class package_exists_e__
      

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                Unassigned
                Reporter:
                a10042 Nick Anderson
              • Votes:
                2 Vote for this issue
                Watchers:
                4 Start watching this issue

                Dates

                • Created:
                  Updated:

                  Summary Panel