From 453c762dafcae24a5f2c643291efc75863d24c01 Mon Sep 17 00:00:00 2001 From: Yury Bushmelev Date: Fri, 20 Dec 2024 18:58:20 +0800 Subject: [PATCH] Implement vhost_dir and vhost_enable_dir support This change allows to use the config files layout similar to apache/nginx (conf.d or sites-{enabled,allowed}). --- README.md | 50 +++++++++ REFERENCE.md | 169 ++++++++++++++++++++++++++++-- manifests/config.pp | 28 ++++- manifests/configfile.pp | 54 ++++++++++ manifests/init.pp | 33 +++++- manifests/vhost.pp | 41 ++++++-- spec/acceptance/init_spec.rb | 42 ++++++++ spec/classes/init_spec.rb | 141 ++++++++++++++++++++++++- spec/defines/configfile_spec.rb | 65 ++++++++++++ spec/defines/vhost_spec.rb | 32 +++++- templates/etc/caddy/caddyfile.epp | 6 +- types/config.pp | 6 ++ types/virtualhost.pp | 2 +- 13 files changed, 638 insertions(+), 31 deletions(-) create mode 100644 manifests/configfile.pp create mode 100644 spec/defines/configfile_spec.rb create mode 100644 types/config.pp diff --git a/README.md b/README.md index 5d5bf9d..e2da141 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,56 @@ caddy::vhost { 'example2': } ``` +Use `conf.d` + `sites-available` + `sites-enabled` layout with `config_files` and `vhosts` parameters set: + +```puppet +class { 'caddy': + config_dir => '/etc/caddy/conf.d', + vhost_dir => '/etc/caddy/sites-available', + vhost_enable_dir => '/etc/caddy/sites-enabled', + config_files => { + admin_port_2020 => { + content => "{\n admin localhost:2020\n}\n", + }, + }, + vhosts => { + port_3000 => { + content => "http://localhost:3000 {\n respond \\"port 3000\\"\n}\n", + }, + port_3001 => { + ensure => 'disabled', + content => "http://localhost:3001 {\n respond \\"port 3001\\"\n}\n", + } + } +} +``` + +Same as above but configured in Hiera: + +```yaml +caddy::config_dir: /etc/caddy/conf.d +caddy::vhost_dir: /etc/caddy/sites-available +caddy::vhost_enable_dir: /etc/caddy/sites-enabled +caddy::config_files: + admin_port_2020: + content: | + { + admin localhost:2020 + } +caddy::vhosts: + port_3000: + content: | + http://localhost:3000 { + respond "port 3000" + } + port_3001: + ensure: disabled + content: | + http://localhost:3001 { + respond "port 3001" + } +``` + ## Reference The [reference][1] documentation of this module is generated using [puppetlabs/puppetlabs-strings][2]. diff --git a/REFERENCE.md b/REFERENCE.md index ee101b9..ed31a63 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -19,10 +19,12 @@ ### Defined types -* [`caddy::vhost`](#caddy--vhost): This defined type handles the Caddy virtual hosts. +* [`caddy::configfile`](#caddy--configfile): This defined type handles a Caddy config file +* [`caddy::vhost`](#caddy--vhost): This defined type handles a Caddy virtual host ### Data types +* [`Caddy::Config`](#Caddy--Config): Caddy config file type * [`Caddy::VirtualHost`](#Caddy--VirtualHost): Caddy virtual host type ## Classes @@ -96,6 +98,11 @@ The following parameters are available in the `caddy` class: * [`caddyfile_content`](#-caddy--caddyfile_content) * [`config_dir`](#-caddy--config_dir) * [`purge_config_dir`](#-caddy--purge_config_dir) +* [`config_files`](#-caddy--config_files) +* [`vhost_dir`](#-caddy--vhost_dir) +* [`purge_vhost_dir`](#-caddy--purge_vhost_dir) +* [`vhost_enable_dir`](#-caddy--vhost_enable_dir) +* [`purge_vhost_enable_dir`](#-caddy--purge_vhost_enable_dir) * [`vhosts`](#-caddy--vhosts) ##### `version` @@ -389,19 +396,136 @@ Whether to purge Caddy config directory. Default value: `true` +##### `config_files` + +Data type: `Hash[String[1], Caddy::Config]` + +Hash of config files to create. + +Default value: `{}` + +##### `vhost_dir` + +Data type: `Stdlib::Absolutepath` + +Where to store Caddy available virtual host configs. Set this to +/etc/caddy/vhost.d if you'd prefer to keep virtual hosts separated from +configs. +Set this to /etc/caddy/sites-available to simulate nginx/apache behavior +(see vhost_enable_dir also). + +Default value: `'/etc/caddy/config'` + +##### `purge_vhost_dir` + +Data type: `Boolean` + +Whether to purge Caddy available virtual host directory. + +Default value: `$purge_config_dir` + +##### `vhost_enable_dir` + +Data type: `Optional[Stdlib::Absolutepath]` + +Where to load Caddy virtual host configs from. Set this parameter to /etc/caddy/sites-enabled +to simulate nginx/apache behavior. + +Default value: `undef` + +##### `purge_vhost_enable_dir` + +Data type: `Boolean` + +Whether to purge Caddy enabled virtual host directory. + +Default value: `$purge_vhost_dir` + ##### `vhosts` Data type: `Hash[String[1], Caddy::VirtualHost]` -List of virtual hosts to create. +Hash of virtual hosts to create. Default value: `{}` ## Defined types +### `caddy::configfile` + +This defined type handles a Caddy config file + +#### Examples + +##### Configure Caddy logging + +```puppet +caddy::configfile { 'subdomain-log': + source => 'puppet:///modules/caddy/etc/caddy/config/logging.conf', +} +``` + +##### Same as above but using content + +```puppet +$log_config = @(SUBDOMAIN_LOG) + (subdomain-log) { + log { + hostnames {args[0]} + output file /var/log/caddy/{args[0]}.log + } + } + | SUBDOMAIN_LOG + +caddy::configfile { 'subdomain-log': + content => $log_config, +} +``` + +#### Parameters + +The following parameters are available in the `caddy::configfile` defined type: + +* [`ensure`](#-caddy--configfile--ensure) +* [`source`](#-caddy--configfile--source) +* [`content`](#-caddy--configfile--content) +* [`config_dir`](#-caddy--configfile--config_dir) + +##### `ensure` + +Data type: `Enum['present','absent']` + +Make the config file either present or absent. + +Default value: `'present'` + +##### `source` + +Data type: `Optional[Stdlib::Filesource]` + +Source (path) for the caddy config file. + +Default value: `undef` + +##### `content` + +Data type: `Optional[String]` + +String with the caddy config file. + +Default value: `undef` + +##### `config_dir` + +Data type: `Stdlib::Absolutepath` + +Where to store the config file. + +Default value: `$caddy::config_dir` + ### `caddy::vhost` -This defined type handles the Caddy virtual hosts. +This defined type handles a Caddy virtual host #### Examples @@ -429,20 +553,21 @@ The following parameters are available in the `caddy::vhost` defined type: * [`source`](#-caddy--vhost--source) * [`content`](#-caddy--vhost--content) * [`config_dir`](#-caddy--vhost--config_dir) +* [`enable_dir`](#-caddy--vhost--enable_dir) ##### `ensure` -Data type: `Enum['present','absent']` +Data type: `Enum['present','enabled','disabled','absent']` -Make the vhost either present or absent +Make the vhost either present (same as disabled), enabled, disabled or absent. -Default value: `'present'` +Default value: `'enabled'` ##### `source` Data type: `Optional[Stdlib::Filesource]` -Source (path) for the caddy vhost configuration +Source (path) for the caddy vhost configuration. Default value: `undef` @@ -450,7 +575,7 @@ Default value: `undef` Data type: `Optional[String]` -String with the caddy vhost configuration +String with the caddy vhost configuration. Default value: `undef` @@ -458,12 +583,34 @@ Default value: `undef` Data type: `Stdlib::Absolutepath` -Where to store the vhost config file +Where to store the vhost config file. -Default value: `$caddy::config_dir` +Default value: `$caddy::vhost_dir` + +##### `enable_dir` + +Data type: `Optional[Stdlib::Absolutepath]` + +Directory to symlink the vhost config file into (sites-enabled e.g.) if any. + +Default value: `$caddy::vhost_enable_dir` ## Data types +### `Caddy::Config` + +Caddy config file type + +Alias of + +```puppet +Struct[{ + ensure => Optional[Enum['absent', 'present']], + source => Optional[Stdlib::Filesource], + content => Optional[String[1]], +}] +``` + ### `Caddy::VirtualHost` Caddy virtual host type @@ -472,7 +619,7 @@ Alias of ```puppet Struct[{ - ensure => Optional[Enum['absent', 'present']], + ensure => Optional[Enum['present','enabled','disabled','absent']], source => Optional[Stdlib::Filesource], content => Optional[String[1]], }] diff --git a/manifests/config.pp b/manifests/config.pp index 8fe685f..fa2929b 100644 --- a/manifests/config.pp +++ b/manifests/config.pp @@ -24,10 +24,34 @@ ; $caddy::config_dir: purge => $caddy::purge_config_dir, - recurse => true, + recurse => if $caddy::purge_config_dir { true } else { undef }, ; } + # Manage vhost_dir if not the same as config dir + unless $caddy::vhost_dir == $caddy::config_dir { + file { $caddy::vhost_dir: + ensure => directory, + owner => $caddy::caddy_user, + group => $caddy::caddy_group, + mode => '0755', + purge => $caddy::purge_vhost_dir, + recurse => if $caddy::purge_vhost_dir { true } else { undef }, + } + } + + # Manage vhost_enable_dir if defined + if $caddy::vhost_enable_dir { + file { $caddy::vhost_enable_dir: + ensure => directory, + owner => $caddy::caddy_user, + group => $caddy::caddy_group, + mode => '0755', + purge => $caddy::purge_vhost_enable_dir, + recurse => if $caddy::purge_vhost_enable_dir { true } else { undef }, + } + } + if $caddy::manage_caddyfile { # Prefer source over content if both are defined # Fallback to the bundled template if both are unset @@ -35,7 +59,7 @@ $real_content = if $caddy::caddyfile_source { undef } else { $caddy::caddyfile_content.lest || { epp('caddy/etc/caddy/caddyfile.epp', - config_dir => $caddy::config_dir, + include_dirs => unique([$caddy::config_dir] + [$caddy::vhost_enable_dir.lest || { $caddy::vhost_dir }]) ) } } diff --git a/manifests/configfile.pp b/manifests/configfile.pp new file mode 100644 index 0000000..938a3db --- /dev/null +++ b/manifests/configfile.pp @@ -0,0 +1,54 @@ +# @summary This defined type handles a Caddy config file +# +# @param ensure +# Make the config file either present or absent. +# +# @param source +# Source (path) for the caddy config file. +# +# @param content +# String with the caddy config file. +# +# @param config_dir +# Where to store the config file. +# +# @example Configure Caddy logging +# caddy::configfile { 'subdomain-log': +# source => 'puppet:///modules/caddy/etc/caddy/config/logging.conf', +# } +# +# @example Same as above but using content +# $log_config = @(SUBDOMAIN_LOG) +# (subdomain-log) { +# log { +# hostnames {args[0]} +# output file /var/log/caddy/{args[0]}.log +# } +# } +# | SUBDOMAIN_LOG +# +# caddy::configfile { 'subdomain-log': +# content => $log_config, +# } +# +define caddy::configfile ( + Enum['present','absent'] $ensure = 'present', + Optional[Stdlib::Filesource] $source = undef, + Optional[String] $content = undef, + Stdlib::Absolutepath $config_dir = $caddy::config_dir, +) { + include caddy + + if ($ensure == 'present') and !($source or $content) { + fail('Either $source or $content must be specified when $ensure is "present"') + } + + file { "${config_dir}/${title}.conf": + ensure => stdlib::ensure($ensure, 'file'), + content => $content, + source => $source, + mode => '0444', + require => Class['caddy::config'], + notify => Class['caddy::service'], + } +} diff --git a/manifests/init.pp b/manifests/init.pp index ec49d5f..c8e0339 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -126,8 +126,28 @@ # @param purge_config_dir # Whether to purge Caddy config directory. # +# @param config_files +# Hash of config files to create. +# +# @param vhost_dir +# Where to store Caddy available virtual host configs. Set this to +# /etc/caddy/vhost.d if you'd prefer to keep virtual hosts separated from +# configs. +# Set this to /etc/caddy/sites-available to simulate nginx/apache behavior +# (see vhost_enable_dir also). +# +# @param purge_vhost_dir +# Whether to purge Caddy available virtual host directory. +# +# @param vhost_enable_dir +# Where to load Caddy virtual host configs from. Set this parameter to /etc/caddy/sites-enabled +# to simulate nginx/apache behavior. +# +# @param purge_vhost_enable_dir +# Whether to purge Caddy enabled virtual host directory. +# # @param vhosts -# List of virtual hosts to create. +# Hash of virtual hosts to create. # class caddy ( String[1] $version = '2.0.0', @@ -142,6 +162,8 @@ Stdlib::Absolutepath $caddy_home = '/var/lib/caddy', Stdlib::Absolutepath $caddy_ssl_dir = '/etc/ssl/caddy', Stdlib::Absolutepath $config_dir = '/etc/caddy/config', + Stdlib::Absolutepath $vhost_dir = '/etc/caddy/config', + Optional[Stdlib::Absolutepath] $vhost_enable_dir = undef, Enum['personal', 'commercial'] $caddy_license = 'personal', Enum['on','off'] $caddy_telemetry = 'off', String[1] $caddy_features = 'http.git,http.filter,http.ipfilter', @@ -166,6 +188,9 @@ Optional[Stdlib::Filesource] $caddyfile_source = undef, Optional[String[1]] $caddyfile_content = undef, Boolean $purge_config_dir = true, + Boolean $purge_vhost_dir = $purge_config_dir, + Boolean $purge_vhost_enable_dir = $purge_vhost_dir, + Hash[String[1], Caddy::Config] $config_files = {}, Hash[String[1], Caddy::VirtualHost] $vhosts = {}, ) { case $caddy_architecture { @@ -203,6 +228,12 @@ contain caddy::config contain caddy::service + $config_files.each |String[1] $name, Caddy::Config $cfg| { + caddy::configfile { $name: + * => $cfg, + } + } + $vhosts.each |String[1] $name, Caddy::VirtualHost $vhost| { caddy::vhost { $name: * => $vhost, diff --git a/manifests/vhost.pp b/manifests/vhost.pp index 4e5cef7..eaae231 100644 --- a/manifests/vhost.pp +++ b/manifests/vhost.pp @@ -1,16 +1,19 @@ -# @summary This defined type handles the Caddy virtual hosts. +# @summary This defined type handles a Caddy virtual host # # @param ensure -# Make the vhost either present or absent +# Make the vhost either present (same as disabled), enabled, disabled or absent. # # @param source -# Source (path) for the caddy vhost configuration +# Source (path) for the caddy vhost configuration. # # @param content -# String with the caddy vhost configuration +# String with the caddy vhost configuration. # # @param config_dir -# Where to store the vhost config file +# Where to store the vhost config file. +# +# @param enable_dir +# Directory to symlink the vhost config file into (sites-enabled e.g.) if any. # # @example Configure virtual host, based on source # caddy::vhost { 'example1': @@ -23,23 +26,43 @@ # } # define caddy::vhost ( - Enum['present','absent'] $ensure = 'present', + Enum['present','enabled','disabled','absent'] $ensure = 'enabled', Optional[Stdlib::Filesource] $source = undef, Optional[String] $content = undef, - Stdlib::Absolutepath $config_dir = $caddy::config_dir, + Stdlib::Absolutepath $config_dir = $caddy::vhost_dir, + Optional[Stdlib::Absolutepath] $enable_dir = $caddy::vhost_enable_dir, ) { include caddy - if ($ensure == 'present') and !($source or $content) { + if ($ensure != 'absent') and !($source or $content) { fail('Either $source or $content must be specified when $ensure is "present"') } + $file_ensure = $ensure ? { + 'absent' => 'absent', + default => 'file', + } + file { "${config_dir}/${title}.conf": - ensure => stdlib::ensure($ensure, 'file'), + ensure => $file_ensure, content => $content, source => $source, mode => '0444', require => Class['caddy::config'], notify => Class['caddy::service'], } + + if $enable_dir { + $symlink_ensure = $ensure ? { + 'enabled' => 'link', + default => 'absent', + } + + file { "${enable_dir}/${title}.conf": + ensure => $symlink_ensure, + target => "${config_dir}/${title}.conf", + require => Class['caddy::config'], + notify => Class['caddy::service'], + } + } } diff --git a/spec/acceptance/init_spec.rb b/spec/acceptance/init_spec.rb index 46f9677..b275b05 100644 --- a/spec/acceptance/init_spec.rb +++ b/spec/acceptance/init_spec.rb @@ -103,5 +103,47 @@ class { 'caddy': end end end + + context 'with apache-like layout' do + it_behaves_like 'an idempotent resource' do + let(:manifest) do + <<~PUPPET + class { 'caddy': + config_dir => '/etc/caddy/conf.d', + vhost_dir => '/etc/caddy/sites-available', + vhost_enable_dir => '/etc/caddy/sites-enabled', + config_files => { + admin => { + content => "{\n admin localhost:2020\n}\n", + }, + }, + vhosts => { + port_3000 => { + content => "http://localhost:3000 {\n respond \\"port 3000 ok\\"\n}\n", + }, + port_3001 => { + ensure => 'disabled', + content => "http://localhost:3001 {\n respond \\"port 3001 disabled\\"\n}\n", + } + } + } + PUPPET + end + end + + describe command('curl -v http://localhost:2020/config/admin') do + its(:exit_status) { is_expected.to eq 0 } + its(:stdout) { is_expected.to eq "{\"listen\":\"localhost:2020\"}\n" } + end + + describe command('curl -v http://localhost:3000/') do + its(:exit_status) { is_expected.to eq 0 } + its(:stdout) { is_expected.to eq 'port 3000 ok' } + end + + describe port(3001) do + it { is_expected.not_to be_listening } + end + end end # rubocop:enable RSpec/RepeatedExampleGroupDescription diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb index 08b054e..7ba2eec 100644 --- a/spec/classes/init_spec.rb +++ b/spec/classes/init_spec.rb @@ -352,6 +352,140 @@ end end + context 'with config_dir set' do + let(:params) { { config_dir: '/etc/caddy/conf.d' } } + + it do + is_expected.to contain_file('/etc/caddy/conf.d'). + with_ensure('directory'). + with_owner('caddy'). + with_group('caddy'). + with_mode('0755'). + with_purge(true). + with_recurse(true) + end + + it do + is_expected.to contain_file('/etc/caddy/Caddyfile'). + with_content(%r{^import /etc/caddy/conf.d/\*\.conf$}) + end + end + + context 'with purge_config_dir => false' do + let(:params) { { purge_config_dir: false } } + + it do + is_expected.to contain_file('/etc/caddy/config'). + with_ensure('directory'). + with_purge(false). + with_recurse(nil) + end + end + + context 'with vhost_dir set' do + let(:params) { { vhost_dir: '/etc/caddy/vhost.d' } } + + it { is_expected.to contain_file('/etc/caddy/config').with_ensure('directory') } + + it do + is_expected.to contain_file('/etc/caddy/vhost.d'). + with_ensure('directory'). + with_owner('caddy'). + with_group('caddy'). + with_mode('0755'). + with_purge(true). + with_recurse(true) + end + + it do + is_expected.to contain_file('/etc/caddy/Caddyfile'). + with_content(%r{^import /etc/caddy/config/\*\.conf$}). + with_content(%r{^import /etc/caddy/vhost.d/\*\.conf$}) + end + + context 'with purge_vhost_dir => false' do + let(:params) { super().merge(purge_vhost_dir: false) } + + it do + is_expected.to contain_file('/etc/caddy/vhost.d'). + with_ensure('directory'). + with_purge(false). + with_recurse(nil) + end + end + end + + context 'with vhost_enable_dir set' do + let(:params) { { vhost_enable_dir: '/etc/caddy/sites-enabled' } } + + it do + is_expected.to contain_file('/etc/caddy/sites-enabled'). + with_ensure('directory'). + with_owner('caddy'). + with_group('caddy'). + with_mode('0755'). + with_purge(true). + with_recurse(true) + end + + it do + is_expected.to contain_file('/etc/caddy/Caddyfile'). + with_content(%r{^import /etc/caddy/config/\*\.conf$}). + with_content(%r{^import /etc/caddy/sites-enabled/\*\.conf$}) + end + + context 'with purge_vhost_enable_dir => false' do + let(:params) { super().merge(purge_vhost_enable_dir: false) } + + it do + is_expected.to contain_file('/etc/caddy/sites-enabled'). + with_ensure('directory'). + with_purge(false). + with_recurse(nil) + end + end + end + + context 'with both vhost_dir and vhost_enable_dir set' do + let(:params) do + { + vhost_dir: '/etc/caddy/sites-available', + vhost_enable_dir: '/etc/caddy/sites-enabled', + } + end + + it { is_expected.to contain_file('/etc/caddy/sites-available') } + it { is_expected.to contain_file('/etc/caddy/sites-enabled') } + + it do + is_expected.to contain_file('/etc/caddy/Caddyfile'). + with_content(%r{^import /etc/caddy/config/\*\.conf$}). + with_content(%r{^import /etc/caddy/sites-enabled/\*\.conf$}) + end + end + + context 'with configs set' do + let(:params) do + { + config_files: { + example1: { + source: 'puppet:///profiles/caddy/example1.conf', + }, + example2: { + content: "foo\nbar\n", + }, + example3: { + ensure: 'absent', + } + } + } + end + + it { is_expected.to contain_caddy__configfile('example1').with_ensure('present').with_source('puppet:///profiles/caddy/example1.conf') } + it { is_expected.to contain_caddy__configfile('example2').with_ensure('present').with_content("foo\nbar\n") } + it { is_expected.to contain_caddy__configfile('example3').with_ensure('absent') } + end + context 'with vhosts set' do let(:params) do { @@ -360,6 +494,7 @@ source: 'http://example.com/test-example-com.conf', }, 'h2.example.com': { + ensure: 'disabled', content: "localhost:1234{\n file_server\n}\n", }, 'h3.example.com': { @@ -369,9 +504,9 @@ } end - it { is_expected.to contain_file('/etc/caddy/config/h1.example.com.conf').with_source('http://example.com/test-example-com.conf') } - it { is_expected.to contain_file('/etc/caddy/config/h2.example.com.conf').with_content("localhost:1234{\n file_server\n}\n") } - it { is_expected.to contain_file('/etc/caddy/config/h3.example.com.conf').with_ensure('absent') } + it { is_expected.to contain_caddy__vhost('h1.example.com').with_ensure('enabled').with_source('http://example.com/test-example-com.conf') } + it { is_expected.to contain_caddy__vhost('h2.example.com').with_ensure('disabled').with_content("localhost:1234{\n file_server\n}\n") } + it { is_expected.to contain_caddy__vhost('h3.example.com').with_ensure('absent') } end end end diff --git a/spec/defines/configfile_spec.rb b/spec/defines/configfile_spec.rb new file mode 100644 index 0000000..0fd1364 --- /dev/null +++ b/spec/defines/configfile_spec.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'caddy::configfile', type: :define do + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:facts) do + facts + end + let(:pre_condition) { 'class { "caddy": config_dir => "/etc/caddy/config" }' } + let(:title) { 'example' } + + context 'with source' do + let(:params) { { source: 'puppet:///modules/caddy/etc/caddy/config/example1.conf' } } + + it do + is_expected.to contain_file('/etc/caddy/config/example.conf').with( + 'ensure' => 'file', + 'source' => 'puppet:///modules/caddy/etc/caddy/config/example1.conf', + 'mode' => '0444', + 'require' => 'Class[Caddy::Config]', + 'notify' => 'Class[Caddy::Service]' + ) + end + + context 'with config_dir set' do + let(:params) { super().merge(config_dir: '/etc/caddy/conf.d') } + + it { is_expected.to contain_file('/etc/caddy/conf.d/example.conf') } + end + + context 'with ensure => absent' do + let(:params) { super().merge(ensure: 'absent') } + + it { is_expected.to contain_file('/etc/caddy/config/example.conf').with_ensure('absent') } + end + + context 'with custom title' do + let(:title) { 'test' } + + it { is_expected.to contain_file('/etc/caddy/config/test.conf') } + end + end + + context 'with content' do + let(:params) { { content: 'localhost:2015' } } + + it do + is_expected.to contain_file('/etc/caddy/config/example.conf').with( + 'ensure' => 'file', + 'content' => 'localhost:2015', + 'mode' => '0444', + 'require' => 'Class[Caddy::Config]', + 'notify' => 'Class[Caddy::Service]' + ) + end + end + + context 'without source & content' do + it { is_expected.to compile.and_raise_error(%r{Either \$source or \$content must be specified}) } + end + end + end +end diff --git a/spec/defines/vhost_spec.rb b/spec/defines/vhost_spec.rb index 0cae95e..254cc8d 100644 --- a/spec/defines/vhost_spec.rb +++ b/spec/defines/vhost_spec.rb @@ -25,9 +25,37 @@ end context 'with config_dir set' do - let(:params) { super().merge(config_dir: '/etc/caddy/conf.d') } + let(:params) { super().merge(config_dir: '/etc/caddy/sites-available') } - it { is_expected.to contain_file('/etc/caddy/conf.d/example.conf') } + it { is_expected.to contain_file('/etc/caddy/sites-available/example.conf').with_ensure('file') } + end + + context 'with enable_dir set' do + let(:params) { super().merge(enable_dir: '/etc/caddy/sites-enabled') } + + it { is_expected.to contain_file('/etc/caddy/config/example.conf').with_ensure('file') } + + it do + is_expected.to contain_file('/etc/caddy/sites-enabled/example.conf'). + with_ensure('link'). + with_target('/etc/caddy/config/example.conf') + end + + %w[present disabled].each do |ens| + context "with ensure => #{ens}" do + let(:params) { super().merge(ensure: ens) } + + it { is_expected.to contain_file('/etc/caddy/config/example.conf').with_ensure('file') } + it { is_expected.to contain_file('/etc/caddy/sites-enabled/example.conf').with_ensure('absent') } + end + end + + context 'with ensure => absent' do + let(:params) { super().merge(ensure: 'absent') } + + it { is_expected.to contain_file('/etc/caddy/config/example.conf').with_ensure('absent') } + it { is_expected.to contain_file('/etc/caddy/sites-enabled/example.conf').with_ensure('absent') } + end end context 'with ensure => absent' do diff --git a/templates/etc/caddy/caddyfile.epp b/templates/etc/caddy/caddyfile.epp index b65848f..2d45d26 100644 --- a/templates/etc/caddy/caddyfile.epp +++ b/templates/etc/caddy/caddyfile.epp @@ -1,8 +1,10 @@ <%- | - String[1] $config_dir, + Array[String[1]] $include_dirs, | -%> # # THIS FILE IS MANAGED BY PUPPET # -import <%= $config_dir %>/*.conf +<%- $include_dirs.each |$dir| { -%> +import <%= $dir %>/*.conf +<%- } -%> diff --git a/types/config.pp b/types/config.pp new file mode 100644 index 0000000..33588a5 --- /dev/null +++ b/types/config.pp @@ -0,0 +1,6 @@ +# @summary Caddy config file type +type Caddy::Config = Struct[{ + ensure => Optional[Enum['absent', 'present']], + source => Optional[Stdlib::Filesource], + content => Optional[String[1]], +}] diff --git a/types/virtualhost.pp b/types/virtualhost.pp index 8b5dd04..1d65fae 100644 --- a/types/virtualhost.pp +++ b/types/virtualhost.pp @@ -1,6 +1,6 @@ # @summary Caddy virtual host type type Caddy::VirtualHost = Struct[{ - ensure => Optional[Enum['absent', 'present']], + ensure => Optional[Enum['present','enabled','disabled','absent']], source => Optional[Stdlib::Filesource], content => Optional[String[1]], }]