diff --git a/REFERENCE.md b/REFERENCE.md index fb5cc41..ee101b9 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -21,6 +21,10 @@ * [`caddy::vhost`](#caddy--vhost): This defined type handles the Caddy virtual hosts. +### Data types + +* [`Caddy::VirtualHost`](#Caddy--VirtualHost): Caddy virtual host type + ## Classes ### `caddy` @@ -87,6 +91,12 @@ The following parameters are available in the `caddy` class: * [`repo_settings`](#-caddy--repo_settings) * [`package_name`](#-caddy--package_name) * [`package_ensure`](#-caddy--package_ensure) +* [`manage_caddyfile`](#-caddy--manage_caddyfile) +* [`caddyfile_source`](#-caddy--caddyfile_source) +* [`caddyfile_content`](#-caddy--caddyfile_content) +* [`config_dir`](#-caddy--config_dir) +* [`purge_config_dir`](#-caddy--purge_config_dir) +* [`vhosts`](#-caddy--vhosts) ##### `version` @@ -339,6 +349,54 @@ Whether to install or remove the caddy package. Only relevant when $install_meth Default value: `$version` +##### `manage_caddyfile` + +Data type: `Boolean` + +Whether to manage Caddyfile. + +Default value: `true` + +##### `caddyfile_source` + +Data type: `Optional[Stdlib::Filesource]` + +Caddyfile source. + +Default value: `undef` + +##### `caddyfile_content` + +Data type: `Optional[String[1]]` + +Caddyfile content. + +Default value: `undef` + +##### `config_dir` + +Data type: `Stdlib::Absolutepath` + +Where to store Caddy configs + +Default value: `'/etc/caddy/config'` + +##### `purge_config_dir` + +Data type: `Boolean` + +Whether to purge Caddy config directory. + +Default value: `true` + +##### `vhosts` + +Data type: `Hash[String[1], Caddy::VirtualHost]` + +List of virtual hosts to create. + +Default value: `{}` + ## Defined types ### `caddy::vhost` @@ -367,14 +425,24 @@ caddy::vhost { 'example2: The following parameters are available in the `caddy::vhost` defined type: +* [`ensure`](#-caddy--vhost--ensure) * [`source`](#-caddy--vhost--source) * [`content`](#-caddy--vhost--content) +* [`config_dir`](#-caddy--vhost--config_dir) + +##### `ensure` + +Data type: `Enum['present','absent']` + +Make the vhost either present or absent + +Default value: `'present'` ##### `source` Data type: `Optional[Stdlib::Filesource]` -source (path) for the caddy vhost configuration +Source (path) for the caddy vhost configuration Default value: `undef` @@ -382,7 +450,31 @@ Default value: `undef` Data type: `Optional[String]` -string with the caddy vhost configuration +String with the caddy vhost configuration Default value: `undef` +##### `config_dir` + +Data type: `Stdlib::Absolutepath` + +Where to store the vhost config file + +Default value: `$caddy::config_dir` + +## Data types + +### `Caddy::VirtualHost` + +Caddy virtual host type + +Alias of + +```puppet +Struct[{ + ensure => Optional[Enum['absent', 'present']], + source => Optional[Stdlib::Filesource], + content => Optional[String[1]], +}] +``` + diff --git a/files/etc/caddy/Caddyfile b/files/etc/caddy/Caddyfile deleted file mode 100644 index 4a1f549..0000000 --- a/files/etc/caddy/Caddyfile +++ /dev/null @@ -1,5 +0,0 @@ -# -# THIS FILE IS MANAGED BY PUPPET -# - -import config/*.conf diff --git a/manifests/config.pp b/manifests/config.pp index d4d3eb9..8fe685f 100644 --- a/manifests/config.pp +++ b/manifests/config.pp @@ -22,17 +22,31 @@ owner => 'root', group => 'root', ; + $caddy::config_dir: + purge => $caddy::purge_config_dir, + recurse => true, + ; + } + + if $caddy::manage_caddyfile { + # Prefer source over content if both are defined + # Fallback to the bundled template if both are unset + $real_source = $caddy::caddyfile_source + $real_content = if $caddy::caddyfile_source { undef } else { + $caddy::caddyfile_content.lest || { + epp('caddy/etc/caddy/caddyfile.epp', + config_dir => $caddy::config_dir, + ) + } + } - ['/etc/caddy/Caddyfile']: + file { '/etc/caddy/Caddyfile': ensure => file, mode => '0444', - source => 'puppet:///modules/caddy/etc/caddy/Caddyfile', - require => File['/etc/caddy'], - ; - - ['/etc/caddy/config']: - purge => true, - recurse => true, - ; + owner => $caddy::caddy_user, + group => $caddy::caddy_group, + source => $real_source, + content => $real_content, + } } } diff --git a/manifests/init.pp b/manifests/init.pp index 7147b8a..ec49d5f 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -111,6 +111,24 @@ # @param package_ensure # Whether to install or remove the caddy package. Only relevant when $install_method is 'repo'. # +# @param manage_caddyfile +# Whether to manage Caddyfile. +# +# @param caddyfile_source +# Caddyfile source. +# +# @param caddyfile_content +# Caddyfile content. +# +# @param config_dir +# Where to store Caddy configs +# +# @param purge_config_dir +# Whether to purge Caddy config directory. +# +# @param vhosts +# List of virtual hosts to create. +# class caddy ( String[1] $version = '2.0.0', Optional[Enum['github','repo']] $install_method = undef, @@ -123,6 +141,7 @@ Stdlib::Absolutepath $caddy_log_dir = '/var/log/caddy', Stdlib::Absolutepath $caddy_home = '/var/lib/caddy', Stdlib::Absolutepath $caddy_ssl_dir = '/etc/ssl/caddy', + Stdlib::Absolutepath $config_dir = '/etc/caddy/config', Enum['personal', 'commercial'] $caddy_license = 'personal', Enum['on','off'] $caddy_telemetry = 'off', String[1] $caddy_features = 'http.git,http.filter,http.ipfilter', @@ -143,6 +162,11 @@ Hash[String[1],Any] $repo_settings = {}, String[1] $package_name = 'caddy', String[1] $package_ensure = $version, + Boolean $manage_caddyfile = true, + Optional[Stdlib::Filesource] $caddyfile_source = undef, + Optional[String[1]] $caddyfile_content = undef, + Boolean $purge_config_dir = true, + Hash[String[1], Caddy::VirtualHost] $vhosts = {}, ) { case $caddy_architecture { 'x86_64', 'amd64': { $arch = 'amd64' } @@ -179,6 +203,12 @@ contain caddy::config contain caddy::service + $vhosts.each |String[1] $name, Caddy::VirtualHost $vhost| { + caddy::vhost { $name: + * => $vhost, + } + } + Class['caddy::install'] -> Class['caddy::config'] ~> Class['caddy::service'] diff --git a/manifests/vhost.pp b/manifests/vhost.pp index 12b99ef..4e5cef7 100644 --- a/manifests/vhost.pp +++ b/manifests/vhost.pp @@ -1,7 +1,16 @@ # @summary This defined type handles the Caddy virtual hosts. # -# @param source source (path) for the caddy vhost configuration -# @param content string with the caddy vhost configuration +# @param ensure +# Make the vhost either present or absent +# +# @param source +# Source (path) for the caddy vhost configuration +# +# @param content +# String with the caddy vhost configuration +# +# @param config_dir +# Where to store the vhost config file # # @example Configure virtual host, based on source # caddy::vhost { 'example1': @@ -14,12 +23,19 @@ # } # define caddy::vhost ( - Optional[Stdlib::Filesource] $source = undef, - Optional[String] $content = undef, + Enum['present','absent'] $ensure = 'present', + Optional[Stdlib::Filesource] $source = undef, + Optional[String] $content = undef, + Stdlib::Absolutepath $config_dir = $caddy::config_dir, ) { include caddy - file { "/etc/caddy/config/${title}.conf": - ensure => file, + + 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', diff --git a/spec/acceptance/init_spec.rb b/spec/acceptance/init_spec.rb index 3282d62..46f9677 100644 --- a/spec/acceptance/init_spec.rb +++ b/spec/acceptance/init_spec.rb @@ -93,7 +93,7 @@ class { 'caddy': } caddy::vhost {'example1': - source => 'puppet:///modules/caddy/etc/caddy/config/example1.conf', + content => "localhost:3000 {\n respond \\'example1\\'\n}\n" } caddy::vhost {'example2': diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb index e7fbcc1..08b054e 100644 --- a/spec/classes/init_spec.rb +++ b/spec/classes/init_spec.rb @@ -116,7 +116,8 @@ 'owner' => 'caddy', 'group' => 'caddy', 'mode' => '0444', - 'source' => 'puppet:///modules/caddy/etc/caddy/Caddyfile' + 'source' => nil, + 'content' => %r{^import /etc/caddy/config/\*\.conf$} ). that_requires('File[/etc/caddy]') end @@ -319,6 +320,59 @@ it { is_expected.to contain_service('caddy').with_enable(false) } end + + context 'with manage_caddyfile => false' do + let(:params) { { manage_caddyfile: false } } + + it { is_expected.not_to contain_file('/etc/caddy/Caddyfile') } + end + + context 'with caddyfile_source set' do + let(:params) { { caddyfile_source: 'http://example.com/Caddyfile' } } + + it { is_expected.to contain_file('/etc/caddy/Caddyfile').with_source('http://example.com/Caddyfile').with_content(nil) } + end + + context 'with caddyfile_content set' do + let(:params) { { caddyfile_content: "localhost\nfile_server\n" } } + + it { is_expected.to contain_file('/etc/caddy/Caddyfile').with_source(nil).with_content("localhost\nfile_server\n") } + end + + context 'with both caddyfile_source and caddyfile_content set' do + let(:params) do + { + caddyfile_source: 'http://example.com/Caddyfile', + caddyfile_content: "localhost\nfile_server\n", + } + end + + it 'prefers source over content' do + is_expected.to contain_file('/etc/caddy/Caddyfile').with_source('http://example.com/Caddyfile').with_content(nil) + end + end + + context 'with vhosts set' do + let(:params) do + { + vhosts: { + 'h1.example.com': { + source: 'http://example.com/test-example-com.conf', + }, + 'h2.example.com': { + content: "localhost:1234{\n file_server\n}\n", + }, + 'h3.example.com': { + ensure: 'absent', + } + } + } + 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') } + end end end end diff --git a/spec/defines/vhost_spec.rb b/spec/defines/vhost_spec.rb index a6be06b..0cae95e 100644 --- a/spec/defines/vhost_spec.rb +++ b/spec/defines/vhost_spec.rb @@ -8,17 +8,14 @@ let(:facts) do facts end + let(:pre_condition) { 'class { "caddy": config_dir => "/etc/caddy/config" }' } + let(:title) { 'example' } context 'with source' do - let(:title) { 'example1' } - let(:params) do - { - source: 'puppet:///modules/caddy/etc/caddy/config/example1.conf' - } - end + let(:params) { { source: 'puppet:///modules/caddy/etc/caddy/config/example1.conf' } } it do - expect(subject).to contain_file('/etc/caddy/config/example1.conf').with( + is_expected.to contain_file('/etc/caddy/config/example.conf').with( 'ensure' => 'file', 'source' => 'puppet:///modules/caddy/etc/caddy/config/example1.conf', 'mode' => '0444', @@ -26,18 +23,31 @@ '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(:title) { 'example2' } - let(:params) do - { - content: 'localhost:2015' - } - end + let(:params) { { content: 'localhost:2015' } } it do - expect(subject).to contain_file('/etc/caddy/config/example2.conf').with( + is_expected.to contain_file('/etc/caddy/config/example.conf').with( 'ensure' => 'file', 'content' => 'localhost:2015', 'mode' => '0444', @@ -46,6 +56,10 @@ ) 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/templates/etc/caddy/caddyfile.epp b/templates/etc/caddy/caddyfile.epp new file mode 100644 index 0000000..b65848f --- /dev/null +++ b/templates/etc/caddy/caddyfile.epp @@ -0,0 +1,8 @@ +<%- | + String[1] $config_dir, +| -%> +# +# THIS FILE IS MANAGED BY PUPPET +# + +import <%= $config_dir %>/*.conf diff --git a/types/virtualhost.pp b/types/virtualhost.pp new file mode 100644 index 0000000..8b5dd04 --- /dev/null +++ b/types/virtualhost.pp @@ -0,0 +1,6 @@ +# @summary Caddy virtual host type +type Caddy::VirtualHost = Struct[{ + ensure => Optional[Enum['absent', 'present']], + source => Optional[Stdlib::Filesource], + content => Optional[String[1]], +}]