From 9a80cc2170d39f382eb982a06dac4ed1e4dbaf41 Mon Sep 17 00:00:00 2001 From: Yury Bushmelev Date: Sat, 30 Nov 2024 23:35:18 +0800 Subject: [PATCH] Implement 'repo' install method --- .fixtures.yml | 3 ++ REFERENCE.md | 54 +++++++++++++++++++++--- manifests/init.pp | 32 +++++++++++--- manifests/install.pp | 44 ++++++++++++------- manifests/install/repo.pp | 44 +++++++++++++++++++ spec/acceptance/init_spec.rb | 29 +++++++++++++ spec/classes/init_spec.rb | 77 +++++++++++++++++++++++++++++++++- spec/spec_helper_acceptance.rb | 2 +- 8 files changed, 256 insertions(+), 29 deletions(-) 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..94f8c26 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -14,6 +14,9 @@ * `caddy::config`: This class handles the Caddy config. * `caddy::install`: This class handles the Caddy archive. +* `caddy::install::github`: This class handles Caddy installation from the github releases +* `caddy::install::repo`: This class handles Caddy installation from a package repository +* `caddy::install::site`: This class handles Caddy installation from the github releases * `caddy::service`: This class handles the Caddy service. ### Defined types @@ -82,6 +85,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) +* [`distribution_channel`](#-caddy--distribution_channel) +* [`package_name`](#-caddy--package_name) +* [`package_ensure`](#-caddy--package_ensure) ##### `version` @@ -93,9 +100,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 +113,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 +289,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 +297,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 +305,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` + +##### `distribution_channel` + +Data type: `Enum['stable','testing']` + +Whether to use stable or testing distribution channel. Only relevant on Debian family and only when $install_method is 'repo'. + +Default value: `'stable'` + +##### `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/manifests/init.pp b/manifests/init.pp index a91c55f..446e237 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 distribution_channel +# Whether to use stable or testing distribution channel. Only relevant on Debian family and only when $install_method is 'repo'. +# +# @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, + Enum['stable','testing'] $distribution_channel = 'stable', + 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 61bc2c3..6bb8e7b 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" @@ -37,6 +38,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' @@ -60,21 +76,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..a14a115 --- /dev/null +++ b/manifests/install/repo.pp @@ -0,0 +1,44 @@ +# @summary +# This class handles Caddy installation from a package repository +# +# @api private +# +class caddy::install::repo { + assert_private() + + case $facts['os']['family'] { + 'Debian': { + include apt + + if $caddy::manage_repo { + apt::source { 'caddy': + location => "https://dl.cloudsmith.io/public/caddy/${caddy::distribution_channel}/deb/debian", + release => 'any-version', + repos => 'main', + key => { + name => "caddy-${caddy::distribution_channel}-archive-keyring.asc", + source => "https://dl.cloudsmith.io/public/caddy/${caddy::distribution_channel}/gpg.key", + }, + before => Package[$caddy::package_name], + } + } + } + 'RedHat': { + include yum + + if $caddy::manage_repo { + yum::copr { '@caddy/caddy': + ensure => 'enabled', + before => Package[$caddy::package_name], + } + } + } + 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..e7fe952 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 shell('/opt/puppetlabs/bin/facter os.family').stdout + when 'Debian' + '2.8.3' + else + latest_release[1..] + 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..4c022d2 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,74 @@ 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(%r{stable}). + with_key( + 'name' => %r{stable}, + 'source' => %r{stable} + ).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 + + context 'with distribution_channel => testing' do + let(:params) { super().merge(distribution_channel: 'testing') } + + it do + is_expected.to contain_apt__source('caddy'). + with_location(%r{testing}). + with_key( + 'name' => %r{testing}, + 'source' => %r{testing} + ).that_comes_before('Package[caddy]') + end + end + end + when 'RedHat' + context 'on RedHat family' do + it { is_expected.to contain_class('yum') } + 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').with_ensure('enabled').that_comes_before('Package[caddy]') } + end + end + else + it { is_expected.to raise_error(%r{has no support for 'repo' install method}) } + 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..1804fe8 100644 --- a/spec/spec_helper_acceptance.rb +++ b/spec/spec_helper_acceptance.rb @@ -5,6 +5,6 @@ require 'voxpupuli/acceptance/spec_helper_acceptance' -configure_beaker(modules: :metadata) +configure_beaker(modules: :fixtures) Dir['./spec/support/acceptance/**/*.rb'].sort.each { |f| require f }