Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

Is there a way to force puppet to do certain things first? For instance, I need it to install an RPM on all servers to add a yum repository (IUS Community) before I install any of the packages.

share|improve this question
    
For a more complex use case, see also my related question. –  Matt McClure Sep 20 '12 at 17:06
add comment

7 Answers

up vote 23 down vote accepted

If you want to make sure a repository is installed on all your server then I would suggest something like this

node default {
   include base
}

class base {
   yumrepo { "IUS":
      baseurl => "http://dl.iuscommunity.org/pub/ius/stable/$operatingsystem/$operatingsystemrelease/$architecture",
      descr => "IUS Community repository",
      enabled => 1,
      gpgcheck => 0
   }
}

Then, for any node that extends base you can say

class foo {
   package { "bar": ensure => installed, require => Yumrepo["IUS"] }
}

This will ensure that

  • The package bar will not be installed unless the IUS repository is defined
  • The package will not attempt to install before the IUS repository is defined
share|improve this answer
1  
I think in class foo it should be require rather than requires ... –  Hamish Downer Feb 21 '10 at 19:58
    
Thanks for the catch –  Dave Cheney Feb 21 '10 at 22:39
    
Ah, ok. This is pretty awesome. I didn't see the yumrepo in there - thanks! –  Jonathan Haddad Feb 25 '10 at 20:11
    
It only works with distros that use Yum, so Rhel5 only, not Rhel4 –  Dave Cheney Feb 25 '10 at 20:12
2  
What happens if I don't know what repository has a package? For example a package might be available in the fedora repository on Fedora and in the epel repository on RHEL, CentOS etc. This means that if I use a 3rd party recipe/module I'll have to customize it. –  Cristian Ciupitu Jul 6 '11 at 0:36
add comment

You could use Tags. This would allow you to tag the repo installer with firstrun or something,

then run

 puppetd --tags firstrun

and it would only execute the modules/statements matching the tag.

share|improve this answer
    
This is exactly what I was looking for - thanks Tom! –  Jonathan Haddad Feb 12 '10 at 0:00
add comment

That's weird. Puppet make a song and dance about being so much better than cfengine at ordering operations. When I look at the puppet site, it looks like if you want to "make puppet do certain things" you have to start programming in ruby, otherwise it is completely uncertain what it will do. This solution seems pretty clunky compared to cf's bundlesequence. My money's still on cfengine 3 I have to say.

share|improve this answer
    
welcome to brave new world where system administration and software engineering are forever blended. –  monomyth Feb 17 '10 at 5:15
2  
You never addressed his question; the comment is irrelevant to the question and the discussion. –  Mei May 20 '11 at 18:11
    
This should have been a comment, not an answer. –  Cristian Ciupitu Jul 6 '11 at 0:50
    
Puppet is declarative, so it doesn't make claims about ordering anything. –  rox0r May 24 '12 at 1:39
add comment

The key thing you need to use is the require keyword - "Evaluate one or more classes, adding the required class as a dependency."

An example using an apt repository could be:

class installcustompackages {
   # make sure we have the repository file and public key
   file { "/etc/apt/sources.list.d/myrepo.list":
      source => "puppet://puppet/files/etc/apt/sources.list.d/myrepo.list",
      ensure => present;
          "/etc/apt/trusted.gpg":
      source => "puppet://puppet/files/etc/apt/trusted.gpg",
   }

   # do an update whenever the list or trusted key file change
   exec { "/usr/bin/apt-get update":
      alias => "aptgetupdate",
      require => [ File["/etc/apt/sources.list.d/myrepo.list"], File["/etc/apt/trusted.gpg"] ],
      subscribe => [ File["/etc/apt/sources.list.d/myrepo.list"], File["/etc/apt/trusted.gpg"] ],
      refreshonly => true;
   }

   package { "mypackage":
      ensure => latest,
      require => Exec["aptgetupdate"];
             "mypackage2":
      ensure => latest,
      require => Exec["aptgetupdate"];
   }

   service { "myservice":
      enable => false,
      require => Package[mypackage];
   }
}

(Adapted from this example of puppet bootstrapping).

So you can see how each stage requires that the previous one be done first. I'll leave you to work out how to apply this to yum as I'm not familiar with where it stores it's files.

share|improve this answer
add comment

Puppet reads the config from top to bottom, so if you include a class with the yum repo first in that class, this repo will be added before anything else.

If you use the require settings on a package, you will ensure that the required resource type is present before adding the package, as such:

node 'yournode.domain.com' {
   package { "bar": ensure => installed, require => Yumrepo["IUS"] }
   yumrepo { "IUS":
      baseurl => "http://dl.iuscommunity.org/pub/ius/stable/$operatingsystem/$operatingsystemrelease/$architecture",
      descr => "IUS Community repository",
      enabled => 1,
      gpgcheck => 0
   }
}

This code above will add the repo before adding the package.

share|improve this answer
8  
Puppet uses a declarative language, so it does not worry about the order of things in the file. Your first paragraph is wrong I'm afraid. The correct way to do this is to use the require keyword, which you have done in the second part. –  Hamish Downer Jul 12 '10 at 9:34
add comment

(I found this question after I replied almost the same.. so thought my answer applies here as well and it's worth repeating it (it's safer to have an answer in two places..)

As far as I understand, this is exactly what stages are for -- they let you group and order class executions. I use "stages" to update and configure APT at Debian servers, which should be very similar to what you are going to do with YUM.

First of all, you declare "yum" stage at top level (above "nodes"), so that classes in "yum" stage will be executed before "main" ones:

stage { 'yum' : before => Stage['main'] }

Then, you assign stage to the classes. You can do this right in your node definition:

node default {
  class { 'yumrepos' : stage => yum }

  include packages
}
share|improve this answer
    
Thanks for this :) I personally prefer this approach to the accepted answer. –  Michael Mior Mar 29 '13 at 12:23
add comment

Although stages can handle this and so can specific yum repo dependencies, better is to declare the relationship generically.

Just put Yumrepo <| |> -> Package <| provider != 'rpm' |> in your puppet manifest.

node default {
  Yumrepo <| |> -> Package <| provider != 'rpm' |>
}

This makes it so that all yumrepo types will get processed before any packages that don't have 'rpm' as their provider. That latter exclusion is so that I can use the (for example) epel-release RPM package to help install the yum repo.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.