Package installation can be tricky sometimes when using configuration management tools, as the order in which package operations are performed can have an impact on the final result, sometimes a disastrous impact. Months ago I had been looking for a way to make apt-get a bit less proactive when trying to solve dependencies and removing packages and came up with the following package method that we now have in our library.
To use it, just put it in your policies and use apt_get_safe in your policies instead of apt_get wherever you want a more prudential approach to package installations.
I’m putting it here in the hope that it may be useful for everyone. I have used it successfully in Debian 5, 6, 7, 8 and on CFEngine 3.4.4 (where I borrowed parts of the masterfiles from 3.5 and 3.6 like, e.g., the debian_knowledge bundle) and 3.6.x. Enjoy!
body package_method apt_get_safe
# Make a more prudential apt_get method. Use it to reduce the likeliness
# of unexpected upgrades or removals
{
package_changes => "bulk";
package_list_command => "$(debian_knowledge.call_dpkg) -l";
package_list_name_regex => ".i\s+([^\s]+).*";
package_list_version_regex => ".i\s+[^\s]+\s+([^\s]+).*";
package_installed_regex => ".i.*"; # packages that have been uninstalled may be listed
package_name_convention => "$(name)";
# set it to "0" to avoid caching of list during upgrade
package_list_update_ifelapsed => "240";
# Target a specific release, such as backports
package_add_command => "$(debian_knowledge.call_apt_get) $(debian_knowledge.dpkg_options) -o APT::Get::Remove=false -o APT::Get::force-yes=false --yes install";
package_list_update_command => "$(debian_knowledge.call_apt_get) update";
package_delete_command => "$(debian_knowledge.call_apt_get) $(debian_knowledge.dpkg_options) --yes -q remove";
package_update_command => "$(debian_knowledge.call_apt_get) $(debian_knowledge.dpkg_options) -o APT::Get::Only-Upgrade=true -o APT::Get::Remove=false -o APT::Get::force-yes=false --yes install";
package_patch_command => "$(debian_knowledge.call_apt_get) $(debian_knowledge.dpkg_options) -o APT::Get::Only-Upgrade=true -o APT::Get::Remove=false -o APT::Get::force-yes=false --yes install";
package_verify_command => "$(debian_knowledge.call_dpkg) -s";
package_noverify_returncode => "1";
package_patch_list_command => "$(debian_knowledge.call_apt_get) --just-print dist-upgrade";
package_patch_name_regex => "^Inst\s+(\S+)\s+.*";
package_patch_version_regex => "^Inst\s+\S+\s+\[?\(?([^\],\s]+).*";
# make correct version comparisons
package_version_less_command => "$(debian_knowledge.dpkg_compare_less)";
package_version_equal_command => "$(debian_knowledge.dpkg_compare_equal)";
}