Recipe for Mixing In Multiple apt Repositories

Our situation: local mirrors of Debian and Ubuntu repositories in /debian and /ubuntu directory trees. Debian security repository mirrored in /debian-security. Local apt repository of commercial software packaged in .deb format for easier deployment. Occasional need to bring in packages from backports, debian-multimedia, or other offshoot repositories.

Proposed Solution

Instead of having one sources.list for each node, replace it with files in the sources.list.d folder, one file per repository/component combination. Automatically rerun ‘apt-get update’ after each file change.

Core Classes and Definitions

class apt_defaults {
  case $operatingsystem {
    debian: {

      $apt_dir = "/root/etc/apt"
      $sources_dir = "${apt_dir}/sources.list.d"

      exec { "apt-update":
        command     => "/usr/bin/apt-get update",
        refreshonly => true;
      }
      cron { "apt-update":
        command => "/usr/bin/apt-get update",
        user    => root,
        hour    => 22,
        minute  => 0;
      }
      # I don't want kernel upgrades to happen automatically, since I need to schedule
      # reboots around others' work:
      exec { "hold-kernels":
        command => "for name in `dpkg --get-selections | grep linux-image | grep -v hold | awk '{print \$1}'`; do echo \$name hold | dpkg --set-selections; done",
        onlyif  => "dpkg --get-selections | grep linux-image | grep -q install"
      }

      file {
        "sources.list.d":
          path     => "${sources_dir}",
          ensure   => directory,
          checksum => md5,
          owner    => root,
          group    => root,
          mode     => 0755;
        "${apt_dir}/sources.list":
          ensure => absent;
      }
    }
    default: {
      err("apt_defaults class is for Debian-derived systems.")
      err("${fqdn} runs ${operatingsystem}.")
    }
  }
}

define aptrepo (
  $apt_dir = "${apt_defaults::apt_dir}",
  $sources_dir = "${apt_defaults::sources_dir}",
  $source_type = "deb",
  $uri = "http://ftpmirror.our.domain/${lsbdistid}/",
  $distribution = "${lsbdistcodename}",
  $component = "main"
) {
  file {
    "aptrepo_${name}":
      path => "${sources_dir}/${name}",
      content => "${source_type} ${uri} ${distribution} ${component}\n",
      owner   => root,
      group   => root,
      mode    => 0644,
      ensure  => present,
      notify  => Exec["apt-update"];
  }
}

Example Repository Definitions

class apt_main {
# Debian -- deb http://ftpmirror.our.domain/debian/ etch main
# Ubuntu -- deb http://ftpmirror.our.domain/ubuntu/ feisty main
  include apt_defaults
  case $operatingsystem {
    debian: {
      aptrepo {
        "main.list":
          component => "main",
      }
    }
    default: {
      err("apt_main class is for Debian-derived systems.")
      err("${fqdn} runs ${operatingsystem}.")
    }
  }
}

class apt_contrib {
# Debian -- deb http://ftpmirror.our.domain/debian/ etch contrib
  include apt_defaults
  case $lsbdistid {
    debian: {
      aptrepo {
        "contrib.list":
          component => "contrib",
      }
    }
    default: {
      err("apt_contrib class is for Debian systems.")
      err("${fqdn} runs ${lsbdistid}.")
    }
  }
}

class apt_main_security {
# Debian -- deb http://ftpmirror.our.domain/debian-security etch/updates main
# Ubuntu -- deb http://ftpmirror.our.domain/ubuntu feisty-security main
  include apt_defaults
  case $operatingsystem {
    debian: {
      aptrepo {
        "main_security.list":
          uri       => $lsbdistid ? {
            "debian" => "http://ftpmirror.our.domain/debian-security/",
            "ubuntu" => "http://ftpmirror.our.domain/ubuntu",
          },
          distribution => $lsbdistid ? {
            "debian" => "${lsbdistcodename}/updates",
            "ubuntu" => "${lsbdistcodename}-security",
          },
          component =>  "main",
      }
    }
    default: {
      err("apt_main_security class is for Debian-derived systems.")
      err("${fqdn} runs ${operatingsystem}.")
    }
  }
}

Ubuntu

On Ubuntu change the source dir:

  $apt_dir = "/etc/apt"

Also the files saved have to end in “.list” so change the file creation definition in the aptrepo command to:

  path => "${sources_dir}/${name}.list",