diff --git a/.fixtures.yml b/.fixtures.yml
index 160f990..c450cd4 100644
--- a/.fixtures.yml
+++ b/.fixtures.yml
@@ -3,3 +3,6 @@ fixtures:
archive: https://github.com/voxpupuli/puppet-archive.git
stdlib: https://github.com/puppetlabs/puppetlabs-stdlib.git
systemd: https://github.com/voxpupuli/puppet-systemd.git
+ apt: https://github.com/puppetlabs/puppetlabs-apt.git
+ yum: https://github.com/voxpupuli/puppet-yum.git
+ augeas_core: https://github.com/puppetlabs/puppetlabs-augeas_core.git # required by puppet-yum
diff --git a/README.md b/README.md
index d8dc619..5d5bf9d 100644
--- a/README.md
+++ b/README.md
@@ -13,9 +13,9 @@
1. [Description](#description)
1. [Setup - The basics of getting started with Caddy](#setup)
- * [What Caddy affects](#what-Caddy-affects)
+ * [What Caddy affects](#what-caddy-affects)
* [Setup requirements](#setup-requirements)
- * [Beginning with Caddy](#beginning-with-Caddy)
+ * [Beginning with Caddy](#beginning-with-caddy)
1. [Usage - Configuration options and additional functionality](#usage)
1. [Limitations - OS compatibility, etc.](#limitations)
1. [Development - Guide for contributing to the module](#development)
@@ -41,10 +41,14 @@ want to install Caddy 1.x, you should use version v2.0.0 of this module.
This module has the following dependencies:
-* [camptocamp/systemd](https://github.com/camptocamp/puppet-systemd)
+* [puppet/systemd](https://github.com/voxpupuli/puppet-systemd)
* [puppet/archive](https://github.com/voxpupuli/puppet-archive)
* [puppetlabs/stdlib](https://github.com/puppetlabs/puppetlabs-stdlib)
-* [stm/file_capability](https://github.com/smoeding/puppet-file_capability)
+
+When `install_method` is set to 'repo', this module implicitly requires either
+[puppetlabs-apt](https://github.com/puppetlabs/puppetlabs-apt) module for
+Debian distro family, or [puppet-yum](https://github.com/voxpupuli/puppet-yum)
+module for RedHat distro family.
### Beginning with Caddy
@@ -56,7 +60,7 @@ include caddy
## Usage
-Install customised version of Caddy
+Install customized version of Caddy
```puppet
class { 'caddy':
@@ -97,10 +101,15 @@ The [reference][1] documentation of this module is generated using [puppetlabs/p
This module has been tested on:
-* RedHat 7/8
-* CentOS 7/8
-* Debian 8/9/10
-* Ubuntu 16.04/18.04
+* AlmaLinux 8/9
+* CentOS 9
+* Debian 11/12
+* OracleLinux 8/9
+* RedHat 8/9
+* Rocky 8/9
+* Ubuntu 20.04/22.04/24.04
+
+For the official list of all tested distributions, please take a look at the [metadata.json](https://github.com/voxpupuli/puppet-caddy/blob/master/metadata.json#L24)
## Development
diff --git a/REFERENCE.md b/REFERENCE.md
index 7119083..fb5cc41 100644
--- a/REFERENCE.md
+++ b/REFERENCE.md
@@ -14,6 +14,7 @@
* `caddy::config`: This class handles the Caddy config.
* `caddy::install`: This class handles the Caddy archive.
+* `caddy::install::repo`: This class handles Caddy installation from a package repository
* `caddy::service`: This class handles the Caddy service.
### Defined types
@@ -82,6 +83,10 @@ The following parameters are available in the `caddy` class:
* [`service_name`](#-caddy--service_name)
* [`service_ensure`](#-caddy--service_ensure)
* [`service_enable`](#-caddy--service_enable)
+* [`manage_repo`](#-caddy--manage_repo)
+* [`repo_settings`](#-caddy--repo_settings)
+* [`package_name`](#-caddy--package_name)
+* [`package_ensure`](#-caddy--package_ensure)
##### `version`
@@ -93,9 +98,12 @@ Default value: `'2.0.0'`
##### `install_method`
-Data type: `Optional[Enum['github']]`
+Data type: `Optional[Enum['github','repo']]`
-Which source is used.
+Which source to use for the Caddy installation. See https://caddyserver.com/docs/install.
+* `undef` (default) - download from the official Caddy site
+* `github` - download from Github releases
+* `repo` - install from an OS repository
Default value: `undef`
@@ -103,7 +111,7 @@ Default value: `undef`
Data type: `Stdlib::Absolutepath`
-Directory where the Caddy binary is stored.
+Directory where the Caddy binary is stored. Not used when $install_method is 'repo'.
Default value: `'/opt/caddy'`
@@ -279,7 +287,7 @@ Default value: `true`
Data type: `String[1]`
-Customise the name of the system service
+Customise the name of the system service.
Default value: `'caddy'`
@@ -287,7 +295,7 @@ Default value: `'caddy'`
Data type: `Stdlib::Ensure::Service`
-Whether the service should be running or stopped
+Whether the service should be running or stopped.
Default value: `'running'`
@@ -295,10 +303,42 @@ Default value: `'running'`
Data type: `Boolean`
-Whether the service should be enabled or disabled
+Whether the service should be enabled or disabled.
Default value: `true`
+##### `manage_repo`
+
+Data type: `Boolean`
+
+Whether the APT/YUM(COPR) repository should be installed. Only relevant when $install_method is 'repo'.
+
+Default value: `true`
+
+##### `repo_settings`
+
+Data type: `Hash[String[1],Any]`
+
+Distro-specific repository settings.
+
+Default value: `{}`
+
+##### `package_name`
+
+Data type: `String[1]`
+
+Name of the caddy package to use. Only relevant when $install_method is 'repo'.
+
+Default value: `'caddy'`
+
+##### `package_ensure`
+
+Data type: `String[1]`
+
+Whether to install or remove the caddy package. Only relevant when $install_method is 'repo'.
+
+Default value: `$version`
+
## Defined types
### `caddy::vhost`
diff --git a/data/family/Debian.yaml b/data/family/Debian.yaml
index 467e790..76c9644 100644
--- a/data/family/Debian.yaml
+++ b/data/family/Debian.yaml
@@ -1,2 +1,11 @@
---
caddy::caddy_shell: '/usr/sbin/nologin'
+
+caddy::repo_settings:
+ location: https://dl.cloudsmith.io/public/caddy/stable/deb/debian
+ release: any-version
+ repos: main
+ key:
+ name: caddy-archive-keyring.asc
+ source: https://dl.cloudsmith.io/public/caddy/stable/gpg.key
+ checksum_value: 5791c2fb6b6e82feb5a69834dd2131f4bcc30af0faec37783b2dc1c5c224a82a
diff --git a/data/family/RedHat.yaml b/data/family/RedHat.yaml
new file mode 100644
index 0000000..36a1f0c
--- /dev/null
+++ b/data/family/RedHat.yaml
@@ -0,0 +1,3 @@
+---
+caddy::repo_settings:
+ copr_repo: '@caddy/caddy'
diff --git a/manifests/init.pp b/manifests/init.pp
index a91c55f..7147b8a 100644
--- a/manifests/init.pp
+++ b/manifests/init.pp
@@ -19,10 +19,13 @@
# Which version is used.
#
# @param install_method
-# Which source is used.
+# Which source to use for the Caddy installation. See https://caddyserver.com/docs/install.
+# * `undef` (default) - download from the official Caddy site
+# * `github` - download from Github releases
+# * `repo` - install from an OS repository
#
# @param install_path
-# Directory where the Caddy binary is stored.
+# Directory where the Caddy binary is stored. Not used when $install_method is 'repo'.
#
# @param manage_user
# Whether or not the module should create the user.
@@ -88,17 +91,29 @@
# Whether or not the module should manage the service.
#
# @param service_name
-# Customise the name of the system service
+# Customise the name of the system service.
#
# @param service_ensure
-# Whether the service should be running or stopped
+# Whether the service should be running or stopped.
#
# @param service_enable
-# Whether the service should be enabled or disabled
+# Whether the service should be enabled or disabled.
+#
+# @param manage_repo
+# Whether the APT/YUM(COPR) repository should be installed. Only relevant when $install_method is 'repo'.
+#
+# @param repo_settings
+# Distro-specific repository settings.
+#
+# @param package_name
+# Name of the caddy package to use. Only relevant when $install_method is 'repo'.
+#
+# @param package_ensure
+# Whether to install or remove the caddy package. Only relevant when $install_method is 'repo'.
#
class caddy (
String[1] $version = '2.0.0',
- Optional[Enum['github']] $install_method = undef,
+ Optional[Enum['github','repo']] $install_method = undef,
Stdlib::Absolutepath $install_path = '/opt/caddy',
Boolean $manage_user = true,
String[1] $caddy_user = 'caddy',
@@ -124,10 +139,15 @@
String[1] $service_name = 'caddy',
Stdlib::Ensure::Service $service_ensure = 'running',
Boolean $service_enable = true,
+ Boolean $manage_repo = true,
+ Hash[String[1],Any] $repo_settings = {},
+ String[1] $package_name = 'caddy',
+ String[1] $package_ensure = $version,
) {
case $caddy_architecture {
'x86_64', 'amd64': { $arch = 'amd64' }
'x86' : { $arch = '386' }
+ 'aarch64' : { $arch = 'arm64' }
default: {
$arch = $caddy_architecture
warning("arch ${arch} may not be supported.")
diff --git a/manifests/install.pp b/manifests/install.pp
index 01ca858..feab931 100644
--- a/manifests/install.pp
+++ b/manifests/install.pp
@@ -8,63 +8,90 @@
$bin_file = "${caddy::install_path}/caddy"
- if $caddy::install_method == 'github' {
- $caddy_url = 'https://github.com/caddyserver/caddy/releases/download'
- $caddy_dl_url = "${caddy_url}/v${caddy::version}/caddy_${caddy::version}_linux_${caddy::arch}.tar.gz"
- $caddy_dl_dir = "/var/cache/caddy_${caddy::version}_linux_${$caddy::arch}.tar.gz"
+ case $caddy::install_method {
+ 'repo': { contain caddy::install::repo }
+ 'github': {
+ $caddy_url = 'https://github.com/caddyserver/caddy/releases/download'
+ $caddy_dl_url = "${caddy_url}/v${caddy::version}/caddy_${caddy::version}_linux_${caddy::arch}.tar.gz"
+ $caddy_dl_dir = "/var/cache/caddy_${caddy::version}_linux_${$caddy::arch}.tar.gz"
- $extract_path = "/var/cache/caddy-${caddy::version}"
+ $extract_path = "/var/cache/caddy-${caddy::version}"
- file { $extract_path:
- ensure => directory,
- owner => 'root',
- group => 'root',
- mode => '0755',
- }
+ file { $extract_path:
+ ensure => directory,
+ owner => 'root',
+ group => 'root',
+ mode => '0755',
+ }
- archive { $caddy_dl_dir:
- ensure => present,
- extract => true,
- extract_path => $extract_path,
- source => $caddy_dl_url,
- username => $caddy::caddy_account_id,
- password => $caddy::caddy_api_key,
- user => 'root',
- group => 'root',
- creates => "${extract_path}/caddy",
- require => File[$extract_path],
- before => File[$bin_file],
- }
+ archive { $caddy_dl_dir:
+ ensure => present,
+ extract => true,
+ extract_path => $extract_path,
+ source => $caddy_dl_url,
+ username => $caddy::caddy_account_id,
+ password => $caddy::caddy_api_key,
+ user => 'root',
+ group => 'root',
+ creates => "${extract_path}/caddy",
+ require => File[$extract_path],
+ before => File[$bin_file],
+ }
- $caddy_source = "/var/cache/caddy-${caddy::version}/caddy"
- } else {
- $caddy_url = 'https://caddyserver.com/api/download'
- $caddy_dl_url = "${caddy_url}?os=linux&arch=${caddy::arch}&plugins=${caddy::caddy_features}&license=${caddy::caddy_license}&telemetry=${caddy::caddy_telemetry}"
+ $caddy_source = "/var/cache/caddy-${caddy::version}/caddy"
- $caddy_source = '/var/cache/caddy-latest'
+ file { $caddy::install_path:
+ ensure => directory,
+ owner => $caddy::caddy_user,
+ group => $caddy::caddy_group,
+ mode => '0755',
+ }
- file { $caddy_source:
- ensure => file,
- owner => 'root',
- group => 'root',
- mode => '0755',
- source => $caddy_dl_url,
- replace => false, # Don't download the file on every run
+ file { $bin_file:
+ ensure => file,
+ owner => 'root',
+ group => 'root',
+ mode => '0755',
+ source => $caddy_source,
+ }
}
- }
+ default: {
+ $caddy_url = 'https://caddyserver.com/api/download'
+ $query_params = {
+ os => 'linux',
+ arch => $caddy::arch,
+ plugins => $caddy::caddy_features,
+ license => $caddy::caddy_license,
+ telemetry => $caddy::caddy_telemetry,
+ }.map |$k, $v| { "${k}=${v}" }.join('&')
- file { $caddy::install_path:
- ensure => directory,
- owner => $caddy::caddy_user,
- group => $caddy::caddy_group,
- mode => '0755',
- }
+ $caddy_dl_url = "${caddy_url}?${query_params}"
- file { $bin_file:
- ensure => file,
- owner => 'root',
- group => 'root',
- mode => '0755',
- source => $caddy_source,
+ $caddy_source = '/var/cache/caddy-latest'
+
+ file { $caddy_source:
+ ensure => file,
+ owner => 'root',
+ group => 'root',
+ mode => '0755',
+ source => $caddy_dl_url,
+ replace => false, # Don't download the file on every run
+ }
+
+ file { $caddy::install_path:
+ ensure => directory,
+ owner => $caddy::caddy_user,
+ group => $caddy::caddy_group,
+ mode => '0755',
+ }
+
+ file { $bin_file:
+ ensure => file,
+ owner => 'root',
+ group => 'root',
+ mode => '0755',
+ source => $caddy_source,
+ }
+ }
}
}
diff --git a/manifests/install/repo.pp b/manifests/install/repo.pp
new file mode 100644
index 0000000..95a3513
--- /dev/null
+++ b/manifests/install/repo.pp
@@ -0,0 +1,76 @@
+# @summary
+# This class handles Caddy installation from a package repository
+#
+# @api private
+#
+class caddy::install::repo {
+ assert_private()
+
+ if $caddy::manage_repo and $caddy::repo_settings.length == 0 {
+ fail("'repo_settings' parameter should be set when 'manage_repo' is true")
+ }
+
+ # Inject `before` into the repository settings
+ $repo = $caddy::repo_settings + {
+ before => Package[$caddy::package_name],
+ }
+
+ case $facts['os']['family'] {
+ 'Debian': {
+ include apt
+
+ if $caddy::manage_repo {
+ # Use this when issues below are resolved
+ # apt::source { 'caddy':
+ # * => $repo,
+ # }
+
+ # Below is a temporary workaround until
+ # https://github.com/puppetlabs/puppetlabs-apt/issues/1196 is resolved.
+ # dl.cloudsmith.io returns no headers Puppet can use to check if file
+ # is changed.
+ # Etag header is not supported, but discussed here:
+ # https://github.com/puppetlabs/puppet/issues/9319
+ # Checksum is not supported by apt::source's key nor by apt::keyring
+ # resource. See https://github.com/puppetlabs/puppetlabs-apt/pull/1199
+
+ if $repo.get('key.source') {
+ $keyring_path = "/etc/apt/keyrings/${$repo.get('key.name')}"
+
+ file { '/etc/apt/keyrings': ensure => 'directory' }
+
+ file { $keyring_path:
+ ensure => 'file',
+ source => $repo.get('key.source'),
+ checksum => $repo.get('key.checksum', 'sha256'),
+ checksum_value => $repo.get('key.checksum_value'),
+ before => Apt::Source['caddy'],
+ }
+ } else {
+ $keyring_path = undef
+ }
+
+ # Drop 'key' from repo settings for now. Also, add `keyring`
+ apt::source { 'caddy':
+ * => $repo - 'key' + { 'keyring' => $keyring_path },
+ }
+ }
+ }
+ 'RedHat': {
+ include yum
+
+ if $caddy::manage_repo {
+ yum::copr { 'caddy':
+ * => $repo,
+ }
+ }
+ }
+ default: {
+ fail("OS family ${facts['os']['family']} has no support for 'repo' install method")
+ }
+ }
+
+ package { $caddy::package_name:
+ ensure => $caddy::package_ensure.lest || { 'installed' },
+ }
+}
diff --git a/spec/acceptance/init_spec.rb b/spec/acceptance/init_spec.rb
index f69e57a..3282d62 100644
--- a/spec/acceptance/init_spec.rb
+++ b/spec/acceptance/init_spec.rb
@@ -56,6 +56,35 @@ class { 'caddy':
end
end
+ context 'when installing from repo' do
+ # Debian repo has multiple versions
+ # RedHat repo has just the latest version at the moment
+ let(:use_version) do
+ case fact('os.family')
+ when 'Debian'
+ '2.8.3'
+ else
+ latest_release.sub(%r{\Av}, '')
+ end
+ end
+
+ it_behaves_like 'an idempotent resource' do
+ let(:manifest) do
+ <<~PUPPET
+ class { 'caddy':
+ install_method => 'repo',
+ version => '#{use_version}',
+ }
+ PUPPET
+ end
+ end
+
+ describe command('caddy version') do
+ its(:exit_status) { is_expected.to eq 0 }
+ its(:stdout) { is_expected.to start_with "v#{use_version}" }
+ end
+ end
+
context 'with vhosts' do
it_behaves_like 'an idempotent resource' do
let(:manifest) do
diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb
index 7a57a54..e7fbcc1 100644
--- a/spec/classes/init_spec.rb
+++ b/spec/classes/init_spec.rb
@@ -11,9 +11,14 @@
case facts[:os]['family']
when 'Debian'
- caddy_shell = '/usr/sbin/nologin'
+ caddy_shell = '/usr/sbin/nologin'
+ has_repo = true
when 'RedHat'
- caddy_shell = '/sbin/nologin'
+ caddy_shell = '/sbin/nologin'
+ has_repo = true
+ else
+ caddy_shell = '/sbin/nologin'
+ has_repo = false
end
context 'with defaults for all parameters' do
@@ -171,6 +176,92 @@
end
end
+ context 'with install_method => repo' do
+ let(:params) { { install_method: 'repo' } }
+
+ case facts[:os]['family']
+ when 'Debian'
+ context 'on Debian family' do
+ it { is_expected.to contain_class('apt') }
+
+ # it do
+ # is_expected.to contain_apt__source('caddy').
+ # with_location('https://dl.cloudsmith.io/public/caddy/stable/deb/debian').
+ # with_key(
+ # 'name' => 'caddy-archive-keyring.asc',
+ # 'source' => 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key'
+ # ).that_comes_before('Package[caddy]')
+ # end
+
+ it do
+ is_expected.to contain_file('/etc/apt/keyrings/caddy-archive-keyring.asc').
+ with_ensure('file').
+ with_source('https://dl.cloudsmith.io/public/caddy/stable/gpg.key').
+ with_checksum('sha256').
+ with_checksum_value('5791c2fb6b6e82feb5a69834dd2131f4bcc30af0faec37783b2dc1c5c224a82a').
+ that_comes_before('Apt::Source[caddy]')
+ end
+
+ it do
+ is_expected.to contain_apt__source('caddy').
+ with_location('https://dl.cloudsmith.io/public/caddy/stable/deb/debian').
+ with_keyring('/etc/apt/keyrings/caddy-archive-keyring.asc').
+ without_key.
+ that_comes_before('Package[caddy]')
+ end
+
+ it { is_expected.to contain_package('caddy').with_ensure('2.0.0') }
+
+ context 'with manage_repo => false' do
+ let(:params) { super().merge(manage_repo: false) }
+
+ it { is_expected.not_to contain_apt__source('caddy') }
+ end
+ end
+ when 'RedHat'
+ context 'on RedHat family' do
+ it { is_expected.to contain_class('yum') }
+
+ it do
+ is_expected.to contain_yum__copr('caddy').
+ with_copr_repo('@caddy/caddy').
+ with_ensure('enabled').
+ that_comes_before('Package[caddy]')
+ end
+
+ it { is_expected.to contain_package('caddy').with_ensure('2.0.0') }
+
+ context 'with manage_repo => false' do
+ let(:params) { super().merge(manage_repo: false) }
+
+ it { is_expected.not_to contain_yum__copr('@caddy/caddy') }
+ end
+ end
+ else
+ it { is_expected.to raise_error(%r{has no support for 'repo' install method}) }
+ end
+
+ context 'without repo_settings' do
+ let(:params) { super().merge(repo_settings: {}) }
+
+ it { is_expected.to raise_error(%r{'repo_settings' parameter should be set}) }
+ end
+
+ if has_repo
+ context 'with package_name => test' do
+ let(:params) { super().merge(package_name: 'test') }
+
+ it { is_expected.to contain_package('test').with_ensure('2.0.0') }
+ end
+
+ context 'with package_ensure => 2.3.4' do
+ let(:params) { super().merge(package_ensure: '2.3.4') }
+
+ it { is_expected.to contain_package('caddy').with_ensure('2.3.4') }
+ end
+ end
+ end
+
context 'with caddy_user => test_user' do
let(:params) { { caddy_user: 'test_user' } }
diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb
index 2681792..124a735 100644
--- a/spec/spec_helper_acceptance.rb
+++ b/spec/spec_helper_acceptance.rb
@@ -5,6 +5,13 @@
require 'voxpupuli/acceptance/spec_helper_acceptance'
-configure_beaker(modules: :metadata)
+configure_beaker(modules: :metadata) do |host|
+ case fact_on(host, 'os.family')
+ when 'Debian'
+ install_puppet_module_via_pmt_on(host, 'puppetlabs-apt')
+ when 'RedHat'
+ install_puppet_module_via_pmt_on(host, 'puppet-yum')
+ end
+end
Dir['./spec/support/acceptance/**/*.rb'].sort.each { |f| require f }