diff --git a/README.md b/README.md
index 44cd89d05c..feb82889fe 100644
--- a/README.md
+++ b/README.md
@@ -225,6 +225,27 @@ apt::source { 'puppetlabs':
+### Generating a DEB822 .sources file
+
+You can also generate a DEB822 format .sources file. This example covers most of the available options.
+
+Use the `source_format` parameter to choose between 'list' and 'sources' (DEB822) formats.
+```puppet
+apt::source { 'debian':
+ source_format => 'sources'
+ comment => 'Official Debian Repository',
+ enabled => true,
+ types => ['deb', 'deb-src'],
+ location => ['http://fr.debian.org/debian', 'http://de.debian.org/debian']
+ release => ['stable', 'stable-updates', 'stable-backports'],
+ repos => ['main', 'contrib', 'non-free'],
+ architecture => ['amd64', 'i386'],
+ allow_unsigned => true,
+ keyring => '/etc/apt/keyrings/debian.gpg'
+ notify_update => false
+}
+```
+
### Configure Apt from Hiera
Instead of specifying your sources directly as resources, you can instead just include the `apt` class, which will pick up the values automatically from hiera.
diff --git a/REFERENCE.md b/REFERENCE.md
index 980848ac4e..08dd08a356 100644
--- a/REFERENCE.md
+++ b/REFERENCE.md
@@ -402,6 +402,10 @@ Default value:
'path' => $sources_list_d,
'ext' => '.list',
},
+ 'sources' => {
+ 'path' => $sources_list_d,
+ 'ext' => '.sources',
+ },
}
```
@@ -1088,11 +1092,25 @@ apt::source { 'puppetlabs':
}
```
+##### Install the puppetlabs apt source (deb822 format)
+
+```puppet
+apt::source { 'puppetlabs':
+ source_format => 'sources'
+ location => ['http://apt.puppetlabs.com'],
+ repos => ['puppet8'],
+ keyring => '/etc/apt/keyrings/puppetlabs.gpg',
+}
+```
+
#### Parameters
The following parameters are available in the `apt::source` defined type:
+* [`source_format`](#-apt--source--source_format)
* [`location`](#-apt--source--location)
+* [`types`](#-apt--source--types)
+* [`enabled`](#-apt--source--enabled)
* [`comment`](#-apt--source--comment)
* [`ensure`](#-apt--source--ensure)
* [`release`](#-apt--source--release)
@@ -1107,14 +1125,39 @@ The following parameters are available in the `apt::source` defined type:
* [`notify_update`](#-apt--source--notify_update)
* [`check_valid_until`](#-apt--source--check_valid_until)
+##### `source_format`
+
+Data type: `Enum['list', 'sources']`
+
+The file format to use for the apt source. See https://wiki.debian.org/SourcesList
+
+Default value: `'list'`
+
##### `location`
-Data type: `Optional[String[1]]`
+Data type: `Optional[Variant[String[1], Array[String[1]]]]`
-Required, unless ensure is set to 'absent'. Specifies an Apt repository.
+Required, unless ensure is set to 'absent'. Specifies an Apt repository. Valid options: a string containing a repository URL.
+DEB822: Supports an array of URL values
Default value: `undef`
+##### `types`
+
+Data type: `Array[Enum['deb','deb-src'], 1, 2]`
+
+DEB822: The package types this source manages.
+
+Default value: `['deb']`
+
+##### `enabled`
+
+Data type: `Boolean`
+
+DEB822: Enable or Disable the APT source.
+
+Default value: `true`
+
##### `comment`
Data type: `String[1]`
@@ -1133,17 +1176,19 @@ Default value: `present`
##### `release`
-Data type: `Optional[String[0]]`
+Data type: `Optional[Variant[String[0], Array[String[0]]]]`
Specifies a distribution of the Apt repository.
+DEB822: Supports an array of values
Default value: `undef`
##### `repos`
-Data type: `String[1]`
+Data type: `Variant[String[1], Array[String[1]]]`
Specifies a component of the Apt repository.
+DEB822: Supports an array of values
Default value: `'main'`
@@ -1194,29 +1239,30 @@ Default value: `undef`
##### `architecture`
-Data type: `Optional[String[1]]`
+Data type: `Optional[Variant[String[1], Array[String[1]]]]`
Tells Apt to only download information for specified architectures. Valid options: a string containing one or more architecture names,
separated by commas (e.g., 'i386' or 'i386,alpha,powerpc').
(if unspecified, Apt downloads information for all architectures defined in the Apt::Architectures option)
+DEB822: Supports an array of values
Default value: `undef`
##### `allow_unsigned`
-Data type: `Boolean`
+Data type: `Optional[Boolean]`
Specifies whether to authenticate packages from this release, even if the Release file is not signed or the signature can't be checked.
-Default value: `false`
+Default value: `undef`
##### `allow_insecure`
-Data type: `Boolean`
+Data type: `Optional[Boolean]`
Specifies whether to allow downloads from insecure repositories.
-Default value: `false`
+Default value: `undef`
##### `notify_update`
@@ -1228,11 +1274,11 @@ Default value: `true`
##### `check_valid_until`
-Data type: `Boolean`
+Data type: `Optional[Boolean]`
Specifies whether to check if the package release date is valid.
-Default value: `true`
+Default value: `undef`
## Data types
diff --git a/manifests/init.pp b/manifests/init.pp
index a1b06fbb81..55b38ed085 100644
--- a/manifests/init.pp
+++ b/manifests/init.pp
@@ -213,6 +213,10 @@
'path' => $sources_list_d,
'ext' => '.list',
},
+ 'sources' => {
+ 'path' => $sources_list_d,
+ 'ext' => '.sources',
+ },
},
Boolean $sources_list_force = false,
Hash $source_key_defaults = {
diff --git a/manifests/setting.pp b/manifests/setting.pp
index 46b347d96a..f057d1aa2a 100644
--- a/manifests/setting.pp
+++ b/manifests/setting.pp
@@ -40,8 +40,8 @@
$setting_type = $title_array[0]
$base_name = join(delete_at($title_array, 0), '-')
- assert_type(Pattern[/\Aconf\z/, /\Apref\z/, /\Alist\z/], $setting_type) |$a, $b| {
- fail("apt::setting resource name/title must start with either 'conf-', 'pref-' or 'list-'")
+ assert_type(Pattern[/\Aconf\z/, /\Apref\z/, /\Alist\z/, /\Asources\z/], $setting_type) |$a, $b| {
+ fail("apt::setting resource name/title must start with either 'conf-', 'pref-', 'list-', or 'sources-'")
}
if $priority !~ Integer {
@@ -51,7 +51,7 @@
}
}
- if ($setting_type == 'list') or ($setting_type == 'pref') {
+ if $setting_type in ['list', 'pref', 'sources'] {
$_priority = ''
} else {
$_priority = $priority
diff --git a/manifests/source.pp b/manifests/source.pp
index e7986697c3..70191993f7 100644
--- a/manifests/source.pp
+++ b/manifests/source.pp
@@ -21,8 +21,26 @@
# },
# }
#
+# @example Install the puppetlabs apt source (deb822 format)
+# apt::source { 'puppetlabs':
+# source_format => 'sources'
+# location => ['http://apt.puppetlabs.com'],
+# repos => ['puppet8'],
+# keyring => '/etc/apt/keyrings/puppetlabs.gpg',
+# }
+#
+# @param source_format
+# The file format to use for the apt source. See https://wiki.debian.org/SourcesList
+#
# @param location
-# Required, unless ensure is set to 'absent'. Specifies an Apt repository.
+# Required, unless ensure is set to 'absent'. Specifies an Apt repository. Valid options: a string containing a repository URL.
+# DEB822: Supports an array of URL values
+#
+# @param types
+# DEB822: The package types this source manages.
+#
+# @param enabled
+# DEB822: Enable or Disable the APT source.
#
# @param comment
# Supplies a comment for adding to the Apt source file.
@@ -32,9 +50,11 @@
#
# @param release
# Specifies a distribution of the Apt repository.
+# DEB822: Supports an array of values
#
# @param repos
# Specifies a component of the Apt repository.
+# DEB822: Supports an array of values
#
# @param include
# Configures include options. Valid options: a hash of available keys.
@@ -66,6 +86,7 @@
# Tells Apt to only download information for specified architectures. Valid options: a string containing one or more architecture names,
# separated by commas (e.g., 'i386' or 'i386,alpha,powerpc').
# (if unspecified, Apt downloads information for all architectures defined in the Apt::Architectures option)
+# DEB822: Supports an array of values
#
# @param allow_unsigned
# Specifies whether to authenticate packages from this release, even if the Release file is not signed or the signature can't be checked.
@@ -80,177 +101,269 @@
# Specifies whether to check if the package release date is valid.
#
define apt::source (
- Optional[String[1]] $location = undef,
+ Enum['list', 'sources'] $source_format = 'list',
+ Array[Enum['deb','deb-src'], 1, 2] $types = ['deb'],
+ Optional[Variant[String[1], Array[String[1]]]] $location = undef,
String[1] $comment = $name,
+ Boolean $enabled = true, # deb822
Enum['present', 'absent'] $ensure = present,
- Optional[String[0]] $release = undef,
- String[1] $repos = 'main',
+ Optional[Variant[String[0], Array[String[0]]]] $release = undef,
+ Variant[String[1], Array[String[1]]] $repos = 'main',
Hash $include = {},
Optional[Variant[String[1], Hash]] $key = undef,
Optional[Stdlib::AbsolutePath] $keyring = undef,
Optional[Variant[Hash, Integer, String[1]]] $pin = undef,
- Optional[String[1]] $architecture = undef,
- Boolean $allow_unsigned = false,
- Boolean $allow_insecure = false,
+ Optional[Variant[String[1], Array[String[1]]]] $architecture = undef,
+ Optional[Boolean] $allow_unsigned = undef,
+ Optional[Boolean] $allow_insecure = undef,
+ Optional[Boolean] $check_valid_until = undef,
Boolean $notify_update = true,
- Boolean $check_valid_until = true,
) {
include apt
$_before = Apt::Setting["list-${title}"]
- if !$release {
- if fact('os.distro.codename') {
- $_release = fact('os.distro.codename')
- } else {
- fail('os.distro.codename fact not available: release parameter required')
- }
- } else {
- $_release = $release
- }
+ case $source_format {
+ 'list': {
+ $_file_suffix = $source_format
- if $release =~ Pattern[/\/$/] {
- $_components = $_release
- } else {
- $_components = "${_release} ${repos}"
- }
+ if !$release {
+ if fact('os.distro.codename') {
+ $_release = fact('os.distro.codename')
+ } else {
+ fail('os.distro.codename fact not available: release parameter required')
+ }
+ } else {
+ $_release = $release
+ }
- if $ensure == 'present' {
- if ! $location {
- fail('cannot create a source entry without specifying a location')
- }
- elsif ($apt::proxy['https_acng']) and ($location =~ /(?i:^https:\/\/)/) {
- $_location = regsubst($location, 'https://','http://HTTPS///')
- }
- else {
- $_location = $location
- }
- } else {
- $_location = undef
- }
+ if $release =~ Pattern[/\/$/] {
+ $_components = $_release
+ } else {
+ $_components = "${_release} ${repos}"
+ }
- $includes = $apt::include_defaults + $include
+ if $ensure == 'present' {
+ if ! $location {
+ fail('cannot create a source entry without specifying a location')
+ }
+ elsif ($apt::proxy['https_acng']) and ($location =~ /(?i:^https:\/\/)/) {
+ $_location = regsubst($location, 'https://','http://HTTPS///')
+ }
+ else {
+ $_location = $location
+ }
+ } else {
+ $_location = undef
+ }
- if $keyring {
- if $key {
- fail('parameters key and keyring are mutually exclusive')
- } else {
- $_list_keyring = $keyring
- }
- } elsif $key {
- if $key =~ Hash {
- unless $key['name'] or $key['id'] {
- fail('key hash must contain a key name (for apt::keyring) or an id (for apt::key)')
+ $includes = $apt::include_defaults + $include
+
+ if $keyring {
+ if $key {
+ fail('parameters key and keyring are mutually exclusive')
+ } else {
+ $_list_keyring = $keyring
+ }
+ } elsif $key {
+ if $key =~ Hash {
+ unless $key['name'] or $key['id'] {
+ fail('key hash must contain a key name (for apt::keyring) or an id (for apt::key)')
+ }
+ if $key['id'] {
+ # defaults like keyserver are only relevant to apt::key
+ $_key = $apt::source_key_defaults + $key
+ } else {
+ $_key = $key
+ }
+ } else {
+ $_key = { 'id' => assert_type(String[1], $key) }
+ }
+ if $_key['ensure'] {
+ $_key_ensure = $_key['ensure']
+ } else {
+ $_key_ensure = $ensure
+ }
+
+ # Old keyserver keys handled by apt-key
+ if $_key =~ Hash and $_key['id'] {
+ # We do not want to remove keys when the source is absent.
+ if $ensure == 'present' {
+ apt::key { "Add key: ${$_key['id']} from Apt::Source ${title}":
+ ensure => $_key_ensure,
+ id => $_key['id'],
+ server => $_key['server'],
+ content => $_key['content'],
+ source => $_key['source'],
+ options => $_key['options'],
+ weak_ssl => $_key['weak_ssl'],
+ before => $_before,
+ }
+ }
+ $_list_keyring = undef
+ }
+ # Modern apt keyrings
+ elsif $_key =~ Hash and $_key['name'] {
+ apt::keyring { $_key['name']:
+ ensure => $_key_ensure,
+ content => $_key['content'],
+ source => $_key['source'],
+ dir => $_key['dir'],
+ filename => $_key['filename'],
+ mode => $_key['mode'],
+ before => $_before,
+ }
+
+ $_list_keyring = if $_key['dir'] and $_key['filename'] {
+ "${_key['dir']}${_key['filename']}"
+ } elsif $_key['filename'] {
+ "/etc/apt/keyrings/${_key['filename']}"
+ } elsif $_key['dir'] {
+ "${_key['dir']}${_key['name']}"
+ } else {
+ "/etc/apt/keyrings/${_key['name']}"
+ }
+ }
+ } else {
+ # No `key` nor `keyring` provided
+ $_list_keyring = undef
}
- if $key['id'] {
- # defaults like keyserver are only relevant to apt::key
- $_key = $apt::source_key_defaults + $key
+
+ $header = epp('apt/_header.epp')
+
+ if $architecture {
+ $_architecture = regsubst($architecture, '\baarch64\b', 'arm64')
} else {
- $_key = $key
+ $_architecture = undef
+ }
+
+ $source_content = epp('apt/source.list.epp', {
+ 'comment' => $comment,
+ 'includes' => $includes,
+ 'options' => delete_undef_values({
+ 'arch' => $_architecture,
+ 'trusted' => $allow_unsigned ? { true => 'yes', false => undef, default => undef },
+ 'allow-insecure' => $allow_insecure ? { true => 'yes', false => undef, default => undef },
+ 'signed-by' => $_list_keyring,
+ 'check-valid-until' => $check_valid_until? { true => undef, false => 'false', default => undef },
+ },
+ ),
+ 'location' => $_location,
+ 'components' => $_components,
+ }
+ )
+
+ if $pin {
+ if $pin =~ Hash {
+ $_pin = $pin + { 'ensure' => $ensure, 'before' => $_before }
+ } elsif ($pin =~ Numeric or $pin =~ String) {
+ $url_split = split($location, '[:\/]+')
+ $host = $url_split[1]
+ $_pin = {
+ 'ensure' => $ensure,
+ 'priority' => $pin,
+ 'before' => $_before,
+ 'origin' => $host,
+ }
+ } else {
+ fail('Received invalid value for pin parameter')
+ }
+
+ apt::pin { $name:
+ * => $_pin,
+ }
}
- } else {
- $_key = { 'id' => assert_type(String[1], $key) }
- }
- if $_key['ensure'] {
- $_key_ensure = $_key['ensure']
- } else {
- $_key_ensure = $ensure
}
+ 'sources': {
+ $_file_suffix = $source_format
- # Old keyserver keys handled by apt-key
- if $_key =~ Hash and $_key['id'] {
- # We do not want to remove keys when the source is absent.
+ if $pin {
+ warning("'pin' parameter is not supported with deb822 format.")
+ }
+ if $key {
+ warning("'key' parameter is not supported with deb822 format.")
+ }
if $ensure == 'present' {
- apt::key { "Add key: ${$_key['id']} from Apt::Source ${title}":
- ensure => $_key_ensure,
- id => $_key['id'],
- server => $_key['server'],
- content => $_key['content'],
- source => $_key['source'],
- options => $_key['options'],
- weak_ssl => $_key['weak_ssl'],
- before => $_before,
+ if ! $location {
+ fail('cannot create a source entry without specifying a location')
}
}
- $_list_keyring = undef
- }
- # Modern apt keyrings
- elsif $_key =~ Hash and $_key['name'] {
- apt::keyring { $_key['name']:
- ensure => $_key_ensure,
- content => $_key['content'],
- source => $_key['source'],
- dir => $_key['dir'],
- filename => $_key['filename'],
- mode => $_key['mode'],
- before => $_before,
+ if (type($location, 'generalized') !~ Type[Array]) {
+ warning('For deb822 sources, location must be specified as an array.')
+ $_location = [$location]
+ }
+ else {
+ $_location = $location
}
- $_list_keyring = if $_key['dir'] and $_key['filename'] {
- "${_key['dir']}${_key['filename']}"
- } elsif $_key['filename'] {
- "/etc/apt/keyrings/${_key['filename']}"
- } elsif $_key['dir'] {
- "${_key['dir']}${_key['name']}"
+ if !$release {
+ if fact('os.distro.codename') {
+ $_release = [fact('os.distro.codename')]
+ } else {
+ fail('os.distro.codename fact not available: release parameter required')
+ }
} else {
- "/etc/apt/keyrings/${_key['name']}"
+ if (type($release, 'generalized') !~ Type[Array]) {
+ warning("For deb822 sources, 'release' must be specified as an array. Converting to array.")
+ $_release = [$release]
+ } else {
+ $_release = $release
+ }
}
- }
- } else {
- # No `key` nor `keyring` provided
- $_list_keyring = undef
- }
-
- $header = epp('apt/_header.epp')
-
- if $architecture {
- $_architecture = regsubst($architecture, '\baarch64\b', 'arm64')
- } else {
- $_architecture = undef
- }
-
- $sourcelist = epp('apt/source.list.epp',
- {
- 'comment' => $comment,
- 'includes' => $includes,
- 'options' => delete_undef_values(
- {
- 'arch' => $_architecture,
- 'trusted' => $allow_unsigned ? { true => 'yes', false => undef },
- 'allow-insecure' => $allow_insecure ? { true => 'yes', false => undef },
- 'signed-by' => $_list_keyring,
- 'check-valid-until' => $check_valid_until? { true => undef, false => 'false' },
- },
- ),
- 'location' => $_location,
- 'components' => $_components,
- },
- )
- apt::setting { "list-${name}":
- ensure => $ensure,
- content => "${header}${sourcelist}",
- notify_update => $notify_update,
- }
+ if (type($repos, 'generalized') !~ Type[Array]) {
+ warning("For deb822 sources, 'repos' must be specified as an array. Converting to array.")
+ $_repos = split($repos, /\s+/)
+ } else {
+ $_repos = $repos
+ }
- if $pin {
- if $pin =~ Hash {
- $_pin = $pin + { 'ensure' => $ensure, 'before' => $_before }
- } elsif ($pin =~ Numeric or $pin =~ String) {
- $url_split = split($location, '[:\/]+')
- $host = $url_split[1]
- $_pin = {
- 'ensure' => $ensure,
- 'priority' => $pin,
- 'before' => $_before,
- 'origin' => $host,
+ if $architecture != undef {
+ if (type($architecture, 'generalized') !~ Type[Array]) {
+ warning("For deb822 sources, 'architecture' must be specified as an array. Converting to array.")
+ $_architecture = split($architecture, '[,]')
+ }
+ else {
+ $_architecture = $architecture
+ }
+ } else {
+ $_architecture = $architecture
+ }
+ case $ensure {
+ 'present': {
+ $header = epp('apt/_header.epp')
+ $source_content = epp('apt/source_deb822.epp', delete_undef_values({
+ 'uris' => $_location,
+ 'suites' => $_release,
+ 'components' => $_repos,
+ 'types' => $types,
+ 'comment' => $comment,
+ 'enabled' => $enabled ? { true => 'yes', false => 'no' },
+ 'architectures' => $_architecture,
+ 'allow_insecure' => $allow_insecure ? { true => 'yes', false => 'no', default => undef },
+ 'repo_trusted' => $allow_unsigned ? { true => 'yes', false => 'no', default => undef },
+ 'check_valid_until' => $check_valid_until ? { true => 'yes', false => 'no', default => undef },
+ 'signed_by' => $keyring,
+ }
+ )
+ )
+ }
+ 'absent': {
+ $header = undef
+ $source_content = undef
+ }
+ default: {
+ fail('Unexpected value for $ensure parameter.')
+ }
}
- } else {
- fail('Received invalid value for pin parameter')
}
-
- apt::pin { $name:
- * => $_pin,
+ default: {
+ fail("Unexpected APT source format: ${source_format}")
}
}
+ apt::setting { "${_file_suffix}-${name}":
+ ensure => $ensure,
+ content => "${header}${source_content}",
+ notify_update => $notify_update,
+ }
}
diff --git a/spec/defines/source_spec.rb b/spec/defines/source_spec.rb
index 5268c03a04..9c619439c0 100644
--- a/spec/defines/source_spec.rb
+++ b/spec/defines/source_spec.rb
@@ -416,4 +416,69 @@
it { is_expected.to contain_apt__setting("list-#{title}").with_notify_update(false) }
end
end
+
+ describe 'deb822 sources' do
+ let :params do
+ {
+ source_format: 'sources',
+ }
+ end
+
+ context 'basic deb822 source' do
+ let :params do
+ super().merge(
+ {
+ location: ['http://debian.mirror.iweb.ca/debian/'],
+ repos: ['main', 'contrib', 'non-free']
+ },
+ )
+ end
+
+ it { is_expected.to contain_apt__setting("sources-#{title}").with_notify_update(true) }
+ end
+
+ context 'complex deb822 source' do
+ let :params do
+ super().merge(
+ {
+ types: ['deb', 'deb-src'],
+ location: ['http://fr.debian.org/debian', 'http://de.debian.org/debian'],
+ release: ['stable', 'stable-updates', 'stable-backports'],
+ repos: ['main', 'contrib', 'non-free'],
+ architecture: ['amd64', 'i386'],
+ allow_unsigned: true,
+ notify_update: false
+ },
+ )
+ end
+
+ it { is_expected.to contain_apt__setting("sources-#{title}").with_notify_update(false) }
+ it { is_expected.to contain_apt__setting("sources-#{title}").with_content(%r{Enabled: yes}) }
+ it { is_expected.to contain_apt__setting("sources-#{title}").with_content(%r{Types: deb deb-src}) }
+ it { is_expected.to contain_apt__setting("sources-#{title}").with_content(%r{URIs: http://fr.debian.org/debian http://de.debian.org/debian}) }
+ it { is_expected.to contain_apt__setting("sources-#{title}").with_content(%r{Suites: stable stable-updates stable-backports}) }
+ it { is_expected.to contain_apt__setting("sources-#{title}").with_content(%r{Components: main contrib non-free}) }
+ it { is_expected.to contain_apt__setting("sources-#{title}").with_content(%r{Architectures: amd64 i386}) }
+ it { is_expected.to contain_apt__setting("sources-#{title}").with_content(%r{Trusted: yes}) }
+ end
+
+ context '.list backwards compatibility' do
+ let :params do
+ super().merge(
+ {
+ location: 'http://debian.mirror.iweb.ca/debian/',
+ release: 'unstable',
+ repos: 'main contrib non-free',
+ key: {
+ id: 'A1BD8E9D78F7FE5C3E65D8AF8B48AD6246925553',
+ server: 'keyserver.ubuntu.com',
+ },
+ pin: '-10'
+ },
+ )
+ end
+
+ it { is_expected.to contain_apt__setting("sources-#{title}").with_notify_update(true) }
+ end
+ end
end
diff --git a/templates/source_deb822.epp b/templates/source_deb822.epp
new file mode 100644
index 0000000000..10802b05d5
--- /dev/null
+++ b/templates/source_deb822.epp
@@ -0,0 +1,36 @@
+<% | String $comment,
+ Enum['yes','no'] $enabled,
+ Array[String] $types,
+ Array[String] $uris,
+ Array[String] $suites,
+ Array[String] $components,
+ Optional[Array] $architectures = undef,
+ Optional[Enum['yes','no']] $allow_insecure = undef,
+ Optional[Enum['yes','no']] $repo_trusted = undef,
+ Optional[Enum['yes','no']] $check_valid_until = undef,
+ Optional[Variant[Stdlib::AbsolutePath,Array[String]]] $signed_by = undef,
+| -%>
+# <%= $comment %>
+Enabled: <%= $enabled %>
+Types: <% $types.each |String $type| { -%> <%= $type %> <% } %>
+URIs: <% $uris.each | String $uri | { -%> <%= $uri %> <% } %>
+Suites: <% $suites.each | String $suite | { -%> <%= $suite %> <% } %>
+Components: <% $components.each | String $component | { -%> <%= $component %> <% } %>
+<% if $architectures { -%>
+Architectures:<% $architectures.each | String $arch | { %> <%= $arch %><% } %>
+<%- } -%>
+<% if $allow_insecure { -%>
+Allow-Insecure: <%= $allow_insecure %>
+<% } -%>
+<% if $repo_trusted { -%>
+Trusted: <%= $repo_trusted %>
+<% } -%>
+<% if $check_valid_until { -%>
+Check-Valid-Until: <%= $check_valid_until %>
+<% } -%>
+<% if $signed_by { -%>
+Signed-By: <% if type($signed_by) =~ Type[Array] { -%><%- $signed_by.each |String $keyring| { -%><%= $keyring %> <% } -%>
+<%- } -%>
+<%- elsif type($signed_by) =~ Type[String] { -%>
+<%= $signed_by -%>
+<%- }} %>