├── .yardopts ├── test ├── cookbooks │ └── postfix-dovecot_test │ │ ├── templates │ │ └── default │ │ │ └── sysctl.conf.erb │ │ ├── README.md │ │ ├── recipes │ │ ├── postfix_postgresql.rb │ │ ├── postgresql_memory.rb │ │ └── default.rb │ │ ├── metadata.rb │ │ └── files │ │ └── default │ │ └── tests │ │ └── minitest │ │ ├── default_test.rb │ │ └── support │ │ └── helpers.rb ├── integration │ ├── postfixpgsql │ │ └── serverspec │ │ │ ├── Gemfile │ │ │ ├── spec_helper.rb │ │ │ └── postfix_postgresql_spec.rb │ ├── ses │ │ └── serverspec │ │ │ ├── Gemfile │ │ │ ├── spec_helper.rb │ │ │ ├── mail_helpers.rb │ │ │ └── postfix_ses_spec.rb │ ├── mysql │ │ └── serverspec │ │ │ ├── Gemfile │ │ │ ├── postfix_mysql_spec.rb │ │ │ ├── spec_helper.rb │ │ │ ├── mysql_spec.rb │ │ │ ├── postfixadmin_spec.rb │ │ │ ├── vmail_spec.rb │ │ │ ├── mail_helpers.rb │ │ │ ├── spam_spec.rb │ │ │ ├── dovecot_spec.rb │ │ │ └── postfix_spec.rb │ └── postgresql │ │ └── serverspec │ │ ├── Gemfile │ │ ├── spec_helper.rb │ │ ├── postfix_postgresql_spec.rb │ │ ├── postfixadmin_spec.rb │ │ ├── vmail_spec.rb │ │ ├── postgresql_spec.rb │ │ ├── mail_helpers.rb │ │ ├── dovecot_spec.rb │ │ └── postfix_spec.rb └── unit │ ├── recipes │ ├── default_spec.rb │ ├── vmail_spec.rb │ ├── spam_spec.rb │ ├── postfix_mysql_spec.rb │ ├── dovecot_spec.rb │ ├── postfixadmin_spec.rb │ ├── postfix_spec.rb │ └── postfix_postgresql_spec.rb │ └── spec_helper.rb ├── templates └── default │ └── default.sieve.erb ├── TODO.md ├── .gitignore ├── .github ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── .kitchen.ses.yml ├── CONTRIBUTING.md ├── attributes ├── spam.rb ├── sieve.rb ├── default.rb ├── ssl_certificate.rb ├── vmail.rb ├── ses.rb └── postfix_postgresql.rb ├── recipes ├── postfix_mysql.rb ├── default.rb ├── postfixadmin.rb ├── vmail.rb ├── spam.rb ├── postfix_postgresql.rb ├── dovecot.rb └── postfix.rb ├── .kitchen.docker.yml ├── Berksfile ├── chefignore ├── Gemfile ├── .kitchen.cloud.yml ├── .travis.yml ├── Guardfile ├── .kitchen.yml ├── Vagrantfile ├── TESTING.md ├── Rakefile ├── CHANGELOG.md ├── metadata.rb ├── LICENSE └── README.md /.yardopts: -------------------------------------------------------------------------------- 1 | --markup markdown 2 | --no-private 3 | --exclude test 4 | '*/**/*.rb' 5 | - 6 | *.md 7 | -------------------------------------------------------------------------------- /test/cookbooks/postfix-dovecot_test/templates/default/sysctl.conf.erb: -------------------------------------------------------------------------------- 1 | # Generated by Chef 2 | <% @values.each do |k, v| -%> 3 | <%= k %>=<%= v %> 4 | <% end -%> 5 | -------------------------------------------------------------------------------- /test/integration/postfixpgsql/serverspec/Gemfile: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # -*- mode: ruby -*- 3 | # vi: set ft=ruby : 4 | 5 | source 'https://rubygems.org' 6 | 7 | gem 'serverspec', '~> 2.0' 8 | -------------------------------------------------------------------------------- /test/cookbooks/postfix-dovecot_test/README.md: -------------------------------------------------------------------------------- 1 | This cookbook is used with [test-kitchen](http://kitchen.ci/) to test the parent, [postfix-dovecot](https://supermarket.chef.io/cookbooks/postfix-dovecot) cookbook. 2 | -------------------------------------------------------------------------------- /templates/default/default.sieve.erb: -------------------------------------------------------------------------------- 1 | require "fileinto"; 2 | 3 | if header :contains "X-Spam-Virus" "Yes" { 4 | fileinto "Spam"; 5 | stop; 6 | } 7 | 8 | if header :contains "X-Spam-Status" "Yes" { 9 | fileinto "Spam"; 10 | stop; 11 | } 12 | -------------------------------------------------------------------------------- /test/integration/ses/serverspec/Gemfile: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # -*- mode: ruby -*- 3 | # vi: set ft=ruby : 4 | 5 | source 'https://rubygems.org' 6 | 7 | gem 'serverspec', '~> 2.0' 8 | gem 'infrataster', '~> 0.3.0' 9 | gem 'rspec-retry', '~> 0.5.0' 10 | -------------------------------------------------------------------------------- /test/integration/mysql/serverspec/Gemfile: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # -*- mode: ruby -*- 3 | # vi: set ft=ruby : 4 | 5 | source 'https://rubygems.org' 6 | 7 | gem 'serverspec', '~> 2.0' 8 | gem 'infrataster', '~> 0.3.0' 9 | gem 'rspec-retry', '~> 0.5.0' 10 | -------------------------------------------------------------------------------- /test/integration/postgresql/serverspec/Gemfile: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # -*- mode: ruby -*- 3 | # vi: set ft=ruby : 4 | 5 | source 'https://rubygems.org' 6 | 7 | gem 'serverspec', '~> 2.0' 8 | gem 'infrataster', '~> 0.3.0' 9 | gem 'rspec-retry', '~> 0.5.0' 10 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | TODO 2 | ==== 3 | 4 | * [ ] Fix Ubuntu `15.04` support in the `postfix-full` cookbook. 5 | * [ ] Add ChefSpec tests to check attribute values. 6 | * [ ] [DSPAM](http://dspam.nuclearelephant.com/) support. 7 | * [ ] [ClamAV](http://www.clamav.net/) support. 8 | * [ ] Webmail. 9 | * [ ] Spam learning. 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .#* 2 | *~ 3 | *# 4 | \#*# 5 | Berksfile.lock 6 | bin 7 | bin/* 8 | .bundle 9 | .bundle/* 10 | .cache 11 | /cookbooks 12 | coverage 13 | doc 14 | Dockerfile-kitchen* 15 | *.gem 16 | Gemfile.lock 17 | .kitchen 18 | .kitchen.local.yml 19 | metadata.json 20 | nodes/ 21 | .*.sw[a-z] 22 | test/kitchen/.kitchen/ 23 | *.un~ 24 | .vagrant 25 | vendor 26 | .yardoc 27 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | [Describe what this change achieves] 4 | 5 | ### Issues Resolved 6 | 7 | [List any existing issues this PR resolves] 8 | 9 | ### Contribution Check List 10 | 11 | - [ ] All tests pass. 12 | - [ ] New functionality includes testing. 13 | - [ ] New functionality has been documented in the README and metadata if applicable. 14 | 15 | See [CONTRIBUTING.md](https://github.com/zuazo/postfix-dovecot-cookbook/blob/master/CONTRIBUTING.md). 16 | -------------------------------------------------------------------------------- /.kitchen.ses.yml: -------------------------------------------------------------------------------- 1 | suites: 2 | - name: default 3 | run_list: recipe[postfix-dovecot_test] 4 | - name: ses 5 | run_list: 6 | - recipe[minitest-handler] 7 | - recipe[postfix-dovecot_test] 8 | attributes: 9 | postfix-dovecot: 10 | ses: 11 | enabled: true 12 | email: <%= ENV['AMAZON_SES_EMAIL_FROM'] %> # SES valid from address, only used in tests 13 | username: <%= ENV['AMAZON_SES_SMTP_USERNAME'] %> 14 | password: <%= ENV['AMAZON_SES_SMTP_PASSWORD'] %> 15 | <% unless ENV['AMAZON_SES_REGION'].nil? %> 16 | region: <%= ENV['AMAZON_SES_REGION'] %> 17 | <% end %> 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | 1. [Fork the repository on Github](https://help.github.com/articles/fork-a-repo). 5 | 2. Create a named feature branch (`$ git checkout -b my-new-feature`). 6 | 3. Write tests for your change (if applicable). 7 | 4. Write your change. 8 | 5. [Run the tests](https://github.com/zuazo/postfix-dovecot-cookbook/blob/master/TESTING.md), ensuring they all pass (`$ bundle exec rake`). 9 | 6. Commit your change (`$ git commit -am 'Add some feature'`). 10 | 7. Push to the branch (`$ git push origin my-new-feature`). 11 | 8. [Submit a Pull Request using Github](https://help.github.com/articles/creating-a-pull-request). 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Cookbook Version 2 | [Version of the cookbook where you are encountering the issue] 3 | 4 | ### Chef Client Version 5 | [Version of chef-client in your environment] 6 | 7 | ### Platform Details 8 | [Operating system distribution and release version. Cloud provider if running in the cloud] 9 | 10 | ### Scenario 11 | [What you are trying to achieve and you can't?] 12 | 13 | ### Steps to Reproduce 14 | [If you are filing an issue what are the things we need to do in order to repro your problem? How are you using this cookbook or any resources it includes?] 15 | 16 | ### Expected Result 17 | [What are you expecting to happen as the consequence of above reproduction steps?] 18 | 19 | ### Actual Result 20 | [What actually happens after the reproduction steps? Include the error output or a link to a gist if possible.] 21 | -------------------------------------------------------------------------------- /test/integration/postfixpgsql/serverspec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2017 Xabier de Zuazo 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'serverspec' 21 | 22 | # Set backend type 23 | set :backend, :exec 24 | -------------------------------------------------------------------------------- /test/cookbooks/postfix-dovecot_test/recipes/postfix_postgresql.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot_test 4 | # Recipe:: postfix_postgresql 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | include_recipe 'postfix-dovecot::postfix_postgresql' 23 | -------------------------------------------------------------------------------- /attributes/spam.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot 4 | # Attributes:: spam 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2013 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | default['postfix-dovecot']['spamc']['recipe'] = 'onddo-spamassassin' 23 | default['postfix-dovecot']['spamc']['enabled'] = false 24 | -------------------------------------------------------------------------------- /recipes/postfix_mysql.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot 4 | # Recipe:: postfix_mysql 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | package 'postfix' 23 | 24 | case node['platform'] 25 | when 'debian', 'ubuntu' then 26 | package 'postfix-mysql' 27 | end 28 | -------------------------------------------------------------------------------- /test/integration/mysql/serverspec/postfix_mysql_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | 22 | describe 'Postfix MySQL' do 23 | describe command('/usr/sbin/postconf -m') do 24 | its(:stdout) { should include 'mysql' } 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /test/integration/mysql/serverspec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'serverspec' 21 | require 'infrataster/rspec' 22 | require 'rspec/retry' 23 | 24 | # Set backend type 25 | set :backend, :exec 26 | 27 | Infrataster::Server.define(:web, '127.0.0.1') 28 | -------------------------------------------------------------------------------- /test/integration/ses/serverspec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'serverspec' 21 | require 'infrataster/rspec' 22 | require 'rspec/retry' 23 | 24 | # Set backend type 25 | set :backend, :exec 26 | 27 | Infrataster::Server.define(:web, '127.0.0.1') 28 | -------------------------------------------------------------------------------- /test/integration/postgresql/serverspec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'serverspec' 21 | require 'infrataster/rspec' 22 | require 'rspec/retry' 23 | 24 | # Set backend type 25 | set :backend, :exec 26 | 27 | Infrataster::Server.define(:web, '127.0.0.1') 28 | -------------------------------------------------------------------------------- /test/integration/postfixpgsql/serverspec/postfix_postgresql_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2017 Xabier de Zuazo 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | 22 | describe 'Postfix PostgreSQL' do 23 | describe command('/usr/sbin/postconf -m') do 24 | its(:stdout) { should include 'pgsql' } 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /test/integration/postgresql/serverspec/postfix_postgresql_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | 22 | describe 'Postfix PostgreSQL' do 23 | describe command('/usr/sbin/postconf -m') do 24 | its(:stdout) { should include 'pgsql' } 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /attributes/sieve.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot 4 | # Attributes:: sieve 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2013 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | default['postfix-dovecot']['sieve']['enabled'] = true 23 | default['postfix-dovecot']['sieve']['global_path'] = ::File.join( 24 | node['dovecot']['conf_path'], 'sieve', 'default.sieve' 25 | ) 26 | -------------------------------------------------------------------------------- /test/integration/mysql/serverspec/mysql_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | 22 | describe 'MySQL' do 23 | describe process('mysqld') do 24 | it { should be_running } 25 | end 26 | 27 | describe port(3306) do 28 | it { should be_listening.with('tcp') } 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /recipes/default.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot 4 | # Recipe:: default 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2013 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | include_recipe 'postfix-dovecot::vmail' 23 | include_recipe 'postfix-dovecot::spam' 24 | include_recipe 'postfix-dovecot::postfix' 25 | include_recipe 'postfix-dovecot::postfixadmin' 26 | include_recipe 'postfix-dovecot::dovecot' 27 | -------------------------------------------------------------------------------- /test/integration/mysql/serverspec/postfixadmin_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | 22 | describe 'PostfixAdmin' do 23 | describe server(:web) do 24 | describe http('/login.php') do 25 | it 'returns "Postfix Admin" string' do 26 | expect(response.body).to include('Postfix Admin') 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /attributes/default.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot 4 | # Attributes:: default 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2013 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | default['postfix-dovecot']['postmaster_address'] = 'postmaster@foo.bar' 23 | default['postfix-dovecot']['hostname'] = node['fqdn'] || 'postfix-dovecot.local' 24 | default['postfix-dovecot']['rbls'] = [] 25 | default['postfix-dovecot']['database']['type'] = 'mysql' 26 | -------------------------------------------------------------------------------- /test/integration/postgresql/serverspec/postfixadmin_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | 22 | describe 'PostfixAdmin' do 23 | describe server(:web) do 24 | describe http('/login.php') do 25 | it 'returns "Postfix Admin" string' do 26 | expect(response.body).to include('Postfix Admin') 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /test/integration/ses/serverspec/mail_helpers.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2017 Xabier de Zuazo 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | require 'net/smtp' 22 | 23 | EMAIL_TEMPLATE = <<-EOM 24 | Subject: Some cool subject for testing 25 | 26 | A blackhole email body. 27 | 28 | EOM 29 | .freeze 30 | 31 | def send_email(from, to) 32 | Net::SMTP.start('localhost', 25) do |smtp| 33 | smtp.send_message(EMAIL_TEMPLATE, from, to) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /.kitchen.docker.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: docker 4 | use_sudo: false 5 | 6 | # If you add new platforms below, include them in the .travis.yml file matrix 7 | platforms: 8 | - name: centos-6 9 | - name: centos-7 10 | driver_config: 11 | privileged: true 12 | run_command: /sbin/init 13 | - name: debian-7 14 | run_list: recipe[apt] 15 | - name: debian-8 16 | run_list: recipe[apt] 17 | # Failed to connect to bus: No such file or directory 18 | driver_config: 19 | privileged: true 20 | run_command: /sbin/init 21 | - name: ubuntu-12.04 22 | run_list: recipe[apt] 23 | - name: ubuntu-14.04 24 | run_list: recipe[apt] 25 | - name: ubuntu-16.04 26 | run_list: recipe[apt] 27 | driver_config: 28 | privileged: true 29 | run_command: /sbin/init 30 | - name: ubuntu-16.10 31 | run_list: recipe[apt] 32 | driver_config: 33 | privileged: true 34 | run_command: /sbin/init 35 | 36 | # Non-official images with systemd 37 | # Unknown system type: Linux 3.16.0-4-amd64 38 | # - name: scientific-6.8 39 | # driver_config: 40 | # image: ringo/scientific:6.8 41 | # platform: rhel 42 | - name: scientific-7.2 43 | driver_config: 44 | image: ringo/scientific:7.2 45 | platform: rhel 46 | -------------------------------------------------------------------------------- /recipes/postfixadmin.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot 4 | # Recipe:: postfixadmin 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2013 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | node.default['postfixadmin']['server_name'] = 23 | node['postfix-dovecot']['hostname'] 24 | node.default['postfixadmin']['common_name'] = 25 | node['postfix-dovecot']['hostname'] 26 | node.default['postfixadmin']['database']['type'] = 27 | node['postfix-dovecot']['database']['type'] 28 | 29 | include_recipe 'postfixadmin' 30 | include_recipe 'postfixadmin::map_files' 31 | -------------------------------------------------------------------------------- /test/integration/mysql/serverspec/vmail_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | 22 | describe 'Vmail' do 23 | describe user('vmail') do 24 | it { should exist } 25 | it { should belong_to_group 'vmail' } 26 | it { should have_uid 5000 } 27 | it { should have_home_directory '/var/vmail' } 28 | it { should have_login_shell '/bin/false' } 29 | end 30 | 31 | describe group('vmail') do 32 | it { should exist } 33 | it { should have_gid 5000 } 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /test/integration/postgresql/serverspec/vmail_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | 22 | describe 'Vmail' do 23 | describe user('vmail') do 24 | it { should exist } 25 | it { should belong_to_group 'vmail' } 26 | it { should have_uid 5000 } 27 | it { should have_home_directory '/var/vmail' } 28 | it { should have_login_shell '/bin/false' } 29 | end 30 | 31 | describe group('vmail') do 32 | it { should exist } 33 | it { should have_gid 5000 } 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /test/cookbooks/postfix-dovecot_test/metadata.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot_test 4 | # Author:: Xabier de Zuazo () 5 | # Copyright:: Copyright (c) 2013 Onddo Labs, SL. 6 | # License:: Apache License, Version 2.0 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | name 'postfix-dovecot_test' 22 | maintainer 'Xabier de Zuazo' 23 | maintainer_email 'xabier@zuazo.org' 24 | license 'Apache 2.0' 25 | description 'This cookbook is used with test-kitchen to test the parent, '\ 26 | 'postfix-dovecot cookbook' 27 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) 28 | version '0.0.1' 29 | 30 | depends 'postfix-dovecot' 31 | depends 'sysctl', '~> 0.8.0' 32 | -------------------------------------------------------------------------------- /Berksfile: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # -*- mode: ruby -*- 3 | # vi: set ft=ruby : 4 | 5 | # More info at http://berkshelf.com/#the-berksfile 6 | 7 | source 'https://supermarket.chef.io' 8 | my_cookbook = 'postfix-dovecot' 9 | 10 | # Berkshelf helper to include a local cookbook from disk. 11 | # 12 | # @param name [String] cookbook name. 13 | # @param version [String] cookbook version requirement. 14 | # @param options [Hash] #cookbook method options. 15 | # return void 16 | def local_cookbook(name, version = '>= 0.0.0', options = {}) 17 | cookbook(name, version, { 18 | path: "../../cookbooks/#{name}" 19 | }.merge(options)) 20 | end 21 | 22 | metadata 23 | cookbook 'apt' 24 | cookbook 'selinux' 25 | 26 | # Minitest Chef Handler 27 | # More info at https://github.com/calavera/minitest-chef-handler 28 | if ::File.directory?(::File.join('files', 'default', 'tests', 'minitest')) || 29 | ::File.directory?( 30 | ::File.join( 31 | 'test', 'cookbooks', "#{my_cookbook}_test", 'files', 'default', 'tests', 32 | 'minitest' 33 | ) 34 | ) 35 | cookbook 'minitest-handler' 36 | end 37 | 38 | # Integration tests cookbook: 39 | if ::File.directory?("./test/cookbooks/#{my_cookbook}_test") 40 | cookbook "#{my_cookbook}_test", path: "./test/cookbooks/#{my_cookbook}_test" 41 | end 42 | -------------------------------------------------------------------------------- /attributes/ssl_certificate.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot 4 | # Attributes:: ssl_certificate 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2015 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | %w(old intermediate modern).each do |level| 23 | # Read protocols array. 24 | protos = node['ssl_certificate']['service'][level]['protocols'] 25 | 26 | # Format the protocols list for Postfix and Dovecot 27 | default['ssl_certificate']['service'][level]['postfix']['protocols'] = 28 | protos.join(', ') 29 | default['ssl_certificate']['service'][level]['dovecot']['protocols'] = 30 | protos.join(' ') 31 | end 32 | -------------------------------------------------------------------------------- /test/cookbooks/postfix-dovecot_test/files/default/tests/minitest/default_test.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2013-2015 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require File.expand_path('../support/helpers', __FILE__) 21 | 22 | describe 'postfix-dovecot::default' do 23 | include Helpers::PostfixDovecotTest 24 | 25 | describe 'postfix' do 26 | it 'should be able to send mails through SES' do 27 | skip unless node['postfix-dovecot']['ses']['enabled'] 28 | send_test_mail( 29 | node['postfix-dovecot']['ses']['email'], 'blackhole@zuazo.org' 30 | ) 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /attributes/vmail.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot 4 | # Attributes:: vmail 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2013 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | default['postfix-dovecot']['spamc']['recipe'] = 'onddo-spamassassin' 23 | default['postfix-dovecot']['spamc']['enabled'] = false 24 | 25 | default['postfix-dovecot']['vmail']['user'] = 'vmail' 26 | default['postfix-dovecot']['vmail']['group'] = 27 | node['postfix-dovecot']['vmail']['user'] 28 | default['postfix-dovecot']['vmail']['uid'] = 5000 29 | default['postfix-dovecot']['vmail']['gid'] = 30 | node['postfix-dovecot']['vmail']['uid'] 31 | default['postfix-dovecot']['vmail']['home'] = '/var/vmail' 32 | -------------------------------------------------------------------------------- /recipes/vmail.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot 4 | # Recipe:: vmail 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2013 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | user node['postfix-dovecot']['vmail']['user'] do 23 | comment node['postfix-dovecot']['vmail']['user'].capitalize 24 | home node['postfix-dovecot']['vmail']['home'] 25 | shell '/bin/false' 26 | uid node['postfix-dovecot']['vmail']['uid'] 27 | manage_home true 28 | system true 29 | end 30 | 31 | group node['postfix-dovecot']['vmail']['group'] do 32 | gid node['postfix-dovecot']['vmail']['gid'] 33 | members [node['postfix-dovecot']['vmail']['user']] 34 | system true 35 | append true 36 | end 37 | -------------------------------------------------------------------------------- /test/unit/recipes/default_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014-2015 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require_relative '../spec_helper' 21 | 22 | describe 'postfix-dovecot::default' do 23 | let(:chef_run) { ChefSpec::SoloRunner.new.converge(described_recipe) } 24 | before do 25 | stub_command('/usr/sbin/apache2 -t').and_return(true) 26 | end 27 | 28 | %w( 29 | postfix-dovecot::vmail 30 | postfix-dovecot::spam 31 | postfix-dovecot::postfix 32 | postfix-dovecot::postfixadmin 33 | postfix-dovecot::dovecot 34 | ).each do |recipe| 35 | it "includes #{recipe} recipe" do 36 | expect(chef_run).to include_recipe(recipe) 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /attributes/ses.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot 4 | # Attributes:: ses 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2013 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | default['postfix-dovecot']['ses']['enabled'] = false 23 | default['postfix-dovecot']['ses']['source'] = 'attributes' 24 | default['postfix-dovecot']['ses']['vault'] = 'amazon' 25 | default['postfix-dovecot']['ses']['item'] = 'ses' 26 | default['postfix-dovecot']['ses']['username'] = 'USERNAME' 27 | default['postfix-dovecot']['ses']['password'] = 'PASSWORD' 28 | default['postfix-dovecot']['ses']['region'] = 'us-east-1' 29 | default['postfix-dovecot']['ses']['servers'] = [ 30 | "email-smtp.#{node['postfix-dovecot']['ses']['region']}.amazonaws.com:587" 31 | ] 32 | -------------------------------------------------------------------------------- /test/integration/postgresql/serverspec/postgresql_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | 22 | def centos? 23 | File.exist?('/etc/centos-release') 24 | end 25 | 26 | family = os[:family].downcase 27 | release = os[:release].to_i 28 | 29 | postgres = 30 | if %w(centos redhat scientific amazon).include?(family) 31 | if centos? && release >= 7 32 | 'postgres' 33 | else 34 | 'master' 35 | end 36 | else 37 | 'postgres' 38 | end 39 | 40 | describe 'PostgreSQL' do 41 | describe process(postgres) do 42 | it { should be_running } 43 | end 44 | 45 | describe port(5432) do 46 | it { should be_listening } 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /chefignore: -------------------------------------------------------------------------------- 1 | # Put files/directories that should be ignored in this file when uploading 2 | # or sharing to the community site. 3 | # Lines that start with '# ' are comments. 4 | 5 | # OS generated files # 6 | ###################### 7 | .DS_Store 8 | Icon? 9 | nohup.out 10 | ehthumbs.db 11 | Thumbs.db 12 | 13 | # SASS # 14 | ######## 15 | .sass-cache 16 | 17 | # EDITORS # 18 | ########### 19 | \#* 20 | .#* 21 | *~ 22 | *.sw[a-z] 23 | *.bak 24 | REVISION 25 | TAGS* 26 | tmtags 27 | *_flymake.* 28 | *_flymake 29 | *.tmproj 30 | .project 31 | .settings 32 | mkmf.log 33 | 34 | ## COMPILED ## 35 | ############## 36 | a.out 37 | *.o 38 | *.pyc 39 | *.so 40 | *.com 41 | *.class 42 | *.dll 43 | *.exe 44 | */rdoc/ 45 | 46 | # Testing # 47 | ########### 48 | .watchr 49 | .rspec 50 | test/unit/* 51 | test/unit/fixtures/* 52 | test/* 53 | features/* 54 | Guardfile 55 | Procfile 56 | 57 | # SCM # 58 | ####### 59 | .git 60 | */.git 61 | .gitignore 62 | .gitmodules 63 | .gitconfig 64 | .gitattributes 65 | .svn 66 | */.bzr/* 67 | */.hg/* 68 | */.svn/* 69 | 70 | # Berkshelf # 71 | ############# 72 | Berksfile 73 | Berksfile.lock 74 | cookbooks/* 75 | tmp 76 | 77 | # Cookbooks # 78 | ############# 79 | CONTRIBUTING 80 | CHANGELOG* 81 | 82 | # Strainer # 83 | ############ 84 | Colanderfile 85 | Strainerfile 86 | .colander 87 | .strainer 88 | 89 | # Vagrant # 90 | ########### 91 | .vagrant 92 | Vagrantfile 93 | 94 | # Travis # 95 | ########## 96 | .travis.yml 97 | -------------------------------------------------------------------------------- /test/integration/mysql/serverspec/mail_helpers.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2017 Xabier de Zuazo 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | require 'net/smtp' 22 | 23 | EMAIL_TEMPLATE = <<-EOM 24 | Subject: Some cool subject for testing 25 | 26 | A hamish email body. 27 | 28 | Fingerprint: %s 29 | EOM 30 | .freeze 31 | 32 | def send_email(fingerprint) 33 | msgstr = format(EMAIL_TEMPLATE, fingerprint) 34 | Net::SMTP.start('localhost', 25) do |smtp| 35 | smtp.send_message( 36 | msgstr, 37 | 'team@onddo.com', 38 | 'postmaster@foobar.com' 39 | ) 40 | end 41 | end 42 | 43 | def all_file_contents(path) 44 | Dir.glob(path).reduce('') do |result, file| 45 | result + "\n" + File.read(file) 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /test/integration/postgresql/serverspec/mail_helpers.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2017 Xabier de Zuazo 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | require 'net/smtp' 22 | 23 | EMAIL_TEMPLATE = <<-EOM 24 | Subject: Some cool subject for testing 25 | 26 | A hamish email body. 27 | 28 | Fingerprint: %s 29 | EOM 30 | .freeze 31 | 32 | def send_email(fingerprint) 33 | msgstr = format(EMAIL_TEMPLATE, fingerprint) 34 | Net::SMTP.start('localhost', 25) do |smtp| 35 | smtp.send_message( 36 | msgstr, 37 | 'team@onddo.com', 38 | 'postmaster@foobar.com' 39 | ) 40 | end 41 | end 42 | 43 | def all_file_contents(path) 44 | Dir.glob(path).reduce('') do |result, file| 45 | result + "\n" + File.read(file) 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /test/unit/recipes/vmail_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014-2015 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require_relative '../spec_helper' 21 | 22 | describe 'postfix-dovecot::vmail' do 23 | let(:chef_run) { ChefSpec::SoloRunner.new.converge(described_recipe) } 24 | 25 | it 'creates vmail user' do 26 | expect(chef_run).to create_user('vmail') 27 | .with_comment('Vmail') 28 | .with_home('/var/vmail') 29 | .with_shell('/bin/false') 30 | .with_uid(5000) 31 | .with_manage_home(true) 32 | .with_system(true) 33 | end 34 | 35 | it 'creates vmail group' do 36 | expect(chef_run).to create_group('vmail') 37 | .with_gid(5000) 38 | .with_members(%w(vmail)) 39 | .with_system(true) 40 | .with_append(true) 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /test/cookbooks/postfix-dovecot_test/files/default/tests/minitest/support/helpers.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2013 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'net/smtp' 21 | 22 | module Helpers 23 | # Test helpers to send emails via SMTP 24 | module PostfixDovecotTest 25 | include MiniTest::Chef::Assertions 26 | include MiniTest::Chef::Context 27 | include MiniTest::Chef::Resources 28 | 29 | def template(from, to) 30 | <<-EOM 31 | From: #{from} 32 | To: #{to} 33 | Subject: Some cool subject for testing 34 | 35 | A blackhole email body. 36 | 37 | EOM 38 | end 39 | 40 | def send_test_mail(from, to) 41 | Net::SMTP.start('localhost', 25) do |smtp| 42 | smtp.send_message( 43 | template(from, to), 44 | from, 45 | to 46 | ) 47 | end 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /test/unit/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'chefspec' 21 | require 'chefspec/berkshelf' 22 | require 'should_not/rspec' 23 | 24 | RSpec.configure do |config| 25 | # Prohibit using the should syntax 26 | config.expect_with :rspec do |spec| 27 | spec.syntax = :expect 28 | end 29 | 30 | # Run specs in random order to surface order dependencies. If you find an 31 | # order dependency and want to debug it, you can fix the order by providing 32 | # the seed, which is printed after each run. 33 | # --seed 1234 34 | config.order = 'random' 35 | 36 | # ChefSpec configuration 37 | config.log_level = :fatal 38 | config.color = true 39 | config.formatter = :documentation 40 | config.tty = true 41 | config.platform = 'ubuntu' 42 | config.version = '12.04' 43 | end 44 | 45 | at_exit { ChefSpec::Coverage.report! } 46 | -------------------------------------------------------------------------------- /test/unit/recipes/spam_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014-2015 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require_relative '../spec_helper' 21 | 22 | describe 'postfix-dovecot::spam' do 23 | let(:chef_runner) { ChefSpec::SoloRunner.new } 24 | let(:chef_run) { chef_runner.converge(described_recipe) } 25 | before do 26 | stub_command('grep -e " --daemonize\\| -d" /etc/sysconfig/spamassassin') 27 | .and_return(false) 28 | end 29 | 30 | it 'does not include onddo-spamassassin recipe by default' do 31 | expect(chef_run).to_not include_recipe('onddo-spamassassin') 32 | end 33 | 34 | context 'with spamc enabled' do 35 | before do 36 | chef_runner.node.set['postfix-dovecot']['spamc']['enabled'] = true 37 | end 38 | 39 | it 'includes onddo-spamassassin recipe by default' do 40 | expect(chef_run).to include_recipe('onddo-spamassassin') 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # -*- mode: ruby -*- 3 | # vi: set ft=ruby : 4 | 5 | # More info at http://bundler.io/gemfile.html 6 | # 7 | # Many of the gem versions installed here are based on the versions installed 8 | # by ChefDK. 9 | 10 | source 'https://rubygems.org' 11 | 12 | chef_version = ENV.key?('CHEF_VERSION') ? ENV['CHEF_VERSION'] : nil 13 | 14 | group :doc do 15 | gem 'yard', '~> 0.9.5' 16 | end 17 | 18 | group :test do 19 | gem 'rake' 20 | gem 'berkshelf', '~> 6.0' 21 | end 22 | 23 | group :style do 24 | gem 'foodcritic', '~> 6.3.0' 25 | gem 'rubocop', '= 0.40.0' 26 | end 27 | 28 | group :unit do 29 | gem 'chef', chef_version unless chef_version.nil? 30 | gem 'chefspec', '~> 6.0' 31 | gem 'simplecov', '~> 0.13.0' 32 | gem 'should_not', '~> 1.1' 33 | gem 'chef-vault', '~> 2.3' 34 | gem 'chef-encrypted-attributes', '~> 0.4' 35 | end 36 | 37 | group :integration do 38 | gem 'test-kitchen', '~> 1.13' 39 | end 40 | 41 | group :integration_docker do 42 | gem 'kitchen-docker', '~> 2.1' 43 | end 44 | 45 | group :integration_vagrant do 46 | gem 'vagrant-wrapper', '~> 2.0' 47 | gem 'kitchen-vagrant', '~> 1.0' 48 | end 49 | 50 | group :integration_cloud do 51 | gem 'kitchen-ec2', '~> 1.2' 52 | gem 'kitchen-digitalocean', '~> 0.9.5' 53 | end 54 | 55 | group :guard do 56 | gem 'guard', '~> 2.14' 57 | gem 'guard-foodcritic', '~> 2.1' 58 | gem 'guard-rubocop', '~> 1.1' 59 | gem 'guard-rspec', '~> 4.3' 60 | # Temporary disabled: Error is: cannot load such file -- guard/kitchen 61 | # gem 'guard-kitchen', '~> 0.0' 62 | end 63 | 64 | group :travis do 65 | gem 'coveralls', '~> 0.7', require: false 66 | end 67 | -------------------------------------------------------------------------------- /test/unit/recipes/postfix_mysql_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014-2015 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require_relative '../spec_helper' 21 | 22 | describe 'postfix-dovecot::postfix_mysql' do 23 | let(:chef_runner) { ChefSpec::SoloRunner.new } 24 | let(:chef_run) { chef_runner.converge(described_recipe) } 25 | 26 | it 'installs postfix package' do 27 | expect(chef_run).to install_package('postfix') 28 | end 29 | 30 | context 'with CentOS' do 31 | before do 32 | chef_runner.node.automatic['platform'] = 'centos' 33 | end 34 | 35 | it 'does not install postfix-mysql package' do 36 | expect(chef_run).to_not install_package('postfix-mysql') 37 | end 38 | end 39 | 40 | context 'with Ubuntu' do 41 | before do 42 | chef_runner.node.automatic['platform'] = 'ubuntu' 43 | end 44 | 45 | it 'installs postfix-mysql package' do 46 | expect(chef_run).to install_package('postfix-mysql') 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /recipes/spam.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot 4 | # Recipe:: spam 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2013 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | if node['postfix-dovecot']['spamc']['enabled'] 23 | if node['postfix-dovecot']['spamc']['recipe'] == 'onddo-spamassassin' 24 | node.default['spamassassin']['spamd']['enabled'] = true 25 | node.default['spamassassin']['spamd']['options'] = %w( 26 | --create-prefs 27 | --max-children 3 28 | --helper-home-dir 29 | ) 30 | # local.cf 31 | node.default['spamassassin']['conf']['rewrite_header'] = [ 32 | Subject: '[SPAM]' 33 | ] 34 | node.default['spamassassin']['conf']['report_safe'] = false 35 | node.default['spamassassin']['conf']['lock_method'] = 'flock' 36 | node.default['postfix-dovecot']['spamc']['path'] = 37 | node['spamassassin']['spamc']['path'] 38 | 39 | include_recipe node['postfix-dovecot']['spamc']['recipe'] 40 | else 41 | node.default['postfix-dovecot']['spamc']['path'] = '/usr/bin/spamc' 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /test/cookbooks/postfix-dovecot_test/recipes/postgresql_memory.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot_test 4 | # Recipe:: postgresql_memory 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | def getconf(var) 23 | cmd = Mixlib::ShellOut.new("getconf #{var}").run_command 24 | cmd.error! 25 | cmd.stdout.split("\n")[-1] 26 | end 27 | 28 | if node['postgresql']['version'].to_f <= 9.3 && 29 | node['platform'] != 'scientific' 30 | page_size = getconf('PAGE_SIZE').to_i 31 | phys_pages = getconf('_PHYS_PAGES').to_i 32 | 33 | shmall = phys_pages / 2 34 | shmmax = shmall * page_size 35 | 36 | execute 'sysctl -p /etc/sysctl.d/postgresql.conf' do 37 | action :nothing 38 | end 39 | 40 | template '/etc/sysctl.d/postgresql.conf' do 41 | source 'sysctl.conf.erb' 42 | variables( 43 | values: { 44 | 'kernel.shmall' => shmall, 45 | 'kernel.shmmax' => shmmax 46 | } 47 | ) 48 | only_if { ::File.exist?('/etc/sysctl.d') } 49 | notifies :run, 'execute[sysctl -p /etc/sysctl.d/postgresql.conf]', 50 | :immediately 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /test/integration/ses/serverspec/postfix_ses_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | require 'net/smtp' 22 | require_relative 'mail_helpers' 23 | 24 | describe 'Postfix' do 25 | describe command('/usr/sbin/postconf') do 26 | its(:exit_status) { should eq 0 } 27 | its(:stderr) { should eq '' } 28 | end 29 | 30 | describe process('master') do 31 | it { should be_running } 32 | end 33 | 34 | describe 'when an email is sent through smtp' do 35 | let(:from) { 'from@foobar.com' } 36 | let(:to) { 'blackhole@zuazo.org' } 37 | let(:pattern) do 38 | "postfix/smtp.* to=<#{to}>, relay=.*.amazonaws.com.*, .*status=sent" 39 | end 40 | let(:mail_log) do 41 | if ::File.exist?('/var/log/maillog') 42 | '/var/log/maillog' 43 | else 44 | '/var/log/mail.log' 45 | end 46 | end 47 | before(:context) { send_email(from, to) } 48 | 49 | it 'is able to receive it', retry: 30, retry_wait: 1 do 50 | expect(::File.read(mail_log)).to include pattern 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /.kitchen.cloud.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | aws_access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %> 4 | aws_secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %> 5 | aws_ssh_key_id: <%= ENV['AWS_KEYPAIR_NAME'] %> 6 | ssh: 7 | forward_agent: true 8 | 9 | provisioner: 10 | name: chef_zero 11 | require_chef_omnibus: latest 12 | 13 | platforms: 14 | - name: centos-6.4 15 | driver_plugin: digitalocean 16 | driver_config: 17 | image_id: 562354 18 | flavor_id: 63 19 | region_id: 4 20 | ssh_key_ids: <%= ENV['DIGITAL_OCEAN_SSH_KEY_IDS'] %> 21 | <% if ENV['SSH_AGENT_PID'].nil? %> 22 | ssh_key: <%= ENV['DIGITAL_OCEAN_SSH_KEY_PATH'] %> 23 | <% end %> 24 | 25 | - name: fedora-17 26 | driver_plugin: digitalocean 27 | driver_config: 28 | image_id: 32428 29 | flavor_id: 63 30 | region_id: 4 31 | ssh_key_ids: <%= ENV['DIGITAL_OCEAN_SSH_KEY_IDS'] %> 32 | <% if ENV['SSH_AGENT_PID'].nil? %> 33 | ssh_key: <%= ENV['DIGITAL_OCEAN_SSH_KEY_PATH'] %> 34 | <% end %> 35 | 36 | - name: ubuntu-1204 37 | driver_plugin: digitalocean 38 | driver_config: 39 | image_id: 1505447 40 | flavor_id: 63 41 | region_id: 4 42 | ssh_key_ids: <%= ENV['DIGITAL_OCEAN_SSH_KEY_IDS'] %> 43 | <% if ENV['SSH_AGENT_PID'].nil? %> 44 | ssh_key: <%= ENV['DIGITAL_OCEAN_SSH_KEY_PATH'] %> 45 | <% end %> 46 | run_list: 47 | - recipe[apt] 48 | 49 | - name: amazon-2011.02.1 50 | driver_plugin: ec2 51 | driver_config: 52 | image_id: ami-8e1fece7 53 | flavor_id: t1.micro 54 | username: ec2-user 55 | <% if ENV['SSH_AGENT_PID'].nil? %> 56 | ssh_key: <%= ENV['EC2_SSH_KEY_PATH'] %> 57 | <% end %> 58 | 59 | - name: amazon-2013.09.2 60 | driver_plugin: ec2 61 | driver_config: 62 | image_id: ami-bba18dd2 63 | flavor_id: t1.micro 64 | username: ec2-user 65 | <% if ENV['SSH_AGENT_PID'].nil? %> 66 | ssh_key: <%= ENV['EC2_SSH_KEY_PATH'] %> 67 | <% end %> 68 | -------------------------------------------------------------------------------- /test/cookbooks/postfix-dovecot_test/recipes/default.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot_test 4 | # Recipe:: default 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2013 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | if node['postfix-dovecot']['database']['type'] == 'postgresql' 23 | include_recipe 'postfix-dovecot_test::postgresql_memory' 24 | end 25 | 26 | node.default['postfix-dovecot']['spamc']['enabled'] = true 27 | 28 | node.default['postgresql']['password']['postgres'] = 'vagrant_postgres' 29 | node.default['postfixadmin']['mysql']['server_root_password'] = 'vagrant_root' 30 | 31 | node.default['postfixadmin']['database']['password'] = 'postfix_pass' 32 | node.default['postfixadmin']['setup_password'] = '4dm1n' 33 | node.default['postfixadmin']['setup_password_salt'] = 'salt' 34 | 35 | include_recipe 'postfix-dovecot' 36 | 37 | postfixadmin_admin 'admin@foobar.com' do 38 | password 'p@ssw0rd1' 39 | end 40 | 41 | postfixadmin_domain 'foobar.com' do 42 | login_username 'admin@foobar.com' 43 | login_password 'p@ssw0rd1' 44 | end 45 | 46 | postfixadmin_mailbox 'postmaster@foobar.com' do 47 | password 'p0stm@st3r1' 48 | login_username 'admin@foobar.com' 49 | login_password 'p@ssw0rd1' 50 | end 51 | 52 | package 'lsof' # required for integration tests 53 | package 'wget' # required for integration tests 54 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | rvm: 2 | - 2.2 3 | - 2.3 4 | 5 | sudo: required 6 | 7 | services: docker 8 | 9 | env: 10 | matrix: 11 | - TESTS="style unit" CHEF_VERSION="~> 12.0" 12 | # - TESTS="integration[mysql-centos-6,verify]" 13 | - TESTS="integration[mysql-debian-8,verify]" 14 | - TESTS="integration[postgresql-debian-8,verify]" 15 | - TESTS="integration[postfixpgsql-debian-7,verify]" 16 | - TESTS="integration[postfixpgsql-debian-8,verify]" 17 | - TESTS="integration[postfixpgsql-ubuntu-1204,verify]" 18 | - TESTS="integration[postfixpgsql-ubuntu-1404,verify]" 19 | - TESTS="integration[postfixpgsql-ubuntu-1604,verify]" 20 | - TESTS="integration[postfixpgsql-ubuntu-1610,verify]" 21 | 22 | matrix: 23 | exclude: 24 | - rvm: 2.2 25 | env: TESTS="integration[mysql-centos-6,verify]" 26 | - rvm: 2.2 27 | env: TESTS="integration[mysql-debian-8,verify]" 28 | - rvm: 2.2 29 | env: TESTS="integration[postgresql-debian-8,verify]" 30 | - rvm: 2.2 31 | env: TESTS="integration[postfixpgsql-debian-7,verify]" 32 | - rvm: 2.2 33 | env: TESTS="integration[postfixpgsql-debian-8,verify]" 34 | - rvm: 2.2 35 | env: TESTS="integration[postfixpgsql-ubuntu-1204,verify]" 36 | - rvm: 2.2 37 | env: TESTS="integration[postfixpgsql-ubuntu-1404,verify]" 38 | - rvm: 2.2 39 | env: TESTS="integration[postfixpgsql-ubuntu-1604,verify]" 40 | - rvm: 2.2 41 | env: TESTS="integration[postfixpgsql-ubuntu-1610,verify]" 42 | 43 | before_install: 44 | - chef --version &> /dev/null || curl -L https://www.getchef.com/chef/install.sh | sudo bash -s -- -P chefdk -v 1.2.22 45 | - eval "$(/opt/chefdk/bin/chef shell-init bash)" 46 | 47 | install: 48 | - chef exec bundle install --jobs=3 --retry=3 --without='doc integration_vagrant integration_cloud guard' 49 | 50 | before_script: 51 | # https://github.com/zuazo/kitchen-in-travis-native/issues/1#issuecomment-142455888 52 | - sudo iptables -L DOCKER || ( echo "DOCKER iptables chain missing" ; sudo iptables -N DOCKER ) 53 | - chef --version 54 | - cookstyle --version 55 | - foodcritic --version 56 | 57 | script: travis_retry chef exec bundle exec rake $TESTS 58 | -------------------------------------------------------------------------------- /test/integration/mysql/serverspec/spam_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | require_relative 'mail_helpers' 22 | 23 | family = os[:family].downcase 24 | 25 | spamd = 26 | case family 27 | when 'debian', 'ubuntu' 28 | '/usr/sbin/spamd' 29 | else 30 | 'spamd' 31 | end 32 | 33 | describe 'SpamAssassin' do 34 | let(:gtube) do 35 | 'XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X' 36 | end 37 | 38 | describe command('which spamc') do 39 | its(:exit_status) { should eq 0 } 40 | its(:stderr) { should eq '' } 41 | end 42 | 43 | describe process(spamd) do 44 | it { should be_running } 45 | end 46 | 47 | it 'detects spam correctly', if: !::File.exist?('/etc/fedora-release') do 48 | expect(command("echo '#{gtube}' | spamc").stdout) 49 | .to match(/X-Spam-Flag: +YES/i) 50 | end 51 | 52 | describe( 53 | 'when spam is sent through smtp', if: !::File.exist?('/etc/fedora-release') 54 | ) do 55 | gtube = 56 | 'XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X' 57 | fingerprint = "#{gtube} - #{Time.new.to_i}" 58 | let(:maildir) { '/var/vmail/foobar.com/postmaster' } 59 | let(:spamdir) { "#{maildir}/.Spam/new" } 60 | before(:context) { send_email(fingerprint) } 61 | 62 | it 'filters it correctly', retry: 30, retry_wait: 1 do 63 | expect(all_file_contents("#{spamdir}/*")).to include fingerprint 64 | end 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /test/unit/recipes/dovecot_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014-2015 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require_relative '../spec_helper' 21 | 22 | describe 'postfix-dovecot::dovecot' do 23 | let(:chef_runner) { ChefSpec::SoloRunner.new } 24 | let(:chef_run) { chef_runner.converge(described_recipe) } 25 | before do 26 | allow(::File).to receive(:exist?).and_call_original 27 | expect(::File).to receive(:exist?).with('/etc/dovecot/sieve') 28 | .and_return(false) 29 | end 30 | 31 | it 'generates SMTP SSL certificate' do 32 | expect(chef_run).to create_ssl_certificate('dovecot2') 33 | end 34 | 35 | it 'includes dovecot recipe' do 36 | expect(chef_run).to include_recipe('dovecot') 37 | end 38 | 39 | it 'creates sievec resource' do 40 | resource = chef_run.execute('sievec sieve_global_path') 41 | expect(resource).to do_nothing 42 | end 43 | 44 | it 'creates sieve_global_dir directory' do 45 | expect(chef_run).to create_directory('/etc/dovecot/sieve') 46 | .with_owner('root') 47 | .with_group('root') 48 | .with_mode('00755') 49 | .with_recursive(true) 50 | end 51 | 52 | it 'creates sieve_global_path file' do 53 | expect(chef_run).to create_template('/etc/dovecot/sieve/default.sieve') 54 | .with_owner('root') 55 | .with_group('root') 56 | .with_mode('00644') 57 | end 58 | 59 | it 'sieve_global_path file notifies sievec' do 60 | resource = chef_run.template('/etc/dovecot/sieve/default.sieve') 61 | expect(resource).to notify('execute[sievec sieve_global_path]') 62 | .to(:run).delayed 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /test/unit/recipes/postfixadmin_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014-2015 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require_relative '../spec_helper' 21 | 22 | describe 'postfix-dovecot::postfixadmin' do 23 | let(:hostname) { 'my_hostname' } 24 | let(:db_type) { 'postgresql' } 25 | let(:db_name) { 'postfixadmin_db' } 26 | let(:db_password) { 'postfixadmin_pass' } 27 | let(:chef_runner) { ChefSpec::SoloRunner.new } 28 | let(:chef_run) { chef_runner.converge(described_recipe) } 29 | let(:node) { chef_runner.node } 30 | before do 31 | node.set['postfix-dovecot']['hostname'] = hostname 32 | node.set['postfix-dovecot']['database']['type'] = db_type 33 | node.set['postfixadmin']['database']['name'] = db_name 34 | node.set['postgresql']['password']['postgres'] = db_password 35 | 36 | stub_command('/usr/sbin/apache2 -t').and_return(true) 37 | stub_command( 38 | "psql -c 'SELECT lanname FROM pg_catalog.pg_language' #{db_name} "\ 39 | "| grep '^ plpgsql$'" 40 | ).and_return(false) 41 | stub_command('ls /var/lib/postgresql/9.1/main/recovery.conf') 42 | .and_return(true) 43 | end 44 | 45 | it 'sets node["postfixadmin"]["server_name"] attribute' do 46 | expect(chef_run.node['postfixadmin']['server_name']).to eq(hostname) 47 | end 48 | 49 | it 'sets node["postfixadmin"]["common_name"] attribute' do 50 | expect(chef_run.node['postfixadmin']['common_name']).to eq(hostname) 51 | end 52 | 53 | it 'sets node["postfixadmin"]["database"]["type"] attribute' do 54 | expect(chef_run.node['postfixadmin']['database']['type']).to eq(db_type) 55 | end 56 | 57 | it 'includes postfixadmin recipe' do 58 | expect(chef_run).to include_recipe('postfixadmin') 59 | end 60 | 61 | it 'includes postfixadmin::map_files recipe' do 62 | expect(chef_run).to include_recipe('postfixadmin::map_files') 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # -*- mode: ruby -*- 3 | # vi: set ft=ruby : 4 | 5 | # More info at https://github.com/guard/guard#readme 6 | 7 | # Style Tests 8 | # =========== 9 | # - Foodcritic 10 | # - RuboCop 11 | 12 | group :style, 13 | halt_on_fail: true do 14 | guard :foodcritic, 15 | cli: '--exclude test/unit', 16 | cookbook_paths: '.', 17 | all_on_start: false do 18 | watch(%r{attributes/.+\.rb$}) 19 | watch(%r{definitions/.+\.rb$}) 20 | watch(%r{libraries/.+\.rb$}) 21 | watch(%r{providers/.+\.rb$}) 22 | watch(%r{recipes/.+\.rb$}) 23 | watch(%r{resources/.+\.rb$}) 24 | watch(%r{templates/.+\.erb$}) 25 | watch('metadata.rb') 26 | end 27 | 28 | guard :rubocop, 29 | all_on_start: false do 30 | watch(/.+\.rb$/) 31 | watch('Gemfile') 32 | watch('Rakefile') 33 | watch('Capfile') 34 | watch('Guardfile') 35 | watch('Podfile') 36 | watch('Thorfile') 37 | watch('Vagrantfile') 38 | watch('Berksfile') 39 | watch('Cheffile') 40 | watch('Vagabondfile') 41 | end 42 | end # group style 43 | 44 | # Unit Tests 45 | # ========== 46 | # - test/unit/libraries/${library}_spec.rb: Unit tests for libraries. 47 | # - test/unit/recipes/${recipe}_spec.rb: ChefSpec tests for recipes. 48 | # - test/unit/resources/${resource}_spec.rb: ChefSpec tests for resources. 49 | 50 | group :unit do 51 | guard :rspec, 52 | cmd: 'bundle exec rake unit', 53 | all_on_start: false do 54 | watch(%r{^libraries/(.+)\.rb$}) do |m| 55 | "test/unit/libraries/#{m[1]}_spec.rb" 56 | end 57 | watch(%r{^recipes/(.+)\.rb$}) { |m| "test/unit/recipes/#{m[1]}_spec.rb" } 58 | watch(%r{^(?:providers|resources)/(.+)\.rb$}) do |m| 59 | "test/unit/resources/#{m[1]}_spec.rb" 60 | end 61 | watch(%r{^test/unit/.+_spec\.rb$}) 62 | watch('test/unit/spec_helper.rb') { 'spec' } 63 | end 64 | end # group unit 65 | 66 | # Integration Tests 67 | # ================= 68 | # - test-kitchen 69 | # 70 | # Temporary disabled. See the Gemfile. 71 | 72 | # group :integration do 73 | # guard 'kitchen', 74 | # all_on_start: false do 75 | # watch(%r{attributes/.+\.rb$}) 76 | # watch(%r{definitions/.+\.rb$}) 77 | # watch(%r{libraries/.+\.rb$}) 78 | # watch(%r{providers/.+\.rb$}) 79 | # watch(%r{recipes/.+\.rb$}) 80 | # watch(%r{resources/.+\.rb$}) 81 | # watch(%r{files/.+}) 82 | # watch(%r{templates/.+\.erb$}) 83 | # watch('metadata.rb') 84 | # watch(%r{test/.+$}) 85 | # watch('Berksfile') 86 | # end 87 | # end # group integration 88 | 89 | scope groups: [:style, :unit] 90 | -------------------------------------------------------------------------------- /test/integration/mysql/serverspec/dovecot_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | require 'net/imap' 22 | 23 | describe 'Dovecot' do 24 | describe command('doveconf') do 25 | its(:exit_status) { should eq 0 } 26 | its(:stderr) { should eq '' } 27 | end 28 | 29 | describe process('dovecot') do 30 | it { should be_running } 31 | end 32 | 33 | # imap 34 | describe port(143) do 35 | it { should be_listening.with('tcp') } 36 | end 37 | 38 | # imaps 39 | describe port(993) do 40 | it { should be_listening.with('tcp') } 41 | end 42 | 43 | it 'connects to imap SSL' do 44 | expect( 45 | command('echo | openssl s_client -connect 127.0.0.1:imaps') 46 | .exit_status 47 | ).to eq 0 48 | end 49 | 50 | it 'connects to imap with startls' do 51 | expect( 52 | command('echo | openssl s_client -starttls imap -connect 127.0.0.1:imap') 53 | .exit_status 54 | ).to eq 0 55 | end 56 | 57 | it 'is able to login using imap (plain)' do 58 | imap = Net::IMAP.new('localhost') 59 | imap.authenticate('PLAIN', 'postmaster@foobar.com', 'p0stm@st3r1') 60 | imap.examine('INBOX') 61 | imap.close 62 | end 63 | 64 | describe file('/etc/dovecot/sieve') do 65 | it { should be_directory } 66 | it { should be_mode 755 } 67 | it { should be_owned_by 'root' } 68 | it { should be_grouped_into 'root' } 69 | end 70 | 71 | describe file('/etc/dovecot/sieve/default.sieve') do 72 | it { should be_file } 73 | it { should be_mode 644 } 74 | it { should be_owned_by 'root' } 75 | it { should be_grouped_into 'root' } 76 | end 77 | 78 | describe file('/etc/dovecot/sieve/default.svbin') do 79 | it { should be_file } 80 | it { should be_mode 644 } 81 | it { should be_owned_by 'root' } 82 | it { should be_grouped_into 'root' } 83 | end 84 | end 85 | -------------------------------------------------------------------------------- /test/integration/postgresql/serverspec/dovecot_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | require 'net/imap' 22 | 23 | describe 'Dovecot' do 24 | describe command('doveconf') do 25 | its(:exit_status) { should eq 0 } 26 | its(:stderr) { should eq '' } 27 | end 28 | 29 | describe process('dovecot') do 30 | it { should be_running } 31 | end 32 | 33 | # imap 34 | describe port(143) do 35 | it { should be_listening.with('tcp') } 36 | end 37 | 38 | # imaps 39 | describe port(993) do 40 | it { should be_listening.with('tcp') } 41 | end 42 | 43 | it 'connects to imap SSL' do 44 | expect( 45 | command('echo | openssl s_client -connect 127.0.0.1:imaps') 46 | .exit_status 47 | ).to eq 0 48 | end 49 | 50 | it 'connects to imap with startls' do 51 | expect( 52 | command('echo | openssl s_client -starttls imap -connect 127.0.0.1:imap') 53 | .exit_status 54 | ).to eq 0 55 | end 56 | 57 | it 'is able to login using imap (plain)' do 58 | imap = Net::IMAP.new('localhost') 59 | imap.authenticate('PLAIN', 'postmaster@foobar.com', 'p0stm@st3r1') 60 | imap.examine('INBOX') 61 | imap.close 62 | end 63 | 64 | describe file('/etc/dovecot/sieve') do 65 | it { should be_directory } 66 | it { should be_mode 755 } 67 | it { should be_owned_by 'root' } 68 | it { should be_grouped_into 'root' } 69 | end 70 | 71 | describe file('/etc/dovecot/sieve/default.sieve') do 72 | it { should be_file } 73 | it { should be_mode 644 } 74 | it { should be_owned_by 'root' } 75 | it { should be_grouped_into 'root' } 76 | end 77 | 78 | describe file('/etc/dovecot/sieve/default.svbin') do 79 | it { should be_file } 80 | it { should be_mode 644 } 81 | it { should be_owned_by 'root' } 82 | it { should be_grouped_into 'root' } 83 | end 84 | end 85 | -------------------------------------------------------------------------------- /.kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: vagrant 4 | network: 5 | - ["forwarded_port", {guest: 80, host: 8080, auto_correct: true}] 6 | 7 | provisioner: 8 | name: chef_zero 9 | require_chef_omnibus: 12 10 | # client_rb: 11 | # treat_deprecation_warnings_as_errors: true # WiP on some depends 12 | 13 | platforms: 14 | - name: ubuntu-12.04 15 | run_list: recipe[apt] 16 | - name: ubuntu-14.04 17 | run_list: recipe[apt] 18 | - name: ubuntu-16.04 19 | run_list: recipe[apt] 20 | - name: ubuntu-16.10 21 | run_list: recipe[apt] 22 | - name: debian-7.11 23 | run_list: recipe[apt] 24 | - name: debian-8.6 25 | run_list: recipe[apt] 26 | - name: centos-6.8 27 | run_list: recipe[selinux::disabled] 28 | - name: centos-7.3 29 | run_list: recipe[selinux::disabled] 30 | - name: fedora-23 31 | - name: fedora-24 32 | run_list: recipe[selinux::disabled] 33 | - name: fedora-25 34 | run_list: recipe[selinux::disabled] 35 | 36 | suites: 37 | - name: mysql 38 | run_list: 39 | - recipe[minitest-handler] 40 | - recipe[postfix-dovecot_test] 41 | excludes: 42 | # mysql: No candidate version available for mysql-community-server 43 | - centos-7 44 | # postfix-full: Starting Postfix Mail Transport Agent: postfix failed 45 | - debian-7 46 | # postfix-full: * Starting Postfix Mail Transport Agent postfix ...fail! 47 | - ubuntu-12.04 48 | # postfix-full: * Starting Postfix Mail Transport Agent postfix ...fail! 49 | - ubuntu-14.04 50 | # apache2: No candidate version available for libapache2-mod-php5 51 | - ubuntu-16.04 52 | # mysql: undefined method `split' for nil:NilClass 53 | - ubuntu-16.10 54 | # spamassassin: cpio: cap_set_file failed - Operation not supported 55 | - scientific-7.2 56 | - name: postgresql 57 | excludes: 58 | - amazon-2011.02.1 59 | - amazon-2013.09.2 60 | # apache2: cpio: cap_set_file failed - Operation not supported 61 | - centos-7 62 | # postfix-full: Starting Postfix Mail Transport Agent: postfix failed 63 | - debian-7 64 | # postfix-full: * Starting Postfix Mail Transport Agent postfix ...fail! 65 | - ubuntu-12.04 66 | # postfix-full: * Starting Postfix Mail Transport Agent postfix ...fail! 67 | - ubuntu-14.04 68 | # apache2: No candidate version available for libapache2-mod-php5 69 | - ubuntu-16.04 70 | # php: No candidate version available for php5-cgi 71 | - ubuntu-16.10 72 | # spamassassin: cpio: cap_set_file failed - Operation not supported 73 | - scientific-7.2 74 | run_list: 75 | - recipe[minitest-handler] 76 | - recipe[postfix-dovecot_test] 77 | attributes: 78 | postfix-dovecot: 79 | database: 80 | type: postgresql 81 | - name: postfixpgsql 82 | excludes: 83 | - amazon-2011.02.1 84 | - amazon-2013.09.2 85 | run_list: 86 | - recipe[postfix-dovecot_test::postfix_postgresql] 87 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # -*- mode: ruby -*- 3 | # vi: set ft=ruby : 4 | 5 | # See TESTING.md file. 6 | 7 | Vagrant.configure('2') do |config| 8 | # All Vagrant configuration is done here. The most common configuration 9 | # options are documented and commented below. For a complete reference, please 10 | # see the online documentation at vagrantup.com. 11 | 12 | config.vm.hostname = 'postfix-dovecot.local' 13 | 14 | # Opscode Chef Vagrant box to use. 15 | # More boxes here: https://github.com/opscode/bento 16 | opscode_box = 'opscode-ubuntu-12.04' 17 | 18 | # Every Vagrant virtual environment requires a box to build off of. 19 | config.vm.box = opscode_box 20 | 21 | # The url from where the 'config.vm.box' box will be fetched if it doesn't 22 | # already exist on the user's system. 23 | config.vm.box_url = 24 | 'http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/'\ 25 | "#{opscode_box.sub('-', '_')}_chef-provisionerless.box" 26 | 27 | # Assign this VM to a host-only network IP, allowing you to access it via the 28 | # IP. Host-only networks can talk to the host machine as well as any other 29 | # machines on the same network, but cannot be accessed (through this network 30 | # interface) by any external networks. 31 | config.vm.network :private_network, ip: '10.73.57.123' 32 | 33 | # Create a public network, which generally matched to bridged network. Bridged 34 | # networks make the machine appear as another physical device on your network. 35 | 36 | # config.vm.network :public_network 37 | 38 | # Create a forwarded port mapping which allows access to a specific port 39 | # within the machine from a port on the host machine. In the example below, 40 | # accessing 'localhost:8080' will access port 80 on the guest machine. 41 | config.vm.network :forwarded_port, guest: 80, host: 8080, auto_correct: true 42 | config.vm.network :forwarded_port, guest: 443, host: 8443, auto_correct: true 43 | 44 | # The time in seconds that Vagrant will wait for the machine to boot and be 45 | # accessible. 46 | config.vm.boot_timeout = 120 47 | 48 | # Share an additional folder to the guest VM. The first argument is the path 49 | # on the host to the actual folder. The second argument is the path on the 50 | # guest to mount the folder. And the optional third argument is a set of 51 | # non-required options. 52 | # config.vm.synced_folder '../data', '/vagrant_data' 53 | 54 | # Provider-specific configuration so you can fine-tune various backing 55 | # providers for Vagrant. These expose provider-specific options. 56 | # Example for VirtualBox: 57 | # 58 | # config.vm.provider :virtualbox do |vb| 59 | # # Don't boot with headless mode 60 | # vb.gui = true 61 | # 62 | # # Use VBoxManage to customize the VM. For example to change memory: 63 | # vb.memory = 1024 64 | # end 65 | # 66 | # View the documentation for the provider you're using for more information on 67 | # available options. 68 | 69 | # Install the latest version of Chef. 70 | config.omnibus.chef_version = :latest 71 | 72 | # Enabling the Berkshelf plugin. To enable this globally, add this 73 | # configuration option to your ~/.vagrant.d/Vagrantfile file. 74 | config.berkshelf.enabled = true 75 | 76 | # The path to the Berksfile to use with Vagrant Berkshelf. 77 | # config.berkshelf.berksfile_path = './Berksfile' 78 | 79 | # An array of symbols representing groups of cookbook described in the 80 | # Vagrantfile to exclusively install and copy to Vagrant's shelf. 81 | # config.berkshelf.only = [] 82 | 83 | # An array of symbols representing groups of cookbook described in the 84 | # Vagrantfile to skip installing and copying to Vagrant's shelf. 85 | # config.berkshelf.except = [] 86 | 87 | config.vm.provision :chef_solo do |chef| 88 | chef.json = { 89 | postfixadmin: { 90 | setup_password: 'admin' 91 | } 92 | } 93 | 94 | chef.run_list = %w( 95 | recipe[apt] 96 | recipe[postfix-dovecot_test::default] 97 | ) 98 | end 99 | end 100 | -------------------------------------------------------------------------------- /recipes/postfix_postgresql.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot 4 | # Recipe:: postfix_postgresql 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | if %w(debian ubuntu).include?(node['platform']) || 23 | (node['platform'] == 'fedora' && node['platform_version'].to_i >= 23) 24 | package 'postfix' 25 | package 'postfix-pgsql' 26 | elsif %w(centos fedora redhat amazon scientific).include?(node['platform']) 27 | include_recipe 'build-essential' 28 | 29 | node['postfix-dovecot']['postfix']['srpm']['packages'].each do |pkg| 30 | package pkg 31 | end 32 | 33 | repos = node.default['postfix-dovecot']['yum'].keys 34 | 35 | # TODO: use yum-centos cookbook 36 | repos.each do |repo| 37 | # compile time action required for yumdownloader 38 | yum_repository node['postfix-dovecot']['yum'][repo]['name'] do 39 | repositoryid repo 40 | baseurl node['postfix-dovecot']['yum'][repo]['baseurl'] 41 | gpgcheck node['postfix-dovecot']['yum'][repo]['gpgcheck'] 42 | enabled node['postfix-dovecot']['yum'][repo]['enabled'] 43 | gpgkey node['postfix-dovecot']['yum'][repo]['gpgkey'] 44 | end.run_action(:create) 45 | end 46 | 47 | buildroot = '/root/rpmbuild' 48 | 49 | if %w(amazon).include?(node['platform']) 50 | 51 | srpm = 52 | if Mixlib::ShellOut.new('postconf -m | grep -qFw pgsql') 53 | .run_command.error? 54 | cmd = Mixlib::ShellOut.new( 55 | 'yum install postfix > /dev/null 2>&1 && '\ 56 | 'yes | get_reference_source -p postfix | '\ 57 | 'grep "^Corresponding source RPM to found package : " | '\ 58 | 'sed "s/^Corresponding source RPM to found package : //"' 59 | ).run_command 60 | cmd.error! 61 | cmd.stdout.split("\n")[-1] 62 | end 63 | raise 'Sources for postfix RPM not found.' if srpm.nil? 64 | 65 | directory "#{buildroot}/SRPMS" do 66 | recursive true 67 | end 68 | 69 | link "#{buildroot}/SRPMS/#{srpm}" do 70 | to "/usr/src/srpm/debug/#{srpm}" 71 | end 72 | 73 | else # !amazon 74 | 75 | # required for yumdownload 76 | package('yum-utils').run_action(:install) 77 | 78 | cmd = Mixlib::ShellOut.new('yumdownloader --source --urls postfix') 79 | .run_command 80 | cmd.error! 81 | url = cmd.stdout.split("\n")[-1] 82 | 83 | srpm = ::File.basename(url) 84 | 85 | execute 'yumdownloader postfix' do 86 | command "yumdownloader --source --destdir=#{buildroot}/SRPMS postfix" 87 | creates "#{buildroot}/SRPMS/#{srpm}" 88 | end 89 | 90 | end 91 | 92 | rpm_regexp = node['postfix-dovecot']['postfix']['srpm']['rpm_regexp'] 93 | rpm = rpm_regexp.nil? ? srpm : srpm.sub(rpm_regexp[0], rpm_regexp[1]) 94 | rpm_file = "#{buildroot}/RPMS/#{node['kernel']['machine']}/#{rpm}" 95 | 96 | yum_package 'postfix (without postgresql)' do 97 | package_name 'postfix' 98 | not_if 'postconf -m | grep -qFw pgsql' 99 | action :remove 100 | end 101 | 102 | # TODO: do not compile as root 103 | rpmbuild_args = node['postfix-dovecot']['postfix']['srpm']['rpm_build_args'] 104 | execute 'compile postfix from SRPM' do 105 | command "rpmbuild #{rpmbuild_args} --rebuild '#{buildroot}/SRPMS/#{srpm}'" 106 | environment('HOME' => '/root') 107 | not_if { rpm.nil? || srpm.nil? } 108 | creates "#{buildroot}/RPMS/#{node['kernel']['machine']}/#{rpm}" 109 | end 110 | 111 | execute 'install postfix from SRPM' do 112 | command "rpm -i '#{rpm_file}'" 113 | not_if { rpm.nil? } 114 | not_if 'rpm -q postfix' 115 | end 116 | 117 | else 118 | package 'postfix' 119 | end 120 | -------------------------------------------------------------------------------- /test/integration/mysql/serverspec/postfix_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | require 'net/smtp' 22 | require_relative 'mail_helpers' 23 | 24 | describe 'Postfix' do 25 | describe command('/usr/sbin/postconf') do 26 | its(:exit_status) { should eq 0 } 27 | its(:stderr) { should eq '' } 28 | end 29 | 30 | describe process('master') do 31 | it { should be_running } 32 | end 33 | 34 | # smtp 35 | describe port(25) do 36 | it { should be_listening.with('tcp') } 37 | end 38 | 39 | # ssmtp 40 | describe port(465) do 41 | it { should be_listening.with('tcp') } 42 | end 43 | 44 | # submission 45 | describe port(587) do 46 | it { should be_listening.with('tcp') } 47 | end 48 | 49 | it 'connects to smtp SSL' do 50 | expect( 51 | command('echo | openssl s_client -connect 127.0.0.1:465') 52 | .exit_status 53 | ).to eq 0 54 | end 55 | 56 | it 'connects to smtp with starttls' do 57 | expect( 58 | command('echo | openssl s_client -starttls smtp -connect 127.0.0.1:smtp') 59 | .exit_status 60 | ).to eq 0 61 | end 62 | 63 | it 'is able to login using submission (plain)' do 64 | smtp = Net::SMTP.new 'localhost', 587 65 | ctx = OpenSSL::SSL::SSLContext.new 66 | ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE 67 | smtp.enable_starttls(ctx) 68 | smtp.start( 69 | 'onddo.com', 'postmaster@foobar.com', 'p0stm@st3r1', :plain 70 | ) { |_smtp| puts 'OK' } 71 | end 72 | 73 | describe 'when an email is sent through smtp' do 74 | fingerprint = "G27XB6yIyYyM99Tv8UXW#{Time.new.to_i}" 75 | let(:maildir) { '/var/vmail/foobar.com/postmaster' } 76 | before(:context) { send_email(fingerprint) } 77 | 78 | it 'is able to receive it', retry: 30, retry_wait: 1 do 79 | expect(all_file_contents("#{maildir}/new/*")).to include fingerprint 80 | end 81 | end 82 | 83 | family = os[:family].downcase 84 | key_dir, cert_dir = 85 | if %w(debian ubuntu).include?(family) 86 | %w(/etc/ssl/private /etc/ssl/certs) 87 | elsif %w(redhat centos fedora scientific amazon).include?(family) 88 | %w(/etc/pki/tls/private /etc/pki/tls/certs) 89 | else 90 | %w(/etc /etc) 91 | end 92 | 93 | describe file("#{cert_dir}/postfix.pem") do 94 | it { should be_file } 95 | it { should be_mode 644 } 96 | it { should be_owned_by 'root' } 97 | it { should be_grouped_into 'root' } 98 | end 99 | 100 | describe file("#{key_dir}/postfix.key") do 101 | it { should be_file } 102 | it { should be_mode 600 } 103 | it { should be_owned_by 'root' } 104 | it { should be_grouped_into 'root' } 105 | end 106 | 107 | describe file('/etc/mailname') do 108 | it { should be_file } 109 | it { should be_mode 644 } 110 | it { should be_owned_by 'root' } 111 | it { should be_grouped_into 'root' } 112 | end 113 | 114 | describe file('/var/spool/postfix/etc') do 115 | it { should be_directory } 116 | it { should be_mode 755 } 117 | it { should be_owned_by 'root' } 118 | it { should be_grouped_into 'root' } 119 | end 120 | 121 | %w( 122 | etc/resolv.conf 123 | etc/localtime 124 | etc/services 125 | etc/hosts 126 | etc/nsswitch.conf 127 | etc/nss_mdns.config 128 | ).each do |chroot_file| 129 | describe file("/var/spool/postfix/#{chroot_file}"), 130 | if: ::File.exist?("/#{chroot_file}") do 131 | it { should be_file } 132 | it { should be_mode 644 } 133 | it { should be_owned_by 'root' } 134 | it { should be_grouped_into 'root' } 135 | end 136 | end 137 | end 138 | -------------------------------------------------------------------------------- /test/integration/postgresql/serverspec/postfix_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'spec_helper' 21 | require 'net/smtp' 22 | require_relative 'mail_helpers' 23 | 24 | describe 'Postfix' do 25 | describe command('/usr/sbin/postconf') do 26 | its(:exit_status) { should eq 0 } 27 | its(:stderr) { should eq '' } 28 | end 29 | 30 | describe process('master') do 31 | it { should be_running } 32 | end 33 | 34 | # smtp 35 | describe port(25) do 36 | it { should be_listening.with('tcp') } 37 | end 38 | 39 | # ssmtp 40 | describe port(465) do 41 | it { should be_listening.with('tcp') } 42 | end 43 | 44 | # submission 45 | describe port(587) do 46 | it { should be_listening.with('tcp') } 47 | end 48 | 49 | it 'connects to smtp SSL' do 50 | expect( 51 | command('echo | openssl s_client -connect 127.0.0.1:465') 52 | .exit_status 53 | ).to eq 0 54 | end 55 | 56 | it 'connects to smtp with starttls' do 57 | expect( 58 | command('echo | openssl s_client -starttls smtp -connect 127.0.0.1:smtp') 59 | .exit_status 60 | ).to eq 0 61 | end 62 | 63 | it 'is able to login using submission (plain)' do 64 | smtp = Net::SMTP.new 'localhost', 587 65 | ctx = OpenSSL::SSL::SSLContext.new 66 | ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE 67 | smtp.enable_starttls(ctx) 68 | smtp.start( 69 | 'onddo.com', 'postmaster@foobar.com', 'p0stm@st3r1', :plain 70 | ) { |_smtp| puts 'OK' } 71 | end 72 | 73 | describe 'when an email is sent through smtp' do 74 | fingerprint = "G27XB6yIyYyM99Tv8UXW#{Time.new.to_i}" 75 | let(:maildir) { '/var/vmail/foobar.com/postmaster' } 76 | before(:context) { send_email(fingerprint) } 77 | 78 | it 'is able to receive it', retry: 30, retry_wait: 1 do 79 | expect(all_file_contents("#{maildir}/new/*")).to include fingerprint 80 | end 81 | end 82 | 83 | family = os[:family].downcase 84 | key_dir, cert_dir = 85 | if %w(debian ubuntu).include?(family) 86 | %w(/etc/ssl/private /etc/ssl/certs) 87 | elsif %w(redhat centos fedora scientific amazon).include?(family) 88 | %w(/etc/pki/tls/private /etc/pki/tls/certs) 89 | else 90 | %w(/etc /etc) 91 | end 92 | 93 | describe file("#{cert_dir}/postfix.pem") do 94 | it { should be_file } 95 | it { should be_mode 644 } 96 | it { should be_owned_by 'root' } 97 | it { should be_grouped_into 'root' } 98 | end 99 | 100 | describe file("#{key_dir}/postfix.key") do 101 | it { should be_file } 102 | it { should be_mode 600 } 103 | it { should be_owned_by 'root' } 104 | it { should be_grouped_into 'root' } 105 | end 106 | 107 | describe file('/etc/mailname') do 108 | it { should be_file } 109 | it { should be_mode 644 } 110 | it { should be_owned_by 'root' } 111 | it { should be_grouped_into 'root' } 112 | end 113 | 114 | describe file('/var/spool/postfix/etc') do 115 | it { should be_directory } 116 | it { should be_mode 755 } 117 | it { should be_owned_by 'root' } 118 | it { should be_grouped_into 'root' } 119 | end 120 | 121 | %w( 122 | etc/resolv.conf 123 | etc/localtime 124 | etc/services 125 | etc/hosts 126 | etc/nsswitch.conf 127 | etc/nss_mdns.config 128 | ).each do |chroot_file| 129 | describe file("/var/spool/postfix/#{chroot_file}"), 130 | if: ::File.exist?("/#{chroot_file}") do 131 | it { should be_file } 132 | it { should be_mode 644 } 133 | it { should be_owned_by 'root' } 134 | it { should be_grouped_into 'root' } 135 | end 136 | end 137 | end 138 | -------------------------------------------------------------------------------- /attributes/postfix_postgresql.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot 4 | # Attributes:: postfix_postgresql 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2014 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | releasever = node['platform_version'].to_i # TODO: avoid this 23 | yum_default = node.default['postfix-dovecot']['yum'] 24 | srpm_default = node.default['postfix-dovecot']['postfix']['srpm'] 25 | 26 | if %w(centos scientific).include?(node['platform']) 27 | if node['platform_version'].to_i >= 7 28 | srpm_default['packages'] = %w( 29 | postgresql-devel rpm-build zlib-devel openldap-devel libdb-devel 30 | cyrus-sasl-devel pcre-devel openssl-devel perl-Date-Calc gcc 31 | mariadb-devel pkgconfig ed tar systemd-sysv 32 | ) 33 | if node['platform'] == 'scientific' 34 | srpm_default['rpm_regexp'] = [ 35 | /\.src\./, ".#{node['kernel']['machine']}." 36 | ] 37 | else 38 | srpm_default['rpm_regexp'] = [ 39 | /\.src\./, ".#{node['platform']}.#{node['kernel']['machine']}." 40 | ] 41 | end 42 | srpm_default['rpm_build_args'] = '--with=pgsql' 43 | else 44 | srpm_default['packages'] = %w( 45 | postgresql-devel rpm-build zlib-devel openldap-devel db4-devel 46 | cyrus-sasl-devel pcre-devel openssl-devel perl-Date-Calc gcc 47 | mysql-devel pkgconfig ed tar 48 | ) 49 | srpm_default['rpm_regexp'] = [ 50 | /_[0-9]+(\.[0-9]+)?\.src\./, "\\1.#{node['kernel']['machine']}." 51 | ] 52 | srpm_default['rpm_build_args'] = '--define="PGSQL 1"' 53 | 54 | yum_default['base-source']['name'] = 'CentOS-$releasever - Base Sources' 55 | yum_default['base-source']['baseurl'] = 56 | 'http://vault.centos.org/centos/$releasever/os/Source/' 57 | yum_default['base-source']['gpgcheck'] = true 58 | yum_default['base-source']['enabled'] = false 59 | yum_default['base-source']['gpgkey'] = 60 | "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-#{releasever}" 61 | 62 | yum_default['updates-source']['name'] = 63 | 'CentOS-$releasever - Updates Sources' 64 | yum_default['updates-source']['baseurl'] = 65 | 'http://vault.centos.org/centos/$releasever/updates/Source/' 66 | yum_default['updates-source']['gpgcheck'] = true 67 | yum_default['updates-source']['enabled'] = false 68 | yum_default['updates-source']['gpgkey'] = 69 | "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-#{releasever}" 70 | 71 | yum_default['extras-source']['name'] = 'CentOS-$releasever - Extras Sources' 72 | yum_default['extras-source']['baseurl'] = 73 | 'http://vault.centos.org/centos/$releasever/extras/Source/' 74 | yum_default['extras-source']['gpgcheck'] = true 75 | yum_default['extras-source']['enabled'] = false 76 | yum_default['extras-source']['gpgkey'] = 77 | "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-#{releasever}" 78 | end 79 | elsif %w(fedora redhat).include?(node['platform']) 80 | # Uses MariaDB since fedora 19 81 | # TODO: test with older versions 82 | srpm_default['packages'] = %w( 83 | postgresql-devel rpm-build zlib-devel openldap-devel libdb-devel 84 | cyrus-sasl-devel pcre-devel openssl-devel perl-Date-Calc gcc 85 | mariadb-devel pkgconfig ed tar libicu-devel sqlite-devel tinycdb-devel 86 | ) 87 | 88 | srpm_default['rpm_regexp'] = [ 89 | /\.src\./, ".#{node['kernel']['machine']}." 90 | ] 91 | srpm_default['rpm_build_args'] = '--with=pgsql' 92 | elsif %w(amazon).include?(node['platform']) 93 | # TODO: this does not work, postfix source needs to be patched to support 94 | # linux3 kernels: 95 | # http://patches.netspiders.net/postfix/postfix-2.6.6-linux3.patch 96 | # http://patches.netspiders.net/postfix/postfix-2.6.6-linux3.spec.patch 97 | srpm_default['packages'] = %w( 98 | postgresql-devel rpm-build zlib-devel openldap-devel db4-devel 99 | cyrus-sasl-devel pcre-devel openssl-devel perl-Date-Calc gcc 100 | mysql-devel pkgconfig ed tar 101 | ) 102 | srpm_default['rpm_regexp'] = [ 103 | /\.src\./, ".#{node['kernel']['machine']}." 104 | ] 105 | srpm_default['rpm_build_args'] = '--with=pgsql' 106 | end 107 | -------------------------------------------------------------------------------- /TESTING.md: -------------------------------------------------------------------------------- 1 | Testing 2 | ======= 3 | 4 | ## Installing the Requirements 5 | 6 | You must have [VirtualBox](https://www.virtualbox.org/) and [Vagrant](http://www.vagrantup.com/) installed. 7 | 8 | You can install gem dependencies with bundler: 9 | 10 | $ gem install bundler 11 | $ bundle install --without travis 12 | 13 | ## Generating the Documentation 14 | 15 | This will generate the documentation for the source files inside the [*libraries/*](https://github.com/zuazo/postfix-dovecot-cookbook/tree/master/libraries) directory. 16 | 17 | $ bundle exec rake doc 18 | 19 | The documentation is included in the source code itself. 20 | 21 | ## Syntax Style Tests 22 | 23 | We use the following tools to test the code style: 24 | 25 | * [RuboCop](https://github.com/bbatsov/rubocop#readme) 26 | * [foodcritic](http://www.foodcritic.io/) 27 | 28 | To run the tests: 29 | 30 | $ bundle exec rake style 31 | 32 | ## Unit Tests 33 | 34 | We use [ChefSpec](https://github.com/sethvargo/chefspec#readme) and [RSpec](http://rspec.info/) for the unit tests. RSpec is generally used to test the libraries or some Ruby specific code. 35 | 36 | The unit test files are placed in the [*test/unit/*](https://github.com/zuazo/postfix-dovecot-cookbook/tree/master/test/unit) directory. 37 | 38 | To run the tests: 39 | 40 | $ bundle exec rake unit 41 | 42 | ## Integration Tests 43 | 44 | We use [Test Kitchen](http://kitchen.ci/) to run the tests and the tests are written using [Serverspec](http://serverspec.org/). 45 | 46 | The integration test files are placed in the [*test/integration/*](https://github.com/zuazo/postfix-dovecot-cookbook/tree/master/test/integration) directory. Some cookbooks required by this tests are in the [*test/cookbooks/*](https://github.com/zuazo/postfix-dovecot-cookbook/tree/master/test/cookbooks) directory. 47 | 48 | To run the tests: 49 | 50 | $ bundle exec rake integration:vagrant 51 | 52 | Or: 53 | 54 | $ bundle exec kitchen list 55 | $ bundle exec kitchen test 56 | [...] 57 | 58 | ### Integration Tests in Docker 59 | 60 | You can run the integration tests using [Docker](https://www.docker.com/) instead of Vagrant if you prefer. 61 | 62 | Of course, you need to have [Docker installed](https://docs.docker.com/engine/installation/). 63 | 64 | $ wget -qO- https://get.docker.com/ | sh 65 | 66 | Then use the `integration:docker` rake task to run the tests: 67 | 68 | $ bundle exec rake integration:docker 69 | 70 | ### Integration Tests in the Cloud 71 | 72 | You can run the tests in the cloud instead of using Vagrant. First, you must set the following environment variables: 73 | 74 | * `AWS_ACCESS_KEY_ID` 75 | * `AWS_SECRET_ACCESS_KEY` 76 | * `AWS_KEYPAIR_NAME`: EC2 SSH public key name. This is the name used in Amazon EC2 Console's Key Pars section. 77 | * `EC2_SSH_KEY_PATH`: EC2 SSH private key local full path. Only when you are not using an SSH Agent. 78 | * `DIGITALOCEAN_ACCESS_TOKEN` 79 | * `DIGITALOCEAN_SSH_KEY_IDS`: DigitalOcean SSH numeric key IDs. 80 | * `DIGITALOCEAN_SSH_KEY_PATH`: DigitalOcean SSH private key local full path. Only when you are not using an SSH Agent. 81 | 82 | Then use the `integration:cloud` rake task to run the tests: 83 | 84 | $ bundle exec rake integration:cloud 85 | 86 | ## Amazon SES Tests 87 | 88 | You need to set the following environment variables: 89 | 90 | * `AMAZON_SES_EMAIL_FROM`: SES valid from address, only used in tests. 91 | * `AMAZON_SES_SMTP_USERNAME`: See [Obtaining Your Amazon SES SMTP Credentials](http://docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-credentials.html) documentation. 92 | * `AMAZON_SES_SMTP_PASSWORD` 93 | * `AMAZON_SES_REGION`: Amazon SES region (optional). 94 | 95 | Then, you must configure test-kitchen to use [.kitchen.ses.yml](/.kitchen.ses.yml) configuration file: 96 | 97 | $ export AMAZON_SES_EMAIL_FROM="no-reply@sesdomain.com" 98 | $ export AMAZON_SES_SMTP_USERNAME="..." 99 | $ export AMAZON_SES_SMTP_PASSWORD="..." 100 | $ export AMAZON_SES_REGION="..." 101 | $ export KITCHEN_LOCAL_YAML=".kitchen.ses.yml" 102 | $ bundle exec kitchen list 103 | [...] 104 | 105 | ## Guard 106 | 107 | Guard is a tool that runs the tests automatically while you are making changes to the source files. 108 | 109 | To run Guard: 110 | 111 | $ guard 112 | 113 | More info at [Guard Readme](https://github.com/guard/guard#readme). 114 | 115 | ## Available Rake Tasks 116 | 117 | There are multiple Rake tasks that you can use to run the tests: 118 | 119 | $ rake -T 120 | 121 | See [Rakefile documentation](https://github.com/ruby/rake/blob/master/doc/rakefile.rdoc) for more information. 122 | 123 | ## Using Vagrant with the Vagrantfile 124 | 125 | ### Vagrantfile Requirements 126 | 127 | * [ChefDK](https://downloads.chef.io/chef-dk/) 128 | * Berkhelf and Omnibus vagrant plugins: 129 | ``` 130 | $ vagrant plugin install vagrant-berkshelf vagrant-omnibus 131 | ``` 132 | * The path correctly set for ChefDK: 133 | ``` 134 | $ export PATH="/opt/chefdk/bin:${PATH}" 135 | ``` 136 | 137 | ### Vagrantfile Usage 138 | 139 | $ vagrant up 140 | 141 | To run Chef again on the same machine: 142 | 143 | $ vagrant provision 144 | 145 | To destroy the machine: 146 | 147 | $ vagrant destroy 148 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # -*- mode: ruby -*- 3 | # vi: set ft=ruby : 4 | 5 | # 6 | # Available Rake tasks: 7 | # 8 | # $ rake -T 9 | # rake clean # Clean some generated files 10 | # rake default # Run doc, style, unit and integration tests 11 | # rake doc # Generate Ruby documentation 12 | # rake integration[regexp,action] # Run Test Kitchen integration tests 13 | # rake integration:cloud[regexp,action] # Run Kitchen tests in the cloud 14 | # rake integration:docker[regexp,action] # Run Kitchen tests using docker 15 | # rake integration:ses[regexp,action] # Run Test Kitchen tests with SES 16 | # rake integration:vagrant[regexp,action] # Run Kitchen tests using vagrant 17 | # rake style # Run all style checks 18 | # rake style:chef # Run Chef style checks using foodcritic 19 | # rake style:ruby # Run Ruby style checks using rubocop 20 | # rake style:ruby:auto_correct # Auto-correct RuboCop offenses 21 | # rake unit # Run ChefSpec unit tests 22 | # rake yard # Generate Ruby documentation using yard 23 | # 24 | # More info at https://github.com/ruby/rake/blob/master/doc/rakefile.rdoc 25 | # 26 | 27 | require 'bundler/setup' 28 | 29 | # Checks if we are inside a Continuous Integration machine. 30 | # 31 | # @return [Boolean] whether we are inside a CI. 32 | # @example 33 | # ci? #=> false 34 | def ci? 35 | ENV['CI'] == 'true' 36 | end 37 | 38 | desc 'Clean some generated files' 39 | task :clean do 40 | %w( 41 | Berksfile.lock 42 | .bundle 43 | .cache 44 | coverage 45 | Gemfile.lock 46 | .kitchen 47 | metadata.json 48 | vendor 49 | ).each { |f| FileUtils.rm_rf(Dir.glob(f)) } 50 | end 51 | 52 | desc 'Generate Ruby documentation using yard' 53 | task :yard do 54 | require 'yard' 55 | YARD::Rake::YardocTask.new do |t| 56 | t.stats_options = %w(--list-undoc) 57 | end 58 | end 59 | 60 | desc 'Generate Ruby documentation' 61 | task doc: %w(yard) 62 | 63 | namespace :style do 64 | require 'rubocop/rake_task' 65 | desc 'Run Ruby style checks using rubocop' 66 | RuboCop::RakeTask.new(:ruby) 67 | 68 | require 'foodcritic' 69 | desc 'Run Chef style checks using foodcritic' 70 | FoodCritic::Rake::LintTask.new(:chef) do |t| 71 | t.options = { 72 | fail_tags: ['any'], 73 | progress: true 74 | } 75 | end 76 | end 77 | 78 | desc 'Run all style checks' 79 | task style: %w(style:chef style:ruby) 80 | 81 | desc 'Run ChefSpec unit tests' 82 | task :unit do 83 | require 'rspec/core/rake_task' 84 | RSpec::Core::RakeTask.new(:unit) do |t| 85 | t.rspec_opts = '--color --format progress' 86 | t.pattern = 'test/unit/**{,/*/**}/*_spec.rb' 87 | end 88 | end 89 | 90 | desc 'Run Test Kitchen integration tests' 91 | namespace :integration do 92 | # Generates the `Kitchen::Config` class configuration values. 93 | # 94 | # @param loader_config [Hash] loader configuration options. 95 | # @return [Hash] configuration values for the `Kitchen::Config` class. 96 | def kitchen_config(loader_config = {}) 97 | {}.tap do |config| 98 | unless loader_config.empty? 99 | @loader = Kitchen::Loader::YAML.new(loader_config) 100 | config[:loader] = @loader 101 | end 102 | end 103 | end 104 | 105 | # Gets a collection of instances. 106 | # 107 | # @param regexp [String] regular expression to match against instance names. 108 | # @param config [Hash] configuration values for the `Kitchen::Config` class. 109 | # @return [Collection] all instances. 110 | def kitchen_instances(regexp, config) 111 | instances = Kitchen::Config.new(config).instances 112 | return instances if regexp.nil? || regexp == 'all' 113 | instances.get_all(Regexp.new(regexp)) 114 | end 115 | 116 | # Runs a test kitchen action against some instances. 117 | # 118 | # @param action [String] kitchen action to run (defaults to `'test'`). 119 | # @param regexp [String] regular expression to match against instance names. 120 | # @param loader_config [Hash] loader configuration options. 121 | # @return void 122 | def run_kitchen(action, regexp, loader_config = {}) 123 | action = 'test' if action.nil? 124 | require 'kitchen' 125 | Kitchen.logger = Kitchen.default_file_logger 126 | config = kitchen_config(loader_config) 127 | kitchen_instances(regexp, config).each { |i| i.send(action) } 128 | end 129 | 130 | desc 'Run Test Kitchen integration tests using vagrant' 131 | task :vagrant, [:regexp, :action] do |_t, args| 132 | run_kitchen(args.action, args.regexp) 133 | end 134 | 135 | desc 'Run Test Kitchen integration tests using docker' 136 | task :docker, [:regexp, :action] do |_t, args| 137 | run_kitchen(args.action, args.regexp, local_config: '.kitchen.docker.yml') 138 | end 139 | 140 | desc 'Run Test Kitchen integration tests in the cloud' 141 | task :cloud, [:regexp, :action] do |_t, args| 142 | run_kitchen(args.action, args.regexp, local_config: '.kitchen.cloud.yml') 143 | end 144 | 145 | desc 'Run Test Kitchen integration tests with SES' 146 | task :ses, [:regexp, :action] do |_t, args| 147 | run_kitchen(args.action, args.regexp, local_config: '.kitchen.ses.yml') 148 | end 149 | end 150 | 151 | desc 'Run Test Kitchen integration tests' 152 | task :integration, [:regexp, :action] => 153 | ci? ? %w(integration:docker) : %w(integration:vagrant) 154 | 155 | desc 'Run doc, style, unit and integration tests' 156 | task default: %w(doc style unit integration) 157 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to the `postfix-dovecot` cookbook will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). 5 | 6 | ## [Unreleased] 7 | - ... 8 | 9 | ## [3.0.0] - 2017-03-14 10 | ### Added 11 | - metadata: Add `chef_version`. 12 | - README: Add github and license badges. 13 | 14 | ### Changed 15 | - Update some cookbook versions: 16 | - `chef-vault` from `1` to `2`. 17 | - `dovecot` from `2` to `3`. 18 | - `postfixadmin` from `2` to `3` (fixes [issue #7](https://github.com/zuazo/postfix-dovecot-cookbook/issues/7), thanks [Arunderwood](https://github.com/arunderwood) for reporting). 19 | - `ssl_certificate` from `1` to `2`. 20 | - `onddo-spamassassin` from `1` to `2`. 21 | - `yum` from `3` to `5`. 22 | - Dovecot: enable SSL explicitly. 23 | - Update RuboCop to version `0.40` and fix new offenses. 24 | - CHANGELOG: Follow "Keep a CHANGELOG". 25 | 26 | ### Removed 27 | - Drop Chef `< 12.5` support. 28 | - Drop Ruby `< 2.2` support. 29 | - Metadata: Remove grouping ([RFC-85](https://github.com/chef/chef-rfc/blob/8d47f1d0afa5a2313ed2010e0eda318edc28ba47/rfc085-remove-unused-metadata.md)). 30 | - Remove `postfix_full` recipe. 31 | - README: Remove documentation about locale (old). 32 | 33 | ### Fixed 34 | - Fix CentOS 7 and Scientific support with PostgreSQL. 35 | - Fix PostgreSQL support on CentOS and Fedora. 36 | - Fix Chef `13` deprecation warnings. 37 | 38 | ## [2.0.1] - 2015-09-03 39 | ### Fixed 40 | - Fix typo in `-f` argument to `/usr/lib/dovecot/deliver` ([issue #5](https://github.com/zuazo/postfix-dovecot-cookbook/pull/5), thanks [Uwe Stuehler](https://github.com/ustuehler)). 41 | 42 | ## [2.0.0] - 2015-08-22 43 | ### Changed 44 | - Update the `postfixadmin` cookbook to version `2` ([See the `postfixadmin` cookbook CHANGELOG for the update process](https://github.com/zuazo/postfixadmin-cookbook/blob/master/CHANGELOG.md#upgrading-from-a-1xy-cookbook-release)). 45 | - Update `onddo-spamassassin` cookbook to version `1` ([See the `postfixadmin` cookbook CHANGELOG for the update process](https://github.com/onddo/spamassassin-cookbook/blob/master/CHANGELOG.md#v100-2015-04-29)). 46 | - Update chef links to use *chef.io* domain. 47 | - Update contact information and links after migration. 48 | - Update RuboCop to `0.33.0`. 49 | 50 | ### Added 51 | - metadata: Add `source_url` and `issues_url`. 52 | - README: Put the cookbook name in the title. 53 | 54 | ## [1.2.0] - 2015-01-09 55 | ### Added 56 | - Add Dovecot SSL certificate generation. 57 | - Integrate with `ssl_certificate` cookbook version `1.2`. 58 | 59 | ### Changed 60 | - Gemfile: Update RuboCop to `0.28.0`. 61 | 62 | ### Fixed 63 | - metadata: Fix attributes default types. 64 | - README: Fix some typos and update Supermarket links. 65 | 66 | ## [1.1.0] - 2014-11-09 67 | ### Added 68 | - Add RBL support. 69 | - Allow postfix configuration (tables and master.cf) to be modfied easily. 70 | - Create Postfix tables directory, required by SES. 71 | 72 | ### Changed 73 | - Improve SES support: 74 | - Read the SES credentials from chef vault bag. 75 | - Add `node['postfix-dovecot']['ses']['region']` attribute. 76 | - Update SES servers. 77 | - metadata: update to use `dovecot` cookbook version `2`. 78 | - Simplify `smtp_tls_CAfile` attribute case. 79 | - Homogenize license headers. 80 | - README: 81 | - Use single quotes in examples. 82 | - Use markdown tables. 83 | - Fix *Usage Examples* title. 84 | 85 | ### Fixed 86 | - `::dovecot` recipe: Fix password reading with encrypt attributes enabled. 87 | - Fix new RuboCop offenses. 88 | 89 | ## [1.0.0] - 2014-10-07 90 | ### Added 91 | - Integrate with `ssl_certificate` cookbook. 92 | - Add PostgreSQL support. 93 | 94 | ### Changed 95 | - Rename `::postfix_full` recipe to `::postfix`. 96 | - Update to work with `postfixadmin` cookbook `1.0.0`. 97 | - Improve Postfix chroot file creation, based on `postfix-full` master code. 98 | - Set `common_name` for PostfixAdmin and Postfix SSL certs. 99 | - metadata: use pessimistic version constraints. 100 | - Use `#default_unless` instead of `#set_unless`. 101 | - `::postfixadmin` recipe: remove `#set_unless` usage. 102 | - README: 103 | - Separate README file in multiple files. 104 | - Add some badges. 105 | - Some small documentation fixes. 106 | 107 | ### Removed 108 | - Drop Ruby `< 1.9.3` support. 109 | - Drop Chef `< 11.14.2` support. 110 | 111 | ### Fixed 112 | - Fix hostname attribute default value when FQDN is not set. 113 | - Fix all *RuboCop* offenses. 114 | 115 | ## [0.3.0] - 2014-09-14 116 | ### Added 117 | - Ensure */etc/mailname* file creation. 118 | - Add Fedora and Amazon Linux support. 119 | 120 | ### Changed 121 | - Depends on `postfixadmin` cookbook version `< 1.0.0`. 122 | - README: Amazon SES Tests section: KITCHEN_LOCAL_YAML variable value fixed. 123 | 124 | ## [0.2.0] - 2013-08-09 125 | ### Added 126 | - Add [Amazon SES](http://aws.amazon.com/ses/) support. 127 | - Add SES tests. 128 | 129 | ### Fixed 130 | - Fix *resolv.conf* inside chroot in CentOS. 131 | 132 | ## 0.1.0 - 2013-06-16 133 | 134 | - Initial release of `postfix-dovecot`. 135 | 136 | [Unreleased]: https://github.com/zuazo/postfix-dovecot-cookbook/compare/3.0.0...HEAD 137 | [3.0.0]: https://github.com/zuazo/postfix-dovecot-cookbook/compare/2.0.1...3.0.0 138 | [2.0.1]: https://github.com/zuazo/postfix-dovecot-cookbook/compare/2.0.0...2.0.1 139 | [2.0.0]: https://github.com/zuazo/postfix-dovecot-cookbook/compare/1.2.0...2.0.0 140 | [1.2.0]: https://github.com/zuazo/postfix-dovecot-cookbook/compare/1.1.0...1.2.0 141 | [1.1.0]: https://github.com/zuazo/postfix-dovecot-cookbook/compare/1.0.0...1.1.0 142 | [1.0.0]: https://github.com/zuazo/postfix-dovecot-cookbook/compare/0.3.0...1.0.0 143 | [0.3.0]: https://github.com/zuazo/postfix-dovecot-cookbook/compare/0.2.0...0.3.0 144 | [0.2.0]: https://github.com/zuazo/postfix-dovecot-cookbook/compare/0.1.0...0.2.0 145 | -------------------------------------------------------------------------------- /recipes/dovecot.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot 4 | # Recipe:: dovecot 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2013-2015 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | Chef::Recipe.send(:include, Chef::EncryptedAttributesHelpers) 23 | self.encrypted_attributes_enabled = node['postfixadmin']['encrypt_attributes'] 24 | password = encrypted_attribute_read(%w(postfixadmin database password)) 25 | 26 | def sql_concat(*args) 27 | case node['postfix-dovecot']['database']['type'] 28 | when 'postgresql' 29 | args.join(' || ') 30 | else # when 'mysql' 31 | "CONCAT(#{args.join(', ')})" 32 | end 33 | end 34 | 35 | node.default['dovecot']['conf_files_group'] = 36 | node['postfix-dovecot']['vmail']['user'] 37 | 38 | node.default['dovecot']['conf']['disable_plaintext_auth'] = false 39 | node.default['dovecot']['conf_files_mode'] = '00640' 40 | 41 | # 10-logging.conf 42 | node.default['dovecot']['conf']['log_path'] = 'syslog' 43 | node.default['dovecot']['conf']['syslog_facility'] = 'mail' 44 | node.default['dovecot']['conf']['log_timestamp'] = '"%Y-%m-%d %H:%M:%S"' 45 | 46 | # 10-mail.conf 47 | node.default['dovecot']['conf']['mail_location'] = 'maildir:~/Maildir' 48 | node.default['dovecot']['conf']['mail_privileged_group'] = 'mail' 49 | 50 | # 10-master.conf 51 | node.default['dovecot']['services']['auth']['listeners'] = [ 52 | # auth_socket_path points to this userdb socket by default. It's typically 53 | # used by dovecot-lda, doveadm, possibly imap process, etc. Its default 54 | # permissions make it readable only by root, but you may need to relax these 55 | # permissions. Users that have access to this socket are able to get a list 56 | # of all usernames and get results of everyone's userdb lookups. 57 | { 58 | 'unix:auth-userdb' => { 59 | mode: '0600', 60 | user: node['postfix-dovecot']['vmail']['user'], 61 | group: node['postfix-dovecot']['vmail']['group'] 62 | } 63 | }, 64 | # Postfix smtp-auth 65 | { 66 | 'unix:/var/spool/postfix/private/auth' => { 67 | # TODO: reinforcing this 68 | mode: '0666', 69 | user: 'postfix', 70 | group: 'postfix' 71 | } 72 | } 73 | ] 74 | 75 | # 15-lda.conf 76 | node.default['dovecot']['conf']['postmaster_address'] = 77 | node['postfix-dovecot']['postmaster_address'] 78 | node.default['dovecot']['conf']['hostname'] = 79 | node['postfix-dovecot']['hostname'] 80 | node.default['dovecot']['conf']['lda_mailbox_autocreate'] = true 81 | node.default['dovecot']['conf']['lda_mailbox_autosubscribe'] = true 82 | if node['postfix-dovecot']['sieve']['enabled'] 83 | node.default['dovecot']['protocols']['lda']['mail_plugins'] = %w( 84 | $mail_plugins sieve 85 | ) 86 | else 87 | # not required 88 | node.default['dovecot']['protocols']['lda']['mail_plugins'] = %w( 89 | $mail_plugins 90 | ) 91 | end 92 | 93 | # 20-imap.conf 94 | node.default['dovecot']['protocols']['imap'] = {} 95 | 96 | # 90-sieve.conf 97 | if node['postfix-dovecot']['sieve']['enabled'] 98 | node.default['dovecot']['plugins']['sieve']['sieve'] = '~/.dovecot.sieve' 99 | node.default['dovecot']['plugins']['sieve']['sieve_dir'] = '~/sieve' 100 | node.default['dovecot']['plugins']['sieve']['sieve_global_path'] = 101 | node['postfix-dovecot']['sieve']['global_path'] 102 | end 103 | 104 | # auth-sql.conf.ext 105 | node.default['dovecot']['auth']['sql']['passdb']['args'] = 106 | '/etc/dovecot/dovecot-sql.conf.ext' 107 | node.default['dovecot']['auth']['sql']['userdb']['args'] = 108 | '/etc/dovecot/dovecot-sql.conf.ext' 109 | 110 | # auth-static.conf.ext 111 | node.default['dovecot']['auth']['static']['userdb']['args'] = [ 112 | "uid=#{node['postfix-dovecot']['vmail']['user']}", 113 | "gid=#{node['postfix-dovecot']['vmail']['group']}", 114 | "home=#{node['postfix-dovecot']['vmail']['home']}/%d/%n", 115 | 'allow_all_users=yes' 116 | ] 117 | 118 | # auth-system.conf.ext 119 | node.default['dovecot']['auth']['system'] = {} 120 | 121 | # dovecot-sql.conf.ext 122 | db_type = 123 | case node['postfix-dovecot']['database']['type'] 124 | when 'mysql' 125 | 'mysql' 126 | when 'postgresql' 127 | 'pgsql' 128 | end 129 | node.default['dovecot']['conf']['sql']['driver'] = db_type 130 | node.default['dovecot']['conf']['sql']['connect'] = [ 131 | "host=#{node['postfixadmin']['database']['host']}", 132 | "dbname=#{node['postfixadmin']['database']['name']}", 133 | "user=#{node['postfixadmin']['database']['user']}", 134 | "password=#{password}" 135 | ] 136 | case node['postfixadmin']['conf']['encrypt'] 137 | when 'md5crypt' 138 | node.default['dovecot']['conf']['sql']['default_pass_scheme'] = 'MD5-CRYPT' 139 | when 'md5' 140 | node.default['dovecot']['conf']['sql']['default_pass_scheme'] = 'PLAIN-MD5' 141 | when 'cleartext' 142 | node.default['dovecot']['conf']['sql']['default_pass_scheme'] = 'PLAIN' 143 | else 144 | log 'Unknown postfixadmin encrypt mode, '\ 145 | "#{node['postfixadmin']['conf']['encrypt']}, using PLAIN" do 146 | level :warn 147 | end 148 | node.default['dovecot']['conf']['sql']['default_pass_scheme'] = 'PLAIN' 149 | end 150 | node.default['dovecot']['conf']['sql']['password_query'] = [ 151 | 'SELECT username AS user, password', 152 | 'FROM mailbox', 153 | 'WHERE username = \'%u\' AND active = \'1\'' 154 | ] 155 | home_sql = 156 | sql_concat("'#{node['postfix-dovecot']['vmail']['home']}/'", 'maildir') 157 | mail_sql = 158 | sql_concat( 159 | "'maildir:#{node['postfix-dovecot']['vmail']['home']}/'", 'maildir' 160 | ) 161 | node.default['dovecot']['conf']['sql']['user_query'] = [ 162 | 'SELECT', 163 | ' username AS user,', 164 | ' password,', 165 | " #{node['postfix-dovecot']['vmail']['uid']} as uid,", 166 | " #{node['postfix-dovecot']['vmail']['gid']} as gid,", 167 | " #{home_sql} AS home,", 168 | " #{mail_sql} AS mail ", 169 | 'FROM mailbox', 170 | 'WHERE username = \'%u\' AND active = \'1\'' 171 | ] 172 | 173 | node.default['dovecot']['conf']['sql']['iterate_query'] = [ 174 | 'SELECT username AS user', 175 | 'FROM mailbox WHERE active = \'1\'' 176 | ] 177 | 178 | # 10-ssl.conf 179 | self.class.send(:include, Chef::SslCertificateCookbook::ServiceHelpers) 180 | @ssl_config = ssl_config_for_service('dovecot') 181 | node.default['dovecot']['conf']['ssl'] = true 182 | node.default['dovecot']['conf']['ssl_protocols'] = @ssl_config['protocols'] 183 | node.default['dovecot']['conf']['ssl_cipher_list'] = @ssl_config['cipher_suite'] 184 | cert = ssl_certificate 'dovecot2' do 185 | namespace node['postfix-dovecot'] 186 | notifies :restart, 'service[dovecot]' 187 | end 188 | node.default['dovecot']['conf']['ssl_cert'] = "<#{cert.chain_combined_path}" 189 | node.default['dovecot']['conf']['ssl_key'] = "<#{cert.key_path}" 190 | 191 | include_recipe 'dovecot' 192 | 193 | # this should go after installing dovecot, sievec is required 194 | execute 'sievec sieve_global_path' do 195 | command "sievec '#{node['dovecot']['plugins']['sieve']['sieve_global_path']}'" 196 | action :nothing 197 | end 198 | 199 | sieve_global_dir = ::File.dirname( 200 | node['dovecot']['plugins']['sieve']['sieve_global_path'] 201 | ) 202 | 203 | directory sieve_global_dir do 204 | owner 'root' 205 | group 'root' 206 | mode '00755' 207 | recursive true 208 | not_if do 209 | ::File.exist?(sieve_global_dir) || 210 | !node['postfix-dovecot']['sieve']['enabled'] 211 | end 212 | end 213 | 214 | template node['dovecot']['plugins']['sieve']['sieve_global_path'] do 215 | source 'default.sieve.erb' 216 | # TODO: reinforcing this 217 | owner 'root' 218 | group 'root' 219 | mode '00644' 220 | only_if { node['postfix-dovecot']['sieve']['enabled'] } 221 | notifies :run, 'execute[sievec sieve_global_path]' 222 | end 223 | -------------------------------------------------------------------------------- /test/unit/recipes/postfix_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014-2015 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require_relative '../spec_helper' 21 | require 'chef-vault' 22 | 23 | describe 'postfix-dovecot::postfix' do 24 | let(:hostname) { 'my_hostname' } 25 | let(:chef_runner) { ChefSpec::SoloRunner.new } 26 | let(:chef_run) { chef_runner.converge(described_recipe) } 27 | let(:node) { chef_runner.node } 28 | chroot_files = %w( 29 | etc/resolv.conf 30 | etc/localtime 31 | etc/services 32 | etc/hosts 33 | etc/nsswitch.conf 34 | etc/nss_mdns.config 35 | ) 36 | before do 37 | node.set['postfix-dovecot']['hostname'] = hostname 38 | allow(::File).to receive(:exist?).and_call_original 39 | allow(::File).to receive(:exist?).with('/var/spool/postfix/etc') 40 | .and_return(false) 41 | allow(::IO).to receive(:read).and_call_original 42 | chroot_files.each do |chroot_file| 43 | allow(::File).to receive(:exist?).with("/#{chroot_file}") 44 | .and_return(true) 45 | allow(::IO).to receive(:read).with("/#{chroot_file}") 46 | .and_return("content:#{chroot_file}") 47 | end 48 | end 49 | 50 | it 'removes sendmail package' do 51 | expect(chef_run).to remove_package('sendmail') 52 | end 53 | 54 | it 'includes postfix_mysql recipe by default' do 55 | expect(chef_run).to include_recipe('postfix-dovecot::postfix_mysql') 56 | end 57 | 58 | it 'creates tables directory' do 59 | expect(chef_run).to create_directory('/etc/postfix/tables') 60 | .with_owner('root') 61 | .with_group('root') 62 | .with_mode(00755) 63 | end 64 | 65 | context 'with MySQL' do 66 | before do 67 | chef_runner.node.set['postfix-dovecot']['database']['type'] = 68 | 'mysql' 69 | end 70 | 71 | it 'includes postfix_mysql recipe' do 72 | expect(chef_run).to include_recipe('postfix-dovecot::postfix_mysql') 73 | end 74 | end 75 | 76 | context 'with PostgreSQL' do 77 | before do 78 | chef_runner.node.set['postfix-dovecot']['database']['type'] = 79 | 'postgresql' 80 | end 81 | 82 | it 'includes postfix_postgresql recipe' do 83 | expect(chef_run).to include_recipe('postfix-dovecot::postfix_postgresql') 84 | end 85 | end 86 | 87 | it 'generates SMTP SSL certificate' do 88 | expect(chef_run).to create_ssl_certificate('postfix') 89 | end 90 | 91 | it 'creates myorigin file' do 92 | expect(chef_run).to create_file('/etc/mailname') 93 | .with_content(hostname) 94 | end 95 | 96 | it 'includes postfix-full recipe' do 97 | expect(chef_run).to include_recipe('postfix-full') 98 | end 99 | 100 | it 'creates chroot etc directory' do 101 | expect(chef_run).to create_directory('/var/spool/postfix/etc') 102 | .with_user('root') 103 | .with_group('root') 104 | .with_mode('0755') 105 | end 106 | 107 | chroot_files.each do |chroot_file| 108 | it "creates chroot #{chroot_file} file" do 109 | expect(chef_run).to create_file("/var/spool/postfix/#{chroot_file}") 110 | .with_user('root') 111 | .with_group('root') 112 | .with_mode('0644') 113 | end 114 | end # each chroot_file 115 | 116 | it 'etc/resolv.conf creation notifies postfix restart' do 117 | resource = chef_run.file('/var/spool/postfix/etc/resolv.conf') 118 | expect(resource).to notify('service[postfix]').to(:restart) 119 | end 120 | 121 | context 'with RBLs' do 122 | before do 123 | node.set['postfix-dovecot']['rbls'] = %w( 124 | dnsbl.sorbs.net 125 | zen.spamhaus.org 126 | bl.spamcop.net 127 | cbl.abuseat.org 128 | ) 129 | end 130 | 131 | it 'adds blacklists to the smtpd_recipient_restrictions' do 132 | chef_run 133 | expect(node['postfix']['main']['smtpd_recipient_restrictions']) 134 | .to match(/, reject_rbl_client zen\.spamhaus\.org,/) 135 | end 136 | end 137 | 138 | context 'with SES enabled' do 139 | let(:attr_username) { 'AMAZON_SES_USERNAME_ATTR' } 140 | let(:attr_password) { 'AMAZON_SES_PASSWORD_ATTR' } 141 | let(:attr_credentials) do 142 | { 143 | 'username' => attr_username, 144 | 'password' => attr_password 145 | } 146 | end 147 | let(:vault_item) { 'ses' } 148 | let(:vault_username) { 'AMAZON_SES_USERNAME_VAULT' } 149 | let(:vault_password) { 'AMAZON_SES_PASSWORD_VAULT' } 150 | let(:vault_credentials) do 151 | { 152 | 'username' => vault_username, 153 | 'password' => vault_password 154 | } 155 | end 156 | before do 157 | node.set['postfix-dovecot']['ses']['enabled'] = true 158 | node.set['postfix-dovecot']['ses']['username'] = attr_username 159 | node.set['postfix-dovecot']['ses']['password'] = attr_password 160 | node.set['postfix-dovecot']['ses']['item'] = vault_item 161 | allow(ChefVault::Item).to receive(:vault?).with('amazon', 'ses') 162 | .and_return(true) 163 | allow(ChefVault::Item).to receive(:load).with('amazon', 'ses') 164 | .and_return(vault_credentials) 165 | end 166 | 167 | it 'does not use chef-vault by default' do 168 | chef_run 169 | expect(node['postfix-dovecot']['ses']['source']).to eq('attributes') 170 | end 171 | 172 | context 'with Chef Vault' do 173 | before do 174 | node.set['postfix-dovecot']['ses']['source'] = 'chef-vault' 175 | end 176 | 177 | it 'includes chef-vault recipe' do 178 | expect(chef_run).to include_recipe('chef-vault') 179 | end 180 | 181 | it 'reads chef vault' do 182 | expect(ChefVault::Item).to receive(:load) 183 | .with('amazon', 'ses').once.and_return(vault_credentials) 184 | chef_run 185 | end 186 | 187 | it 'creates postmap sasl_passwd resource' do 188 | resource = chef_run.execute('postmap /etc/postfix/tables/sasl_passwd') 189 | expect(resource).to do_nothing 190 | end 191 | 192 | it 'creates sasl_passwd file' do 193 | expect(chef_run).to create_file('/etc/postfix/tables/sasl_passwd') 194 | .with_owner('root') 195 | .with_group(0) 196 | .with_mode('00640') 197 | end 198 | 199 | it 'sets vault credentials inside sasl_passwd file' do 200 | credentials = "#{vault_username}:#{vault_password}" 201 | sasl_passwd_content = 202 | "email-smtp.us-east-1.amazonaws.com:587 #{credentials}" 203 | expect(chef_run).to create_file('/etc/postfix/tables/sasl_passwd') 204 | .with_content(sasl_passwd_content + "\n") 205 | end 206 | 207 | context 'sasl_passwd file' do 208 | let(:resource) { chef_run.file('/etc/postfix/tables/sasl_passwd') } 209 | 210 | it 'notifies postmap sasl_passwd' do 211 | expect(resource) 212 | .to notify('execute[postmap /etc/postfix/tables/sasl_passwd]') 213 | .to(:run).delayed 214 | end 215 | end # context sasl_passwd file 216 | end # context with Chef Vault 217 | 218 | context 'without Chef Vault' do 219 | before do 220 | node.set['postfix-dovecot']['ses']['source'] = 'attributes' 221 | end 222 | 223 | it 'does not include chef-vault recipe' do 224 | expect(chef_run).to_not include_recipe('chef-vault') 225 | end 226 | 227 | it 'does not read the chef vault' do 228 | expect(ChefVault::Item).to_not receive(:load) 229 | .with('api_dev_kinton_eu', 'ses') 230 | chef_run 231 | end 232 | 233 | it 'creates postmap sasl_passwd resource' do 234 | resource = chef_run.execute('postmap /etc/postfix/tables/sasl_passwd') 235 | expect(resource).to do_nothing 236 | end 237 | 238 | it 'creates sasl_passwd file' do 239 | expect(chef_run).to create_file('/etc/postfix/tables/sasl_passwd') 240 | .with_owner('root') 241 | .with_group(0) 242 | .with_mode('00640') 243 | end 244 | 245 | it 'sets vault credentials inside sasl_passwd file' do 246 | credentials = "#{attr_username}:#{attr_password}" 247 | sasl_passwd_content = 248 | "email-smtp.us-east-1.amazonaws.com:587 #{credentials}" 249 | expect(chef_run).to create_file('/etc/postfix/tables/sasl_passwd') 250 | .with_content(sasl_passwd_content + "\n") 251 | end 252 | 253 | context 'sasl_passwd file' do 254 | let(:resource) { chef_run.file('/etc/postfix/tables/sasl_passwd') } 255 | 256 | it 'notifies postmap sasl_passwd' do 257 | expect(resource) 258 | .to notify('execute[postmap /etc/postfix/tables/sasl_passwd]') 259 | .to(:run).delayed 260 | end 261 | end # context sasl_passwd file 262 | end # context without Chef Vault 263 | end # context with SES enabled 264 | end 265 | -------------------------------------------------------------------------------- /metadata.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot 4 | # Author:: Xabier de Zuazo () 5 | # Copyright:: Copyright (c) 2013-2015 Onddo Labs, SL. 6 | # License:: Apache License, Version 2.0 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | name 'postfix-dovecot' 22 | maintainer 'Xabier de Zuazo' 23 | maintainer_email 'xabier@zuazo.org' 24 | license 'Apache 2.0' 25 | description 'Installs and configures a mail server using Postfix, Dovecot, '\ 26 | 'PostfixAdmin and SpamAssassin, including Amazon SES support.' 27 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) 28 | version '3.1.0' # WiP 29 | 30 | if respond_to?(:source_url) 31 | source_url "https://github.com/zuazo/#{name}-cookbook" 32 | end 33 | if respond_to?(:issues_url) 34 | issues_url "https://github.com/zuazo/#{name}-cookbook/issues" 35 | end 36 | 37 | chef_version '>= 12.5' if respond_to?(:chef_version) 38 | 39 | supports 'amazon' 40 | supports 'centos', '>= 6.0' 41 | supports 'debian', '>= 7.0' 42 | supports 'fedora', '>= 17.0' 43 | supports 'ubuntu', '>= 12.04' 44 | 45 | recipe 'postfix-dovecot::default', 'Installs and configures everything.' 46 | recipe 'postfix-dovecot::vmail', 'Creates vmail user.' 47 | recipe 'postfix-dovecot::spam', 'Installs and configures SpamAssassin.' 48 | recipe 'postfix-dovecot::postfix', 'Installs and configures Postfix.' 49 | recipe 'postfix-dovecot::postfix_mysql', 50 | 'Installs Postfix package with MySQL support.' 51 | recipe 'postfix-dovecot::postfix_postgresql', 52 | 'Installs Postfix package with PostgreSQL support.' 53 | recipe 'postfix-dovecot::postfixadmin', 'Installs and configures PostfixAdmin.' 54 | recipe 'postfix-dovecot::dovecot', 'Installs and configures Dovecot 2.' 55 | 56 | depends 'chef-vault', '~> 2.0' 57 | depends 'build-essential', '~> 8.0' 58 | depends 'dovecot', '~> 3.0' 59 | depends 'onddo-spamassassin', '~> 2.0' 60 | depends 'postfixadmin', '~> 3.0' 61 | depends 'postfix-full', '~> 0.1' 62 | depends 'ssl_certificate', '~> 2.0' 63 | depends 'yum', '~> 5.0' 64 | 65 | attribute 'postfix-dovecot/postmaster_address', 66 | display_name: 'postmaster address', 67 | description: 'Postmaster mail address.', 68 | type: 'string', 69 | required: 'recommended', 70 | default: 'postmaster@foo.bar' 71 | 72 | attribute 'postfix-dovecot/rbls', 73 | display_name: 'postfix rbls', 74 | description: 'Mail RBLs array.', 75 | type: 'array', 76 | required: 'recommended', 77 | default: [] 78 | 79 | attribute 'postfix-dovecot/hostname', 80 | display_name: 'hostname', 81 | description: 'Hostname.', 82 | type: 'string', 83 | required: 'recommended', 84 | calculated: true 85 | 86 | attribute 'postfix-dovecot/database/type', 87 | display_name: 'postfix database type', 88 | description: 'Postfix database type.', 89 | choice: %w(mysql postgresql), 90 | type: 'string', 91 | required: 'optional', 92 | default: 'mysql' 93 | 94 | attribute 'postfix-dovecot/sieve/enabled', 95 | display_name: 'sieve enabled', 96 | description: 'Whether to enable sieve.', 97 | type: 'string', 98 | choice: %w(true false), 99 | required: 'recommended', 100 | default: 'true' 101 | 102 | attribute 'postfix-dovecot/sieve/global_path', 103 | display_name: 'sieve global_path', 104 | description: 'Sieve global path.', 105 | type: 'string', 106 | required: 'optional', 107 | calculated: true 108 | 109 | attribute 'postfix-dovecot/spamc/enabled', 110 | display_name: 'spamc enabled', 111 | description: 'Whether to enable SpamAssassin.', 112 | type: 'string', 113 | choice: %w(true false), 114 | required: 'optional', 115 | default: 'true' 116 | 117 | attribute 'postfix-dovecot/spamc/recipe', 118 | display_name: 'spamc recipe', 119 | description: 'Spamc recipe name to use.', 120 | type: 'string', 121 | required: 'optional', 122 | default: 'onddo-spamassassin' 123 | 124 | attribute 'postfix-dovecot/vmail/user', 125 | display_name: 'vmail user', 126 | description: 'Virtual mail system user name.', 127 | type: 'string', 128 | required: 'optional', 129 | default: 'vmail' 130 | 131 | attribute 'postfix-dovecot/vmail/group', 132 | display_name: 'vmail group', 133 | description: 'Virtual mail system group name.', 134 | type: 'string', 135 | required: 'optional', 136 | calculated: true 137 | 138 | attribute 'postfix-dovecot/vmail/uid', 139 | display_name: 'vmail uid', 140 | description: 'Virtual mail system user id.', 141 | type: 'string', 142 | required: 'optional', 143 | default: '5000' 144 | 145 | attribute 'postfix-dovecot/vmail/gid', 146 | display_name: 'vmail gid', 147 | description: 'Virtual mail system group id.', 148 | type: 'string', 149 | required: 'optional', 150 | calculated: true 151 | 152 | attribute 'postfix-dovecot/vmail/home', 153 | display_name: 'vmail home', 154 | description: 'Virtual mail user home path.', 155 | type: 'string', 156 | required: 'optional', 157 | default: '/var/vmail' 158 | 159 | attribute 'postfix-dovecot/ses/enabled', 160 | display_name: 'ses enabled', 161 | description: 'Whether to enable Amazon SES.', 162 | type: 'string', 163 | choice: %w(true false), 164 | required: 'recommended', 165 | default: 'false' 166 | 167 | attribute 'postfix-dovecot/ses/source', 168 | display_name: 'ses credentials source', 169 | description: 'Where to read the credentials from.', 170 | type: 'string', 171 | choice: %w(attributes chef-vault), 172 | required: 'recommended', 173 | default: 'attributes' 174 | 175 | attribute 'postfix-dovecot/ses/vault', 176 | display_name: 'ses credentials vault', 177 | description: 'Chef Vault bag to read SES credentials from.', 178 | type: 'string', 179 | required: 'recommended', 180 | default: 'amazon' 181 | 182 | attribute 'postfix-dovecot/ses/item', 183 | display_name: 'ses credentials vault item', 184 | description: 'Chef Vault item.', 185 | type: 'string', 186 | required: 'recommended', 187 | default: 'ses' 188 | 189 | attribute 'postfix-dovecot/ses/region', 190 | display_name: 'ses region', 191 | description: 'Amazon AWS region, used to calculate the servers.', 192 | type: 'string', 193 | required: 'optional', 194 | default: 'us-east-1' 195 | 196 | attribute 'postfix-dovecot/ses/servers', 197 | display_name: 'ses servers', 198 | description: 'Amazon SES SMTP servers.', 199 | type: 'array', 200 | required: 'optional', 201 | default: %w( 202 | email-smtp.us-east-1.amazonaws.com:25 203 | ses-smtp-prod-335357831.us-east-1.elb.amazonaws.com:25 204 | ) 205 | 206 | attribute 'postfix-dovecot/ses/username', 207 | display_name: 'ses username', 208 | description: 'Amazon SES SMTP username.', 209 | type: 'string', 210 | required: 'recommended', 211 | default: 'USERNAME' 212 | 213 | attribute 'postfix-dovecot/ses/password', 214 | display_name: 'ses password', 215 | description: 'Amazon SES SMTP password.', 216 | type: 'string', 217 | required: 'recommended', 218 | default: 'PASSWORD' 219 | 220 | attribute 'postfix-dovecot/yum', 221 | display_name: 'yum repositories', 222 | description: 223 | 'A list of yum repositories to add to include the source SRPMs.', 224 | type: 'hash', 225 | required: 'optional', 226 | calculated: true 227 | 228 | attribute 'postfix-dovecot/srpm/packages', 229 | display_name: 'srpm packages', 230 | description: 'Packages required for compiling Postfix from sources.', 231 | type: 'array', 232 | required: 'optional', 233 | calculated: true 234 | 235 | attribute 'postfix-dovecot/srpm/rpm_regexp', 236 | display_name: 'srpm rpm regexp', 237 | description: 238 | 'An array with two values, a pattern and a replacement. This'\ 239 | 'Regexp is used to get the final Postfix RPM name from the SRPM '\ 240 | 'name.', 241 | type: 'array', 242 | required: 'optional', 243 | calculated: true 244 | 245 | attribute 'postfix-dovecot/srpm/rpm_regexp', 246 | display_name: 'srpm rpm regexp', 247 | description: 248 | 'A string with the arguments to pass to rpmbuild application. '\ 249 | 'Normally contains the required option to enable PostgreSQL in '\ 250 | 'the Postfix SRPM.', 251 | type: 'hash', 252 | required: 'optional', 253 | calculated: true 254 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | Copyright 2013-2015 Xabier de Zuazo 179 | 180 | Licensed under the Apache License, Version 2.0 (the "License"); 181 | you may not use this file except in compliance with the License. 182 | You may obtain a copy of the License at 183 | 184 | http://www.apache.org/licenses/LICENSE-2.0 185 | 186 | Unless required by applicable law or agreed to in writing, software 187 | distributed under the License is distributed on an "AS IS" BASIS, 188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 189 | See the License for the specific language governing permissions and 190 | limitations under the License. 191 | -------------------------------------------------------------------------------- /recipes/postfix.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Cookbook Name:: postfix-dovecot 4 | # Recipe:: postfix 5 | # Author:: Xabier de Zuazo () 6 | # Copyright:: Copyright (c) 2013-2015 Onddo Labs, SL. 7 | # License:: Apache License, Version 2.0 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | package 'sendmail' do 23 | action :remove 24 | end 25 | 26 | db_type = 27 | case node['postfix-dovecot']['database']['type'] 28 | when 'mysql' 29 | include_recipe 'postfix-dovecot::postfix_mysql' 30 | 'mysql' 31 | when 'postgresql' 32 | include_recipe 'postfix-dovecot::postfix_postgresql' 33 | 'pgsql' 34 | end 35 | 36 | tables_path = "#{node['postfix']['base_dir']}/tables" 37 | # check if we can get the tables path from the postfixadmin cookbook 38 | if node['postfixadmin'] && node['postfixadmin']['map_files'] && 39 | node['postfixadmin']['map_files']['path'] 40 | tables_path = node['postfixadmin']['map_files']['path'] 41 | else 42 | directory tables_path do 43 | recursive true 44 | owner 'root' 45 | group 'root' 46 | mode 00755 47 | action :create 48 | end 49 | end 50 | 51 | # 52 | # master.cf 53 | # 54 | 55 | # submission inet n - - - - smtpd 56 | # -o syslog_name=postfix/submission 57 | # -o smtpd_tls_security_level=encrypt 58 | # -o smtpd_sasl_auth_enable=yes 59 | # -o smtpd_client_restrictions=permit_sasl_authenticated,reject 60 | # -o milter_macro_daemon_name=ORIGINATING 61 | node.default['postfix']['master']['inet:submission']['command'] = 'smtpd' 62 | node.default['postfix']['master']['inet:submission']['private'] = false 63 | node.default['postfix']['master']['inet:submission']['args'] = 64 | [ 65 | '-o syslog_name=postfix/submission', 66 | '-o smtpd_tls_security_level=encrypt', 67 | '-o smtpd_sasl_auth_enable=yes', 68 | '-o smtpd_client_restrictions=permit_sasl_authenticated,reject', 69 | '-o milter_macro_daemon_name=ORIGINATING' 70 | ] 71 | 72 | # smtps inet n - - - - smtpd 73 | # -o syslog_name=postfix/smtps 74 | # -o smtpd_tls_wrappermode=yes 75 | # -o smtpd_sasl_auth_enable=yes 76 | # -o smtpd_client_restrictions=permit_sasl_authenticated,reject 77 | # -o milter_macro_daemon_name=ORIGINATING 78 | node.default['postfix']['master']['inet:smtps']['command'] = 'smtpd' 79 | node.default['postfix']['master']['inet:smtps']['private'] = false 80 | node.default['postfix']['master']['inet:smtps']['args'] = 81 | [ 82 | '-o syslog_name=postfix/smtps', 83 | '-o smtpd_tls_wrappermode=yes', 84 | '-o smtpd_sasl_auth_enable=yes', 85 | '-o smtpd_client_restrictions=permit_sasl_authenticated,reject', 86 | '-o milter_macro_daemon_name=ORIGINATING' 87 | ] 88 | 89 | # dovecot unix - n n - - pipe 90 | # flags=DRhu user=vmail:vmail argv=/usr/bin/spamc -e /usr/lib/dovecot/deliver 91 | # -f ${sender} -d ${recipient} 92 | dovecot_argv = [ 93 | "#{node['dovecot']['lib_path']}/deliver", 94 | '-f ${sender}', 95 | '-d ${recipient}' 96 | ] 97 | if node['postfix-dovecot']['spamc']['enabled'] 98 | dovecot_argv.unshift("#{node.default['postfix-dovecot']['spamc']['path']} -e") 99 | end 100 | node.default['postfix']['master']['dovecot']['command'] = 'pipe' 101 | node.default['postfix']['master']['dovecot']['unpriv'] = false 102 | node.default['postfix']['master']['dovecot']['chroot'] = false 103 | node.default['postfix']['master']['dovecot']['args'] = 104 | [ 105 | "flags=DRhu user=#{node['postfix-dovecot']['vmail']['user']}:"\ 106 | "#{node['postfix-dovecot']['vmail']['group']} "\ 107 | "argv=#{dovecot_argv.join(' ')}" 108 | ] 109 | 110 | # 111 | # main.cf 112 | # 113 | 114 | node.default['postfix']['main']['mynetworks'] = 115 | '127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128' 116 | node.default['postfix']['main']['recipient_delimiter'] = '+' 117 | node.default['postfix']['tables']['aliases']['_type'] = 'hash' 118 | node.default['postfix']['tables']['aliases']['_set'] = 'alias_maps' 119 | node.default['postfix']['tables']['aliases']['_add'] = 'alias_database' 120 | node.default['postfix']['tables']['aliases']['_file'] = '/etc/aliases' 121 | node.default['postfix']['tables']['aliases']['_cmd'] = 'postalias' 122 | node.default['postfix']['tables']['aliases']['postmaster:'] = 'root' 123 | 124 | node.default['postfix']['main']['smtpd_banner'] = '$myhostname ESMTP $mail_name' 125 | node.default['postfix']['main']['biff'] = false 126 | node.default['postfix']['main']['append_dot_mydomain'] = 'no' 127 | node.default['postfix']['main']['readme_directory'] = false 128 | node.default['postfix']['main']['smtpd_helo_required'] = true 129 | 130 | node.default['postfix']['main']['smtpd_helo_restrictions'] = %w( 131 | permit_mynetworks 132 | reject_invalid_hostname 133 | permit 134 | ) 135 | smtpd_recipient_restrictions = %w( 136 | permit_mynetworks 137 | permit_sasl_authenticated 138 | reject_invalid_hostname 139 | reject_non_fqdn_hostname 140 | reject_non_fqdn_recipient 141 | reject_unknown_recipient_domain 142 | reject_unauth_pipelining 143 | reject_unauth_destination 144 | ) 145 | smtpd_recipient_restrictions += 146 | node['postfix-dovecot']['rbls'].map { |rbl| "reject_rbl_client #{rbl}" } 147 | smtpd_recipient_restrictions << 'permit' 148 | node.default['postfix']['main']['smtpd_recipient_restrictions'] = 149 | smtpd_recipient_restrictions 150 | 151 | # TLS parameters 152 | node.default_unless['postfix-dovecot']['common_name'] = 153 | node['postfix-dovecot']['hostname'] 154 | cert = ssl_certificate 'postfix' do 155 | namespace node['postfix-dovecot'] 156 | notifies :restart, 'service[postfix]' 157 | end 158 | node.default['postfix']['main']['smtpd_tls_cert_file'] = 159 | cert.chain_combined_path 160 | node.default['postfix']['main']['smtpd_tls_key_file'] = cert.key_path 161 | node.default['postfix']['main']['smtpd_use_tls'] = true 162 | node.default['postfix']['main']['smtpd_tls_session_cache_database'] = 163 | 'btree:${data_directory}/smtpd_scache' 164 | node.default['postfix']['main']['smtp_tls_session_cache_database'] = 165 | 'btree:${data_directory}/smtp_scache' 166 | self.class.send(:include, Chef::SslCertificateCookbook::ServiceHelpers) 167 | @ssl_config = ssl_config_for_service('postfix') 168 | node.default['postfix']['main']['smtpd_tls_mandatory_ciphers'] = 'high' 169 | node.default['postfix']['main']['smtpd_tls_mandatory_protocols'] = 170 | @ssl_config['protocols'] 171 | 172 | # SASL authentication 173 | node.default['postfix']['main']['smtpd_sasl_auth_enable'] = true 174 | node.default['postfix']['main']['smtpd_sasl_path'] = 'private/auth' 175 | node.default['postfix']['main']['smtpd_sasl_type'] = 'dovecot' 176 | node.default['postfix']['main']['smtpd_tls_auth_only'] = true 177 | 178 | # Virtual delivery 179 | node.default['postfix']['main']['virtual_mailbox_domains'] = [ 180 | "proxy:#{db_type}:#{tables_path}/db_virtual_domains_maps.cf" 181 | ] 182 | node.default['postfix']['main']['virtual_alias_maps'] = [ 183 | "proxy:#{db_type}:#{tables_path}/db_virtual_alias_maps.cf", 184 | "proxy:#{db_type}:#{tables_path}/db_virtual_alias_domain_maps.cf", 185 | "proxy:#{db_type}:#{tables_path}/db_virtual_alias_domain_catchall_maps.cf" 186 | ] 187 | node.default['postfix']['main']['virtual_mailbox_maps'] = [ 188 | "proxy:#{db_type}:#{tables_path}/db_virtual_mailbox_maps.cf", 189 | "proxy:#{db_type}:#{tables_path}/db_virtual_alias_domain_mailbox_maps.cf" 190 | ] 191 | node.default['postfix']['main']['virtual_mailbox_base'] = 192 | node['postfix-dovecot']['vmail']['home'] 193 | node.default['postfix']['main']['virtual_uid_maps'] = 194 | "static:#{node['postfix-dovecot']['vmail']['uid']}" 195 | node.default['postfix']['main']['virtual_gid_maps'] = 196 | "static:#{node['postfix-dovecot']['vmail']['gid']}" 197 | node.default['postfix']['main']['virtual_transport'] = 'dovecot' 198 | node.default['postfix']['main']['dovecot_destination_recipient_limit'] = 1 199 | 200 | # Amazon SES 201 | if node['postfix-dovecot']['ses']['enabled'] 202 | ses_credentials_hs = 203 | case node['postfix-dovecot']['ses']['source'] 204 | when 'chef-vault', 'vault' 205 | ses_vault = node['postfix-dovecot']['ses']['vault'] 206 | include_recipe 'chef-vault' 207 | chef_vault_item(ses_vault, node['postfix-dovecot']['ses']['item']) 208 | else 209 | node['postfix-dovecot']['ses'] 210 | end 211 | ses_credentials = [ 212 | ses_credentials_hs['username'], 213 | ses_credentials_hs['password'] 214 | ].join(':') 215 | 216 | node.default['postfix']['main']['relayhost'] = 217 | node['postfix-dovecot']['ses']['servers'][0] 218 | node.default['postfix']['main']['smtp_sasl_auth_enable'] = true 219 | node.default['postfix']['main']['smtp_sasl_security_options'] = 'noanonymous' 220 | node.default['postfix']['main']['smtp_use_tls'] = true 221 | node.default['postfix']['main']['smtp_tls_security_level'] = 'encrypt' 222 | node.default['postfix']['main']['smtp_tls_note_starttls_offer'] = true 223 | 224 | node.default['postfix']['main']['smtp_sasl_password_maps'] = 225 | "hash:#{tables_path}/sasl_passwd" 226 | sasl_passwd_content = 227 | node['postfix-dovecot']['ses']['servers'].reduce('') do |r, server| 228 | r + "#{server} #{ses_credentials}\n" 229 | end 230 | 231 | execute "postmap #{tables_path}/sasl_passwd" do 232 | user 'root' 233 | group 0 234 | action :nothing 235 | end 236 | 237 | file "#{tables_path}/sasl_passwd" do 238 | owner 'root' 239 | group 0 240 | mode '00640' 241 | content sasl_passwd_content 242 | notifies :run, "execute[postmap #{tables_path}/sasl_passwd]" 243 | end 244 | 245 | node.default['postfix']['main']['smtp_tls_CAfile'] = 246 | case node['platform'] 247 | when 'redhat', 'centos', 'scientific', 'fedora', 'suse', 'amazon' then 248 | '/etc/ssl/certs/ca-bundle.crt' 249 | when 'debian', 'ubuntu' then 250 | '/etc/ssl/certs/ca-certificates.crt' 251 | else 252 | Chef::Log.warn( 253 | "Unsupported platform: #{node['platform']}, trying to guess CA "\ 254 | 'certificates file location' 255 | ) 256 | '/etc/ssl/certs/ca-certificates.crt' 257 | end 258 | end 259 | 260 | node['postfix']['main'].each do |key, value| 261 | node.default['postfix']['main'][key] = value.join(', ') if value.is_a?(Array) 262 | end 263 | 264 | file node['postfix']['main']['myorigin'] do 265 | content node['postfix-dovecot']['hostname'] 266 | end 267 | 268 | include_recipe 'postfix-full' 269 | 270 | # Create some chroot dir/files, until postfix-full >= 0.1.3 is released: 271 | # https://github.com/mswart/chef-postfix-full/pull/8 272 | 273 | postfix_chroot = 274 | node['postfix']['main']['queue_directory'] || '/var/spool/postfix' 275 | chroot_files = %w( 276 | etc/resolv.conf 277 | etc/localtime 278 | etc/services 279 | etc/hosts 280 | etc/nsswitch.conf 281 | etc/nss_mdns.config 282 | ) 283 | 284 | chroot_files.each do |path| 285 | dir_path = ::File.dirname(path) 286 | chroot_dir_path = ::File.join(postfix_chroot, dir_path) 287 | 288 | begin 289 | resources(directory: chroot_dir_path) 290 | rescue Chef::Exceptions::ResourceNotFound 291 | directory chroot_dir_path do 292 | owner 'root' 293 | group 'root' 294 | mode '0755' 295 | recursive true 296 | not_if { dir_path.empty? || ::File.exist?(chroot_dir_path) } 297 | end 298 | end 299 | 300 | full_path = ::File.join('', path) 301 | file_exist = ::File.exist?(full_path) 302 | file_content = file_exist ? IO.read(full_path) : nil # avoid ENOENT error 303 | 304 | file ::File.join(postfix_chroot, path) do 305 | owner 'root' 306 | group 'root' 307 | mode '0644' 308 | content file_content 309 | only_if { file_exist } 310 | notifies :restart, 'service[postfix]' 311 | end 312 | end 313 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Postfix Dovecot Cookbook 2 | ======================== 3 | [![GitHub](http://img.shields.io/badge/github-zuazo/postfix--dovecot--cookbook-blue.svg?style=flat)](https://github.com/zuazo/postfix-dovecot-cookbook) 4 | [![License](https://img.shields.io/github/license/zuazo/postfix-dovecot-cookbook.svg?style=flat)](#license-and-author) 5 | 6 | [![Cookbook Version](https://img.shields.io/cookbook/v/postfix-dovecot.svg?style=flat)](https://supermarket.chef.io/cookbooks/postfix-dovecot) 7 | [![Dependency Status](http://img.shields.io/gemnasium/zuazo/postfix-dovecot-cookbook.svg?style=flat)](https://gemnasium.com/zuazo/postfix-dovecot-cookbook) 8 | [![Build Status](http://img.shields.io/travis/zuazo/postfix-dovecot-cookbook.svg?style=flat)](https://travis-ci.org/zuazo/postfix-dovecot-cookbook) 9 | 10 | Installs and configures a mail server using [Postfix](http://www.postfix.org/), [Dovecot](http://www.dovecot.org/), [PostfixAdmin](http://postfixadmin.sourceforge.net/) and [SpamAssassin](http://spamassassin.apache.org/), including [Amazon SES](http://aws.amazon.com/ses/) support. 11 | 12 | Requirements 13 | ============ 14 | 15 | ## Supported Platforms 16 | 17 | This cookbook has been tested on the following platforms: 18 | 19 | * Amazon Linux 20 | * CentOS `>= 6.0` 21 | * Debian `>= 7.0` 22 | * Fedora `>= 17.0` 23 | * Ubuntu `>= 12.04` 24 | 25 | Please, [let us know](https://github.com/zuazo/postfix-dovecot-cookbook/issues/new?title=I%20have%20used%20it%20successfully%20on%20...) if you use it successfully on any other platform. 26 | 27 | ## Required Cookbooks 28 | 29 | * [chef-vault](https://supermarket.chef.io/cookbooks/chef-vault) 30 | * [build-essential](https://supermarket.chef.io/cookbooks/build-essential) 31 | * [dovecot](https://supermarket.chef.io/cookbooks/dovecot) 32 | * [onddo-spamassassin](https://supermarket.chef.io/cookbooks/onddo-spamassassin) 33 | * [postfixadmin](https://supermarket.chef.io/cookbooks/postfixadmin) 34 | * [postfix-full](https://supermarket.chef.io/cookbooks/postfix-full) by [Malte Swart](https://github.com/mswart) 35 | * [ssl_certificate](https://supermarket.chef.io/cookbooks/ssl_certificate) 36 | * [yum](https://supermarket.chef.io/cookbooks/yum) 37 | 38 | ## Required Applications 39 | 40 | * Dovecot `>= 2`: requires this version of dovecot to be available by the distribution's package manager 41 | * Chef `12.5` or higher. 42 | * Ruby `2.2` or higher. 43 | 44 | Attributes 45 | ========== 46 | 47 | | Attribute | Default | Description | 48 | |:--------------------------------------------------|:-----------------------|:----------------------------------| 49 | | `node['postfix-dovecot']['postmaster_address']` | `'postmaster@foo.bar'` | Postmaster mail address. 50 | | `node['postfix-dovecot']['hostname']` | `node['fqdn']` | Hostname. 51 | | `node['postfix-dovecot']['rbls']` | `[]` | Mail RBLs array. 52 | | `node['postfix-dovecot']['database']['type']` | `'mysql'` | Database type. Possible values are: `'mysql'`, `'postgresql'` (Please, see [below](#postgresql-support)). 53 | | `node['postfix-dovecot']['sieve']['enabled']` | `true` | Whether to enable sieve. 54 | | `node['postfix-dovecot']['sieve']['global_path']` | `"#{default['dovecot']['conf_path']}/sieve/default.sieve"` | Sieve global path. 55 | | `node['postfix-dovecot']['spamc']['enabled']` | `true` | Whether to enable SpamAssassin. 56 | | `node['postfix-dovecot']['spamc']['recipe']` | `'onddo-spamassassin'` | Spamc recipe name to use. 57 | | `node['postfix-dovecot']['vmail']['user']` | `'vmail'` | Virtual mail system user name. 58 | | `node['postfix-dovecot']['vmail']['group']` | `node['postfix-dovecot']['vmail']['user']` | Virtual mail system group name. 59 | | `node['postfix-dovecot']['vmail']['uid']` | `5000` | Virtual mail system user id. 60 | | `node['postfix-dovecot']['vmail']['gid']` | `node['postfix-dovecot']['vmail']['uid']` | Virtual mail system group id. 61 | | `node['postfix-dovecot']['vmail']['home']` | `'/var/vmail'` | Virtual mail user home path. 62 | 63 | ## Amazon SES Attributes 64 | 65 | You can use `node['postfix-dovecot']['ses']['enabled']` to enable SES for sending emails. 66 | 67 | | Attribute | Default | Description | 68 | |:---------------------------------------------|:---------------|:----------------------------------| 69 | | `node['postfix-dovecot']['ses']['enabled']` | `false` | Whether to enable [Amazon SES](http://aws.amazon.com/ses/). 70 | | `node['postfix-dovecot']['ses']['source']` | `'attributes'` | Where to read the credentials from. Possible values: `'attributes'`, `'chef-vault'`. 71 | | `node['postfix-dovecot']['ses']['vault']` | `'amazon'` | Chef Vault bag to read SES credentials from. 72 | | `node['postfix-dovecot']['ses']['item']` | `'ses'` | Chef Vault item. 73 | | `node['postfix-dovecot']['ses']['region']` | `'us-east-1'` | Amazon AWS region, used to calculate the servers. 74 | | `node['postfix-dovecot']['ses']['servers']` | *calculated* | Amazon SES SMTP servers array. 75 | | `node['postfix-dovecot']['ses']['username']` | `'USERNAME'` | SES SMTP username. See [Obtaining Your Amazon SES SMTP Credentials](http://docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-credentials.html) documentation. 76 | | `node['postfix-dovecot']['ses']['password']` | `'PASSWORD'` | Amazon SES SMTP password. 77 | 78 | When Chef Vault is disabled in `node['postfix-dovecot']['ses']['source']`, this is the default behavior, the credentials are read from `['username']` and `['password']` attributes. 79 | 80 | When credentials should be read using `chef-vault`, the Chef Vault bag must have the following structure: 81 | 82 | ```json 83 | { 84 | "username": "AMAZON_USERNAME", 85 | "password": "AMAZON_PASSWORD" 86 | } 87 | ``` 88 | 89 | See the [Chef-Vault documentation](https://github.com/Nordstrom/chef-vault/blob/master/README.md) to learn how to create chef-vault bags. 90 | 91 | ## The SSL Certificate 92 | 93 | This cookbook uses the [`ssl_certificate`](https://supermarket.chef.io/cookbooks/ssl_certificate) cookbook to create the SSL certificate. The namespace used is `node['postfix-dovecot']`. For example: 94 | 95 | ```ruby 96 | node.default['postfix-dovecot']['common_name'] = 'mail.example.com' 97 | include_recipe 'postfix-dovecot' 98 | ``` 99 | 100 | This certificate is used for Postfix and Dovecot. For PostfixAdmin, you should use the `node['postfixadmin']` namespace. 101 | 102 | You can also tweak the supported SSL ciphers [setting the `node['ssl_certificate']['service']['compatibility']` attribute](https://github.com/zuazo/ssl_certificate-cookbook#securing-server-side-tls): 103 | 104 | ```ruby 105 | node.default['ssl_certificate']['service']['compatibility'] = :modern 106 | 107 | include_recipe 'postfix-dovecot' 108 | ``` 109 | 110 | See the [`ssl_certificate` namespace documentation](https://supermarket.chef.io/cookbooks/ssl_certificate#namespaces) for more information. 111 | 112 | Recipes 113 | ======= 114 | 115 | ## postfix-dovecot::default 116 | 117 | Installs and configures everything. 118 | 119 | ## postfix-dovecot::vmail 120 | 121 | Creates vmail user. 122 | 123 | ## postfix-dovecot::spam 124 | 125 | Installs and configures SpamAssassin. 126 | 127 | ## postfix-dovecot::postfix 128 | 129 | Installs and configures Postfix. 130 | 131 | ## postfix-dovecot::postfix_mysql 132 | 133 | Installs Postfix package with MySQL support. Used by the `postfix-dovecot::postfix` recipe. 134 | 135 | ## postfix-dovecot::postfix_postgresql 136 | 137 | Installs Postfix package with PostgreSQL support. Used by the `postfix-dovecot::postfix` recipe. 138 | 139 | ## postfix-dovecot::postfixadmin 140 | 141 | Installs and configures PostfixAdmin. 142 | 143 | ## postfix-dovecot::dovecot 144 | 145 | Installs and configures Dovecot 2. 146 | 147 | Usage Examples 148 | ============== 149 | 150 | ## Including in a Cookbook Recipe 151 | 152 | Running it from a recipe: 153 | 154 | ```ruby 155 | node['postfix-dovecot']['postmaster_address'] = 'postmaster@foobar.com' 156 | node['postfix-dovecot']['hostname'] = 'mail.foobar.com' 157 | 158 | include_recipe 'postfix-dovecot::default' 159 | 160 | postfixadmin_admin 'admin@admindomain.com' do 161 | password 'sup3r-s3cr3t-p4ss' 162 | action :create 163 | end 164 | 165 | postfixadmin_domain 'foobar.com' do 166 | login_username 'admin@admindomain.com' 167 | login_password 'sup3r-s3cr3t-p4ss' 168 | end 169 | 170 | postfixadmin_mailbox 'bob@foobar.com' do 171 | password 'alice' 172 | login_username 'admin@admindomain.com' 173 | login_password 'sup3r-s3cr3t-p4ss' 174 | end 175 | 176 | postfixadmin_alias 'billing@foobar.com' do 177 | goto 'bob@foobar.com' 178 | login_username 'admin@admindomain.com' 179 | login_password 'sup3r-s3cr3t-p4ss' 180 | end 181 | ``` 182 | 183 | Don't forget to include the `postfix-dovecot` cookbook as a dependency in the metadata. 184 | 185 | ```ruby 186 | # metadata.rb 187 | # [...] 188 | 189 | depends 'postfix-dovecot' 190 | ``` 191 | 192 | ## Including in the Run List 193 | 194 | Another alternative is to include the default recipe in your *Run List*. 195 | 196 | ```json 197 | { 198 | "name": "mail.example.com", 199 | "[...]": "[...]", 200 | "run_list": [ 201 | "[...]", 202 | "recipe[postfix-dovecot]" 203 | ] 204 | } 205 | ``` 206 | 207 | ## Enabling Some RBLs 208 | 209 | You can enable some [RBLs](http://en.wikipedia.org/wiki/DNSBL) to avoid spam: 210 | 211 | ```ruby 212 | node.default['postfix-dovecot']['rbls'] = %w( 213 | dnsbl.sorbs.net 214 | zen.spamhaus.org 215 | bl.spamcop.net 216 | cbl.abuseat.org 217 | ) 218 | include_recipe 'postfix-dovecot::default' 219 | ``` 220 | 221 | PostgreSQL Support 222 | ================== 223 | 224 | PostgreSQL support should be considered **experimental** at the moment. Use at your own risk. 225 | 226 | [Any feedback you can provide regarding the PostgreSQL support](https://github.com/zuazo/postfix-dovecot-cookbook/issues/new?title=PostgreSQL%20Support) will be greatly appreciated. 227 | 228 | ## PostgreSQL Support on CentOS and Fedora 229 | 230 | The latest CentOS and Fedora versions come without PostgreSQL support in their Postfix package. So we need to recompile it using the SRPM, enabling the PostgreSQL support. 231 | 232 | The `postfix-dovecot::postfix_postgresql` recipe takes care of it transparently. This recipe has been tested using `test-kitchen`, but it may not work for all cases. This code has been tested in the following platforms: 233 | 234 | * CentOS `6.5` and `7.0` 235 | * Fedora `19` and `20`. 236 | 237 | Please, [let us know](https://github.com/zuazo/postfix-dovecot-cookbook/issues/new?title=I%20have%20tested%20PostgreSQL%20support%20successfully%20on%20...) if you use PostgreSQL support successfully on any other platform. 238 | 239 | ## PostgreSQL Support on Amazon Linux 240 | 241 | Support for PostgreSQL on Amazon Linux is still not finished because of the need to patch the provided SRPM. Its implementation would require a little monkey-patching. 242 | 243 | Please, open an issue if [you need the support of PostgreSQL on Amazon Linux](https://github.com/zuazo/postfix-dovecot-cookbook/issues/new?title=We%20need%20PostgreSQL%20support%20on%20Amazon%20Linux). 244 | 245 | ## PostgreSQL Versions < 9.3 246 | 247 | If you are using PostgreSQL version `< 9.3`, you may need to adjust the `shmmax` and `shmall` kernel parameters to configure the shared memory. You can see [the example used for the integration tests](test/cookbooks/postfix-dovecot_test/recipes/postgresql_memory.rb). 248 | 249 | ## PostgreSQL Support Related Attributes 250 | 251 | Some cookbook attributes are used internally to add PostgreSQL support. They can make your journey smoother if you need to improve PostgreSQL support. 252 | 253 | | Attribute | Default | Description | 254 | |:---------------------------------------------------------------|:-------------|:-------------------------------| 255 | | `node['postfix-dovecot']['yum']` | *calculated* | A list of yum repositories to add to include the source SRPMs. 256 | | `node['postfix-dovecot']['postfix']['srpm']['packages']` | *calculated* | Packages required for compiling Postfix from sources. 257 | | `node['postfix-dovecot']['postfix']['srpm']['rpm_regexp']` | *calculated* | An array with two values, a pattern and a replacement. This Regexp is used to get the final Postfix RPM name from the SRPM name. 258 | | `node['postfix-dovecot']['postfix']['srpm']['rpm_build_args']` | *calculated* | A string with the arguments to pass to *rpmbuild* application. Normally contains the required option to enable PostgreSQL in the Postfix SRPM. 259 | 260 | See the [attributes/postfix_postgresql.rb](/attributes/postfix_postgresql.rb) file for default examples. 261 | 262 | Please do not hesitate [to make a PR](https://github.com/zuazo/postfix-dovecot-cookbook/blob/master/TESTING.md) if you improve the PostgreSQL support ;-) 263 | 264 | Testing 265 | ======= 266 | 267 | See [TESTING.md](https://github.com/zuazo/postfix-dovecot-cookbook/blob/master/TESTING.md). 268 | 269 | Contributing 270 | ============ 271 | 272 | Please do not hesitate to [open an issue](https://github.com/zuazo/postfix-dovecot-cookbook/issues/new) with any questions or problems. 273 | 274 | See [CONTRIBUTING.md](https://github.com/zuazo/postfix-dovecot-cookbook/blob/master/CONTRIBUTING.md). 275 | 276 | TODO 277 | ==== 278 | 279 | See [TODO.md](https://github.com/zuazo/postfix-dovecot-cookbook/blob/master/TODO.md). 280 | 281 | 282 | License and Author 283 | ================== 284 | 285 | | | | 286 | |:---------------------|:-----------------------------------------| 287 | | **Author:** | [Xabier de Zuazo](https://github.com/zuazo) () 288 | | **Contributor:** | [Uwe Stuehler](https://github.com/ustuehler) 289 | | **Copyright:** | Copyright (c) 2015, Xabier de Zuazo 290 | | **Copyright:** | Copyright (c) 2014-2015, Onddo Labs, SL. 291 | | **License:** | Apache License, Version 2.0 292 | 293 | Licensed under the Apache License, Version 2.0 (the "License"); 294 | you may not use this file except in compliance with the License. 295 | You may obtain a copy of the License at 296 | 297 | http://www.apache.org/licenses/LICENSE-2.0 298 | 299 | Unless required by applicable law or agreed to in writing, software 300 | distributed under the License is distributed on an "AS IS" BASIS, 301 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 302 | See the License for the specific language governing permissions and 303 | limitations under the License. 304 | -------------------------------------------------------------------------------- /test/unit/recipes/postfix_postgresql_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # 3 | # Author:: Xabier de Zuazo () 4 | # Copyright:: Copyright (c) 2014-2015 Onddo Labs, SL. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require_relative '../spec_helper' 21 | 22 | describe 'postfix-dovecot::postfix_postgresql' do 23 | let(:chef_runner) { ChefSpec::SoloRunner.new } 24 | let(:chef_run) { chef_runner.converge(described_recipe) } 25 | let(:node) { chef_runner.node } 26 | let(:buildroot) { '/root/rpmbuild' } 27 | 28 | context 'with RPM platforms' do 29 | let(:yd_shell_out) { instance_double('Mixlib::ShellOut') } 30 | let(:srpm) { 'foobar-1.0_19.src.tar.gz' } 31 | let(:rpm) { "foobar-1.0_19.centos.#{node['kernel']['machine']}.tar.gz" } 32 | before do 33 | node.automatic['platform'] = 'centos' 34 | allow(Mixlib::ShellOut).to receive(:new) 35 | .with('yumdownloader --source --urls postfix').and_return(yd_shell_out) 36 | allow(yd_shell_out).to receive(:run_command).and_return(yd_shell_out) 37 | allow(yd_shell_out).to receive(:error!) 38 | allow(yd_shell_out).to receive(:stdout) 39 | .and_return("http://example.org/#{srpm}") 40 | stub_command('postconf -m | grep -qFw pgsql').and_return(false) 41 | stub_command('rpm -q postfix').and_return(false) 42 | end 43 | 44 | it 'does not install postfix package' do 45 | expect(chef_run).to_not install_package('postfix') 46 | end 47 | 48 | it 'does not install postfix-pgsql package' do 49 | expect(chef_run).to_not install_package('postfix-pgsql') 50 | end 51 | 52 | it 'installs yum-utils package at compile time' do 53 | expect(chef_run).to install_package('yum-utils').at_compile_time 54 | end 55 | 56 | it 'searches the source using yumdownloader' do 57 | expect(Mixlib::ShellOut).to receive(:new).once 58 | .with('yumdownloader --source --urls postfix').and_return(yd_shell_out) 59 | chef_run 60 | end 61 | 62 | it 'checks yumdownloader for errors' do 63 | expect(yd_shell_out).to receive(:error!) 64 | chef_run 65 | end 66 | 67 | it 'executes yumdownloader postfix' do 68 | expect(chef_run).to run_execute('yumdownloader postfix') 69 | .with_command( 70 | "yumdownloader --source --destdir=#{buildroot}/SRPMS postfix" 71 | ) 72 | .with_creates("#{buildroot}/SRPMS/#{srpm}") 73 | end 74 | 75 | it 'removes postfix if no pgsql support' do 76 | stub_command('postconf -m | grep -qFw pgsql').and_return(false) 77 | expect(chef_run).to remove_yum_package('postfix (without postgresql)') 78 | .with_package_name('postfix') 79 | end 80 | 81 | { 82 | 'foobar-1.0_19.centos.x86_64.tar.gz' => 83 | [/\.src\./, '.centos.x86_64.'], 84 | 'foobar-1.0.x86_64.tar.gz' => 85 | [/_[0-9]+\.src\./, '.x86_64.'], 86 | 'foobar-1.0_19.x86_64.tar.gz' => 87 | [/\.src\./, '.x86_64.'] 88 | }.each do |rpm, rpm_regexp| 89 | it "returns #{rpm} using #{rpm_regexp} RPM regexp" do 90 | node.set['postfix-dovecot']['postfix']['srpm']['rpm_regexp'] = 91 | rpm_regexp 92 | expect(chef_run).to run_execute('install postfix from SRPM') 93 | .with_command("rpm -i '#{buildroot}/RPMS/x86_64/#{rpm}'") 94 | end 95 | end 96 | 97 | it 'does not remove postfix if pgsql support' do 98 | stub_command('postconf -m | grep -qFw pgsql').and_return(true) 99 | expect(chef_run).to_not remove_yum_package('postfix (without postgresql)') 100 | .with_package_name('postfix') 101 | end 102 | 103 | it 'compiles postfix SRPM' do 104 | expect(chef_run).to run_execute('compile postfix from SRPM') 105 | .with_environment('HOME' => '/root') 106 | .with_creates("#{buildroot}/RPMS/#{node['kernel']['machine']}/#{rpm}") 107 | end 108 | 109 | it 'installs postfix SRPM if not installed' do 110 | stub_command('rpm -q postfix').and_return(false) 111 | expect(chef_run).to run_execute('install postfix from SRPM') 112 | .with_command( 113 | "rpm -i '#{buildroot}/RPMS/#{node['kernel']['machine']}/#{rpm}'" 114 | ) 115 | end 116 | 117 | it 'does not install postfix SRPM if installed' do 118 | stub_command('rpm -q postfix').and_return(true) 119 | expect(chef_run).to_not run_execute('install postfix from SRPM') 120 | end 121 | 122 | context 'with CentOS 7' do 123 | let(:rpm) do 124 | "postfix-2.10.1-6.el7.centos.#{node['kernel']['machine']}.rpm" 125 | end 126 | let(:srpm) { 'postfix-2.10.1-6.el7.src.rpm' } 127 | let(:rpmbuild_args) { '--with=pgsql' } 128 | before do 129 | node.automatic['platform'] = 'centos' 130 | node.automatic['platform_version'] = '7.0' 131 | end 132 | 133 | %w( 134 | postgresql-devel rpm-build zlib-devel openldap-devel libdb-devel 135 | cyrus-sasl-devel pcre-devel openssl-devel perl-Date-Calc gcc 136 | mariadb-devel pkgconfig ed tar systemd-sysv 137 | ).each do |pkg| 138 | it "installs #{pkg} package" do 139 | expect(chef_run).to install_package(pkg) 140 | end 141 | end 142 | 143 | it 'installs the correct RPM' do 144 | expect(chef_run).to run_execute('install postfix from SRPM') 145 | .with_command("rpm -i '#{buildroot}/RPMS/x86_64/#{rpm}'") 146 | end 147 | 148 | it 'uses the correct rpmbuild args' do 149 | expect(chef_run).to run_execute('compile postfix from SRPM') 150 | .with_command( 151 | "rpmbuild #{rpmbuild_args} --rebuild '#{buildroot}/SRPMS/#{srpm}'" 152 | ) 153 | end 154 | end # context on CentOS 7 155 | 156 | context 'with CentOS 6' do 157 | let(:rpm) { "postfix-2.6.6-6.el6.1.#{node['kernel']['machine']}.rpm" } 158 | let(:srpm) { 'postfix-2.6.6-6.el6_7.1.src.rpm' } 159 | let(:rpmbuild_args) { '--define="PGSQL 1"' } 160 | before do 161 | node.automatic['platform'] = 'centos' 162 | node.automatic['platform_version'] = '6.0' 163 | end 164 | 165 | %w( 166 | postgresql-devel rpm-build zlib-devel openldap-devel db4-devel 167 | cyrus-sasl-devel pcre-devel openssl-devel perl-Date-Calc gcc 168 | mysql-devel pkgconfig ed 169 | ).each do |pkg| 170 | it "installs #{pkg} package" do 171 | expect(chef_run).to install_package(pkg) 172 | end 173 | end 174 | 175 | it 'installs the correct RPM' do 176 | expect(chef_run).to run_execute('install postfix from SRPM') 177 | .with_command("rpm -i '#{buildroot}/RPMS/x86_64/#{rpm}'") 178 | end 179 | 180 | it 'uses the correct rpmbuild args' do 181 | expect(chef_run).to run_execute('compile postfix from SRPM') 182 | .with_command( 183 | "rpmbuild #{rpmbuild_args} --rebuild '#{buildroot}/SRPMS/#{srpm}'" 184 | ) 185 | end 186 | 187 | [ 188 | 'CentOS-$releasever - Base Sources', 189 | 'CentOS-$releasever - Updates Sources', 190 | 'CentOS-$releasever - Extras Sources' 191 | ].each do |repo| 192 | it "configures #{repo} yum repository at compile time" do 193 | expect(chef_run).to create_yum_repository(repo).at_compile_time 194 | end 195 | end 196 | end # context on CentOS 6 197 | 198 | context 'with Fedora' do 199 | let(:rpm) { "foobar-1.0_19.#{node['kernel']['machine']}.tar.gz" } 200 | let(:rpmbuild_args) { '--with=pgsql' } 201 | before do 202 | node.automatic['platform'] = 'fedora' 203 | node.automatic['platform_version'] = '6.0' 204 | end 205 | 206 | %w( 207 | postgresql-devel rpm-build zlib-devel openldap-devel libdb-devel 208 | cyrus-sasl-devel pcre-devel openssl-devel perl-Date-Calc gcc 209 | mariadb-devel pkgconfig ed tar libicu-devel sqlite-devel tinycdb-devel 210 | ).each do |pkg| 211 | it "installs #{pkg} package" do 212 | expect(chef_run).to install_package(pkg) 213 | end 214 | end 215 | 216 | it 'installs the correct RPM' do 217 | expect(chef_run).to run_execute('install postfix from SRPM') 218 | .with_command("rpm -i '#{buildroot}/RPMS/x86_64/#{rpm}'") 219 | end 220 | 221 | it 'uses the correct rpmbuild args' do 222 | expect(chef_run).to run_execute('compile postfix from SRPM') 223 | .with_command( 224 | "rpmbuild #{rpmbuild_args} --rebuild '#{buildroot}/SRPMS/#{srpm}'" 225 | ) 226 | end 227 | end # context on Fedora 228 | 229 | context 'with Fedora 24' do 230 | before do 231 | node.automatic['platform'] = 'fedora' 232 | node.automatic['platform_version'] = '23.0' 233 | end 234 | 235 | %w( 236 | postfix 237 | postfix-pgsql 238 | ).each do |pkg| 239 | it "installs #{pkg} package" do 240 | expect(chef_run).to install_package(pkg) 241 | end 242 | end 243 | end # context on Fedora 23 244 | 245 | context 'with Amazon' do 246 | let(:pc_shell_out) { instance_double('Mixlib::ShellOut') } 247 | let(:gr_shell_out) { instance_double('Mixlib::ShellOut') } 248 | let(:rpm) { "foobar-1.0_19.#{node['kernel']['machine']}.tar.gz" } 249 | let(:rpmbuild_args) { '--with=pgsql' } 250 | before do 251 | node.automatic['platform'] = 'amazon' 252 | node.automatic['platform_version'] = '2013.09.2' 253 | 254 | allow(Mixlib::ShellOut).to receive(:new) 255 | .with('postconf -m | grep -qFw pgsql').and_return(pc_shell_out) 256 | allow(pc_shell_out).to receive(:run_command).and_return(pc_shell_out) 257 | allow(pc_shell_out).to receive(:error?).and_return(true) 258 | 259 | allow(Mixlib::ShellOut).to receive(:new) 260 | .with( 261 | 'yum install postfix > /dev/null 2>&1 && '\ 262 | 'yes | get_reference_source -p postfix | '\ 263 | 'grep "^Corresponding source RPM to found package : " | '\ 264 | 'sed "s/^Corresponding source RPM to found package : //"' 265 | ).and_return(gr_shell_out) 266 | allow(gr_shell_out).to receive(:run_command).and_return(gr_shell_out) 267 | allow(gr_shell_out).to receive(:error!) 268 | allow(gr_shell_out).to receive(:stdout) 269 | .and_return(srpm) 270 | end 271 | 272 | it 'searches the source using get_reference_source' do 273 | expect(Mixlib::ShellOut).to receive(:new).once 274 | .with( 275 | 'yum install postfix > /dev/null 2>&1 && '\ 276 | 'yes | get_reference_source -p postfix | '\ 277 | 'grep "^Corresponding source RPM to found package : " | '\ 278 | 'sed "s/^Corresponding source RPM to found package : //"' 279 | ).and_return(gr_shell_out) 280 | chef_run 281 | end 282 | 283 | it 'checks get_reference_source for errors' do 284 | expect(gr_shell_out).to receive(:error!) 285 | chef_run 286 | end 287 | 288 | it 'creates /root/rpmbuild/SRPMS directory' do 289 | expect(chef_run).to create_directory('/root/rpmbuild/SRPMS') 290 | .with_recursive(true) 291 | end 292 | 293 | it 'links SRPM to /usr/src/srpm/debug/' do 294 | expect(chef_run).to create_link("/root/rpmbuild/SRPMS/#{srpm}") 295 | .with_to("/usr/src/srpm/debug/#{srpm}") 296 | end 297 | 298 | %w( 299 | postgresql-devel rpm-build zlib-devel openldap-devel db4-devel 300 | cyrus-sasl-devel pcre-devel openssl-devel perl-Date-Calc gcc 301 | mysql-devel pkgconfig ed 302 | ).each do |pkg| 303 | it "installs #{pkg} package" do 304 | expect(chef_run).to install_package(pkg) 305 | end 306 | end 307 | 308 | it 'installs the correct RPM' do 309 | expect(chef_run).to run_execute('install postfix from SRPM') 310 | .with_command("rpm -i '#{buildroot}/RPMS/x86_64/#{rpm}'") 311 | end 312 | 313 | it 'uses the correct rpmbuild args' do 314 | expect(chef_run).to run_execute('compile postfix from SRPM') 315 | .with_command( 316 | "rpmbuild #{rpmbuild_args} --rebuild '#{buildroot}/SRPMS/#{srpm}'" 317 | ) 318 | end 319 | end # context on Amazon 320 | 321 | context 'with Scientific 7' do 322 | let(:rpm) { "postfix-2.10.1-6.el7.#{node['kernel']['machine']}.rpm" } 323 | let(:srpm) { 'postfix-2.10.1-6.el7.src.rpm' } 324 | let(:rpmbuild_args) { '--with=pgsql' } 325 | before do 326 | node.automatic['platform'] = 'scientific' 327 | node.automatic['platform_version'] = '7.0' 328 | end 329 | 330 | %w( 331 | postgresql-devel rpm-build zlib-devel libdb-devel 332 | cyrus-sasl-devel pcre-devel openssl-devel perl-Date-Calc gcc 333 | mariadb-devel pkgconfig ed tar systemd-sysv 334 | ).each do |pkg| 335 | it "installs #{pkg} package" do 336 | expect(chef_run).to install_package(pkg) 337 | end 338 | end 339 | 340 | it 'installs the correct RPM' do 341 | expect(chef_run).to run_execute('install postfix from SRPM') 342 | .with_command("rpm -i '#{buildroot}/RPMS/x86_64/#{rpm}'") 343 | end 344 | 345 | it 'uses the correct rpmbuild args' do 346 | expect(chef_run).to run_execute('compile postfix from SRPM') 347 | .with_command( 348 | "rpmbuild #{rpmbuild_args} --rebuild '#{buildroot}/SRPMS/#{srpm}'" 349 | ) 350 | end 351 | end # context on Scientific 7 352 | end # context on RPM platforms 353 | 354 | context 'with APT platforms' do 355 | before { node.automatic['platform'] = 'ubuntu' } 356 | 357 | it 'installs postfix package' do 358 | expect(chef_run).to install_package('postfix') 359 | end 360 | 361 | it 'installs postfix-pgsql package' do 362 | expect(chef_run).to install_package('postfix-pgsql') 363 | end 364 | end 365 | 366 | context 'with Unknown platforms' do 367 | before { node.automatic['platform'] = 'unknown' } 368 | 369 | it 'installs postfix package' do 370 | expect(chef_run).to install_package('postfix') 371 | end 372 | end # context on APT platforms 373 | end 374 | --------------------------------------------------------------------------------