Switch using os.release.major for apt-transport-https
[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`, `weak_ssl`,
40 #   and/or `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 $allow_insecure                       = false,
74   Boolean $notify_update                        = true,
75 ) {
76
77   include ::apt
78
79   $_before = Apt::Setting["list-${title}"]
80
81   if !$release {
82     if fact('os.distro.codename') {
83       $_release = fact('os.distro.codename')
84     } else {
85       fail('os.distro.codename fact not available: release parameter required')
86     }
87   } else {
88     $_release = $release
89   }
90
91   if $ensure == 'present' {
92     if ! $location {
93       fail('cannot create a source entry without specifying a location')
94     }
95     elsif ($::apt::proxy['https_acng']) and ($location =~ /(?i:^https:\/\/)/) {
96       $_location = regsubst($location, 'https://','http://HTTPS///')
97     }
98     else {
99       $_location = $location
100     }
101     # Newer oses, do not need the package for HTTPS transport.
102     $_transport_https_releases = [ '7', '8', '9', '14.04', '16.04' ]
103     if (fact('os.release.major') in $_transport_https_releases) and $_location =~ /(?i:^https:\/\/)/ {
104       ensure_packages('apt-transport-https')
105       Package['apt-transport-https'] -> Class['apt::update']
106     }
107   } else {
108     $_location = undef
109   }
110
111   $includes = merge($::apt::include_defaults, $include)
112
113   if $key and $keyring {
114     fail("parameters key and keyring are mutualy exclusive")
115   }
116
117   if $key {
118     if $key =~ Hash {
119       unless $key['id'] {
120         fail('key hash must contain at least an id entry')
121       }
122       $_key = merge($::apt::source_key_defaults, $key)
123     } else {
124       $_key = { 'id' => assert_type(String[1], $key) }
125     }
126   }
127
128   $header = epp('apt/_header.epp')
129
130   if $architecture {
131     $_architecture = regsubst($architecture, '\baarch64\b', 'arm64')
132   } else {
133     $_architecture = undef
134   }
135
136   $sourcelist = epp('apt/source.list.epp', {
137     'comment'          => $comment,
138     'includes'         => $includes,
139     'options'          => delete_undef_values({
140       'arch'           => $architecture,
141       'trusted'        => $allow_unsigned ? {true => "yes", false => undef},
142       'allow-insecure' => $allow_insecure ? {true => "yes", false => undef},
143       'signed-by'      => $keyring,
144     }),
145     'location'         => $_location,
146     'release'          => $_release,
147     'repos'            => $repos,
148   })
149
150   apt::setting { "list-${name}":
151     ensure        => $ensure,
152     content       => "${header}${sourcelist}",
153     notify_update => $notify_update,
154   }
155
156   if $pin {
157     if $pin =~ Hash {
158       $_pin = merge($pin, { 'ensure' => $ensure, 'before' => $_before })
159     } elsif ($pin =~ Numeric or $pin =~ String) {
160       $url_split = split($location, '[:\/]+')
161       $host      = $url_split[1]
162       $_pin = {
163         'ensure'   => $ensure,
164         'priority' => $pin,
165         'before'   => $_before,
166         'origin'   => $host,
167       }
168     } else {
169       fail('Received invalid value for pin parameter')
170     }
171     create_resources('apt::pin', { "${name}" => $_pin })
172   }
173
174   # We do not want to remove keys when the source is absent.
175   if $key and ($ensure == 'present') {
176     if $_key =~ Hash {
177       if $_key['ensure'] != undef {
178         $_ensure = $_key['ensure']
179       } else {
180         $_ensure = $ensure
181       }
182
183       apt::key { "Add key: ${$_key['id']} from Apt::Source ${title}":
184         ensure   => $_ensure,
185         id       => $_key['id'],
186         server   => $_key['server'],
187         content  => $_key['content'],
188         source   => $_key['source'],
189         options  => $_key['options'],
190         weak_ssl => $_key['weak_ssl'],
191         before   => $_before,
192       }
193     }
194   }
195 }