Skip to content

Instantly share code, notes, and snippets.

@mdkent
Created February 3, 2010 00:40
Show Gist options
  • Save mdkent/293207 to your computer and use it in GitHub Desktop.
Save mdkent/293207 to your computer and use it in GitHub Desktop.
# minimal defaults for the main postfix setup
# by defaul postfix will be a null client setup
# to forward to sysmail only.
set[:postfix][:conf][:alias_database] = "hash:/etc/mail/aliases"
set[:postfix][:conf][:alias_maps] = "hash:/etc/mail/aliases"
set[:postfix][:conf][:html_directory] = "no"
set[:postfix][:conf][:inet_interfaces] = "localhost"
set[:postfix][:conf][:mail_owner] = "postfix"
set[:postfix][:conf][:mydestination] = nil
set[:postfix][:conf][:mydomain] = "work.com"
set[:postfix][:conf][:relayhost] = "sysmail.work.com"
set[:postfix][:conf][:setgid_group] = "postdrop"
set[:postfix][:conf][:local_transport] = "error:5.1.1 Mailbox unavailable"
set[:postfix][:conf][:master_service_disable] = "inet"
set[:postfix][:conf][:command_directory] = "/usr/sbin"
set[:postfix][:conf][:config_directory] = "/etc/postfix"
set[:postfix][:conf][:daemon_directory] = "/usr/libexec/postfix"
set[:postfix][:conf][:data_directory] = "/var/lib/postfix"
set[:postfix][:conf][:myhostname] = hostname
#
# setup per-env vars
#
case company[:environment]
when "dev"
set[:postfix][:conf][:canonical_maps] = "regexp:/etc/postfix/canonical"
set[:postfix][:canonical] = { '!/^sysadmin@work.com|^root|^root@.*.work.com/' => 'dev@someplace.com' }
when "qa"
set[:postfix][:conf][:canonical_maps] = "regexp:/etc/postfix/canonical"
set[:postfix][:canonical] = { '!/^sysadmin@work.com|^root|^root@.*.work.com/' => 'qa@someplace.com' }
when "stage"
set[:postfix][:conf][:canonical_maps] = nil
set[:postfix][:canonical] = nil
#set_unless[:postfix][:conf][:canonical_maps] = "regexp:/etc/postfix/canonical"
#set_unless[:postfix][:canonical] = { '!/^sysadmin@work.com|^root|^root@.*.work.com/' => 'stage@someplace.com' }
else
set[:postfix][:conf][:canonical_maps] = nil
set[:postfix][:canonical] = nil
end
# only if we are called by FastMail Role
# postfix::multi shouldn't be called directly only by a Role.
#
if role?("mail_fastmail")
# TODO: abstract the ip adress defines from the cookbook.
case hostname
when "fm1", "sfpfm01"
set[:postfix][:multi]["postfix-sysmail"]["conf"]["inet_interfaces"] = "127.0.0.20,127.0.1.6"
set[:postfix][:multi]["postfix-sysmail"]["conf"]["myhostname"] = "fm1-sys"
set[:postfix][:multi]["postfix-fastmail"]["conf"]["inet_interfaces"] = "127.0.0.21,127.0.1.7"
set[:postfix][:multi]["postfix-fastmail"]["conf"]["myhostname"] = "fm1"
when "fm6", "sfpfm06"
set[:postfix][:multi]["postfix-sysmail"]["conf"]["inet_interfaces"] = "127.0.0.16, 127.0.1.4"
set[:postfix][:multi]["postfix-sysmail"]["conf"]["myhostname"] = "fm6-sys"
set[:postfix][:multi]["postfix-fastmail"]["conf"]["inet_interfaces"] = "127.0.0.17, 127.0.1.5"
set[:postfix][:multi]["postfix-fastmail"]["conf"]["myhostname"] = "fm6"
else
Chef::Log.info("We Fell through not case for #{hostname}")
set[:postfix][:multi]["postfix-sysmail"]["conf"]["inet_interfaces"] = "127.0.0.2"
set[:postfix][:multi]["postfix-fastmail"]["conf"]["inet_interfaces"] = "127.0.0.3"
end
# fastmail servers should enable mem FS mount
set[:postfix][:multi]["postfix-fastmail"]["memqueue"] = "50"
end
# config auto-generated by chef.
# anything you do here will be wiped out shortly!
<% @postconf.each do |k, v| -%>
<% if v -%>
<%= k %>=<%= v %>
<% end -%>
<% end -%>
<% if @node[:postfix][:debug] -%>
# DEBUGGING ENABLED
debug_peer_level = <%= @node[:postfix][:debug][:debug_peer_level] %>
debug_peer_list = <%= @node[:postfix][:debug][:debug_peer_list] %>
debugger_command = <%= @node[:postfix][:debug][:debugger_command] %>
<% end -%>
map.erb
# this file is maintained by chef
# changes localy will be overrode
<% @map.each do |k, v| -%>
<%= k %> <%= v %>
<% end -%>
package "sendmail" do
action :remove
end
package "postfix" do
action :install
end
service "postfix" do
supports :status => true, :restart => true, :reload => true
action :enable
end
directory "/etc/mail" do
owner "root"
group "root"
mode "0755"
action :create
end
link "/etc/aliases.db" do
to "/etc/mail/aliases.db"
end
# ensure perms on the lock (had issues with upgrades)
file "/var/lib/postfix/master.lock" do
mode "600"
owner "postfix"
group "postfix"
end
# null exec for rebuilding transport db
# would be nice to pass this a param for the file
# prob move this to a define ?
# can we notify a define. ill look into it
execute "transport.map" do
command "/usr/sbin/postmap /etc/postfix/transport"
action :nothing
notifies :reload, resources(:service => "postfix")
end
# exec to rebuild virt tables
execute "virtual.map" do
command "/usr/sbin/postmap /etc/postfix/virtual"
action :nothing
notifies :reload, resources(:service => "postfix")
end
# TODO: move this stuiff outta flat files
# template it like the transports etc.
remote_file "/etc/postfix/virtual" do
source "default_virtual_aliases"
mode "0644"
notifies :run, resources(:execute => "virtual.map")
end
#
# default instance stuff
# every box will always have a default instance for doing sending
# then each instance ontop of that (sysmail fastmail)
# its the way postfix reccomends for postmulti-compat.
#
%w{main master}.each do |cfg|
template "/etc/postfix/#{cfg}.cf" do
source "#{cfg}.cf.erb"
mode "644"
variables(:postconf => @node[:postfix][:conf].sort)
end
end
if @node[:postfix][:transports]
# build transports file
template "/etc/postfix/transport" do
source "map.erb"
mode "644"
variables(:map => @node[:postfix][:transports].sort)
notifies :run, resources(:execute => "transport.map")
end
end
#
# canonical maps based on env
#
execute "canonical.map" do
command "/usr/sbin/postmap /etc/postfix/canonical"
action :nothing
notifies :reload, resources(:service => "postfix")
end
if @node[:postfix][:canonical]
template "/etc/postfix/canonical" do
source "map.erb"
mode "644"
variables(:map => @node[:postfix][:canonical].sort)
notifies :run, resources(:execute => "canonical.map")
end
end
Chef::Log.info(node.run_list.inspect)
# unsure latest
# options doesn't work for yum right now "no good reason not too"
# would love to be able to add options "--enablerepo work-test"
package "postfix" do
action :upgrade
end
# multi instance stuff
if @node[:postfix][:multi]
# mem fs is only on fastmail instance
# enable postmulti
execute "multi.init" do
command "postmulti -e init && touch /etc/postfix/multi.enabled"
creates "/etc/postfix/multi.enabled"
action :run
end
# loop over all multi instances and asemble templates.
postconf = Hash.new
multidir = String.new
@node[:postfix][:multi].each do |instance, settings|
# should do some checking here the instance name has to always start with
# "postfix-" to be compatable
instance = instance.downcase
if instance !~ /^postfix-/
Chef::Log.error("Instance '#{instance}' in posfix[:multi] not 'postfix-' prefix, Skipping")
next
end
# we can't have this setup b4 hand
# so well re-gen after each run. this is a bit of a hack to make sure
# mult-instance support works.
if multidir.empty?
multidir << "/etc/#{instance}"
else
multidir << ",/etc/#{instance}"
end
@node[:postfix][:conf][:multi_instance_directories] = multidir
Chef::Log.info("Instance Dirs: #{multidir}")
# set the instance atrribs
# this way we keep postmulti support even after we generated the instance's version
# of main.cf tho i dunno if this gets merged into settings here nor not.
# may want to make the hash merge against @node[..][instance][conf] instead of settings
# if settings isn't a proper ref to @node .. should be tho..
@node[:postfix][:multi][instance]['conf']['multi_instance_name'] = instance
@node[:postfix][:multi][instance]['conf']['config_directory'] = "/etc/#{instance}"
@node[:postfix][:multi][instance]['conf']['data_directory'] = "/var/lib/#{instance}"
@node[:postfix][:multi][instance]['conf']['queue_directory'] = "/var/spool/#{instance}"
group = @node[:postfix][:multi][instance]['conf']['multi_instance_group'] || "mta"
execute "#{instance}.create" do
command "postmulti -I #{instance} -G #{group} -e create"
creates "/etc/#{instance}"
action :run
end
# convert postfix config into hash to merge instance's config into it.
postconf = @node[:postfix][:conf].to_hash.merge(@node[:postfix][:multi][instance]['conf'])
execute "#{instance}.transport.map" do
command "/usr/sbin/postmap /etc/#{instance}/transport"
action :nothing
notifies :reload, resources(:service => "postfix")
end
# TEMPLATES! assseemmmmmbleee!!!
template "/etc/#{instance}/main.cf" do
source "main.cf.erb"
mode 0644
notifies :restart, resources(:service => "postfix")
# so much pain here.. need to pass in an array. may as well sort it.
# could also use .to_a to flatten this.
variables(:postconf => postconf.sort)
end
# push transports
instance_transports = Hash.new
if @node[:postfix][:transports]
if @node[:postfix][:multi][instance]['transports']
instance_transports = @node[:postfix][:transports].to_hash.merge(@node[:postfix][:multi][instance]['transports'])
else
instance_transports = @node[:postfix][:transports].to_hash
end
template "/etc/#{instance}/transport" do
source "map.erb"
mode "644"
variables(:map => instance_transports.sort)
notifies :run, resources(:execute => "#{instance}.transport.map")
end
end
# mount/create mem fs and restart instance if attribs say so
if @node[:postfix][:multi][instance]['memqueue']
# calculate the memfs size based on the % value from the attrib * 0.000001 to convrt form kB to G
memfs_size = (@node[:memory][:total].to_i * 0.000001) * (@node[:postfix][:multi][instance]['memqueue'].to_i * 0.01)
Chef::Log.info("TmpFS for #{instance}.
ohai reports: #{@node[:memory][:total]}
configured percent: #{@node[:postfix][:multi][instance]['memqueue']}
calculated: #{memfs_size.to_i}gB")
mount "/var/spool/#{instance}" do
pass 0
fstype "tmpfs"
device "/dev/null"
options "nr_inodes=999k,mode=755,size=#{memfs_size.to_i}g"
action [:mount, :enable]
notifies :restart, resources(:service => "postfix")
end
end
instance_transports.clear
postconf.clear
end
end
name "mail_fastmail"
description "Fastmail Mail layer Role"
recipes "postfix::multi"
override_attributes "postfix" => {
#
# fastmail defaults these settings will merge into mult-instance settings
# multi-instance settings take precedence.
#
"multi" => {
"postfix-fastmail" => {
"conf" =>{
"multi_instance_enable" => "yes",
"multi_instance_wrapper" => nil,
"master_service_disable" => nil,
"relayhost" => nil,
"smtpd_client_connection_count_limit" => "0",
"smtpd_client_event_limit_exceptions" => "$mynetworks",
"mydomain" => "work.com",
"default_process_limit" => "2000",
"deadbeats_concurancy_limit" => "20",
},
"transports" => {
"att.net" => "att:",
"bellsouth.net" => "deadbeats:",
".bellsouth.net"=> "deadbeats:",
".hotmail.com" => "deadbeats:",
".msn.com" => "deadbeats:",
"hotmail.com" => "deadbeats:",
"msn.com" => "deadbeats:",
"yahoo.com" => "deadbeats:",
".yahoo.com" => "deadbeats:"
},
"canonical" => {}
},
"postfix-sysmail" => {
"conf" => {
# this is the required minimum set for an instance
"multi_instance_enable" => "yes",
"multi_instance_wrapper" => nil,
"master_service_disable" => nil,
"relayhost" => nil,
},
"transports" => {},
"canonical" => {}
}
},
"transports" => {
"relay" => ":[mh.work.com]",
"worknews.com" => ":[intake.work.com]",
},
"conf" => {
"multi_instance_enable" => "yes",
"multi_instance_wrapper" => "/usr/sbin/postmulti -p --",
"fallback_relay" => "mh.work.com",
"bounce_queue_lifetime" => "10m",
"default_process_limit" => 200,
"hash_queue_depth" => 3,
"hash_queue_names" => "incoming, active, deferred, defer, bounce, flush",
"ignore_mx_lookup_error" => "yes",
"in_flow_delay" => "5s",
"maximal_queue_lifetime" => "5h",
"mynetworks" => '127.253.0.0/24, 127.1.0.0/18',
"qmgr_message_active_limit" => 30000,
"qmgr_message_recipient_limit" => 30000,
"relay_domains" => "worknews.com",
"relay_transport" => "relay",
"smtp_randomize_addresses" => "yes",
"smtpd_error_sleep_time" => 1,
"smtpd_hard_error_limit" => 100,
"smtpd_soft_error_limit" => 10,
"soft_bounce" => "no",
"transport_maps" => "hash:/etc/postfix/transport",
"connection_cache_ttl_limit" => "1s",
"default_destination_concurrency_limit" => 15,
"local_destination_concurrency_limit" => 2,
"unknown_local_recipient_reject_code" => 550,
}
},
"work" => {
"routes" => {
"127.1.0.0/18" => {
'gateway' => '127.1.1.1',
},
"0.0.0.0/0" => {
'gateway' => '127.0.0.1',
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment