diff --git a/REFERENCE.md b/REFERENCE.md index 03d8fbf..9c6e144 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -1,813 +1,813 @@ # Reference ## Table of Contents **Classes** _Public Classes_ * [`letsencrypt`](#letsencrypt): Install and configure Certbot, the LetsEncrypt client * [`letsencrypt::install`](#letsencryptinstall): Installs the Let's Encrypt client. * [`letsencrypt::plugin::dns_rfc2136`](#letsencryptplugindns_rfc2136): Installs and configures the dns-rfc2136 plugin * [`letsencrypt::renew`](#letsencryptrenew): Configures renewal of Let's Encrypt certificates using Certbot _Private Classes_ * `letsencrypt::config`: Configures the Let's Encrypt client. **Defined types** * [`letsencrypt::certonly`](#letsencryptcertonly): Request a certificate using the `certonly` installer * [`letsencrypt::hook`](#letsencrypthook): Creates hook scripts. **Functions** * [`letsencrypt::letsencrypt_lookup`](#letsencryptletsencrypt_lookup): **Data types** * [`Letsencrypt::Cron::Hour`](#letsencryptcronhour): mimic hour setting in cron as defined in man 5 crontab * [`Letsencrypt::Cron::Minute`](#letsencryptcronminute): mimic minute setting in cron as defined in man 5 crontab * [`Letsencrypt::Cron::Monthday`](#letsencryptcronmonthday): mimic monthday setting in cron as defined in man 5 crontab * [`Letsencrypt::Plugin`](#letsencryptplugin): List of accepted plugins ## Classes ### letsencrypt Install and configure Certbot, the LetsEncrypt client #### Examples ##### ```puppet class { 'letsencrypt' : email => 'letsregister@example.com', config => { 'server' => 'https://acme-staging-v02.api.letsencrypt.org/directory', }, } ``` #### Parameters The following parameters are available in the `letsencrypt` class. ##### `email` Data type: `Optional[String]` The email address to use to register with Let's Encrypt. This takes precedence over an 'email' setting defined in $config. Default value: `undef` ##### `path` Data type: `String` The path to the letsencrypt installation. Default value: '/opt/letsencrypt' ##### `venv_path` Data type: `Any` virtualenv path for vcs-installed Certbot Default value: '/opt/letsencrypt/.venv' ##### `environment` Data type: `Array` An optional array of environment variables (in addition to VENV_PATH) Default value: [] ##### `repo` Data type: `String` A Git URL to install the Let's encrypt client from. Default value: 'https://github.com/certbot/certbot.git' ##### `version` Data type: `String` The Git ref (tag, sha, branch) to check out when installing the client with the `vcs` method. -Default value: 'v0.30.2' +Default value: 'v0.39.0' ##### `package_name` Data type: `String` Name of package and command to use when installing the client with the `package` method. Default value: 'certbot' ##### `package_ensure` Data type: `Any` The value passed to `ensure` when installing the client with the `package` method. Default value: 'installed' ##### `package_command` Data type: `String` Path or name for letsencrypt executable when installing the client with the `package` method. Default value: 'certbot' ##### `config_file` Data type: `String` The path to the configuration file for the letsencrypt cli. Default value: "${config_dir}/cli.ini" ##### `config` Data type: `Hash` A hash representation of the letsencrypt configuration file. Default value: {'server' => 'https://acme-v02.api.letsencrypt.org/directory'} ##### `cron_scripts_path` Data type: `String` The path for renewal scripts called by cron Default value: "${facts['puppet_vardir']}/letsencrypt" ##### `cron_owner_group` Data type: `String` Group owner of cron renew scripts. Default value: 'root' ##### `manage_config` Data type: `Boolean` A feature flag to toggle the management of the letsencrypt configuration file. Default value: `true` ##### `manage_install` Data type: `Boolean` A feature flag to toggle the management of the letsencrypt client installation. Default value: `true` ##### `manage_dependencies` Data type: `Boolean` A feature flag to toggle the management of the letsencrypt dependencies. Default value: `true` ##### `configure_epel` Data type: `Boolean` A feature flag to include the 'epel' class and depend on it for package installation. ##### `install_method` Data type: `Enum['package', 'vcs']` Method to install the letsencrypt client, either package or vcs. Default value: 'package' ##### `agree_tos` Data type: `Boolean` A flag to agree to the Let's Encrypt Terms of Service. Default value: `true` ##### `unsafe_registration` Data type: `Boolean` A flag to allow using the 'register-unsafely-without-email' flag. Default value: `false` ##### `config_dir` Data type: `Stdlib::Unixpath` The path to the configuration directory. Default value: '/etc/letsencrypt' ##### `key_size` Data type: `Integer[2048]` Size for the RSA public key Default value: 4096 ##### `renew_pre_hook_commands` Data type: `Any` Array of commands to run in a shell before obtaining/renewing any certificates. Default value: [] ##### `renew_post_hook_commands` Data type: `Any` Array of commands to run in a shell after attempting to obtain/renew certificates. Default value: [] ##### `renew_deploy_hook_commands` Data type: `Any` Array of commands to run in a shell once for each successfully issued/renewed certificate. Two environmental variables are supplied by certbot: - $RENEWED_LINEAGE: Points to the live directory with the cert files and key. Example: /etc/letsencrypt/live/example.com - $RENEWED_DOMAINS: A space-delimited list of renewed certificate domains. Example: "example.com www.example.com" Default value: [] ##### `renew_additional_args` Data type: `Any` Array of additional command line arguments to pass to 'certbot renew'. Default value: [] ##### `renew_cron_ensure` Data type: `Any` Intended state of the cron resource running certbot renew. Default value: 'absent' ##### `renew_cron_hour` Data type: `Any` Optional string, integer or array of hour(s) the renewal command should run. E.g. '[0,12]' to execute at midnight and midday. hour. Default value: fqdn_rand(24) ##### `renew_cron_minute` Data type: `Any` Optional string, integer or array of minute(s) the renewal command should run. E.g. 0 or '00' or [0,30]. Default value: fqdn_rand(60, fqdn_rand_string(10)) ##### `renew_cron_monthday` Data type: `Any` Optional string, integer or array of monthday(s) the renewal command should run. E.g. '2-30/2' to run on even days. Default value: '*' ### letsencrypt::install Installs the Let's Encrypt client. #### Parameters The following parameters are available in the `letsencrypt::install` class. ##### `manage_install` Data type: `Boolean` A feature flag to toggle the management of the letsencrypt client installation. Default value: $letsencrypt::manage_install ##### `manage_dependencies` Data type: `Boolean` A feature flag to toggle the management of the letsencrypt dependencies. Default value: $letsencrypt::manage_dependencies ##### `configure_epel` Data type: `Boolean` A feature flag to include the 'epel' class and depend on it for package installation. Default value: $letsencrypt::configure_epel ##### `install_method` Data type: `Enum['package', 'vcs']` Method to install the letsencrypt client Default value: $letsencrypt::install_method ##### `path` Data type: `String` The path to the letsencrypt installation. Default value: $letsencrypt::path ##### `repo` Data type: `String` A Git URL to install the Let's encrypt client from. Default value: $letsencrypt::repo ##### `version` Data type: `String` The Git ref (tag, sha, branch) to check out when installing the client with the `vcs` method. Default value: $letsencrypt::version ##### `package_ensure` Data type: `String` The value passed to `ensure` when installing the client with the `package` method. Default value: $letsencrypt::package_ensure ##### `package_name` Data type: `String` Name of package to use when installing the client with the `package` method. Default value: $letsencrypt::package_name ### letsencrypt::plugin::dns_rfc2136 This class installs and configures the Let's Encrypt dns-rfc2136 plugin. https://certbot-dns-rfc2136.readthedocs.io #### Parameters The following parameters are available in the `letsencrypt::plugin::dns_rfc2136` class. ##### `server` Data type: `Stdlib::Host` Target DNS server. ##### `key_name` Data type: `String[1]` TSIG key name. ##### `key_secret` Data type: `String[1]` TSIG key secret. ##### `key_algorithm` Data type: `String[1]` TSIG key algorithm. Default value: 'HMAC-SHA512' ##### `port` Data type: `Stdlib::Port` Target DNS port. Default value: 53 ##### `propagation_seconds` Data type: `Integer` Number of seconds to wait for the DNS server to propagate the DNS-01 challenge. Default value: 10 ##### `manage_package` Data type: `Boolean` Manage the plugin package. Default value: `true` ##### `package_name` Data type: `String[1]` The name of the package to install when $manage_package is true. ##### `config_dir` Data type: `Stdlib::Absolutepath` The path to the configuration directory. Default value: $letsencrypt::config_dir ### letsencrypt::renew Configures renewal of Let's Encrypt certificates using the certbot renew command. Note: Hooks set here will run before/after/for ALL certificates, including any not managed by Puppet. If you want to create hooks for specific certificates only, create them using letsencrypt::certonly. #### Parameters The following parameters are available in the `letsencrypt::renew` class. ##### `pre_hook_commands` Data type: `Variant[String[1], Array[String[1]]]` Array of commands to run in a shell before obtaining/renewing any certificates. Default value: $letsencrypt::renew_pre_hook_commands ##### `post_hook_commands` Data type: `Variant[String[1], Array[String[1]]]` Array of commands to run in a shell after attempting to obtain/renew certificates. Default value: $letsencrypt::renew_post_hook_commands ##### `deploy_hook_commands` Data type: `Variant[String[1], Array[String[1]]]` Array of commands to run in a shell once for each successfully issued/renewed certificate. Two environmental variables are supplied by certbot: - $RENEWED_LINEAGE: Points to the live directory with the cert files and key. Example: /etc/letsencrypt/live/example.com - $RENEWED_DOMAINS: A space-delimited list of renewed certificate domains. Example: "example.com www.example.com" Default value: $letsencrypt::renew_deploy_hook_commands ##### `additional_args` Data type: `Array[String[1]]` Array of additional command line arguments to pass to 'certbot renew'. Default value: $letsencrypt::renew_additional_args ##### `cron_ensure` Data type: `Enum['present', 'absent']` Intended state of the cron resource running certbot renew Default value: $letsencrypt::renew_cron_ensure ##### `cron_hour` Data type: `Letsencrypt::Cron::Hour` Optional string, integer or array of hour(s) the renewal command should run. E.g. '[0,12]' to execute at midnight and midday. Default: fqdn-seeded random hour. Default value: $letsencrypt::renew_cron_hour ##### `cron_minute` Data type: `Letsencrypt::Cron::Minute` Optional string, integer or array of minute(s) the renewal command should run. E.g. 0 or '00' or [0,30]. Default: fqdn-seeded random minute. Default value: $letsencrypt::renew_cron_minute ##### `cron_monthday` Data type: `Letsencrypt::Cron::Monthday` Optional string, integer or array of monthday(s) the renewal command should run. E.g. '2-30/2' to run on even days. Default: Every day. Default value: $letsencrypt::renew_cron_monthday ## Defined types ### letsencrypt::certonly This type can be used to request a certificate using the `certonly` installer. #### Parameters The following parameters are available in the `letsencrypt::certonly` defined type. ##### `ensure` Data type: `Enum['present','absent']` Intended state of the resource Will remove certificates for specified domains if set to 'absent'. Will also remove cronjobs and renewal scripts if `manage_cron` is set to 'true'. Default value: 'present' ##### `domains` Data type: `Array[String[1]]` An array of domains to include in the CSR. Default value: [$title] ##### `custom_plugin` Data type: `Boolean` Whether to use a custom plugin in additional_args and disable -a flag. Default value: `false` ##### `plugin` Data type: `Letsencrypt::Plugin` The authenticator plugin to use when requesting the certificate. Default value: 'standalone' ##### `webroot_paths` Data type: `Array[Stdlib::Unixpath]` An array of webroot paths for the domains in `domains`. Required if using `plugin => 'webroot'`. If `domains` and `webroot_paths` are not the same length, the last `webroot_paths` element will be used for all subsequent domains. Default value: [] ##### `letsencrypt_command` Data type: `String[1]` Command to run letsencrypt Default value: $letsencrypt::command ##### `additional_args` Data type: `Array[String[1]]` An array of additional command line arguments to pass to the `letsencrypt-auto` command. Default value: [] ##### `environment` Data type: `Array[String[1]]` An optional array of environment variables (in addition to VENV_PATH). Default value: [] ##### `key_size` Data type: `Integer[2048]` Size for the RSA public key Default value: $letsencrypt::key_size ##### `manage_cron` Data type: `Boolean` Indicating whether or not to schedule cron job for renewal. Runs daily but only renews if near expiration, e.g. within 10 days. Default value: `false` ##### `suppress_cron_output` Data type: `Boolean` Redirect cron output to devnull Default value: `false` ##### `cron_before_command` Data type: `Optional[String[1]]` Representation of a command that should be run before renewal command Default value: `undef` ##### `cron_success_command` Data type: `Optional[String[1]]` Representation of a command that should be run if the renewal command succeeds. Default value: `undef` ##### `cron_hour` Data type: `Variant[Integer[0,23], String, Array]` Optional hour(s) that the renewal command should execute. e.g. '[0,12]' execute at midnight and midday. Default - seeded random hour. Default value: fqdn_rand(24, $title) ##### `cron_minute` Data type: `Variant[Integer[0,59], String, Array]` Optional minute(s) that the renewal command should execute. e.g. 0 or '00' or [0,30]. Default - seeded random minute. Default value: fqdn_rand(60, fqdn_rand_string(10, $title)) ##### `cron_monthday` Data type: `Array[Variant[Integer[0, 59], String[1]]]` Optional string, integer or array of monthday(s) the renewal command should run. E.g. '2-30/2' to run on even days. Default: Every day. Default value: ['*'] ##### `config_dir` Data type: `Stdlib::Unixpath` The path to the configuration directory. Default value: $letsencrypt::config_dir ##### `pre_hook_commands` Data type: `Variant[String[1], Array[String[1]]]` Array of commands to run in a shell before attempting to obtain/renew the certificate. Default value: [] ##### `post_hook_commands` Data type: `Variant[String[1], Array[String[1]]]` Array of command(s) to run in a shell after attempting to obtain/renew the certificate. Default value: [] ##### `deploy_hook_commands` Data type: `Variant[String[1], Array[String[1]]]` Array of command(s) to run in a shell once if the certificate is successfully issued. Two environmental variables are supplied by certbot: - $RENEWED_LINEAGE: Points to the live directory with the cert files and key. Example: /etc/letsencrypt/live/example.com - $RENEWED_DOMAINS: A space-delimited list of renewed certificate domains. Example: "example.com www.example.com" Default value: [] ### letsencrypt::hook This type is used by letsencrypt::renew and letsencrypt::certonly to create hook scripts. #### Parameters The following parameters are available in the `letsencrypt::hook` defined type. ##### `type` Data type: `Enum['pre', 'post', 'deploy']` Hook type. ##### `hook_file` Data type: `String[1]` Path to deploy hook script. ##### `commands` Data type: `Variant[String[1],Array[String[1]]]` Bash commands to execute when the hook is run by certbot. ## Functions ### letsencrypt::letsencrypt_lookup Type: Ruby 4.x API The letsencrypt::letsencrypt_lookup function. #### `letsencrypt::letsencrypt_lookup(Any $cn)` The letsencrypt::letsencrypt_lookup function. Returns: `Any` ##### `cn` Data type: `Any` ## Data types ### Letsencrypt::Cron::Hour mimic hour setting in cron as defined in man 5 crontab Alias of `Variant[Integer[0,23], String[1], Array[ Variant[ Integer[0,23], String[1], ] ]]` ### Letsencrypt::Cron::Minute mimic minute setting in cron as defined in man 5 crontab Alias of `Variant[Integer[0,59], String[1], Array[ Variant[ Integer[0,59], String[1], ] ]]` ### Letsencrypt::Cron::Monthday mimic monthday setting in cron as defined in man 5 crontab Alias of `Variant[Integer[0,31], String[1], Array[ Variant[ Integer[0,31], String[1], ] ]]` ### Letsencrypt::Plugin List of accepted plugins Alias of `Enum['apache', 'standalone', 'webroot', 'nginx', 'dns-route53', 'dns-google', 'dns-cloudflare', 'dns-rfc2136']` diff --git a/manifests/init.pp b/manifests/init.pp index 90177dc..5bb1b90 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -1,132 +1,132 @@ # @summary Install and configure Certbot, the LetsEncrypt client # # Install and configure Certbot, the LetsEncrypt client # # @example # class { 'letsencrypt' : # email => 'letsregister@example.com', # config => { # 'server' => 'https://acme-staging-v02.api.letsencrypt.org/directory', # }, # } # # @param email # The email address to use to register with Let's Encrypt. This takes # precedence over an 'email' setting defined in $config. # @param path The path to the letsencrypt installation. # @param venv_path virtualenv path for vcs-installed Certbot # @param environment An optional array of environment variables (in addition to VENV_PATH) # @param repo A Git URL to install the Let's encrypt client from. # @param version The Git ref (tag, sha, branch) to check out when installing the client with the `vcs` method. # @param package_name Name of package and command to use when installing the client with the `package` method. # @param package_ensure The value passed to `ensure` when installing the client with the `package` method. # @param package_command Path or name for letsencrypt executable when installing the client with the `package` method. # @param config_file The path to the configuration file for the letsencrypt cli. # @param config A hash representation of the letsencrypt configuration file. # @param cron_scripts_path The path for renewal scripts called by cron # @param cron_owner_group Group owner of cron renew scripts. # @param manage_config A feature flag to toggle the management of the letsencrypt configuration file. # @param manage_install A feature flag to toggle the management of the letsencrypt client installation. # @param manage_dependencies A feature flag to toggle the management of the letsencrypt dependencies. # @param configure_epel A feature flag to include the 'epel' class and depend on it for package installation. # @param install_method Method to install the letsencrypt client, either package or vcs. # @param agree_tos A flag to agree to the Let's Encrypt Terms of Service. # @param unsafe_registration A flag to allow using the 'register-unsafely-without-email' flag. # @param config_dir The path to the configuration directory. # @param key_size Size for the RSA public key # @param renew_pre_hook_commands Array of commands to run in a shell before obtaining/renewing any certificates. # @param renew_post_hook_commands Array of commands to run in a shell after attempting to obtain/renew certificates. # @param renew_deploy_hook_commands # Array of commands to run in a shell once for each successfully issued/renewed # certificate. Two environmental variables are supplied by certbot: # - $RENEWED_LINEAGE: Points to the live directory with the cert files and key. # Example: /etc/letsencrypt/live/example.com # - $RENEWED_DOMAINS: A space-delimited list of renewed certificate domains. # Example: "example.com www.example.com" # @param renew_additional_args Array of additional command line arguments to pass to 'certbot renew'. # @param renew_cron_ensure Intended state of the cron resource running certbot renew. # @param renew_cron_hour # Optional string, integer or array of hour(s) the renewal command should run. # E.g. '[0,12]' to execute at midnight and midday. # hour. # @param renew_cron_minute # Optional string, integer or array of minute(s) the renewal command should # run. E.g. 0 or '00' or [0,30]. # @param renew_cron_monthday # Optional string, integer or array of monthday(s) the renewal command should # run. E.g. '2-30/2' to run on even days. # class letsencrypt ( Boolean $configure_epel, Optional[String] $email = undef, String $path = '/opt/letsencrypt', $venv_path = '/opt/letsencrypt/.venv', Array $environment = [], String $repo = 'https://github.com/certbot/certbot.git', - String $version = 'v0.30.2', + String $version = 'v0.39.0', String $package_name = 'certbot', $package_ensure = 'installed', String $package_command = 'certbot', Stdlib::Unixpath $config_dir = '/etc/letsencrypt', String $config_file = "${config_dir}/cli.ini", Hash $config = {'server' => 'https://acme-v02.api.letsencrypt.org/directory'}, String $cron_scripts_path = "${facts['puppet_vardir']}/letsencrypt", String $cron_owner_group = 'root', Boolean $manage_config = true, Boolean $manage_install = true, Boolean $manage_dependencies = true, Enum['package', 'vcs'] $install_method = 'package', Boolean $agree_tos = true, Boolean $unsafe_registration = false, Integer[2048] $key_size = 4096, # $renew_* should only be used in letsencrypt::renew (blame rspec) $renew_pre_hook_commands = [], $renew_post_hook_commands = [], $renew_deploy_hook_commands = [], $renew_additional_args = [], $renew_cron_ensure = 'absent', $renew_cron_hour = fqdn_rand(24), $renew_cron_minute = fqdn_rand(60, fqdn_rand_string(10)), $renew_cron_monthday = '*', ) { if $manage_install { contain letsencrypt::install # lint:ignore:relative_classname_inclusion Class['letsencrypt::install'] ~> Exec['initialize letsencrypt'] Class['letsencrypt::install'] -> Class['letsencrypt::renew'] } $command = $install_method ? { 'package' => $package_command, 'vcs' => "${venv_path}/bin/letsencrypt", } $command_init = $install_method ? { 'package' => $package_command, 'vcs' => "${path}/letsencrypt-auto", } if $manage_config { contain letsencrypt::config # lint:ignore:relative_classname_inclusion Class['letsencrypt::config'] -> Exec['initialize letsencrypt'] } contain letsencrypt::renew # TODO: do we need this command when installing from package? exec { 'initialize letsencrypt': command => "${command_init} -h", path => $facts['path'], environment => concat([ "VENV_PATH=${venv_path}" ], $environment), refreshonly => true, } # Used in letsencrypt::certonly Exec["letsencrypt certonly ${title}"] file { '/usr/local/sbin/letsencrypt-domain-validation': ensure => file, owner => 'root', group => 'root', mode => '0500', source => "puppet:///modules/${module_name}/domain-validation.sh", } } diff --git a/spec/classes/letsencrypt_spec.rb b/spec/classes/letsencrypt_spec.rb index 658ef6c..1a5e615 100644 --- a/spec/classes/letsencrypt_spec.rb +++ b/spec/classes/letsencrypt_spec.rb @@ -1,298 +1,298 @@ require 'spec_helper' describe 'letsencrypt' do on_supported_os.each do |os, facts| context "on #{os}" do let :facts do facts end context 'when specifying an email address with the email parameter' do let(:params) { additional_params.merge(default_params) } let(:default_params) { { email: 'foo@example.com' } } let(:additional_params) { {} } describe 'with defaults' do it { is_expected.to compile } epel = facts[:osfamily] == 'RedHat' && facts[:operatingsystem] != 'Fedora' it 'contains File[/usr/local/sbin/letsencrypt-domain-validation]' do is_expected.to contain_file('/usr/local/sbin/letsencrypt-domain-validation'). with_ensure('file'). with_owner('root'). with_group('root'). with_mode('0500'). with_source('puppet:///modules/letsencrypt/domain-validation.sh') end it 'contains the correct resources' do is_expected.to contain_class('letsencrypt::install'). with(configure_epel: epel, manage_install: true, manage_dependencies: true, repo: 'https://github.com/certbot/certbot.git', - version: 'v0.30.2'). + version: 'v0.39.0'). that_notifies('Exec[initialize letsencrypt]'). that_comes_before('Class[letsencrypt::renew]') is_expected.to contain_exec('initialize letsencrypt') is_expected.to contain_class('letsencrypt::config').that_comes_before('Exec[initialize letsencrypt]') is_expected.to contain_class('letsencrypt::renew'). with(pre_hook_commands: [], post_hook_commands: [], deploy_hook_commands: [], additional_args: [], cron_ensure: 'absent', cron_monthday: ['*']) is_expected.to contain_cron('letsencrypt-renew').with_ensure('absent') if facts[:osfamily] == 'FreeBSD' is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini email foo@example.com') is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini server https://acme-v02.api.letsencrypt.org/directory') is_expected.to contain_file('letsencrypt-renewal-hooks-puppet'). with(ensure: 'directory', path: '/usr/local/etc/letsencrypt/renewal-hooks-puppet', owner: 'root', group: 'root', mode: '0755', recurse: true, purge: true) else is_expected.to contain_ini_setting('/etc/letsencrypt/cli.ini email foo@example.com') is_expected.to contain_ini_setting('/etc/letsencrypt/cli.ini server https://acme-v02.api.letsencrypt.org/directory') is_expected.to contain_file('letsencrypt-renewal-hooks-puppet').with_path('/etc/letsencrypt/renewal-hooks-puppet') end if facts[:osfamily] == 'RedHat' if epel is_expected.to contain_class('epel').that_comes_before('Package[letsencrypt]') else is_expected.not_to contain_class('epel') end is_expected.to contain_class('letsencrypt::install').with(install_method: 'package').with(package_name: 'certbot') is_expected.to contain_class('letsencrypt').with(package_command: 'certbot') is_expected.to contain_package('letsencrypt').with(name: 'certbot') is_expected.to contain_file('/etc/letsencrypt').with(ensure: 'directory') elsif facts[:osfamily] == 'Debian' is_expected.to contain_class('letsencrypt::install').with(install_method: 'package').with(package_name: 'certbot') is_expected.to contain_file('/etc/letsencrypt').with(ensure: 'directory') elsif facts[:operatingsystem] == 'Gentoo' is_expected.to contain_class('letsencrypt::install').with(install_method: 'package').with(package_name: 'app-crypt/certbot') is_expected.to contain_class('letsencrypt').with(package_command: 'certbot') is_expected.to contain_package('letsencrypt').with(name: 'app-crypt/certbot') is_expected.to contain_file('/etc/letsencrypt').with(ensure: 'directory') elsif facts[:operatingsystem] == 'OpenBSD' is_expected.to contain_class('letsencrypt::install').with(install_method: 'package').with(package_name: 'certbot') is_expected.to contain_class('letsencrypt').with(package_command: 'certbot') is_expected.to contain_package('letsencrypt').with(name: 'certbot') is_expected.to contain_file('/etc/letsencrypt').with(ensure: 'directory') elsif facts[:operatingsystem] == 'FreeBSD' is_expected.to contain_class('letsencrypt::install').with(install_method: 'package').with(package_name: 'py27-certbot') is_expected.to contain_class('letsencrypt').with(package_command: 'certbot') is_expected.to contain_package('letsencrypt').with(name: 'py27-certbot') is_expected.to contain_file('/usr/local/etc/letsencrypt').with(ensure: 'directory') else is_expected.to contain_class('letsencrypt::install').with(install_method: 'vcs') is_expected.to contain_file('/etc/letsencrypt').with(ensure: 'directory') end end end # describe 'with defaults' describe 'with custom path' do let(:additional_params) { { path: '/usr/lib/letsencrypt', install_method: 'vcs' } } it { is_expected.to contain_class('letsencrypt::install').with_path('/usr/lib/letsencrypt') } it { is_expected.to contain_exec('initialize letsencrypt').with_command('/usr/lib/letsencrypt/letsencrypt-auto -h') } end describe 'with custom environment variables' do let(:additional_params) { { environment: ['FOO=bar', 'FIZZ=buzz'] } } it { is_expected.to contain_exec('initialize letsencrypt').with_environment(['VENV_PATH=/opt/letsencrypt/.venv', 'FOO=bar', 'FIZZ=buzz']) } end describe 'with custom repo' do let(:additional_params) { { repo: 'git://foo.com/letsencrypt.git' } } it { is_expected.to contain_class('letsencrypt::install').with_repo('git://foo.com/letsencrypt.git') } end describe 'with custom version' do let(:additional_params) { { version: 'foo' } } it { is_expected.to contain_class('letsencrypt::install').with_path('/opt/letsencrypt').with_version('foo') } end describe 'with custom package_ensure' do let(:additional_params) { { package_ensure: '0.3.0-1.el7' } } it { is_expected.to contain_class('letsencrypt::install').with_package_ensure('0.3.0-1.el7') } end describe 'with custom config file' do let(:additional_params) { { config_file: '/etc/letsencrypt/custom_config.ini' } } it { is_expected.to contain_ini_setting('/etc/letsencrypt/custom_config.ini server https://acme-v02.api.letsencrypt.org/directory') } end describe 'with custom config' do let(:additional_params) { { config: { 'foo' => 'bar' } } } case facts[:operatingsystem] when 'FreeBSD' it { is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini foo bar') } else it { is_expected.to contain_ini_setting('/etc/letsencrypt/cli.ini foo bar') } end end describe 'with manage_config set to false' do let(:additional_params) { { manage_config: false } } it { is_expected.not_to contain_class('letsencrypt::config') } end describe 'with manage_install set to false' do let(:additional_params) { { manage_install: false } } it { is_expected.not_to contain_class('letsencrypt::install') } end describe 'with install_method => package' do let(:additional_params) { { install_method: 'package', package_command: 'letsencrypt' } } it { is_expected.to contain_class('letsencrypt::install').with_install_method('package') } it { is_expected.to contain_exec('initialize letsencrypt').with_command('letsencrypt -h') } end describe 'with install_method => vcs' do let(:additional_params) { { install_method: 'vcs' } } it { is_expected.to contain_class('letsencrypt::install').with_install_method('vcs') } it { is_expected.to contain_exec('initialize letsencrypt').with_command('/opt/letsencrypt/letsencrypt-auto -h') } end describe 'with custom config directory' do let(:additional_params) { { config_dir: '/foo/bar/baz' } } it { is_expected.to contain_file('/foo/bar/baz').with(ensure: 'directory') } end context 'when not agreeing to the TOS' do let(:params) { { agree_tos: false } } it { is_expected.to raise_error Puppet::Error, %r{You must agree to the Let's Encrypt Terms of Service} } end context 'with renew' do describe 'pre hook' do let(:additional_params) { { config_dir: '/etc/letsencrypt', renew_pre_hook_commands: ['FooBar'] } } it { is_expected.to contain_letsencrypt__hook('renew-pre').with_hook_file('/etc/letsencrypt/renewal-hooks-puppet/renew-pre.sh') } end describe 'post hook' do let(:additional_params) { { config_dir: '/etc/letsencrypt', renew_post_hook_commands: ['FooBar'] } } it { is_expected.to contain_letsencrypt__hook('renew-post').with_hook_file('/etc/letsencrypt/renewal-hooks-puppet/renew-post.sh') } end describe 'deploy hook' do let(:additional_params) { { config_dir: '/etc/letsencrypt', renew_deploy_hook_commands: ['FooBar'] } } it { is_expected.to contain_letsencrypt__hook('renew-deploy').with_hook_file('/etc/letsencrypt/renewal-hooks-puppet/renew-deploy.sh') } end describe 'renew_cron_ensure' do let(:additional_params) do { install_method: 'package', package_command: 'certbot', renew_cron_ensure: 'present', renew_cron_hour: 0, renew_cron_minute: 0 } end it do is_expected.to contain_cron('letsencrypt-renew'). with(ensure: 'present', command: 'certbot renew -q', hour: 0, minute: 0, monthday: '*') end end describe 'renew_cron_ensure and renew_cron_monthday' do let(:additional_params) { { renew_cron_ensure: 'present', renew_cron_monthday: [1, 15] } } it { is_expected.to contain_cron('letsencrypt-renew').with_ensure('present').with_monthday([1, 15]) } end describe 'renew_cron_ensure and hooks' do let(:additional_params) do { config_dir: '/etc/letsencrypt', install_method: 'package', package_command: 'certbot', renew_cron_ensure: 'present', renew_pre_hook_commands: ['PreBar'], renew_post_hook_commands: ['PostBar'], renew_deploy_hook_commands: ['DeployBar'] } end it do is_expected.to contain_cron('letsencrypt-renew'). with(ensure: 'present', command: 'certbot renew -q --pre-hook "/etc/letsencrypt/renewal-hooks-puppet/renew-pre.sh" --post-hook "/etc/letsencrypt/renewal-hooks-puppet/renew-post.sh" --deploy-hook "/etc/letsencrypt/renewal-hooks-puppet/renew-deploy.sh"') end end describe 'renew_cron_ensure and additional args' do let(:additional_params) do { install_method: 'package', package_command: 'certbot', renew_cron_ensure: 'present', renew_additional_args: ['AdditionalBar'] } end it do is_expected.to contain_cron('letsencrypt-renew'). with(ensure: 'present', command: 'certbot renew -q AdditionalBar') end end end # context 'with renew' end # context 'when specifying an email address with the email parameter' context 'when specifying an email in $config' do let(:params) { { config: { 'email' => 'foo@example.com' } } } it { is_expected.to compile.with_all_deps } case facts[:operatingsystem] when 'FreeBSD' it { is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini email foo@example.com') } else it { is_expected.to contain_ini_setting('/etc/letsencrypt/cli.ini email foo@example.com') } end end context 'when not specifying the email parameter or an email key in $config' do context 'with unsafe_registration set to false' do it { is_expected.to raise_error Puppet::Error, %r{Please specify an email address} } end context 'with unsafe_registration set to true' do let(:params) { { unsafe_registration: true } } case facts[:operatingsystem] when 'FreeBSD' it { is_expected.not_to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini email foo@example.com') } it { is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini register-unsafely-without-email true') } else it { is_expected.not_to contain_ini_setting('/etc/letsencrypt/cli.ini email foo@example.com') } it { is_expected.to contain_ini_setting('/etc/letsencrypt/cli.ini register-unsafely-without-email true') } end end end end end end