title: Puppet - How to only run 'apt-get update' if a package needs to be installed or updated
body: <h1>I can't seem to figure out how to get Puppet to not run 'apt-get update' during every run.</h1>
  
  <hr>
  
  <h2>The standard yet inefficient way:</h2>
  
  <p>The way I've been doing this is with the main Puppet manifest having:</p>
  
  <pre><code>exec { 'apt-get update':
    path =&gt; '/usr/bin',
  }
  </code></pre>
  
  <p>Then each subsequent module that needs a package installed has:</p>
  
  <pre><code>package { 'nginx':
    ensure =&gt; 'present',
    require =&gt; Exec['apt-get update'],
  }
  </code></pre>
  
  <p>The problem with this is that, every time Puppet runs, Apt gets updated. This puts unnecessary load on our systems and network.</p>
  
  <hr>
  
  <h2>The solution I tried, but fails:</h2>
  
  <p>I looked in the Puppet docs and read about <code>subscribe</code> and <code>refreshonly</code>.</p>
  
  <blockquote>
    <p><strong>Refresh</strong>: exec resources can respond to refresh events (via notify, subscribe, or the ~> arrow). The refresh behavior of execs is non-standard, and can be affected by the refresh and refreshonly attributes:</p>
    
    <ul>
    <li>If <strong>refreshonly</strong> is set to true, the exec will only run when it receives an event. This is the most reliable way to use refresh with execs.</li>
    </ul>
    
    <p><strong>subscribe</strong></p>
    
    <p>One or more resources that this resource depends on, expressed as resource references. Multiple resources can be specified as an array of references. When this attribute is present:</p>
    
    <ul>
    <li>The subscribed resource(s) will be applied before this resource.</li>
    </ul>
  </blockquote>
  
  <p>so I tried this in the main Puppet manifest:</p>
  
  <pre><code># Setup this exec type to be used later.
  # Only gets run when needed via "subscribe" calls when installing packages.
  exec { 'apt-get update':
    path =&gt; '/usr/bin',
    refreshonly =&gt; true,
  }
  </code></pre>
  
  <p>Then this in the module manifests:</p>
  
  <pre><code># Ensure that Nginx is installed.
  package { 'nginx':
    ensure =&gt; 'present',
    subscribe =&gt; Exec['apt-get update'],
  }
  </code></pre>
  
  <p>But this fails because <code>apt-get update</code> doesn't get run before installing Nginx, so Apt can't find it.</p>
  
  <hr>
  
  <p>Surely this is something others have encountered? What's the best way to solve this?</p>