Unverified Commit 2d1906b3 authored by Romain Tartière's avatar Romain Tartière Committed by GitHub
Browse files

Add FreeBSD support (#288)



* Do not hardcode /etc/postfix

In order to bring support for FreeBSD, do not use the hardcoded
/etc/postfix path for the directory containing Postfix configuration:
FreeBSD ports are installed with a /usr/local/ prefix (by default) so
the configuration files on FreeBSD are stored in the
/usr/local/etc/postfix directory.

* Add support for FreeBSD

* Make it possible to tune the "root" group

FreeBSD does not have a "root" group.  The corresponding group is named
"wheel".

Allow to setup a custom "root_group", and adjust FreeBSD configuration
to set it to "wheel".

* Adjust the test suite so that it pass on FreeBSD

* Do not depend on $postfix::* before including postfix

Some resources parameters depend on the value of variable from the
postfix class.  Ensure these values are substitued only after including
postfix.

* Move default values from hiera to init.pp

These values are system-dependent, but this helps seeing the usual
default value when genering references.

* Move $manage_mailname parameter

* Explicitely mark internal classes as private

* Remove redundant postfix::params inclusion
Co-authored-by: default avatarRaphaël Pinson <github+aem1eeshi1@raphink.net>
Co-authored-by: default avatarRaphaël Pinson <github+aem1eeshi1@raphink.net>
parent 460dc7ad
---
postfix::confdir: "/usr/local/etc/postfix"
postfix::manage_mailname: false
postfix::manage_mailx: false
postfix::root_group: "wheel"
postfix::params::master_os_template: "postfix/master.cf.FreeBSD.erb"
postfix::params::restart_cmd: "/usr/local/etc/rc.d/postfix reload"
...
......@@ -35,11 +35,14 @@
#
define postfix::canonical (
$destination,
$file='/etc/postfix/canonical',
$file=undef,
$ensure='present'
) {
include postfix
include ::postfix::augeas
$_file = pick($file, "${postfix::confdir}/canonical")
case $ensure {
'present': {
$changes = [
......@@ -58,10 +61,10 @@ define postfix::canonical (
}
augeas {"Postfix canonical - ${name}":
incl => $file,
incl => $_file,
lens => 'Postfix_Canonical.lns',
changes => $changes,
require => [Package['postfix'], Augeas::Lens['postfix_canonical']],
notify => Exec["generate ${file}.db"],
notify => Exec["generate ${_file}.db"],
}
}
......@@ -50,12 +50,14 @@ define postfix::conffile (
Enum['present', 'absent', 'directory'] $ensure = 'present',
Variant[Array[String], String, Undef] $source = undef,
Optional[String] $content = undef,
Stdlib::Absolutepath $path = "/etc/postfix/${name}",
Optional[Stdlib::Absolutepath] $path = undef,
String $mode = '0640',
Hash $options = {},
Boolean $show_diff = true,
) {
include ::postfix::params
include postfix
$_path = pick($path, "${postfix::confdir}/${name}")
if (!defined(Class['postfix'])) {
fail 'You must define class postfix before using postfix::config!'
......@@ -84,7 +86,7 @@ define postfix::conffile (
file { "postfix conffile ${name}":
ensure => $ensure,
path => $path,
path => $_path,
mode => $mode,
owner => 'root',
group => 'postfix',
......
......@@ -31,6 +31,7 @@ define postfix::config (
Optional[String] $value = undef,
Enum['present', 'absent', 'blank'] $ensure = 'present',
) {
include postfix
if ($ensure == 'present') {
assert_type(Pattern[/^.+$/], $value) |$e, $a| {
......@@ -58,10 +59,10 @@ define postfix::config (
}
augeas { "manage postfix '${title}'":
incl => '/etc/postfix/main.cf',
incl => "${postfix::confdir}/main.cf",
lens => 'Postfix_Main.lns',
changes => $changes,
require => File['/etc/postfix/main.cf'],
require => File["${postfix::confdir}/main.cf"],
}
Postfix::Config[$title] ~> Class['postfix::service']
......
class postfix::files {
include ::postfix::params
assert_private()
$alias_maps = $postfix::all_alias_maps
$amavis_procs = $postfix::amavis_procs
......@@ -18,6 +19,7 @@ class postfix::files {
$master_bounce_command = $postfix::master_bounce_command
$master_defer_command = $postfix::master_defer_command
$myorigin = $postfix::myorigin
$manage_mailname = $postfix::manage_mailname
$manage_aliases = $postfix::manage_aliases
$manage_root_alias = $postfix::manage_root_alias
$root_mail_recipient = $postfix::root_mail_recipient
......@@ -41,11 +43,13 @@ class postfix::files {
replace => $manage_conffiles,
}
file { '/etc/mailname':
ensure => 'file',
content => "${::fqdn}\n",
mode => '0644',
seltype => $postfix::params::seltype,
if $manage_mailname {
file { '/etc/mailname':
ensure => 'file',
content => "${::fqdn}\n",
mode => '0644',
seltype => $postfix::params::seltype,
}
}
# Aliases
......@@ -73,10 +77,10 @@ class postfix::files {
)
}
file { '/etc/postfix/master.cf':
file { "${postfix::confdir}/master.cf":
ensure => 'file',
content => $_mastercf_content,
group => 'root',
group => $postfix::root_group,
mode => '0644',
owner => 'root',
seltype => $postfix::params::seltype,
......@@ -84,9 +88,9 @@ class postfix::files {
}
# Config files
file { '/etc/postfix/main.cf':
file { "${postfix::confdir}/main.cf":
ensure => 'file',
group => 'root',
group => $postfix::root_group,
mode => '0644',
owner => 'root',
replace => false,
......
......@@ -93,6 +93,8 @@
# }
#
class postfix (
Stdlib::Absolutepath $confdir = '/etc/postfix',
String $root_group = 'root',
String $alias_maps = 'hash:/etc/aliases',
Optional[Hash] $configs = {},
Integer $amavis_procs = 2,
......@@ -106,6 +108,7 @@ class postfix (
Boolean $mailman = false,
String $maincf_source = "puppet:///modules/${module_name}/main.cf",
Boolean $manage_conffiles = true,
Boolean $manage_mailname = true,
Boolean $manage_mailx = true,
Optional[String] $mastercf_source = undef,
Optional[String] $mastercf_content = undef,
......@@ -151,7 +154,7 @@ class postfix (
$all_alias_maps = $ldap ? {
false => $alias_maps,
true => "${alias_maps}, ldap:/etc/postfix/ldap-aliases.cf",
true => "${alias_maps}, ldap:${confdir}/ldap-aliases.cf",
}
create_resources('::postfix::config', $configs)
......
......@@ -21,7 +21,7 @@ class postfix::ldap {
if $::osfamily == 'Debian' {
package {'postfix-ldap':
before => File['/etc/postfix/ldap-aliases.cf'],
before => File["${postfix::confdir}/ldap-aliases.cf"],
}
}
......@@ -39,7 +39,7 @@ class postfix::ldap {
default => $postfix::ldap_options,
}
file {'/etc/postfix/ldap-aliases.cf':
file {"${postfix::confdir}/ldap-aliases.cf":
ensure => 'file',
owner => 'root',
group => 'postfix',
......
......@@ -12,21 +12,22 @@
# mailman => true,
# }
class postfix::mailman {
include postfix
postfix::config {
'virtual_alias_maps':
value => 'hash:/etc/postfix/virtual';
value => "hash:${postfix::confdir}/virtual";
'transport_maps':
value => 'hash:/etc/postfix/transport';
value => "hash:${postfix::confdir}/transport";
'mailman_destination_recipient_limit':
value => '1';
}
postfix::hash { '/etc/postfix/virtual':
postfix::hash { "${postfix::confdir}/virtual":
ensure => 'present',
}
postfix::hash { '/etc/postfix/transport':
postfix::hash { "${postfix::confdir}/transport":
ensure => 'present',
}
......
......@@ -32,11 +32,14 @@ define postfix::map (
Variant[Array[String], String, Undef] $source = undef,
Optional[Variant[Sensitive[String],String]] $content = undef,
String $type = 'hash',
Stdlib::Absolutepath $path = "/etc/postfix/${name}",
Optional[Stdlib::Absolutepath] $path = undef,
String[4,4] $mode = '0640'
) {
include postfix
include ::postfix::params
$_path = pick($path, "${postfix::confdir}/${name}")
if (!defined(Class['postfix'])) {
fail 'You must define class postfix before using postfix::config!'
}
......@@ -58,7 +61,7 @@ define postfix::map (
file { "postfix map ${name}":
ensure => $ensure,
path => $path,
path => $_path,
source => $source,
content => $content,
owner => 'root',
......@@ -71,7 +74,7 @@ define postfix::map (
if $type !~ /^(cidr|pcre)$/ {
file {"postfix map ${name}.db":
ensure => $ensure,
path => "${path}.db",
path => "${_path}.db",
owner => 'root',
group => 'postfix',
mode => $mode,
......@@ -81,8 +84,8 @@ define postfix::map (
}
$generate_cmd = $ensure ? {
'absent' => "rm ${path}.db",
'present' => "postmap ${path}",
'absent' => "rm ${_path}.db",
'present' => "postmap ${_path}",
}
exec {"generate ${name}.db":
......
......@@ -26,36 +26,41 @@
# }
#
class postfix::mta (
Pattern[/^\S+(?:,\s*\S+)*$/] $mydestination = $postfix::mydestination,
Pattern[/^(?:\S+?(?:(?:,\s+)|(?:\s+))?)*$/] $mynetworks = $postfix::mynetworks,
Pattern[/^\S+$/] $relayhost = $postfix::relayhost,
Optional[Pattern[/^\S+(?:,\s*\S+)*$/]] $mydestination = undef,
Optional[Pattern[/^(?:\S+?(?:(?:,\s+)|(?:\s+))?)*$/]] $mynetworks = undef,
Optional[Pattern[/^\S+$/]] $relayhost = undef,
) {
include postfix
$_mydestination = pick($mydestination, $postfix::mydestination)
$_mynetworks = pick($mynetworks, $postfix::mynetworks)
$_relayhost = pick($relayhost, $postfix::relayhost)
# If direct is specified then relayhost should be blank
if ($relayhost == 'direct') {
if ($_relayhost == 'direct') {
postfix::config { 'relayhost': ensure => 'blank' }
}
else {
postfix::config { 'relayhost': value => $relayhost }
postfix::config { 'relayhost': value => $_relayhost }
}
if ($mydestination == 'blank') {
if ($_mydestination == 'blank') {
postfix::config { 'mydestination': ensure => 'blank' }
} else {
postfix::config { 'mydestination': value => $mydestination }
postfix::config { 'mydestination': value => $_mydestination }
}
postfix::config {
'mynetworks': value => $mynetworks;
'virtual_alias_maps': value => 'hash:/etc/postfix/virtual';
'transport_maps': value => 'hash:/etc/postfix/transport';
'mynetworks': value => $_mynetworks;
'virtual_alias_maps': value => "hash:${postfix::confdir}/virtual";
'transport_maps': value => "hash:${postfix::confdir}/transport";
}
postfix::hash { '/etc/postfix/virtual':
postfix::hash { "${postfix::confdir}/virtual":
ensure => 'present',
}
postfix::hash { '/etc/postfix/transport':
postfix::hash { "${postfix::confdir}/transport":
ensure => 'present',
}
......
class postfix::packages {
include ::postfix::params
assert_private()
package { 'postfix':
ensure => $postfix::postfix_ensure,
......
......@@ -23,17 +23,22 @@
# }
#
class postfix::satellite (
$mydestination = $postfix::mydestination,
$mynetworks = $postfix::mynetworks,
$relayhost = $postfix::relayhost,
$mydestination = undef,
$mynetworks = undef,
$relayhost = undef,
) {
include postfix
assert_type(Pattern[/^\S+$/], $postfix::myorigin)
$_mydestination = pick($mydestination, $postfix::mydestination)
$_mynetworks = pick($mynetworks, $postfix::mynetworks)
$_relayhost = pick($relayhost, $postfix::relayhost)
class { '::postfix::mta':
mydestination => $mydestination,
mynetworks => $mynetworks,
relayhost => $relayhost,
mydestination => $_mydestination,
mynetworks => $_mynetworks,
relayhost => $_relayhost,
}
postfix::virtual { "@${postfix::myorigin}":
......
class postfix::service {
assert_private()
$manage_aliases = $postfix::manage_aliases
......
......@@ -44,11 +44,14 @@
define postfix::transport (
Optional[String] $destination = undef,
Optional[String] $nexthop=undef,
Stdlib::Absolutepath $file='/etc/postfix/transport',
Optional[Stdlib::Absolutepath] $file=undef,
Enum['present', 'absent'] $ensure='present'
) {
include postfix
include ::postfix::augeas
$_file = pick($file, "${postfix::confdir}/transport")
$smtp_nexthop = (String($nexthop) =~ /\[.*\]/)
case $ensure {
......@@ -104,7 +107,7 @@ define postfix::transport (
augeas {"Postfix transport - ${name}":
lens => 'Postfix_Transport.lns',
incl => $file,
incl => $_file,
changes => $changes,
require => Augeas::Lens['postfix_transport'],
}
......@@ -113,7 +116,7 @@ define postfix::transport (
Package['postfix'] -> Postfix::Transport[$title]
}
if defined(Postfix::Hash[$file]) {
Postfix::Transport[$title] ~> Postfix::Hash[$file]
if defined(Postfix::Hash[$_file]) {
Postfix::Transport[$title] ~> Postfix::Hash[$_file]
}
}
......@@ -40,11 +40,14 @@
define postfix::virtual (
Variant[String, Array[String]] $destination,
Stdlib::Absolutepath $file='/etc/postfix/virtual',
Optional[Stdlib::Absolutepath] $file=undef,
Enum['present', 'absent'] $ensure='present'
) {
include postfix
include ::postfix::augeas
$_file = pick($file, "${postfix::confdir}/virtual")
$dest_sets = [$destination].flatten.map |$i, $d| {
$idx = $i+1
"set \$entry/destination[${idx}] '${d}'"
......@@ -69,7 +72,7 @@ define postfix::virtual (
}
augeas {"Postfix virtual - ${name}":
incl => $file,
incl => $_file,
lens => 'Postfix_Virtual.lns',
changes => $changes,
require => Augeas::Lens['postfix_virtual'],
......@@ -79,7 +82,7 @@ define postfix::virtual (
Package['postfix'] -> Postfix::Virtual[$title]
}
if defined(Postfix::Hash[$file]) {
Postfix::Virtual[$title] ~> Postfix::Hash[$file]
if defined(Postfix::Hash[$_file]) {
Postfix::Virtual[$title] ~> Postfix::Hash[$_file]
}
}
......@@ -60,6 +60,13 @@
"29",
"30"
]
},
{
"operatingsystem": "FreeBSD",
"operatingsystemrelease": [
"11",
"12"
]
}
],
"requirements": [
......
......@@ -3,6 +3,31 @@ require 'spec_helper'
describe 'postfix' do
on_supported_os.each do |os, facts|
context "on #{os}" do
let(:postfix_main_cf_path) do
case facts[:osfamily]
when 'FreeBSD' then '/usr/local/etc/postfix/main.cf'
else '/etc/postfix/main.cf'
end
end
let(:postfix_master_cf_path) do
case facts[:osfamily]
when 'FreeBSD' then '/usr/local/etc/postfix/master.cf'
else '/etc/postfix/master.cf'
end
end
let(:postfix_transport_path) do
case facts[:osfamily]
when 'FreeBSD' then '/usr/local/etc/postfix/transport'
else '/etc/postfix/transport'
end
end
let(:postfix_virtual_path) do
case facts[:osfamily]
when 'FreeBSD' then '/usr/local/etc/postfix/virtual'
else '/etc/postfix/virtual'
end
end
let(:facts) do
facts.merge(augeasversion: '1.2.0',
puppetversion: Puppet.version)
......@@ -10,7 +35,6 @@ describe 'postfix' do
context 'when using defaults' do
it { is_expected.to contain_package('postfix') }
it { is_expected.to contain_package('mailx') }
it { is_expected.to contain_exec('newaliases').with_refreshonly('true') }
it { is_expected.to contain_postfix__config('myorigin').with_value('foo.example.com') }
it { is_expected.to contain_postfix__config('alias_maps').with_value('hash:/etc/aliases') }
......@@ -19,10 +43,11 @@ describe 'postfix' do
it { is_expected.to contain_mailalias('root').with_recipient('nobody') }
context 'when on Debian family', excl: facts[:osfamily] != 'Debian' do
it { is_expected.to contain_package('mailx') }
it { is_expected.to contain_file('/etc/mailname').without('seltype').with_content("foo.example.com\n") }
it { is_expected.to contain_file('/etc/aliases').without('seltype').with_content("# file managed by puppet\n") }
it { is_expected.to contain_file('/etc/postfix/master.cf').without('seltype') }
it { is_expected.to contain_file('/etc/postfix/main.cf').without('seltype') }
it { is_expected.to contain_file(postfix_master_cf_path).without('seltype') }
it { is_expected.to contain_file(postfix_main_cf_path).without('seltype') }
it {
is_expected.to contain_service('postfix').with(
......@@ -35,9 +60,10 @@ describe 'postfix' do
end
context 'when on RedHat family', excl: facts[:osfamily] != 'RedHat' do
it { is_expected.to contain_package('mailx') }
it { is_expected.to contain_file('/etc/mailname').with_seltype('postfix_etc_t').with_content("foo.example.com\n") }
it { is_expected.to contain_file('/etc/postfix/master.cf').with_seltype('postfix_etc_t') }
it { is_expected.to contain_file('/etc/postfix/main.cf').with_seltype('postfix_etc_t') }
it { is_expected.to contain_file(postfix_master_cf_path).with_seltype('postfix_etc_t') }
it { is_expected.to contain_file(postfix_main_cf_path).with_seltype('postfix_etc_t') }
it { is_expected.to contain_postfix__config('sendmail_path') }
it { is_expected.to contain_postfix__config('newaliases_path') }
......@@ -91,7 +117,9 @@ describe 'postfix' do
end
context('when on other', excl: (facts[:osfamily] != 'RedHat' || facts[:operatingsystem] == 'Fedora' || ['6', '7', '8'].include?(facts[:operatingsystemmajrelease]))) do
it { is_expected.to contain_file('/etc/aliases').with_seltype('postfix_etc_t').with_content("# file managed by puppet\n") }
context('on Linux', excl: facts[:osfamily] != 'Linux') do
it { is_expected.to contain_file('/etc/aliases').with_seltype('postfix_etc_t').with_content("# file managed by puppet\n") }
end
it {
is_expected.to contain_service('postfix').with(
ensure: 'running',
......@@ -134,7 +162,7 @@ describe 'postfix' do
it { is_expected.to contain_file('/etc/aliases').without('seltype').with_content("# file managed by puppet\n") }
it { is_expected.to contain_exec('newaliases').with_refreshonly('true') }
it {
is_expected.to contain_file('/etc/postfix/master.cf').without('seltype').with_content(
is_expected.to contain_file(postfix_master_cf_path).without('seltype').with_content(
%r{smtp inet n - - - - smtpd},
).with_content(
%r{amavis unix},
......@@ -154,7 +182,7 @@ describe 'postfix' do
%r{^submission inet n},
)
}
it { is_expected.to contain_file('/etc/postfix/main.cf').without('seltype') }
it { is_expected.to contain_file(postfix_main_cf_path).without('seltype') }
it { is_expected.to contain_postfix__config('myorigin').with_value('localhost') }
it { is_expected.to contain_postfix__config('alias_maps').with_value('hash:/etc/aliases') }
......@@ -196,7 +224,7 @@ describe 'postfix' do
end
it 'adjusts the content of /etc/postfix/master.cf specifying the user' do
is_expected.to contain_file('/etc/postfix/master.cf').with_seltype('postfix_etc_t').with_content(%r{user=bar})
is_expected.to contain_file(postfix_master_cf_path).with_content(%r{user=bar})
end
end
context 'when mailman is true' do
......@@ -301,7 +329,7 @@ describe 'postfix' do
end
it 'updates master.cf with the specified flags to smtp' do
is_expected.to contain_file('/etc/postfix/master.cf').with_seltype('postfix_etc_t').with_content(
is_expected.to contain_file(postfix_master_cf_path).with_content(
%r{smtp inet n - - - - smtpd},
).with_content(
%r{^smtp.*\n.*smtpd_client_restrictions=check_client_access,hash:},
......@@ -316,7 +344,7 @@ describe 'postfix' do
end
it 'updates master.cf with the specified flags to smtps' do
is_expected.to contain_file('/etc/postfix/master.cf').with_content(%r{^smtps inet n})
is_expected.to contain_file(postfix_master_cf_path).with_content(%r{^smtps inet n})
end
end
context 'when mta is enabled' do
......@@ -326,8 +354,8 @@ describe 'postfix' do
is_expected.to contain_postfix__config('mydestination').with_value('1.2.3.4')
is_expected.to contain_postfix__config('mynetworks').with_value('127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128')
is_expected.to contain_postfix__config('relayhost').with_value('2.3.4.5')
is_expected.to contain_postfix__config('virtual_alias_maps').with_value('hash:/etc/postfix/virtual')
is_expected.to contain_postfix__config('transport_maps').with_value('hash:/etc/postfix/transport')
is_expected.to contain_postfix__config('virtual_alias_maps').with_value("hash:#{postfix_virtual_path}")
is_expected.to contain_postfix__config('transport_maps').with_value("hash:#{postfix_transport_path}")
end
it { is_expected.to contain_class('postfix::mta') }
context 'and satellite is also enabled' do
......@@ -377,8 +405,8 @@ describe 'postfix' do
is_expected.to contain_postfix__config('mydestination').with_value('1.2.3.4')
is_expected.to contain_postfix__config('mynetworks').with_value('127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128')
is_expected.to contain_postfix__config('relayhost').with_value('2.3.4.5')
is_expected.to contain_postfix__config('virtual_alias_maps').with_value('hash:/etc/postfix/virtual')
is_expected.to contain_postfix__config('transport_maps').with_value('hash:/etc/postfix/transport')
is_expected.to contain_postfix__config('virtual_alias_maps').with_value("hash:#{postfix_virtual_path}")
is_expected.to contain_postfix__config('transport_maps').with_value("hash:#{postfix_transport_path}")
end
context 'and mta is also enabled' do
let(:params) { { mta: true, satellite: true, mydestination: '1.2.3.4', relayhost: '2.3.4.5' } }
......@@ -399,28 +427,28 @@ describe 'postfix' do
let(:params) { { use_amavisd: true } }
it 'updates master.cf with the specified flags to amavis' do
is_expected.to contain_file('/etc/postfix/master.cf').with_content(%r{amavis unix})
is_expected.to contain_file(postfix_master_cf_path).with_content(%r{amavis unix})
end
end
context 'when use_dovecot_lda is true' do
let(:params) { { use_dovecot_lda: true } }
it 'updates master.cf with the specified flags to dovecot' do
is_expected.to contain_file('/etc/postfix/master.cf').with_content(%r{dovecot.*\n.* user=vmail:vmail })
is_expected.to contain_file(postfix_master_cf_path).with_content(%r{dovecot.*\n.* user=vmail:vmail })
end
end
context 'when use_schleuder is true' do
let(:params) { { use_schleuder: true } }
it 'updates master.cf with the specified flags to schleuder' do
is_expected.to contain_file('/etc/postfix/master.cf').with_content(%r{schleuder})
is_expected.to contain_file(postfix_master_cf_path).with_content(%r{schleuder})