Add support for signed-by in source entries
[puppet-modules/puppetlabs-apt.git] / manifests / source.pp
1 # @summary Manages the Apt sources in /etc/apt/sources.list.d/.
2 #
3 # @example Install the puppetlabs apt source
4 #   apt::source { 'puppetlabs':
5 #     location => 'http://apt.puppetlabs.com',
6 #     repos    => 'main',
7 #     key      => {
8 #       id     => '6F6B15509CF8E59E6E469F327F438280EF8D349F',
9 #       server => 'keyserver.ubuntu.com',
10 #     },
11 #   }
12 #
13 # @param location
14 #   Required, unless ensure is set to 'absent'. Specifies an Apt repository. Valid options: a string containing a repository URL.
15 #
16 # @param comment
17 #   Supplies a comment for adding to the Apt source file.
18 #
19 # @param ensure
20 #   Specifies whether the Apt source file should exist. Valid options: 'present' and 'absent'.
21 #
22 # @param release
23 #   Specifies a distribution of the Apt repository.
24 #
25 # @param repos
26 #   Specifies a component of the Apt repository.
27 #
28 # @param include
29 #   Configures include options. Valid options: a hash of available keys.
30 #
31 # @option include [Boolean] :deb
32 #   Specifies whether to request the distribution's compiled binaries. Default true.
33 #
34 # @option include [Boolean] :src
35 #   Specifies whether to request the distribution's uncompiled source code. Default false.
36 #
37 # @param key
38 #   Creates a declaration of the apt::key defined type. Valid options: a string to be passed to the `id` parameter of the `apt::key`
39 #   defined type, or a hash of `parameter => value` pairs to be passed to `apt::key`'s `id`, `server`, `content`, `source`, and/or
40 #   `options` parameters.
41 #
42 # @param keyring
43 #   Absolute path to a file containing the PGP keyring used to sign this repository. Value is used to set signed-by on the source entry.
44 #   See https://wiki.debian.org/DebianRepository/UseThirdParty for details.
45 #
46 # @param pin
47 #   Creates a declaration of the apt::pin defined type. Valid options: a number or string to be passed to the `id` parameter of the
48 #   `apt::pin` defined type, or a hash of `parameter => value` pairs to be passed to `apt::pin`'s corresponding parameters.
49 #
50 # @param architecture
51 #   Tells Apt to only download information for specified architectures. Valid options: a string containing one or more architecture names,
52 #   separated by commas (e.g., 'i386' or 'i386,alpha,powerpc'). Default: undef (if unspecified, Apt downloads information for all architectures
53 #   defined in the Apt::Architectures option).
54 #
55 # @param allow_unsigned
56 #   Specifies whether to authenticate packages from this release, even if the Release file is not signed or the signature can't be checked.
57 #
58 # @param notify_update
59 #   Specifies whether to trigger an `apt-get update` run.
60 #
61 define apt::source(
62   Optional[String] $location                    = undef,
63   String $comment                               = $name,
64   String $ensure                                = present,
65   Optional[String] $release                     = undef,
66   String $repos                                 = 'main',
67   Optional[Variant[Hash]] $include              = {},
68   Optional[Variant[String, Hash]] $key          = undef,
69   Optional[Stdlib::AbsolutePath] $keyring       = undef,
70   Optional[Variant[Hash, Numeric, String]] $pin = undef,
71   Optional[String] $architecture                = undef,
72   Boolean $allow_unsigned                       = false,
73   Boolean $notify_update                        = true,
74 ) {
75
76   include ::apt
77
78   $_before = Apt::Setting["list-${title}"]
79
80   if !$release {
81     if $facts['os']['distro']['codename'] {
82       $_release = $facts['os']['distro']['codename']
83     } else {
84       fail('os.distro.codename fact not available: release parameter required')
85     }
86   } else {
87     $_release = $release
88   }
89
90   if $ensure == 'present' {
91     if ! $location {
92       fail('cannot create a source entry without specifying a location')
93     }
94     elsif ($::apt::proxy['https_acng']) and ($location =~ /(?i:^https:\/\/)/) {
95       $_location = regsubst($location, 'https://','http://HTTPS///')
96     }
97     else {
98       $_location = $location
99     }
100     # Newer oses, do not need the package for HTTPS transport.
101     $_transport_https_releases = [ 'wheezy', 'jessie', 'stretch', 'trusty', 'xenial' ]
102     if ($facts['os']['distro']['codename'] in $_transport_https_releases) and $_location =~ /(?i:^https:\/\/)/ {
103       ensure_packages('apt-transport-https')
104     }
105   } else {
106     $_location = undef
107   }
108
109   $includes = merge($::apt::include_defaults, $include)
110
111   if $key and $keyring {
112     fail("parameters key and keyring are mutualy exclusive")
113   }
114
115   if $key {
116     if $key =~ Hash {
117       unless $key['id'] {
118         fail('key hash must contain at least an id entry')
119       }
120       $_key = merge($::apt::source_key_defaults, $key)
121     } else {
122       $_key = { 'id' => assert_type(String[1], $key) }
123     }
124   }
125
126   $header = epp('apt/_header.epp')
127
128   $sourcelist = epp('apt/source.list.epp', {
129     'comment'          => $comment,
130     'includes'         => $includes,
131     'options'          => delete_undef_values({
132       'arch'      => $architecture,
133       'trusted'   => $allow_unsigned ? {true => "yes", false => undef},
134       'signed-by' => $keyring,
135     }),
136     'location'         => $_location,
137     'release'          => $_release,
138     'repos'            => $repos,
139   })
140
141   apt::setting { "list-${name}":
142     ensure        => $ensure,
143     content       => "${header}${sourcelist}",
144     notify_update => $notify_update,
145   }
146
147   if $pin {
148     if $pin =~ Hash {
149       $_pin = merge($pin, { 'ensure' => $ensure, 'before' => $_before })
150     } elsif ($pin =~ Numeric or $pin =~ String) {
151       $url_split = split($location, '[:\/]+')
152       $host      = $url_split[1]
153       $_pin = {
154         'ensure'   => $ensure,
155         'priority' => $pin,
156         'before'   => $_before,
157         'origin'   => $host,
158       }
159     } else {
160       fail('Received invalid value for pin parameter')
161     }
162     create_resources('apt::pin', { "${name}" => $_pin })
163   }
164
165   # We do not want to remove keys when the source is absent.
166   if $key and ($ensure == 'present') {
167     if $_key =~ Hash {
168       if $_key['ensure'] != undef {
169         $_ensure = $_key['ensure']
170       } else {
171         $_ensure = $ensure
172       }
173
174       apt::key { "Add key: ${$_key['id']} from Apt::Source ${title}":
175         ensure  => $_ensure,
176         id      => $_key['id'],
177         server  => $_key['server'],
178         content => $_key['content'],
179         source  => $_key['source'],
180         options => $_key['options'],
181         before  => $_before,
182       }
183     }
184   }
185 }