From 4681bcb703ee697953c6c3ba1a4602251d5062e8 Mon Sep 17 00:00:00 2001 From: Yury Bushmelev Date: Sat, 30 Nov 2024 22:51:01 +0800 Subject: [PATCH 1/4] Refactor caddy::install --- manifests/install.pp | 81 +++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/manifests/install.pp b/manifests/install.pp index 01ca858..0f71d97 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -8,48 +8,59 @@ $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 { + '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" } + 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('&') - $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_dl_url = "${caddy_url}?${query_params}" - $caddy_source = '/var/cache/caddy-latest' + $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_source: + ensure => file, + owner => 'root', + group => 'root', + mode => '0755', + source => $caddy_dl_url, + replace => false, # Don't download the file on every run + } } } From b72a8bdf49e52ad9fba646214fa56d524b759d9d Mon Sep 17 00:00:00 2001 From: Yury Bushmelev Date: Sat, 30 Nov 2024 23:35:18 +0800 Subject: [PATCH 2/4] Implement 'repo' install method --- .fixtures.yml | 3 ++ REFERENCE.md | 52 ++++++++++++++++--- data/family/Debian.yaml | 9 ++++ data/family/RedHat.yaml | 3 ++ manifests/init.pp | 31 ++++++++--- manifests/install.pp | 44 +++++++++++----- manifests/install/repo.pp | 76 +++++++++++++++++++++++++++ spec/acceptance/init_spec.rb | 29 +++++++++++ spec/classes/init_spec.rb | 95 +++++++++++++++++++++++++++++++++- spec/spec_helper_acceptance.rb | 9 +++- 10 files changed, 322 insertions(+), 29 deletions(-) create mode 100644 data/family/RedHat.yaml create mode 100644 manifests/install/repo.pp 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/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..dfc6257 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,6 +139,10 @@ 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' } diff --git a/manifests/install.pp b/manifests/install.pp index 0f71d97..feab931 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -9,6 +9,7 @@ $bin_file = "${caddy::install_path}/caddy" 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" @@ -38,6 +39,21 @@ } $caddy_source = "/var/cache/caddy-${caddy::version}/caddy" + + 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, + } } default: { $caddy_url = 'https://caddyserver.com/api/download' @@ -61,21 +77,21 @@ 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 { $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, + 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 } From 2864f4139b7f4522f880c52174434f8e0c99e580 Mon Sep 17 00:00:00 2001 From: Yury Bushmelev Date: Sat, 7 Dec 2024 12:51:27 +0800 Subject: [PATCH 3/4] Add aarch64 (arm64) support --- manifests/init.pp | 1 + 1 file changed, 1 insertion(+) diff --git a/manifests/init.pp b/manifests/init.pp index dfc6257..7147b8a 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -147,6 +147,7 @@ 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.") From 1299b733a9f03ccf47722f9220ded93c850dfa3c Mon Sep 17 00:00:00 2001 From: Yury Bushmelev Date: Sat, 14 Dec 2024 11:09:25 +0800 Subject: [PATCH 4/4] Update README.md --- README.md | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) 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