Run `apt-get update` before installing other packages with Puppet

PuppetApt GetZend Server

Puppet Problem Overview


I'm trying to create puppet module which automates installation of zend server CE, this is not important here, but steps are as following

  1. update /etc/apt/source.list
  2. download repos key via wget
  3. do apt-get update
  4. do apt-get install zend-server-ce-5.2

I have init.pp file

class zendserverce {

# https://github.com/puppetlabs/puppetlabs-stdlib
file_line { 'debian_package':
   	path => '/etc/apt/sources.list',
   	line => 'deb http://repos.zend.com/zend-server/deb server non-free'
}

exec { "wget http://repos.zend.com/zend.key -O- |apt-key add -":
    path => ["/usr/bin", "/usr/sbin"]
}

exec { "apt-get update":
	command => "/usr/bin/apt-get update",
	onlyif  => "/bin/sh -c '[ ! -f /var/cache/apt/pkgcache.bin ] || /usr/bin/find /etc/apt/* -cnewer /var/cache/apt/pkgcache.bin | /bin/grep . > /dev/null'",
}

package { "zend-server-ce-php-5.2":
    ensure => "latest"
}

}

Seems that puppet runs commands in different order then I need. Is there any way how to for tell him to run in my desired order?

The output of such snippet is

  [0;36mnotice: /Stage[main]/Mc/Package[mc]/ensure: ensure changed 'purged' to 'latest'[0m
  [1;35merr: /Stage[main]/Zendserverce/Package[zend-server-ce-php-5.2]/ensure: change from purged to latest failed: Could not update: Execution of '/usr/bin/apt-get -q -y -o DPkg::Options::=--force-confold install zend-server-ce-php-5.2' returned 100: Reading package lists...
  Building dependency tree...
  Reading state information...
  E: Couldn't find package zend-server-ce-php-5.2 at /tmp/vagrant-puppet/modules 0/zendserverce/manifests/init.pp:28[0m
  [0;36mnotice: /Stage[main]/Zendserverce/Exec[wget http://repos.zend.com/zend.key -O- |apt-key add -]/returns: executed successfully[0m
  [0;36mnotice: /Stage[main]/Zendserverce/File_line[debian_package]/ensure: created[0m
  [0;36mnotice: Finished catalog run in 6.75 seconds[0m

So it says: Couldn't find package zend-server-ce-php-5.2

Can anyone guide me what is wrong?

Puppet Solutions


Solution 1 - Puppet

Since Puppet 2.6.0 a new feature "relationship syntax" was introduced.

An example in Puppet 2.6.0 and above would look like this:

exec { "apt-update":
	command => "/usr/bin/apt-get update"
}

Exec["apt-update"] -> Package <| |>

Every time a package command is executed, the dependency (in our case 'apt-update') will be triggered fist. You can even define longer chains.

Solution 2 - Puppet

You need to specify the dependency relationships. The easiest/cleanest approach is to use the require parameter which is available for all resource types.

package { "zend-server-ce-php-5.2":
  ensure  => latest,
  require  => Exec['apt-get update'],
}

etc..

Solution 3 - Puppet

I tried previous variant but it doesn't work for me on Ubuntu 10.04

Finaly I prepared the following script, that runs update everytime the repository is older than one week:

exec { 'apt-get update':
    command => "/usr/bin/apt-get update",
    onlyif => "/bin/bash -c 'exit $(( $(( $(date +%s) - $(stat -c %Y /var/lib/apt/lists/$( ls /var/lib/apt/lists/ -tr1|tail -1 )) )) <= 604800 ))'"
}

Hope it helps.

Solution 4 - Puppet

I prefer to put apt-upgrade into a separate stage running before the main stage, so I don't have to hard-wire any dependencies. Check here: http://docs.puppetlabs.com/puppet/2.7/reference/lang_run_stages.html.

A simple example would look like below. It implies you have a separate class for doing the actual apt-update:

stage { "init": before  => Stage["main"] }

class {"apt-update": 
  stage => init, 
  apt_mirror => $apt_mirror 
}

Check my sample LAMPP-box on github to see how the pieces fit together: https://github.com/joerx/vagrant-lampp

Note: be careful with apt-upgrade, as some base boxes break by things like kernel upgrades.

Solution 5 - Puppet

In Puppet 3 this can be done by realizing virtual resources using resource collectors

# so you don't have to fully qualify paths to binaries
Exec { path => ['/usr/bin'] }    

# virtual resource
@exec { 'sudo apt-get update':
   tag => foo_update
}

# realize resource. filter by arbitrary "foo_update"
# tag and relate it to all Package resources
Exec <| tag == foo_update |> -> Package <| |>

Solution 6 - Puppet

Adding this snippet of voodoo worked for us:

  Apt::Pin <| |> -> Package <| |>
  Apt::Source <| |> -> Package <| |>

This forced an update. YMMV.

Solution 7 - Puppet

Package that needs updating APT lists should require Class['apt::update']

package { "zend-server-ce-php-5.2":
   ensure => "latest",
   require => Class['apt::update']
}

If you're using custom APT source, just ensure correct ordering:

Apt::Source['my_source'] 
-> Class['apt::update']

Solution 8 - Puppet

You should really be using the apt module to create sources and add keys: https://forge.puppet.com/puppetlabs/apt

If you're using hiera:

apt::sources:
  'artifactory-pro-debs':
    location: 'http://repos.zend.com/zend-server/deb'
    release: 'server
    repos: 'non-free'
    key:
      source: 'http://repos.zend.com/zend.key'

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJaroView Question on Stackoverflow
Solution 1 - PuppetDrDolView Answer on Stackoverflow
Solution 2 - PuppetczervikView Answer on Stackoverflow
Solution 3 - PuppetPavel ŽeleznýView Answer on Stackoverflow
Solution 4 - PuppetjoerxView Answer on Stackoverflow
Solution 5 - PuppetBrandon CookView Answer on Stackoverflow
Solution 6 - PuppetTimPView Answer on Stackoverflow
Solution 7 - PuppetTombartView Answer on Stackoverflow
Solution 8 - Puppetuser1681190View Answer on Stackoverflow