Verwalten von PPAs mit Puppet

2 Minuten zum lesen

Mit dem von Puppet Labs zur Verfügung gestellten Apt Modul werden PPAs (personal package archive) nur experimentell unterstützt. Daher habe ich mir für das Einbinden und Entfernen von PPAs in meine Ubuntu Konfiguration selbst zwei Defines / benutzerdefinierte Ressourcen erstellt. Das erste Define kümmert sich um die Integration des eigentlichen PPA in die Paketverwaltung. Das zweites Define dient zur Verwaltung des zugehörigen Zertifikats zur Überprüfung der Pakete.

Das Define zur Verwaltung des eigentlichen PPA (pparepo) handhabt die .list Datei im Verzeichnis /etc/apt/sources.list.d/ für das Repository. Ich lege mir für jedes verwaltete PPA eine eigene Datei mit dem Namen des PPA als Name der .list Datei an. Das Define kümmert sich nach dem Hinzufügen bzw. Entfernen der .list Datei auch darum, dass mittels apt-get update auch die Paketverwaltung von der Änderung erfährt.

define pparepo(
  $ensure = present,
  $apt_key = '',
  $comment = '',
  $dist = $lsbdistcodename,
  $supported = ['maverick', 'lucid', 'oneiric', 'precise'],
  $keyserver = 'keyserver.ubuntu.com'
) {
  $ppa_file_name = regsubst($name, '/', '-', 'G')
  $file = "/etc/apt/sources.list.d/pparepo-${ppa_file_name}.list"



  file { "${file}":
  }

  case $ensure {
    present: {
      if ($dist) and ($dist in $supported) {
        File["${file}"] {
          ensure  => file,
          content => "deb http://ppa.launchpad.net/$name/ubuntu ${dist} main #${comment}\n"
        }
        if ( $apt_key ) {
          apt-defines::key { "${apt_key}":
            keyserver => $keyserver
          }
        }
      }
      else {
        File["${file}"] {
          ensure => false
        }
      }
    }
    absent:  {
      File["${file}"] {
        ensure => false
      }
    }
    default: {
      fail "Invalid 'ensure' value '${ensure}' for pparepo"
    }
  }

  exec { "update apt repositories for $name":
    path        => '/bin:/usr/bin',
    environment => 'HOME=/root',
    command     => 'apt-get update',
    user        => 'root',
    group       => 'root',
    logoutput   => on_failure,
    subscribe   => File["${file}"],
    refreshonly => true,
  }



  if ( $apt_key ) {
    Exec["update apt repositories for $name"] {
      require => Apt-defines::Key["${apt_key}"],
    }
  }
}

Steht für das PPA ein Zertifikat zur Verfügung, wird vom pparepo Define das ppakey Define als Abhängigkeit gesetzt. Das Define für die Handhabung des Zertifikats ruft das Kommando apt-key zum Hinzufügen bzw. Entfernen des Zertifikats auf. Das Zertifikat wird hierzu mittels gpg vom Key-Server abgerufen.

define ppakey(
  $ensure = present,
  $keyserver = 'keyserver.ubuntu.com'
) {
  case $ensure {
    present: {
      exec { "Import ${name} to apt keystore":
        path        => '/bin:/usr/bin',
        environment => 'HOME=/root',
        command     => "gpg --keyserver ${keyserver} --recv-keys $name && gpg --export --armor ${name} | apt-key add -",
        user        => 'root',
        group       => 'root',
        unless      => "apt-key list | grep ${name}",
        logoutput   => on_failure,
      }
    }
    absent:  {
      exec { "Remove ${name} from apt keystore":
        path        => '/bin:/usr/bin',
        environment => 'HOME=/root',
        command     => "apt-key del ${name}",
        user        => 'root',
        group       => 'root',
        onlyif      => "apt-key list | grep ${name}",
      }
    }
    default: {
      fail "Invalid 'ensure' value '${ensure}' for ppakey"
    }
  }
}

Möchte man ein Paket aus einem PPA installieren, fügt man in dem Modul die Resource pparepo hinzu. Die eigentlichen Pakete haben dann eine Abhängigkeit zu diesem pparepo, um sicher zu stellen, dass auf jeden Fall erst die PPA Definition eingebunden wird.

class example {
  pparepo { 'blueyed/ppa':
    apt_key => '7CC17CD2',
  }

  package { 'example':
    ensure  => present,
    require => Pparepo["blueyed/ppa"],
  }
}

Ich habe mit diesen beiden Defines bereits einige PPAs zu meiner Standard Ubuntu Konfiguration hinzugefügt. Nach der Grundinstallation kann ich nun mit einem Puppet-Lauf meine eigene Konfiguration anwenden lassen.