Tracking Packages Not Installed by Puppet

technologydebian, freebsd, puppet, and sysadmin

I use puppet to manage my servers (and my laptop), primarily because it’s what we use at work. However, I have a bad habit of just doing things manually rather than through puppet; since I’ve recently begun moving my website to a new host I thought I’d try and track this a little better.

FreeBSD has a helpful tool, ports-mgmt/pkg_cutleaves, for listing and removing packages that are not depended upon by any other packages. So, I generated a list of packages installed by Puppet:

< /var/puppet/state/state.yaml awk -F'[\\[\\]]' '/Package/{print $2}' | sort > /usr/local/etc/pkg_leaves.exclude

Then pkg_cutleaves -lx gives a list of everything not installed by Puppet and not depended upon by anything else.

For Debian, it was a little harder, since I’d never had cause to use the relevant tools before. With some help from Server Fault, I got a list of manually-installed packages with the following script:

set -e
dpkg --get-selections | sed -n 's/\t\+install$//p' > ${all_installed}
</var/lib/apt/extended_states awk -v RS= '/\nAuto-Installed: *1/{print $2}' | sort > ${auto_installed}
comm -23 ${all_installed} ${auto_installed}
rm -f ${all_installed} ${auto_installed}

Then marked everything as being automatically installed:

get-manually-installed|xargs apt-mark markauto

Then, similar to the FreeBSD method, marked all the packages installed by Puppet as manually-installed:

< /var/lib/puppet/state/state.yaml awk -F'[\[\]]' '/Package/{print $2}' | xargs apt-mark manual

Alternatively, to get a list of only manually-installed packages not installed by Puppet:

set -e
get-manually-installed > ${manual}
< /var/lib/puppet/state/state.yaml awk -F'[\[\]]' '/Package/{print $2}' | sort > ${puppet}
comm -23 ${manual} ${puppet}
rm -f ${manual} ${puppet}

Debian should be somewhat easier to maintain than FreeBSD, as anything installed by Puppet will be marked as manually-installed

P.S.: Yes, I’m aware that this is basically the worst way of parsing yaml ever. Sorry. Also note that the name in puppet will be the namevar, so if the namevar isn’t the package name (e.g., package { 'meaningless_string': name => 'real_package_name' }) you lose. Sorry.