Thanks for all the suggestions chaps. I'll certainly check them all out.
I had a scribble on Friday (that's what Friday's are for?) and hacked
up my own provider.
I've added it to our existing apt cookbook. It's intended as a drop-in
replacement for package. If you do an install it only does an update
if the package isn't installed. Ie, the first package to be installed
will trigger the only update for that run. If you do a package upgrade
it makes sure an upgrade is done once only. If all packages are
converged, no update is done.
The flag to indicate if an update has been done is stored on the node
and has to be reset at the start of each run. Is there a better way of
setting transient attributes for the run?
I've posted the code here in case it's any use to anyone else. I'm
going to commit it in dev here and see what comes out in the wash. I'm
sure I've broken/abused something.
actions :install, :upgrade, :remove, :purge
attribute :name, :kind_of => String
action :install do
if(!system("dpkg-query -W -f='${Status}' #{@new_resource.name} > /dev/null"))
process_package :install
end
end
action :upgrade do
process_package :upgrade
end
action :remove do
package @new_resource.name do
action :remove
end
end
action :purge do
package @new_resource.name do
action :purge
end
end
private
def process_package (mode)
Chef::Log.debug("#{mode} of package #{@new_resource.name} requested")
if(!node[:apt_update_performed_this_chef_run])
Chef::Log.debug("apt-get update required for this run, performing")
execute "apt-get update"
node[:apt_update_performed_this_chef_run] = true
else
Chef::Log.debug("apt-get update already performed for this run")
end
package @new_resource.name do
action mode
end
@new_resource.updated_by_last_action(true)
end
On 27 March 2011 14:46, Bryan McLellan btm@loftninjas.org wrote:
On Fri, Mar 25, 2011 at 2:45 AM, Luke Biddell luke.biddell@gmail.com wrote:
So what I'd ideally like is to be able to trigger an apt-get update on
the first package which requires installing. If no packages require
installing, no apt-get update is performed. The fact an update has
been performed needs to be recorded as we don't want to do it for
every package that's installed as it will kill performance. Once is
enough per chef run unless we add/remove a sources.list.d entry (which
I already handle using :notifies).
There are a number of strategies. Here's another I used to do.
Only trigger an apt-get update when a repo or key is added, otherwise
rely on Ubuntu to run a daily apt-get update but run it ourselves if
we need to. Note that I was silently rescuing failures as well.
Run apt-get update to create the stamp file
execute "apt-get-update" do
ignore_failure true
epic_fail true
command "apt-get update"
not_if do File.exists?('/var/lib/apt/periodic/update-success-stamp') end
end
provides /var/lib/apt/periodic/update-success-stamp on apt-get update
package "update-notifier-common" do
ignore_failure true
notifies :run, resources(:execute => "apt-get-update"), :immediately
end
execute "apt-get-update-periodic" do
ignore_failure true
epic_fail true
command "apt-get update"
only_if do
File.exists?('/var/lib/apt/periodic/update-success-stamp') &&
File.mtime('/var/lib/apt/periodic/update-success-stamp') < Time.now - 86400
end
end