From: Tom Hughes Date: Fri, 31 May 2013 19:01:21 +0000 (+0100) Subject: Add a load more cookbooks X-Git-Url: https://git.openstreetmap.org/chef.git/commitdiff_plain/faf8ae12e85eabb050b0f5eceb2cb67ad1de5261 Add a load more cookbooks --- diff --git a/cookbooks/clamav/README.rdoc b/cookbooks/clamav/README.rdoc new file mode 100644 index 000000000..3de2ec7a3 --- /dev/null +++ b/cookbooks/clamav/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/cookbooks/clamav/metadata.rb b/cookbooks/clamav/metadata.rb new file mode 100644 index 000000000..1675e56b8 --- /dev/null +++ b/cookbooks/clamav/metadata.rb @@ -0,0 +1,6 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Installs and configures clamav" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "1.0.0" diff --git a/cookbooks/clamav/recipes/default.rb b/cookbooks/clamav/recipes/default.rb new file mode 100644 index 000000000..ff34b857b --- /dev/null +++ b/cookbooks/clamav/recipes/default.rb @@ -0,0 +1,31 @@ +# +# Cookbook Name:: clamav +# Recipe:: default +# +# Copyright 2011, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package "clamav-daemon" +package "clamav-freshclam" + +service "clamav-daemon" do + action [ :enable, :start ] + supports :status => true, :restart => true +end + +service "clamav-freshclam" do + action [ :enable, :start ] + supports :status => true, :restart => true +end diff --git a/cookbooks/dhcpd/README.md b/cookbooks/dhcpd/README.md new file mode 100644 index 000000000..6b087690a --- /dev/null +++ b/cookbooks/dhcpd/README.md @@ -0,0 +1,57 @@ +DESCRIPTION +=========== + +Configures networking. + +USAGE +===== + +Set the networking attributes in a role, for example from my base.rb: + + :networking => { + :nameservers => [ "10.13.37.120", "10.13.37.40" ], + :search => [ "int.example.org". "example.org" ] + } + +The resulting /etc/resolv.conf will look like: + + search int.example.org example.org + nameserver 10.13.37.120 + nameserver 10.13.37.40 + +LICENSE AND AUTHOR +================== + +Author:: OpenStreetMap Administrators () + +Copyright 2010, OpenStreetMap Foundation. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Based on resolver cookbook: + +Author:: Joshua Timberman () + +Copyright 2009, Opscode, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/cookbooks/dhcpd/attributes/default.rb b/cookbooks/dhcpd/attributes/default.rb new file mode 100644 index 000000000..0844369bb --- /dev/null +++ b/cookbooks/dhcpd/attributes/default.rb @@ -0,0 +1,2 @@ +default[:dhcpd][:first_address] = nil +default[:dhcpd][:last_address] = nil diff --git a/cookbooks/dhcpd/metadata.rb b/cookbooks/dhcpd/metadata.rb new file mode 100644 index 000000000..656d877a0 --- /dev/null +++ b/cookbooks/dhcpd/metadata.rb @@ -0,0 +1,12 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Configures dhcpd" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) +version "1.0.0" +depends "networking" + +attribute "dhcpd", + :display_name => "dhcpd", + :description => "Hash of dhcpd attributes", + :type => "hash" diff --git a/cookbooks/dhcpd/recipes/default.rb b/cookbooks/dhcpd/recipes/default.rb new file mode 100644 index 000000000..0bdba6a32 --- /dev/null +++ b/cookbooks/dhcpd/recipes/default.rb @@ -0,0 +1,46 @@ +# +# Cookbook Name:: dhcpd +# Recipe:: default +# +# Copyright 2011, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include_recipe "networking" + +if node[:lsb][:release].to_f < 12.04 + package_name = "dhcp3-server" + config_file = "/etc/dhcp3/dhcpd.conf" +else + package_name = "isc-dhcp-server" + config_file = "/etc/dhcp/dhcpd.conf" +end + +package package_name + +domain = "#{node[:networking][:roles][:external][:zone]}.openstreetmap.org" + +template config_file do + source "dhcpd.conf.erb" + owner "root" + group "root" + mode 0644 + variables :domain => domain +end + +service package_name do + action [ :enable, :start ] + supports :status => true, :restart => true + subscribes :restart, resources(:template => config_file) +end diff --git a/cookbooks/dhcpd/templates/default/dhcpd.conf.erb b/cookbooks/dhcpd/templates/default/dhcpd.conf.erb new file mode 100644 index 000000000..1872158a4 --- /dev/null +++ b/cookbooks/dhcpd/templates/default/dhcpd.conf.erb @@ -0,0 +1,165 @@ +# DO NOT EDIT - This file is being maintained by Chef + +default-lease-time 600; +max-lease-time 7200; +<% node.interfaces(:role => :internal).each do |interface| -%> + +subnet <%= interface[:network] %> netmask <%= interface[:netmask] %> { + range dynamic-bootp <%= node[:dhcpd][:first_address] %> <%= node[:dhcpd][:last_address] %>; +# option broadcast-address <%= interface[:broadcast] %>; + option routers <%= interface[:gateway] %>; + option domain-name "<%= @domain %>"; + option domain-name-servers <%= interface[:gateway] %>; + option ntp-servers <%= node[:ntp][:servers].join(", ") %>; +} +<% end -%> + +host apc1.<%= @domain %> { + hardware ethernet 00:c0:b7:77:f3:d8; + server-name "apc1.<%= @domain %>"; + fixed-address apc1.<%= @domain %>; +} + +host apc2.<%= @domain %> { + hardware ethernet 00:c0:b7:52:b7:d2; + server-name "apc2.<%= @domain %>"; + fixed-address apc2.<%= @domain %>; +} + +host apc3.<%= @domain %> { + hardware ethernet 00:c0:b7:52:b9:1e; + server-name "apc3.<%= @domain %>"; + fixed-address apc3.<%= @domain %>; +} + +host bowser.oob.openstreetmap.org { + hardware ethernet 00:16:35:c5:dd:9e; + server-name "bowser.oob.openstreetmap.org"; + fixed-address bowser.oob.openstreetmap.org; +} + +host draco.oob.openstreetmap.org { + hardware ethernet 00:1c:c4:7a:da:dc; + server-name "draco.oob.openstreetmap.org"; + fixed-address draco.oob.openstreetmap.org; +} + +host errol.oob.openstreetmap.org { + hardware ethernet 00:e0:81:c0:8d:01; + server-name "errol.oob.openstreetmap.org"; + fixed-address errol.oob.openstreetmap.org; +} + +host eustace.oob.openstreetmap.org { + hardware ethernet 00:17:a4:3c:fb:9c; + server-name "eustace.oob.openstreetmap.org"; + fixed-address eustace.oob.openstreetmap.org; +} + +host faffy.oob.openstreetmap.org { + hardware ethernet 00:17:a4:37:cc:d0; + server-name "faffy.oob.openstreetmap.org"; + fixed-address faffy.oob.openstreetmap.org; +} + +host fiddlestick.oob.openstreetmap.org { + hardware ethernet 00:17:a4:0f:22:c6; + server-name "fiddlestick.oob.openstreetmap.org"; + fixed-address fiddlestick.oob.openstreetmap.org; +} + +host horntail.oob.openstreetmap.org { + hardware ethernet 00:e0:81:46:95:6e; + server-name "horntail.oob.openstreetmap.org"; + fixed-address horntail.oob.openstreetmap.org; +} + +host idris.oob.openstreetmap.org { + hardware ethernet 00:1f:29:68:bd:b6; + server-name "idris.oob.openstreetmap.org"; + fixed-address idris.oob.openstreetmap.org; +} + +host norbert.oob.openstreetmap.org { + hardware ethernet 00:1c:c4:7c:14:f6; + server-name "norbert.oob.openstreetmap.org"; + fixed-address norbert.oob.openstreetmap.org; +} + +host poldi.oob.openstreetmap.org { + hardware ethernet 00:e0:81:c5:2b:b7; + server-name "poldi.oob.openstreetmap.org"; + fixed-address poldi.oob.openstreetmap.org; +} + +host ridley.oob.openstreetmap.org { + hardware ethernet 00:17:a4:39:99:54; + server-name "ridley.oob.openstreetmap.org"; + fixed-address ridley.oob.openstreetmap.org; +} + +host sarel.oob.openstreetmap.org { + hardware ethernet 00:1c:c4:7c:d2:be; + server-name "sarel.oob.openstreetmap.org"; + fixed-address sarel.oob.openstreetmap.org; +} + +host smaug.oob.openstreetmap.org { + hardware ethernet 00:30:48:9d:57:ff; + server-name "smaug.oob.openstreetmap.org"; + fixed-address smaug.oob.openstreetmap.org; +} + +host soup.oob.openstreetmap.org { + hardware ethernet 00:17:a4:37:ec:88; + server-name "soup.oob.openstreetmap.org"; + fixed-address soup.oob.openstreetmap.org; +} + +host spike-01.oob.openstreetmap.org { + hardware ethernet 00:1a:4b:a5:bd:2a; + server-name "spike-01.oob.openstreetmap.org"; + fixed-address spike-01.oob.openstreetmap.org; +} + +host spike-02.oob.openstreetmap.org { + hardware ethernet 00:1b:78:04:37:de; + server-name "spike-02.oob.openstreetmap.org"; + fixed-address spike-02.oob.openstreetmap.org; +} + +host spike-03.oob.openstreetmap.org { + hardware ethernet 00:19:bb:39:3c:64; + server-name "spike-03.oob.openstreetmap.org"; + fixed-address spike-03.oob.openstreetmap.org; +} + +host thorn-01.oob.openstreetmap.org { + hardware ethernet 00:19:bb:35:87:94; + server-name "thorn-01.oob.openstreetmap.org"; + fixed-address thorn-01.oob.openstreetmap.org; +} + +host thorn-02.oob.openstreetmap.org { + hardware ethernet 00:19:bb:39:9b:a6; + server-name "thorn-02.oob.openstreetmap.org"; + fixed-address thorn-02.oob.openstreetmap.org; +} + +host thorn-03.oob.openstreetmap.org { + hardware ethernet 00:19:bb:37:f3:ce; + server-name "thorn-03.oob.openstreetmap.org"; + fixed-address thorn-03.oob.openstreetmap.org; +} + +host urmel.oob.openstreetmap.org { + hardware ethernet 00:19:bb:39:1b:e6; + server-name "urmel.oob.openstreetmap.org"; + fixed-address urmel.oob.openstreetmap.org; +} + +host yevaud.oob.openstreetmap.org { + hardware ethernet 00:e0:81:c0:8d:02; + server-name "yevaud.oob.openstreetmap.org"; + fixed-address yevaud.oob.openstreetmap.org; +} diff --git a/cookbooks/exim/README.rdoc b/cookbooks/exim/README.rdoc new file mode 100644 index 000000000..3de2ec7a3 --- /dev/null +++ b/cookbooks/exim/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/cookbooks/exim/attributes/default.rb b/cookbooks/exim/attributes/default.rb new file mode 100644 index 000000000..e6e7fff0b --- /dev/null +++ b/cookbooks/exim/attributes/default.rb @@ -0,0 +1,9 @@ +default[:exim][:local_domains] = [ "localhost", "@" ] +default[:exim][:relay_to_domains] = [ ] +default[:exim][:relay_from_hosts] = [ "127.0.0.1", "::1" ] +default[:exim][:daemon_smtp_ports] = [ 25 ] +default[:exim][:trusted_users] = [ ] +default[:exim][:smarthost_name] = nil +default[:exim][:smarthost_via] = "mail.openstreetmap.org:26" +default[:exim][:routes] = { } +default[:exim][:aliases][:root] = "tomh" diff --git a/cookbooks/exim/files/default/noreply/gpx b/cookbooks/exim/files/default/noreply/gpx new file mode 100644 index 000000000..6c8a45af4 --- /dev/null +++ b/cookbooks/exim/files/default/noreply/gpx @@ -0,0 +1,18 @@ +This is an automated response to your email, which was sent to an +unattended address. + +The message you replied to was notifying you of the status of your +recent openstreetmap.org GPS trace upload, and you do not generally +need to reply to this message. + +If your trace failed to upload, please start by consulting the +information on our wiki about import failures: + + http://wiki.openstreetmap.org/index.php/GPX_Import_Failures + +If you have encountered a technical problem withe upload service +then please contact support@openstreetmap.org for assistance. + +Thank you, + +OpenStreetMap Administrators diff --git a/cookbooks/exim/files/default/noreply/help b/cookbooks/exim/files/default/noreply/help new file mode 100644 index 000000000..8dfbc31a4 --- /dev/null +++ b/cookbooks/exim/files/default/noreply/help @@ -0,0 +1,13 @@ +This is an automated response to your email, which was sent to an +unattended address. + +If you were trying to reply to a question, answer or comment on +the help.openstreetmap.org web site then you should do so using +the web site as it is not possible to reply by email. + +If you are having problems with the help.openstreetmap.org site +then please contact support@openstreetmap.org for assistance. + +Thank you, + +OpenStreetMap Administrators diff --git a/cookbooks/exim/files/default/noreply/trac b/cookbooks/exim/files/default/noreply/trac new file mode 100644 index 000000000..2628aa827 --- /dev/null +++ b/cookbooks/exim/files/default/noreply/trac @@ -0,0 +1,13 @@ +This is an automated response to your email, which was sent to an +unattended address. + +If you were trying to reply to a comment on a bug report on +the trac.openstreetmap.org web site then you should do so using +the web site as it is not possible to reply by email. + +If you are having problems with the trac.openstreetmap.org site +then please contact support@openstreetmap.org for assistance. + +Thank you, + +OpenStreetMap Administrators diff --git a/cookbooks/exim/files/default/noreply/web b/cookbooks/exim/files/default/noreply/web new file mode 100644 index 000000000..51eab3452 --- /dev/null +++ b/cookbooks/exim/files/default/noreply/web @@ -0,0 +1,18 @@ +This is an automated response to your email, which was sent to an +unattended address. + +If you were trying to confirm your email address after signing +up for an account, or after changing your email address, then you +should click on the link in the original email you received. + +If you need help using OpenStreetMap then you should try our +question and answer site: + + http://help.openstreetmap.org/ + +If you are having technical problems with the web site then please +contact support@openstreetmap.org for assistance. + +Thank you, + +OpenStreetMap Administrators diff --git a/cookbooks/exim/metadata.rb b/cookbooks/exim/metadata.rb new file mode 100644 index 000000000..861ce0931 --- /dev/null +++ b/cookbooks/exim/metadata.rb @@ -0,0 +1,58 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Installs and configures exim" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "1.0.0" +depends "networking" +depends "ssl" + +attribute "exim", + :display_name => "Exim", + :description => "Hash of exim attributes", + :type => "hash" + +attribute "exim/local_domains", + :display_name => "Domains to Handle Locally", + :description => "List of domains we are prepared to accept mail for", + :default => [ "@" ] + +attribute "exim/relay_to_domains", + :display_name => "Domains to Relay To", + :description => "List of domains we are prepared to relay to", + :default => [ ] + +attribute "exim/relay_from_hosts", + :display_name => "Hosts to Relay From", + :description => "List of hosts we are prepared to relay from", + :default => [ "127.0.0.1", "::1" ] + +attribute "exim/daemon_smtp_ports", + :display_name => "Ports to Listen On", + :description => "List of ports we will listen on", + :default => [ 25 ] + +attribute "exim/trusted_users", + :display_name => "Trusted Users", + :description => "List of users we will trust", + :default => [ ] + +attribute "exim/smarthost_name", + :display_name => "Smarthost Name", + :description => "Name of this smarthost", + :default => nil + +attribute "exim/smarthost_via", + :display_name => "Smarthost Via", + :description => "Smarthost to use for sending mail", + :default => "mail.openstreetmap.org:26" + +attribute "exim/routes", + :display_name => "Custom Routes", + :description => "Custom routes for handling local mail", + :default => { } + +attribute "exim/aliases", + :display_name => "Mail Aliases", + :description => "Mail aliases", + :default => { } diff --git a/cookbooks/exim/recipes/default.rb b/cookbooks/exim/recipes/default.rb new file mode 100644 index 000000000..ff38860a0 --- /dev/null +++ b/cookbooks/exim/recipes/default.rb @@ -0,0 +1,108 @@ +# +# Cookbook Name:: exim +# Recipe:: default +# +# Copyright 2011, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include_recipe "networking" +include_recipe "ssl" + +package "exim4" + +if File.exist?("/var/run/clamav/clamd.ctl") + package "exim4-daemon-heavy" +end + +group "ssl-cert" do + action :modify + members "Debian-exim" + append true +end + +service "exim4" do + action [ :enable, :start ] + supports :status => true, :restart => true, :reload => true + subscribes :restart, resources(:cookbook_file => "/etc/ssl/certs/openstreetmap.pem") + subscribes :restart, resources(:file => "/etc/ssl/private/openstreetmap.key") +end + +relay_to_domains = node[:exim][:relay_to_domains] + +node[:exim][:routes].each_value do |route| + relay_to_domains = relay_to_domains | route[:domains] +end + +relay_from_hosts = node[:exim][:relay_from_hosts] + +if node[:exim][:smarthost_name] + search(:node, "exim_smarthost_via:#{node[:exim][:smarthost_name]}\\:*").each do |host| + relay_from_hosts = relay_from_hosts | host.ipaddresses(:role => :external) + end +end + +template "/etc/exim4/exim4.conf" do + source "exim4.conf.erb" + owner "root" + group "Debian-exim" + mode 0644 + variables :relay_to_domains => relay_to_domains.sort, + :relay_from_hosts => relay_from_hosts.sort + notifies :restart, resources(:service => "exim4") +end + +template "/etc/aliases" do + source "aliases.erb" + owner "root" + group "root" + mode 0644 +end + +remote_directory "/etc/exim4/noreply" do + source "noreply" + owner "root" + group "Debian-exim" + mode 0755 + files_owner "root" + files_group "Debian-exim" + files_mode 0755 + purge true +end + +munin_plugin "exim_mailqueue" +munin_plugin "exim_mailstats" + +if not relay_to_domains.empty? or not node[:exim][:local_domains].empty? + node[:exim][:daemon_smtp_ports].each do |port| + firewall_rule "accept-inbound-smtp-#{port}" do + action :accept + source "net" + dest "fw" + proto "tcp:syn" + dest_ports port + source_ports "1024:" + end + end +end + +if node[:exim][:smarthost_via] + firewall_rule "deny-outbound-smtp" do + action :reject + source "fw" + dest "net" + proto "tcp:syn" + dest_ports "smtp" + end +end diff --git a/cookbooks/exim/templates/default/aliases.erb b/cookbooks/exim/templates/default/aliases.erb new file mode 100644 index 000000000..52a7f353d --- /dev/null +++ b/cookbooks/exim/templates/default/aliases.erb @@ -0,0 +1,11 @@ +# DO NOT EDIT - This file is being maintained by Chef + +<% node[:exim][:aliases].keys.sort.each do |a| -%> +<%= a -%>: <%= node[:exim][:aliases][a] %> +<% end -%> + +<% node[:accounts][:users].keys.sort.each do |u| -%> +<% if node[:accounts][:users][u][:status] and node[:accounts][:users][u][:email] -%> +<%= u -%>: <%= node[:accounts][:users][u][:email] %> +<% end -%> +<% end -%> diff --git a/cookbooks/exim/templates/default/exim4.conf.erb b/cookbooks/exim/templates/default/exim4.conf.erb new file mode 100644 index 000000000..c1a842c5b --- /dev/null +++ b/cookbooks/exim/templates/default/exim4.conf.erb @@ -0,0 +1,810 @@ +# $Cambridge: exim/exim-src/src/configure.default,v 1.14 2009/10/16 07:46:13 tom Exp $ + +###################################################################### +# Runtime configuration file for Exim # +###################################################################### + + +# This is a default configuration file which will operate correctly in +# uncomplicated installations. Please see the manual for a complete list +# of all the runtime configuration options that can be included in a +# configuration file. There are many more than are mentioned here. The +# manual is in the file doc/spec.txt in the Exim distribution as a plain +# ASCII file. Other formats (PostScript, Texinfo, HTML, PDF) are available +# from the Exim ftp sites. The manual is also online at the Exim web sites. + + +# This file is divided into several parts, all but the first of which are +# headed by a line starting with the word "begin". Only those parts that +# are required need to be present. Blank lines, and lines starting with # +# are ignored. + + +########### IMPORTANT ########## IMPORTANT ########### IMPORTANT ########### +# # +# Whenever you change Exim's configuration file, you *must* remember to # +# HUP the Exim daemon, because it will not pick up the new configuration # +# until you do. However, any other Exim processes that are started, for # +# example, a process started by an MUA in order to send a message, will # +# see the new configuration as soon as it is in place. # +# # +# You do not need to HUP the daemon for changes in auxiliary files that # +# are referenced from this file. They are read every time they are used. # +# # +# It is usually a good idea to test a new configuration for syntactic # +# correctness before installing it (for example, by running the command # +# "exim -C /config/file.new -bV"). # +# # +########### IMPORTANT ########## IMPORTANT ########### IMPORTANT ########### + + + +###################################################################### +# MAIN CONFIGURATION SETTINGS # +###################################################################### + +# Specify your host's canonical name here. This should normally be the fully +# qualified "official" name of your host. If this option is not set, the +# uname() function is called to obtain the name. In many cases this does +# the right thing and you need not set anything explicitly. + +primary_hostname = <%= node[:fqdn] %> + + +# The next three settings create two lists of domains and one list of hosts. +# These lists are referred to later in this configuration using the syntax +# +local_domains, +relay_to_domains, and +relay_from_hosts, respectively. They +# are all colon-separated lists: + +domainlist local_domains = <%= node[:exim][:local_domains].join(" : ") %> +domainlist relay_to_domains = <%= @relay_to_domains.join(" : ") %> +hostlist relay_from_hosts = <; <%= @relay_from_hosts.join(" ; ") %> + +# Most straightforward access control requirements can be obtained by +# appropriate settings of the above options. In more complicated situations, +# you may need to modify the Access Control Lists (ACLs) which appear later in +# this file. + +# The first setting specifies your local domains, for example: +# +# domainlist local_domains = my.first.domain : my.second.domain +# +# You can use "@" to mean "the name of the local host", as in the default +# setting above. This is the name that is specified by primary_hostname, +# as specified above (or defaulted). If you do not want to do any local +# deliveries, remove the "@" from the setting above. If you want to accept mail +# addressed to your host's literal IP address, for example, mail addressed to +# "user@[192.168.23.44]", you can add "@[]" as an item in the local domains +# list. You also need to uncomment "allow_domain_literals" below. This is not +# recommended for today's Internet. + +# The second setting specifies domains for which your host is an incoming relay. +# If you are not doing any relaying, you should leave the list empty. However, +# if your host is an MX backup or gateway of some kind for some domains, you +# must set relay_to_domains to match those domains. For example: +# +# domainlist relay_to_domains = *.myco.com : my.friend.org +# +# This will allow any host to relay through your host to those domains. +# See the section of the manual entitled "Control of relaying" for more +# information. + +# The third setting specifies hosts that can use your host as an outgoing relay +# to any other host on the Internet. Such a setting commonly refers to a +# complete local network as well as the localhost. For example: +# +# hostlist relay_from_hosts = 127.0.0.1 : 192.168.0.0/16 +# +# The "/16" is a bit mask (CIDR notation), not a number of hosts. Note that you +# have to include 127.0.0.1 if you want to allow processes on your host to send +# SMTP mail by using the loopback address. A number of MUAs use this method of +# sending mail. + +# All three of these lists may contain many different kinds of item, including +# wildcarded names, regular expressions, and file lookups. See the reference +# manual for details. The lists above are used in the access control lists for +# checking incoming messages. The names of these ACLs are defined here: + +acl_smtp_rcpt = acl_check_rcpt +acl_smtp_data = acl_check_data + +# You should not change those settings until you understand how ACLs work. + + +<% if File.exist?("/var/run/clamav/clamd.ctl") -%> +# If you are running a version of Exim that was compiled with the content- +# scanning extension, you can cause incoming messages to be automatically +# scanned for viruses. You have to modify the configuration in two places to +# set this up. The first of them is here, where you define the interface to +# your scanner. This example is typical for ClamAV; see the manual for details +# of what to set for other virus scanners. The second modification is in the +# acl_check_data access control list (see below). + +av_scanner = clamd:/var/run/clamav/clamd.ctl + + +<% end -%> +<% if File.exist?("/var/run/spamd.pid") -%> +# For spam scanning, there is a similar option that defines the interface to +# SpamAssassin. You do not need to set this if you are using the default, which +# is shown in this commented example. As for virus scanning, you must also +# modify the acl_check_data access control list to enable spam scanning. + +spamd_address = 127.0.0.1 783 + + +<% end -%> +# If Exim is compiled with support for TLS, you may want to enable the +# following options so that Exim allows clients to make encrypted +# connections. In the authenticators section below, there are template +# configurations for plaintext username/password authentication. This kind +# of authentication is only safe when used within a TLS connection, so the +# authenticators will only work if the following TLS settings are turned on +# as well. + +# Allow any client to use TLS. + +tls_advertise_hosts = <; !127.0.0.1 ; !::1 + +# Specify the location of the Exim server's TLS certificate and private key. +# The private key must not be encrypted (password protected). You can put +# the certificate and private key in the same file, in which case you only +# need the first setting, or in separate files, in which case you need both +# options. + +tls_certificate = /etc/ssl/certs/openstreetmap.pem +tls_privatekey = /etc/ssl/private/openstreetmap.key + +# In order to support roaming users who wish to send email from anywhere, +# you may want to make Exim listen on other ports as well as port 25, in +# case these users need to send email from a network that blocks port 25. +# The standard port for this purpose is port 587, the "message submission" +# port. See RFC 4409 for details. Microsoft MUAs cannot be configured to +# talk the message submission protocol correctly, so if you need to support +# them you should also allow TLS-on-connect on the traditional but +# non-standard port 465. + +daemon_smtp_ports = <%= node[:exim][:daemon_smtp_ports].join(" : ") %> +# tls_on_connect_ports = 465 + + +# Specify the domain you want to be added to all unqualified addresses +# here. An unqualified address is one that does not contain an "@" character +# followed by a domain. For example, "caesar@rome.example" is a fully qualified +# address, but the string "caesar" (i.e. just a login name) is an unqualified +# email address. Unqualified addresses are accepted only from local callers by +# default. See the recipient_unqualified_hosts option if you want to permit +# unqualified addresses from remote sources. If this option is not set, the +# primary_hostname value is used for qualification. + +qualify_domain = openstreetmap.org + + +# If you want unqualified recipient addresses to be qualified with a different +# domain to unqualified sender addresses, specify the recipient domain here. +# If this option is not set, the qualify_domain value is used. + +qualify_recipient = <%= node[:fqdn] %> + + +# The following line must be uncommented if you want Exim to recognize +# addresses of the form "user@[10.11.12.13]" that is, with a "domain literal" +# (an IP address) instead of a named domain. The RFCs still require this form, +# but it makes little sense to permit mail to be sent to specific hosts by +# their IP address in the modern Internet. This ancient format has been used +# by those seeking to abuse hosts by using them for unwanted relaying. If you +# really do want to support domain literals, uncomment the following line, and +# see also the "domain_literal" router below. + +# allow_domain_literals + + +# No deliveries will ever be run under the uids of users specified by +# never_users (a colon-separated list). An attempt to do so causes a panic +# error to be logged, and the delivery to be deferred. This is a paranoic +# safety catch. There is an even stronger safety catch in the form of the +# FIXED_NEVER_USERS setting in the configuration for building Exim. The list of +# users that it specifies is built into the binary, and cannot be changed. The +# option below just adds additional users to the list. The default for +# FIXED_NEVER_USERS is "root", but just to be absolutely sure, the default here +# is also "root". + +# Note that the default setting means you cannot deliver mail addressed to root +# as if it were a normal user. This isn't usually a problem, as most sites have +# an alias for root that redirects such mail to a human administrator. + +never_users = root + + +# The setting below causes Exim to do a reverse DNS lookup on all incoming +# IP calls, in order to get the true host name. If you feel this is too +# expensive, you can specify the networks for which a lookup is done, or +# remove the setting entirely. + +host_lookup = * + + +# The settings below, which are actually the same as the defaults in the +# code, cause Exim to make RFC 1413 (ident) callbacks for all incoming SMTP +# calls. You can limit the hosts to which these calls are made, and/or change +# the timeout that is used. If you set the timeout to zero, all RFC 1413 calls +# are disabled. RFC 1413 calls are cheap and can provide useful information +# for tracing problem messages, but some hosts and firewalls have problems +# with them. This can result in a timeout instead of an immediate refused +# connection, leading to delays on starting up SMTP sessions. (The default was +# reduced from 30s to 5s for release 4.61.) + +rfc1413_hosts = * +rfc1413_query_timeout = 5s + + +# By default, Exim expects all envelope addresses to be fully qualified, that +# is, they must contain both a local part and a domain. If you want to accept +# unqualified addresses (just a local part) from certain hosts, you can specify +# these hosts by setting one or both of +# +# sender_unqualified_hosts = +# recipient_unqualified_hosts = +# +# to control sender and recipient addresses, respectively. When this is done, +# unqualified addresses are qualified using the settings of qualify_domain +# and/or qualify_recipient (see above). + + +# If you want Exim to support the "percent hack" for certain domains, +# uncomment the following line and provide a list of domains. The "percent +# hack" is the feature by which mail addressed to x%y@z (where z is one of +# the domains listed) is locally rerouted to x@y and sent on. If z is not one +# of the "percent hack" domains, x%y is treated as an ordinary local part. This +# hack is rarely needed nowadays; you should not enable it unless you are sure +# that you really need it. +# +# percent_hack_domains = +# +# As well as setting this option you will also need to remove the test +# for local parts containing % in the ACL definition below. + + +# When Exim can neither deliver a message nor return it to sender, it "freezes" +# the delivery error message (aka "bounce message"). There are also other +# circumstances in which messages get frozen. They will stay on the queue for +# ever unless one of the following options is set. + +# This option unfreezes frozen bounce messages after two days, tries +# once more to deliver them, and ignores any delivery failures. + +ignore_bounce_errors_after = 2d + +# This option cancels (removes) frozen messages that are older than a week. + +timeout_frozen_after = 7d + + +# By default, messages that are waiting on Exim's queue are all held in a +# single directory called "input" which it itself within Exim's spool +# directory. (The default spool directory is specified when Exim is built, and +# is often /var/spool/exim/.) Exim works best when its queue is kept short, but +# there are circumstances where this is not always possible. If you uncomment +# the setting below, messages on the queue are held in 62 subdirectories of +# "input" instead of all in the same directory. The subdirectories are called +# 0, 1, ... A, B, ... a, b, ... z. This has two benefits: (1) If your file +# system degrades with many files in one directory, this is less likely to +# happen; (2) Exim can process the queue one subdirectory at a time instead of +# all at once, which can give better performance with large queues. + +# split_spool_directory = true + + +# Log just about everything we can log so that we have the best +# possible chance of knowing what's going on. + +log_selector = +all -skip_delivery + + +# Define trusted users. + +trusted_users = <%= node[:exim][:trusted_users].join(" : ") %> + + + +###################################################################### +# ACL CONFIGURATION # +# Specifies access control lists for incoming SMTP mail # +###################################################################### + +begin acl + +# This access control list is used for every RCPT command in an incoming +# SMTP message. The tests are run in order until the address is either +# accepted or denied. + +acl_check_rcpt: + + # Accept if the source is local SMTP (i.e. not over TCP/IP). We do this by + # testing for an empty sending host field. + + accept hosts = : +<% if node[:lsb][:release].to_i >= 10.04 -%> + control = dkim_disable_verify +<% end -%> + + ############################################################################# + # The following section of the ACL is concerned with local parts that contain + # @ or % or ! or / or | or dots in unusual places. + # + # The characters other than dots are rarely found in genuine local parts, but + # are often tried by people looking to circumvent relaying restrictions. + # Therefore, although they are valid in local parts, these rules lock them + # out, as a precaution. + # + # Empty components (two dots in a row) are not valid in RFC 2822, but Exim + # allows them because they have been encountered. (Consider local parts + # constructed as "firstinitial.secondinitial.familyname" when applied to + # someone like me, who has no second initial.) However, a local part starting + # with a dot or containing /../ can cause trouble if it is used as part of a + # file name (e.g. for a mailing list). This is also true for local parts that + # contain slashes. A pipe symbol can also be troublesome if the local part is + # incorporated unthinkingly into a shell command line. + # + # Two different rules are used. The first one is stricter, and is applied to + # messages that are addressed to one of the local domains handled by this + # host. The line "domains = +local_domains" restricts it to domains that are + # defined by the "domainlist local_domains" setting above. The rule blocks + # local parts that begin with a dot or contain @ % ! / or |. If you have + # local accounts that include these characters, you will have to modify this + # rule. + + deny message = Restricted characters in address + domains = +local_domains + local_parts = ^[.] : ^.*[@%!/|] + + # The second rule applies to all other domains, and is less strict. The line + # "domains = !+local_domains" restricts it to domains that are NOT defined by + # the "domainlist local_domains" setting above. The exclamation mark is a + # negating operator. This rule allows your own users to send outgoing + # messages to sites that use slashes and vertical bars in their local parts. + # It blocks local parts that begin with a dot, slash, or vertical bar, but + # allows these characters within the local part. However, the sequence /../ + # is barred. The use of @ % and ! is blocked, as before. The motivation here + # is to prevent your users (or your users' viruses) from mounting certain + # kinds of attack on remote sites. + + deny message = Restricted characters in address + domains = !+local_domains + local_parts = ^[./|] : ^.*[@%!] : ^.*/\\.\\./ + ############################################################################# + + # Accept mail to postmaster in any local domain, regardless of the source, + # and without verifying the sender. + + accept local_parts = postmaster + domains = +local_domains + + # Deny incoming mail unless the sender address can be verified. + + deny !hosts = +relay_from_hosts + !verify = sender/callout/defer_ok + + # Accept if the message comes from one of the hosts for which we are an + # outgoing relay. It is assumed that such hosts are most likely to be MUAs, + # so we set control=submission to make Exim treat the message as a + # submission. It will fix up various errors in the message, for example, the + # lack of a Date: header line. If you are actually relaying out out from + # MTAs, you may want to disable this. If you are handling both relaying from + # MTAs and submissions from MUAs you should probably split them into two + # lists, and handle them differently. + + # Recipient verification is omitted here, because in many cases the clients + # are dumb MUAs that don't cope well with SMTP error responses. If you are + # actually relaying out from MTAs, you should probably add recipient + # verification here. + + # Note that, by putting this test before any DNS black list checks, you will + # always accept from these hosts, even if they end up on a black list. The + # assumption is that they are your friends, and if they get onto a black + # list, it is a mistake. + + accept hosts = +relay_from_hosts + control = submission +<% if node[:lsb][:release].to_i >= 10.04 -%> + control = dkim_disable_verify +<% end -%> + + # Accept if the message arrived over an authenticated connection, from + # any host. Again, these messages are usually from MUAs, so recipient + # verification is omitted, and submission mode is set. And again, we do this + # check before any black list tests. + + accept authenticated = * + control = submission +<% if node[:lsb][:release].to_i >= 10.04 -%> + control = dkim_disable_verify +<% end -%> + + # Insist that any other recipient address that we accept is either in one of + # our local domains, or is in a domain for which we explicitly allow + # relaying. Any other domain is rejected as being unacceptable for relaying. + + require message = relay not permitted + domains = +local_domains : +relay_to_domains + + # We also require all accepted addresses to be verifiable. This check will + # do local part verification for local domains, but only check the domain + # for remote domains. The only way to check local parts for the remote + # relay domains is to use a callout (add /callout), but please read the + # documentation about callouts before doing this. + + require verify = recipient + +<% if node[:exim][:dns_blacklists] -%> + # Deny any messages from hosts in certain blacklists. + + deny message = Rejected because $sender_host_address is in a black list at $dnslist_domain\n$dnslist_text + dnslists = <%= node[:exim][:dns_blacklists].join(" : ") %> + +<% end -%> + ############################################################################# + # This check is commented out because it is recognized that not every + # sysadmin will want to do it. If you enable it, the check performs + # Client SMTP Authorization (csa) checks on the sending host. These checks + # do DNS lookups for SRV records. The CSA proposal is currently (May 2005) + # an Internet draft. You can, of course, add additional conditions to this + # ACL statement to restrict the CSA checks to certain hosts only. + # + # require verify = csa + ############################################################################# + + # At this point, the address has passed all the checks that have been + # configured, so we accept it unconditionally. + + accept + + +# This ACL is used after the contents of a message have been received. This +# is the ACL in which you can test a message's headers or body, and in +# particular, this is where you can invoke external virus or spam scanners. +# Some suggested ways of configuring these tests are shown below, commented +# out. Without any tests, this ACL accepts all messages. If you want to use +# such tests, you must ensure that Exim is compiled with the content-scanning +# extension (WITH_CONTENT_SCAN=yes in Local/Makefile). + +acl_check_data: + +<% if File.exist?("/var/run/clamav/clamd.ctl") -%> + # Deny if the message contains a virus. Before enabling this check, you + # must install a virus scanner and set the av_scanner option above. + # + deny demime = * + malware = * + message = This message contains a virus ($malware_name). + +<% end -%> +<% if File.exist?("/var/run/spamd.pid") -%> + # Deny if the message looks like spam. Before enabling this check, you + # must install spamassassin and set the spamd_address option above. + # + deny spam = nobody/deferok + message = This message scored $spam_score SpamAssassin points. + +<% end -%> + # Accept the message. + + accept + + + +###################################################################### +# ROUTERS CONFIGURATION # +# Specifies how addresses are handled # +###################################################################### +# THE ORDER IN WHICH THE ROUTERS ARE DEFINED IS IMPORTANT! # +# An address is passed to each router in turn until it is accepted. # +###################################################################### + +begin routers + +# This router handles aliasing using a linearly searched alias file with the +# name /etc/aliases. When this configuration is installed automatically, +# the name gets inserted into this file from whatever is set in Exim's +# build-time configuration. The default path is the traditional /etc/aliases. +# If you install this configuration by hand, you need to specify the correct +# path in the "data" setting below. +# +##### NB You must ensure that the alias file exists. It used to be the case +##### NB that every Unix had that file, because it was the Sendmail default. +##### NB These days, there are systems that don't have it. Your aliases +##### NB file should at least contain an alias for "postmaster". +# +# If any of your aliases expand to pipes or files, you will need to set +# up a user and a group for these deliveries to run under. You can do +# this by uncommenting the "user" option below (changing the user name +# as appropriate) and adding a "group" option if necessary. Alternatively, you +# can specify "user" on the transports that are used. Note that the transports +# listed below are the same as are used for .forward files; you might want +# to set up different ones for pipe and file deliveries from aliases. + +system_aliases: + driver = redirect + domains = +local_domains + allow_fail + allow_defer + data = ${lookup{$local_part}lsearch{/etc/aliases}} +# user = exim + file_transport = address_file + pipe_transport = address_pipe + +<% if File.directory?("/var/lib/mailman") -%> +# This router handles mail for mailman mailing lists. + +mailman: + driver = accept + domains = +local_domains + condition = ${lookup{$local_part@$domain}lsearch{/var/lib/mailman/data/virtual-mailman}{1}{0}} + require_files = /var/lib/mailman/lists/$local_part/config.pck + local_part_suffix = -bounces : -bounces+* : \ + -confirm+* : -join : -leave : \ + -subscribe : -unsubscribe : \ + -owner : -request : -admin + local_part_suffix_optional + transport = mailman + +<% end -%> +# This router handles mail for noreply.openstreetmap.org + +noreply: + driver = accept + domains = noreply.openstreetmap.org + require_files = /etc/exim4/noreply/$local_part + transport = noreply + +<% node[:exim][:routes].each do |name,details| -%> +# This router handles mail for <%= details[:comment] -%>. + +<%= name -%>: +<% if details[:host] -%> + driver = manualroute +<% else -%> + driver = accept +<% end -%> +<% if details[:domains] -%> + domains = <%= details[:domains].join(" : ") %> +<% end -%> +<% if details[:local_parts] -%> + local_parts = <%= details[:local_parts].join(" : ") %> +<% end -%> +<% if details[:host] -%> +<% if details[:host].kind_of?(Array) -%> + route_data = <%= details[:host].join(":") %> byname +<% else -%> + route_data = <%= details[:host] %> byname +<% end -%> + transport = remote_smtp +<% else -%> + transport = <%= name %> +<% end -%> + +<% end -%> + +<% if node[:exim][:smarthost_via] -%> +# This router routes addresses that are not in local domains by +# forwarding them to a smarthost. + +smarthost: + driver = manualroute + domains = ! +local_domains + transport = remote_smtp + route_data = <%= node[:exim][:smarthost_via].gsub(":", "::") -%> byname + same_domain_copy_routing = yes + no_more +<% else -%> +# This router routes addresses that are not in local domains by doing a DNS +# lookup on the domain name. The exclamation mark that appears in "domains = ! +# +local_domains" is a negating operator, that is, it can be read as "not". The +# recipient's domain must not be one of those defined by "domainlist +# local_domains" above for this router to be used. +# +# If the router is used, any domain that resolves to 0.0.0.0 or to a loopback +# interface address (127.0.0.0/8) is treated as if it had no DNS entry. Note +# that 0.0.0.0 is the same as 0.0.0.0/32, which is commonly treated as the +# local host inside the network stack. It is not 0.0.0.0/0, the default route. +# If the DNS lookup fails, no further routers are tried because of the no_more +# setting, and consequently the address is unrouteable. + +dnslookup: + driver = dnslookup + domains = ! +local_domains + transport = remote_smtp + same_domain_copy_routing = yes + ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8 + no_more +<% end -%> + + +###################################################################### +# TRANSPORTS CONFIGURATION # +###################################################################### +# ORDER DOES NOT MATTER # +# Only one appropriate transport is called for each delivery. # +###################################################################### + +# A transport is used only when referenced from a router that successfully +# handles an address. + +begin transports + + +# This transport is used for delivering messages over SMTP connections. + +remote_smtp: + driver = smtp + + +# This transport is used for handling pipe deliveries generated by alias or +# .forward files. If the pipe generates any standard output, it is returned +# to the sender of the message as a delivery error. Set return_fail_output +# instead of return_output if you want this to happen only when the pipe fails +# to complete normally. You can set different transports for aliases and +# forwards if you want to - see the references to address_pipe in the routers +# section above. + +address_pipe: + driver = pipe + return_output + + +# This transport is used for handling deliveries directly to files that are +# generated by aliasing or forwarding. + +address_file: + driver = appendfile + delivery_date_add + envelope_to_add + return_path_add + + +<% if File.directory?("/var/lib/mailman") -%> +# This transport is used for handling deliveries to mailman mailing lists. + +mailman: + driver = pipe + command = /var/lib/mailman/mail/mailman \ + '${if def:local_part_suffix \ + {${sg{$local_part_suffix}{-(\\w+)(\\+.*)?}{\$1}}} \ + {post}}' \ + $local_part + current_directory = /var/lib/mailman + home_directory = /var/lib/mailman + user = list + group = daemon + freeze_exec_fail = true + + +<% end -%> +# This transport handles mail for noreply.openstreetmap.org + +noreply: + driver = autoreply + from = OpenStreetMap + to = $sender_address + subject = Re: $header_subject: + headers = MIME-Version: 1.0\nContent-Type: text/plain; charset=utf-8 + file = /etc/exim4/noreply/$local_part + user = Debian-exim + group = Debian-exim + +<% node[:exim][:routes].each do |name,details| -%> +<% if details[:command] -%> +# This transport handles mail for <%= details[:comment] -%>. + +<%= name -%>: + driver = pipe + command = <%= details[:command] %> + user = <%= details[:user] %> +<% if details[:group] -%> + group = <%= details[:group] %> +<% end -%> + home_directory = <%= details[:home_directory] %> + return_output + + +<% end -%> +<% end -%> + +###################################################################### +# RETRY CONFIGURATION # +###################################################################### + +begin retry + +# This single retry rule applies to all domains and all errors. It specifies +# retries every 15 minutes for 2 hours, then increasing retry intervals, +# starting at 1 hour and increasing each time by a factor of 1.5, up to 16 +# hours, then retries every 6 hours until 4 days have passed since the first +# failed delivery. + +# WARNING: If you do not have any retry rules at all (this section of the +# configuration is non-existent or empty), Exim will not do any retries of +# messages that fail to get delivered at the first attempt. The effect will +# be to treat temporary errors as permanent. Therefore, DO NOT remove this +# retry rule unless you really don't want any retries. + +# Address or Domain Error Retries +# ----------------- ----- ------- + +* * F,2h,15m; G,16h,1h,1.5; F,4d,6h + + + +###################################################################### +# REWRITE CONFIGURATION # +###################################################################### + +# There are no rewriting specifications in this default configuration file. + +begin rewrite + + + +###################################################################### +# AUTHENTICATION CONFIGURATION # +###################################################################### + +# The following authenticators support plaintext username/password +# authentication using the standard PLAIN mechanism and the traditional +# but non-standard LOGIN mechanism, with Exim acting as the server. +# PLAIN and LOGIN are enough to support most MUA software. +# +# These authenticators are not complete: you need to change the +# server_condition settings to specify how passwords are verified. +# They are set up to offer authentication to the client only if the +# connection is encrypted with TLS, so you also need to add support +# for TLS. See the global configuration options section at the start +# of this file for more about TLS. +# +# The default RCPT ACL checks for successful authentication, and will accept +# messages from authenticated users from anywhere on the Internet. + +begin authenticators + +# PLAIN authentication has no server prompts. The client sends its +# credentials in one lump, containing an authorization ID (which we do not +# use), an authentication ID, and a password. The latter two appear as +# $auth2 and $auth3 in the configuration and should be checked against a +# valid username and password. In a real configuration you would typically +# use $auth2 as a lookup key, and compare $auth3 against the result of the +# lookup, perhaps using the crypteq{}{} condition. + +#PLAIN: +# driver = plaintext +# server_set_id = $auth2 +# server_prompts = : +# server_condition = Authentication is not yet configured +# server_advertise_condition = ${if def:tls_cipher } + +# LOGIN authentication has traditional prompts and responses. There is no +# authorization ID in this mechanism, so unlike PLAIN the username and +# password are $auth1 and $auth2. Apart from that you can use the same +# server_condition setting for both authenticators. + +#LOGIN: +# driver = plaintext +# server_set_id = $auth1 +# server_prompts = <| Username: | Password: +# server_condition = Authentication is not yet configured +# server_advertise_condition = ${if def:tls_cipher } + + +###################################################################### +# CONFIGURATION FOR local_scan() # +###################################################################### + +# If you have built Exim to include a local_scan() function that contains +# tables for private options, you can define those options here. Remember to +# uncomment the "begin" line. It is commented by default because it provokes +# an error with Exim binaries that are not built with LOCAL_SCAN_HAS_OPTIONS +# set in the Local/Makefile. + +# begin local_scan + + +# End of Exim configuration file diff --git a/cookbooks/foundation/README.rdoc b/cookbooks/foundation/README.rdoc new file mode 100644 index 000000000..3de2ec7a3 --- /dev/null +++ b/cookbooks/foundation/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/cookbooks/foundation/metadata.rb b/cookbooks/foundation/metadata.rb new file mode 100644 index 000000000..90a2deae6 --- /dev/null +++ b/cookbooks/foundation/metadata.rb @@ -0,0 +1,7 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Installs and configures Foundation services" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "1.0.0" +depends "wordpress" diff --git a/cookbooks/foundation/recipes/default.rb b/cookbooks/foundation/recipes/default.rb new file mode 100644 index 000000000..7b1fa1d05 --- /dev/null +++ b/cookbooks/foundation/recipes/default.rb @@ -0,0 +1,50 @@ +# +# Cookbook Name:: foundation +# Recipe:: default +# +# Copyright 2013, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include_recipe "wordpress" + +passwords = data_bag_item("foundation", "passwords") + +wordpress_site "blog.osmfoundation.org" do + database_name "osmf-blog" + database_user "osmf-blog-user" + database_password passwords["osmf-blog-user"] +end + +wordpress_theme "osmf-blog-theme" do + site "blog.osmfoundation.org" + repository "http://svn.openstreetmap.org/extensions/wordpress/osmf-blog-theme" +end + +wordpress_plugin "google-analytics-for-wordpress" do + site "blog.osmfoundation.org" +end + +wordpress_plugin "google-sitemap-generator" do + site "blog.osmfoundation.org" +end + +wordpress_plugin "shareadraft" do + site "blog.osmfoundation.org" +end + +wordpress_plugin "sitepress-multilingual-cms" do + site "blog.osmfoundation.org" + source "plugins/sitepress-multilingual-cms" +end diff --git a/cookbooks/git/README.rdoc b/cookbooks/git/README.rdoc new file mode 100644 index 000000000..3de2ec7a3 --- /dev/null +++ b/cookbooks/git/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/cookbooks/git/metadata.rb b/cookbooks/git/metadata.rb new file mode 100644 index 000000000..1b30312ad --- /dev/null +++ b/cookbooks/git/metadata.rb @@ -0,0 +1,21 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Installs and configures git" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "1.0.0" +depends "networking" +depends "apache" + +attribute "git", + :display_name => "Git", + :description => "Hash of Git attributes", + :type => "hash" + +attribute "git/host", + :display_name => "Server Hostname", + :description => "Hostname to use for Git server" + +attribute "git/directory", + :display_name => "Repository Directory", + :description => "Directory to use for Git server repositories" diff --git a/cookbooks/git/recipes/default.rb b/cookbooks/git/recipes/default.rb new file mode 100644 index 000000000..63dea752f --- /dev/null +++ b/cookbooks/git/recipes/default.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: git +# Recipe:: default +# +# Copyright 2011, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package "git-core" diff --git a/cookbooks/git/recipes/server.rb b/cookbooks/git/recipes/server.rb new file mode 100644 index 000000000..c3382a2cf --- /dev/null +++ b/cookbooks/git/recipes/server.rb @@ -0,0 +1,73 @@ +# +# Cookbook Name:: git +# Recipe:: server +# +# Copyright 2011, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include_recipe "apache" +include_recipe "networking" + +package "gitweb" + +apache_module "rewrite" + +git_directory = node[:git][:directory] + +directory git_directory do + owner "git" + group "git" + mode 02775 +end + +template "/etc/gitweb.conf" do + source "gitweb.conf.erb" + owner "root" + group "root" + mode 0644 +end + +apache_site node[:git][:host] do + template "apache.erb" + directory git_directory +end + +firewall_rule "accept-git" do + action :accept + source "net" + dest "fw" + proto "tcp:syn" + dest_ports "git" + source_ports "1024:" +end + +Dir.new(git_directory).select { |name| name =~ /\.git$/ }.each do |repository| + template "#{git_directory}/#{repository}/hooks/post-update" do + source "post-update.erb" + owner "root" + group "git" + mode 0755 + end + + if repository != "dns.git" + template "#{git_directory}/#{repository}/hooks/post-receive" do + source "post-receive.erb" + owner "root" + group "git" + mode 0755 + variables :repository => "#{git_directory}/#{repository}" + end + end +end diff --git a/cookbooks/git/templates/default/apache.erb b/cookbooks/git/templates/default/apache.erb new file mode 100644 index 000000000..e9cb8b701 --- /dev/null +++ b/cookbooks/git/templates/default/apache.erb @@ -0,0 +1,18 @@ +# DO NOT EDIT - This file is being maintained by Chef + + + ServerName <%= @name %> + + CustomLog /var/log/apache2/<%= @name %>-access.log combined + ErrorLog /var/log/apache2/<%= @name %>-error.log + + DocumentRoot <%= @directory %> + HeaderName HEADER + Alias /gitweb /usr/share/gitweb + Alias /git /var/cache/git + ScriptAlias /gitweb.cgi /usr/lib/cgi-bin/gitweb.cgi + + RewriteEngine On + RewriteRule ^/$ /gitweb.cgi%{REQUEST_URI} [L,PT] + RewriteRule ^/(.*\.git/(?!/?(HEAD|info|objects|refs)).*)?$ /gitweb.cgi%{REQUEST_URI} [L,PT] + diff --git a/cookbooks/git/templates/default/gitweb.conf.erb b/cookbooks/git/templates/default/gitweb.conf.erb new file mode 100644 index 000000000..b98c15ae5 --- /dev/null +++ b/cookbooks/git/templates/default/gitweb.conf.erb @@ -0,0 +1,34 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# path to git projects (.git) +$projectroot = "<%= node[:git][:directory] %>"; + +# directory to use for temp files +$git_temp = "/tmp"; + +# target of the home link on top of all pages +#$home_link = $my_uri || "/"; + +# html text to include at home page +$home_text = "indextext.html"; + +# file with project list; by default, simply scan the projectroot dir. +$projects_list = $projectroot; + +# stylesheet to use +$stylesheet = "/gitweb/static/gitweb.css"; + +# logo to use +$logo = "/gitweb/static/git-logo.png"; + +# the 'favicon' +$favicon = "/gitweb/static/git-favicon.png"; + +# URI of gitweb.js (JavaScript code for gitweb) +our $javascript = "/gitweb/static/gitweb.js"; + +# use pretty urls +$feature{'pathinfo'}{'default'} = [1]; + +# define roots for cloning +@git_base_url_list = qw(git://<%= node[:git][:host] %>); diff --git a/cookbooks/git/templates/default/post-receive.erb b/cookbooks/git/templates/default/post-receive.erb new file mode 100644 index 000000000..52075a017 --- /dev/null +++ b/cookbooks/git/templates/default/post-receive.erb @@ -0,0 +1,14 @@ +#!/bin/zsh + +# DO NOT EDIT - This file is being maintained by Chef + +while read oldrev newrev refname +do + if [[ "$refname" = "refs/heads/master" ]] + then + for rev in $(git rev-list ${newrev} ^${oldrev}) + do + sudo -u trac /usr/bin/trac-admin /var/lib/trac changeset added "<%= @repository %>" "${rev}" + done + fi +done diff --git a/cookbooks/git/templates/default/post-update.erb b/cookbooks/git/templates/default/post-update.erb new file mode 100644 index 000000000..40ebafab7 --- /dev/null +++ b/cookbooks/git/templates/default/post-update.erb @@ -0,0 +1,5 @@ +#!/bin/sh + +# DO NOT EDIT - This file is being maintained by Chef + +exec git-update-server-info diff --git a/cookbooks/mailman/README.rdoc b/cookbooks/mailman/README.rdoc new file mode 100644 index 000000000..3de2ec7a3 --- /dev/null +++ b/cookbooks/mailman/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/cookbooks/mailman/metadata.rb b/cookbooks/mailman/metadata.rb new file mode 100644 index 000000000..2cee98b9c --- /dev/null +++ b/cookbooks/mailman/metadata.rb @@ -0,0 +1,7 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Installs and configures mailman" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "1.0.0" +depends "apache" diff --git a/cookbooks/mailman/recipes/default.rb b/cookbooks/mailman/recipes/default.rb new file mode 100644 index 000000000..05f1997ab --- /dev/null +++ b/cookbooks/mailman/recipes/default.rb @@ -0,0 +1,34 @@ +# +# Cookbook Name:: mailman +# Recipe:: default +# +# Copyright 2011, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include_recipe "apache" + +package "mailman" + +service "mailman" do + action [ :enable, :start ] + supports :restart => true, :reload => true +end + +apache_module "expires" +apache_module "rewrite" + +apache_site "lists.openstreetmap.org" do + template "apache.erb" +end diff --git a/cookbooks/mailman/templates/default/apache.erb b/cookbooks/mailman/templates/default/apache.erb new file mode 100644 index 000000000..396bcd56d --- /dev/null +++ b/cookbooks/mailman/templates/default/apache.erb @@ -0,0 +1,49 @@ +# DO NOT EDIT - This file is being maintained by Chef + + + ServerName <%= @name %> + ServerAdmin postmaster@openstreetmap.org + ServerSignature On + + CustomLog /var/log/apache2/<%= @name %>-access.log combined + ErrorLog /var/log/apache2/<%= @name %>-error.log + LogLevel warn + + AddDefaultCharset off + + DocumentRoot <%= @directory %> + + RewriteEngine on + + RewriteCond %{HTTP_REFERER} www\.mailbait\.info + RewriteRule . - [F,L] + + RedirectMatch ^/$ /listinfo + RedirectMatch ^/cgi-bin/mailman/(.*)$ /$1 + + + Options Indexes FollowSymLinks + AllowOverride None + + + Alias /pipermail/ /var/lib/mailman/archives/public/ + Alias /images/ /usr/share/images/mailman/ + + ScriptAlias /admin /usr/lib/cgi-bin/mailman/admin + ScriptAlias /admindb /usr/lib/cgi-bin/mailman/admindb + ScriptAlias /confirm /usr/lib/cgi-bin/mailman/confirm + ScriptAlias /create /usr/lib/cgi-bin/mailman/create + ScriptAlias /edithtml /usr/lib/cgi-bin/mailman/edithtml + ScriptAlias /listinfo /usr/lib/cgi-bin/mailman/listinfo + ScriptAlias /options /usr/lib/cgi-bin/mailman/options + ScriptAlias /private /usr/lib/cgi-bin/mailman/private + ScriptAlias /rmlist /usr/lib/cgi-bin/mailman/rmlist + ScriptAlias /roster /usr/lib/cgi-bin/mailman/roster + ScriptAlias /subscribe /usr/lib/cgi-bin/mailman/subscribe + ScriptAlias /mailman/ /usr/lib/cgi-bin/mailman/ + + + ExpiresActive On + ExpiresDefault "access plus 180 days" + + diff --git a/cookbooks/mysql/README.rdoc b/cookbooks/mysql/README.rdoc new file mode 100644 index 000000000..3de2ec7a3 --- /dev/null +++ b/cookbooks/mysql/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/cookbooks/mysql/attributes/default.rb b/cookbooks/mysql/attributes/default.rb new file mode 100644 index 000000000..e69de29bb diff --git a/cookbooks/mysql/libraries/mysql.rb b/cookbooks/mysql/libraries/mysql.rb new file mode 100644 index 000000000..c0da28f33 --- /dev/null +++ b/cookbooks/mysql/libraries/mysql.rb @@ -0,0 +1,146 @@ +require "chef/mixin/command" +require "rexml/document" + +class Chef + class MySQL + include Chef::Mixin::Command + + USER_PRIVILEGES = [ + :select, :insert, :update, :delete, :create, :drop, :reload, + :shutdown, :process, :file, :grant, :references, :index, :alter, + :show_db, :super, :create_tmp_table, :lock_tables, :execute, + :repl_slave, :repl_client, :create_view, :show_view, :create_routine, + :alter_routine, :create_user, :event, :trigger, :create_tablespace + ] + + DATABASE_PRIVILEGES = [ + :select, :insert, :update, :delete, :create, :drop, :grant, + :references, :index, :alter, :create_tmp_table, :lock_tables, + :create_view, :show_view, :create_routine, :alter_routine, + :execute, :event, :trigger + ] + + def execute(options) + # Create argument array + args = [] + + # Work out how to authenticate + if options[:user] + args.push("--username=#{options[:user]}") + args.push("--password=#{options[:password]}") if options[:password] + else + args.push("--defaults-file=/etc/mysql/debian.cnf") + end + + # Build the other arguments + args.push("--execute=\"#{options[:command]}\"") if options[:command] + + # Get the database to use + database = options[:database] || "mysql" + + # Build the command to run + command = "/usr/bin/mysql #{args.join(' ')} #{database}" + + # Escape backticks in the command + command.gsub!(/`/, "\\\\`") + + # Run the command + run_command(:command => command, :user => "root", :group => "root") + end + + def query(sql, options = {}) + # Get the database to use + database = options[:database] || "mysql" + + # Construct the command string + command = "/usr/bin/mysql --defaults-file=/etc/mysql/debian.cnf --xml --execute='#{sql}' #{database}" + + # Run the query + status, stdout, stderr = output_of_command(command, :user => "root", :group => "root") + handle_command_failures(status, "STDOUT: #{stdout}\nSTDERR: #{stderr}", :output_on_failure => true) + + # Parse the output + document = REXML::Document.new(stdout) + + # Create + records = [] + + # Loop over the rows in the result set + document.root.each_element("/resultset/row") do |row| + # Create a record + record = {} + + # Loop over the fields, adding them to the record + row.each_element("field") do |field| + name = field.attributes["name"].downcase + value = field.text + + record[name.to_sym] = value + end + + # Add the record to the record list + records << record + end + + # Return the record list + records + end + + def users + @users ||= query("SELECT * FROM user").inject({}) do |users,user| + name = "'#{user[:user]}'@'#{user[:host]}'" + + users[name] = USER_PRIVILEGES.inject({}) do |privileges,privilege| + privileges[privilege] = user["#{privilege}_priv".to_sym] == "Y" + privileges + end + + users + end + end + + def databases + @databases ||= query("SHOW databases").inject({}) do |databases,database| + databases[database[:database]] = { + :permissions => {} + } + databases + end + + query("SELECT * FROM db").each do |record| + if database = @databases[record[:db]] + user = "'#{record[:user]}'@'#{record[:host]}'" + + database[:permissions][user] = DATABASE_PRIVILEGES.inject([]) do |privileges,privilege| + privileges << privilege if record["#{privilege}_priv".to_sym] == "Y" + privileges + end + end + end + + @databases + end + + def canonicalise_user(user) + local, host = user.split("@") + + host = "%" unless host + + local = "'#{local}'" unless local =~ /^'.*'$/ + host = "'#{host}'" unless host =~ /^'.*'$/ + + "#{local}@#{host}" + end + + def privilege_name(privilege) + case privilege + when :grant + "GRANT OPTION" + when :create_tmp_table + "CREATE TEMPORARY TABLES" + else + privilege.to_s.upcase.tr("_", " ") + end + end + end +end diff --git a/cookbooks/mysql/metadata.rb b/cookbooks/mysql/metadata.rb new file mode 100644 index 000000000..f77dbf81c --- /dev/null +++ b/cookbooks/mysql/metadata.rb @@ -0,0 +1,11 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Installs and configures mysql" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "1.0.0" + +attribute "mysql", + :display_name => "MySQL", + :description => "Hash of MySQL configuration details", + :type => "hash" diff --git a/cookbooks/mysql/providers/database.rb b/cookbooks/mysql/providers/database.rb new file mode 100644 index 000000000..29b38f70e --- /dev/null +++ b/cookbooks/mysql/providers/database.rb @@ -0,0 +1,87 @@ +# +# Cookbook Name:: mysql +# Provider:: mysql_database +# +# Copyright 2013, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +def load_current_resource + @mysql = Chef::MySQL.new + + @current_resource = Chef::Resource::MysqlDatabase.new(new_resource.name) + @current_resource.database(new_resource.database) + if mysql_database = @mysql.databases[@current_resource.database] + @current_resource.permissions(mysql_database[:permissions]) + end + @current_resource +end + +action :create do + unless @mysql.databases.include?(new_resource.database) + converge_by("create #{new_resource}") do + Chef::Log.info("Creating #{new_resource}") + @mysql.execute(:command => "CREATE DATABASE `#{new_resource.database}`") + end + end + + new_permissions = Hash[new_resource.permissions.collect do |user,privileges| + [@mysql.canonicalise_user(user), privileges] + end] + + @current_resource.permissions.each do |user,privileges| + unless new_permissions[user] + converge_by("revoke all for #{user} on #{new_resource}") do + Chef::Log.info("Revoking all for #{user} on #{new_resource}") + @mysql.execute(:command => "REVOKE ALL ON `#{new_resource.database}`.* FROM #{user}") + end + end + end + + new_permissions.each do |user,new_privileges| + current_privileges = @current_resource.permissions[user] || {} + new_privileges = Array(new_privileges) + + if new_privileges.include?(:all) + new_privileges |= (Chef::MySQL::DATABASE_PRIVILEGES - [:grant]) + end + + Chef::MySQL::DATABASE_PRIVILEGES.each do |privilege| + if new_privileges.include?(privilege) + unless current_privileges.include?(privilege) + converge_by("grant #{privilege} for #{user} on mysql database #{new_resource}") do + Chef::Log.info("Granting #{privilege} for #{user} on mysql database #{new_resource}") + @mysql.execute(:command => "GRANT #{@mysql.privilege_name(privilege)} ON `#{new_resource.database}`.* TO #{user}") + end + end + else + if current_privileges.include?(privilege) + converge_by("revoke #{privilege} for #{user} on #{new_resource}") do + Chef::Log.info("Revoking #{privilege} for #{user} on #{new_resource}") + @mysql.execute(:command => "REVOKE #{@mysql.privilege_name(privilege)} ON `#{new_resource.database}`.* FROM #{user}") + end + end + end + end + end +end + +action :drop do + if @mysql.databases.include?(new_resource.database) + converge_by("drop #{new_resource}") do + Chef::Log.info("Dropping #{new_resource}") + @mysql.execute(:command => "DROP DATABASE `#{new_resource.database}`") + end + end +end diff --git a/cookbooks/mysql/providers/user.rb b/cookbooks/mysql/providers/user.rb new file mode 100644 index 000000000..e027b4f5c --- /dev/null +++ b/cookbooks/mysql/providers/user.rb @@ -0,0 +1,70 @@ +# +# Cookbook Name:: mysql +# Provider:: mysql_user +# +# Copyright 2013, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +def load_current_resource + @mysql = Chef::MySQL.new + + @current_resource = Chef::Resource::MysqlUser.new(new_resource.name) + @current_resource.user(new_resource.user) + if mysql_user = @mysql.users[@current_resource.user] + Chef::MySQL::USER_PRIVILEGES.each do |privilege| + @current_resource.send(privilege, mysql_user[privilege]) + end + end + @current_resource +end + +action :create do + user = @mysql.canonicalise_user(new_resource.user) + password = new_resource.password ? "IDENTIFIED BY '#{new_resource.password}'" : "" + + unless @mysql.users.include?(user) + converge_by("create #{new_resource}") do + Chef::Log.info("Creating #{new_resource}") + @mysql.execute(:command => "CREATE USER #{user} #{password}") + end + end + + Chef::MySQL::USER_PRIVILEGES.each do |privilege| + if new_resource.send(privilege) != @current_resource.send(privilege) + if new_resource.send(privilege) + converge_by("grant #{privilege} for #{new_resource}") do + Chef::Log.info("Granting #{privilege} for #{new_resource}") + @mysql.execute(:command => "GRANT #{@mysql.privilege_name(privilege)} ON *.* TO #{user}") + end + else + converge_by("revoke #{privilege} for #{new_resource}") do + Chef::Log.info("Revoking #{privilege} for #{new_resource}") + @mysql.execute(:command => "REVOKE #{@mysql.privilege_name(privilege)} ON *.* FROM #{user}") + end + end + end + end +end + +action :drop do + user = @mysql.canonicalise_user(new_resource.user) + + if @mysql.users.include?(user) + converge_by("drop #{new_resource}") do + Chef::Log.info("Dropping #{new_resource}") + @mysql.execute(:command => "DROP USER #{user}") + end + end +end diff --git a/cookbooks/mysql/recipes/default.rb b/cookbooks/mysql/recipes/default.rb new file mode 100644 index 000000000..d56fbdc04 --- /dev/null +++ b/cookbooks/mysql/recipes/default.rb @@ -0,0 +1,129 @@ +# +# Cookbook Name:: mysql +# Recipe:: default +# +# Copyright 2013, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package "mysql-server" +package "mysql-client" + +service "mysql" do + action [ :enable, :start ] + supports :status => true, :restart => true, :reload => true +end + +template "/etc/mysql/conf.d/chef.cnf" do + source "my.cnf.erb" + owner "root" + group "root" + mode 0644 + notifies :reload, resources(:service => "mysql") +end + +package "libdbd-mysql-perl" +package "libcache-cache-perl" + +munin_plugin "mysql_bin_relay_log" do + target "mysql_" +end + +munin_plugin "mysql_commands" do + target "mysql_" +end + +munin_plugin "mysql_connections" do + target "mysql_" +end + +munin_plugin "mysql_files_tables" do + target "mysql_" +end + +munin_plugin "mysql_innodb_bpool" do + target "mysql_" +end + +munin_plugin "mysql_innodb_bpool_act" do + target "mysql_" +end + +munin_plugin "mysql_innodb_insert_buf" do + target "mysql_" +end + +munin_plugin "mysql_innodb_io" do + target "mysql_" +end + +munin_plugin "mysql_innodb_io_pend" do + target "mysql_" +end + +munin_plugin "mysql_innodb_log" do + target "mysql_" +end + +munin_plugin "mysql_innodb_rows" do + target "mysql_" +end + +munin_plugin "mysql_innodb_semaphores" do + target "mysql_" +end + +munin_plugin "mysql_innodb_tnx" do + target "mysql_" +end + +munin_plugin "mysql_myisam_indexes" do + target "mysql_" +end + +munin_plugin "mysql_network_traffic" do + target "mysql_" +end + +munin_plugin "mysql_qcache" do + target "mysql_" +end + +munin_plugin "mysql_qcache_mem" do + target "mysql_" +end + +munin_plugin "mysql_replication" do + target "mysql_" +end + +munin_plugin "mysql_select_types" do + target "mysql_" +end + +munin_plugin "mysql_slow" do + target "mysql_" +end + +munin_plugin "mysql_sorts" do + target "mysql_" +end + +munin_plugin "mysql_table_locks" do + target "mysql_" +end + +munin_plugin "mysql_tmp_tables" do + target "mysql_" +end diff --git a/cookbooks/mysql/resources/database.rb b/cookbooks/mysql/resources/database.rb new file mode 100644 index 000000000..60236d8dd --- /dev/null +++ b/cookbooks/mysql/resources/database.rb @@ -0,0 +1,24 @@ +# +# Cookbook Name:: mysql +# Resource:: mysql_database +# +# Copyright 2013, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +actions :create, :drop +default_action :create + +attribute :database, :kind_of => String, :name_attribute => true +attribute :permissions, :kind_of => Hash, :default => {} diff --git a/cookbooks/mysql/resources/user.rb b/cookbooks/mysql/resources/user.rb new file mode 100644 index 000000000..45436c703 --- /dev/null +++ b/cookbooks/mysql/resources/user.rb @@ -0,0 +1,28 @@ +# +# Cookbook Name:: mysql +# Resource:: mysql_user +# +# Copyright 2012, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +actions :create, :drop +default_action :create + +attribute :user, :kind_of => String, :name_attribute => true +attribute :password, :kind_of => String + +Chef::MySQL::USER_PRIVILEGES.each do |privilege| + attribute privilege, :default => false +end diff --git a/cookbooks/mysql/templates/default/my.cnf.erb b/cookbooks/mysql/templates/default/my.cnf.erb new file mode 100644 index 000000000..a03aebc8d --- /dev/null +++ b/cookbooks/mysql/templates/default/my.cnf.erb @@ -0,0 +1 @@ +# DO NOT EDIT - This file is being maintained by Chef diff --git a/cookbooks/networking/README.md b/cookbooks/networking/README.md new file mode 100644 index 000000000..6b087690a --- /dev/null +++ b/cookbooks/networking/README.md @@ -0,0 +1,57 @@ +DESCRIPTION +=========== + +Configures networking. + +USAGE +===== + +Set the networking attributes in a role, for example from my base.rb: + + :networking => { + :nameservers => [ "10.13.37.120", "10.13.37.40" ], + :search => [ "int.example.org". "example.org" ] + } + +The resulting /etc/resolv.conf will look like: + + search int.example.org example.org + nameserver 10.13.37.120 + nameserver 10.13.37.40 + +LICENSE AND AUTHOR +================== + +Author:: OpenStreetMap Administrators () + +Copyright 2010, OpenStreetMap Foundation. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Based on resolver cookbook: + +Author:: Joshua Timberman () + +Copyright 2009, Opscode, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/cookbooks/networking/attributes/default.rb b/cookbooks/networking/attributes/default.rb new file mode 100644 index 000000000..9a03eb3fa --- /dev/null +++ b/cookbooks/networking/attributes/default.rb @@ -0,0 +1,3 @@ +default[:networking][:interfaces] = { } +default[:networking][:nameservers] = [ ] +default[:networking][:search] = [ ] diff --git a/cookbooks/networking/definitions/firewall_rule.rb b/cookbooks/networking/definitions/firewall_rule.rb new file mode 100644 index 000000000..44d141860 --- /dev/null +++ b/cookbooks/networking/definitions/firewall_rule.rb @@ -0,0 +1,52 @@ +# +# Cookbook Name:: networking +# Definition:: firewall_rule +# +# Copyright 2011, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +define :firewall_rule, :action => :accept do + inet = nil + inet6 = nil + + begin + inet = resources(:template => "/etc/shorewall/rules") + inet6 = resources(:template => "/etc/shorewall6/rules") + rescue + end + + rule = Hash[ + :action => params[:action].to_s.upcase, + :source => params[:source], + :dest => params[:dest], + :proto => params[:proto], + :dest_ports => params[:dest_ports] || "-", + :source_ports => params[:source_ports] || "-", + :rate_limit => params[:rate_limit] || "-" + ] + + if params[:family].nil? + inet.variables[:rules] << rule unless inet.nil? + inet6.variables[:rules] << rule unless inet6.nil? + elsif params[:family].to_s == "inet" + inet.variables[:rules] << rule unless inet.nil? + elsif params[:family].to_s == "inet6" + inet6.variables[:rules] << rule unless inet6.nil? + else + log "Unsupported network family" do + level :error + end + end +end diff --git a/cookbooks/networking/libraries/interfaces.rb b/cookbooks/networking/libraries/interfaces.rb new file mode 100644 index 000000000..cc9c11a23 --- /dev/null +++ b/cookbooks/networking/libraries/interfaces.rb @@ -0,0 +1,24 @@ +class Chef + class Node + def interfaces(options = {}, &block) + interfaces = [] + + networking = construct_attributes[:networking] || {} + networking_interfaces = networking[:interfaces] || [] + + networking_interfaces.each do |name,interface| + if options[:role].nil? or interface[:role].to_s == options[:role].to_s + if options[:family].nil? or interface[:family].to_s == options[:family].to_s + if block.nil? + interfaces << interface + else + block.call(interface) + end + end + end + end + + interfaces + end + end +end diff --git a/cookbooks/networking/libraries/ipaddresses.rb b/cookbooks/networking/libraries/ipaddresses.rb new file mode 100644 index 000000000..811c81884 --- /dev/null +++ b/cookbooks/networking/libraries/ipaddresses.rb @@ -0,0 +1,25 @@ +class Chef + class Node + def ipaddresses(options = {}, &block) + addresses = [] + + interfaces(options).each do |interface| + if block.nil? + addresses << interface[:address] + else + block.call(interface[:address]) + end + end + + addresses + end + + def internal_ipaddress + return ipaddresses(:role => :internal).first + end + + def external_ipaddress + return ipaddresses(:role => :external).first + end + end +end diff --git a/cookbooks/networking/metadata.rb b/cookbooks/networking/metadata.rb new file mode 100644 index 000000000..df97c45ab --- /dev/null +++ b/cookbooks/networking/metadata.rb @@ -0,0 +1,25 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Configures networking" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) +version "1.0.0" +recipe "networking", "Configures networking via attributes" +supports "ubuntu" + +attribute "networking", + :display_name => "Networking", + :description => "Hash of networking attributes", + :type => "hash" + +attribute "networking/search", + :display_name => "Resolver Search Path", + :description => "List of domains to search", + :default => "domain" + +attribute "networking/nameservers", + :display_name => "Nameservers", + :description => "List of nameservers to use", + :type => "array", + :default => [""] + diff --git a/cookbooks/networking/recipes/default.rb b/cookbooks/networking/recipes/default.rb new file mode 100644 index 000000000..f68522bcf --- /dev/null +++ b/cookbooks/networking/recipes/default.rb @@ -0,0 +1,330 @@ +# +# Cookbook Name:: networking +# Recipe:: default +# +# Copyright 2010, OpenStreetMap Foundation. +# Copyright 2009, Opscode, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# = Requires +# * node[:networking][:nameservers] + +require "ipaddr" + +node[:networking][:interfaces].each do |name,interface| + if interface[:role] and role = node[:networking][:roles][interface[:role]] + if role[interface[:family]] + node.default[:networking][:interfaces][name][:prefix] = role[interface[:family]][:prefix] + node.default[:networking][:interfaces][name][:gateway] = role[interface[:family]][:gateway] + end + + node.default[:networking][:interfaces][name][:metric] = role[:metric] + node.default[:networking][:interfaces][name][:zone] = role[:zone] + end + + prefix = node[:networking][:interfaces][name][:prefix] + + node.default[:networking][:interfaces][name][:netmask] = (~IPAddr.new(interface[:address]).mask(0)).mask(prefix) + node.default[:networking][:interfaces][name][:network] = IPAddr.new(interface[:address]).mask(prefix) +end + +template "/etc/network/interfaces" do + source "interfaces.erb" + owner "root" + group "root" + mode 0644 +end + +execute "hostname" do + action :nothing + command "/bin/hostname -F /etc/hostname" +end + +template "/etc/hostname" do + source "hostname.erb" + owner "root" + group "root" + mode 0644 + notifies :run, resources(:execute => "hostname") +end + +template "/etc/hosts" do + source "hosts.erb" + owner "root" + group "root" + mode 0644 +end + +link "/etc/resolv.conf" do + action :delete + link_type :symbolic + to "/run/resolvconf/resolv.conf" + only_if { File.symlink?("/etc/resolv.conf") } +end + +template "/etc/resolv.conf" do + source "resolv.conf.erb" + owner "root" + group "root" + mode 0644 +end + +node.interfaces(:role => :internal) do |interface| + if interface[:gateway] and interface[:gateway] != interface[:address] + search(:node, "networking_interfaces*address:#{interface[:gateway]}") do |gateway| + if gateway[:openvpn] + gateway[:openvpn][:tunnels].each_value do |tunnel| + if tunnel[:peer][:address] + route tunnel[:peer][:address] do + netmask "255.255.255.255" + gateway interface[:gateway] + device interface[:interface] + end + end + + if tunnel[:peer][:networks] + tunnel[:peer][:networks].each do |network| + route network[:address] do + netmask network[:netmask] + gateway interface[:gateway] + device interface[:interface] + end + end + end + end + end + end + end +end + +zones = Hash.new + +search(:node, "networking:interfaces").collect do |n| + if n[:fqdn] != node[:fqdn] + n.interfaces.each do |interface| + if interface[:role] == "external" and interface[:zone] + zones[interface[:zone]] ||= Hash.new + zones[interface[:zone]][interface[:family]] ||= Array.new + zones[interface[:zone]][interface[:family]] << interface[:address] + end + end + end +end + +package "shorewall" + +service "shorewall" do + action [ :enable, :start ] + supports :restart => true + status_command "shorewall status" +end + +template "/etc/default/shorewall" do + source "shorewall-default.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "shorewall") +end + +template "/etc/shorewall/shorewall.conf" do + source "shorewall.conf.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "shorewall") +end + +template "/etc/shorewall/zones" do + source "shorewall-zones.erb" + owner "root" + group "root" + mode 0644 + variables :type => "ipv4" + notifies :restart, resources(:service => "shorewall") +end + +template "/etc/shorewall/interfaces" do + source "shorewall-interfaces.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "shorewall") +end + +template "/etc/shorewall/hosts" do + source "shorewall-hosts.erb" + owner "root" + group "root" + mode 0644 + variables :zones => zones + notifies :restart, resources(:service => "shorewall") +end + +template "/etc/shorewall/policy" do + source "shorewall-policy.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "shorewall") +end + +template "/etc/shorewall/rules" do + source "shorewall-rules.erb" + owner "root" + group "root" + mode 0644 + variables :family => "inet", :rules => [] + notifies :restart, resources(:service => "shorewall") +end + +firewall_rule "limit-icmp-echo" do + action :accept + family :inet + source "net" + dest "fw" + proto "icmp" + dest_ports "echo-request" + if node[:lsb][:release].to_f >= 10.04 + rate_limit "s:1/sec:5" + else + rate_limit "1/sec:5" + end +end + +[ "ucl", "ic", "bm" ].each do |zone| + firewall_rule "accept-openvpn-#{zone}" do + action :accept + family :inet + source zone + dest "fw" + proto "udp" + dest_ports "1194:1196" + source_ports "1194:1196" + end +end + +if node[:roles].include?("gateway") + template "/etc/shorewall/masq" do + source "shorewall-masq.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "shorewall") + end +else + file "/etc/shorewall/masq" do + action :delete + notifies :restart, resources(:service => "shorewall") + end +end + +if not node.interfaces(:family => :inet6).empty? + package "shorewall6" + + service "shorewall6" do + action [ :enable, :start ] + supports :restart => true + status_command "shorewall6 status" + end + + template "/etc/default/shorewall6" do + source "shorewall-default.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "shorewall6") + end + + template "/etc/shorewall6/shorewall6.conf" do + source "shorewall6.conf.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "shorewall6") + end + + template "/etc/shorewall6/zones" do + source "shorewall-zones.erb" + owner "root" + group "root" + mode 0644 + variables :type => "ipv6" + notifies :restart, resources(:service => "shorewall6") + end + + template "/etc/shorewall6/interfaces" do + source "shorewall6-interfaces.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "shorewall6") + end + + template "/etc/shorewall6/hosts" do + source "shorewall6-hosts.erb" + owner "root" + group "root" + mode 0644 + variables :zones => zones + notifies :restart, resources(:service => "shorewall6") + end + + template "/etc/shorewall6/policy" do + source "shorewall-policy.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "shorewall6") + end + + template "/etc/shorewall6/rules" do + source "shorewall-rules.erb" + owner "root" + group "root" + mode 0644 + variables :family => "inet6", :rules => [] + notifies :restart, resources(:service => "shorewall6") + end + + firewall_rule "limit-icmp6-echo" do + action :accept + family :inet6 + source "net" + dest "fw" + proto "ipv6-icmp" + dest_ports "echo-request" + if node[:lsb][:release].to_f >= 10.04 + rate_limit "s:1/sec:5" + else + rate_limit "1/sec:5" + end + end +end + +firewall_rule "accept-http" do + action :accept + source "net" + dest "fw" + proto "tcp:syn" + dest_ports "http" +end + +firewall_rule "accept-https" do + action :accept + source "net" + dest "fw" + proto "tcp:syn" + dest_ports "https" +end diff --git a/cookbooks/networking/templates/default/hostname.erb b/cookbooks/networking/templates/default/hostname.erb new file mode 100644 index 000000000..1e80c0c06 --- /dev/null +++ b/cookbooks/networking/templates/default/hostname.erb @@ -0,0 +1 @@ +<%= node[:hostname] %>.openstreetmap.org diff --git a/cookbooks/networking/templates/default/hosts.erb b/cookbooks/networking/templates/default/hosts.erb new file mode 100644 index 000000000..decae8682 --- /dev/null +++ b/cookbooks/networking/templates/default/hosts.erb @@ -0,0 +1,16 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# This machine +127.0.1.1 <%= node[:hostname] -%>.openstreetmap.org <%= node[:hostname] %> + +# IPv4 loopback address +127.0.0.1 localhost ip4-localhost ip4-loopback + +# IPv6 loopback address +::1 localhost ip6-localhost ip6-loopback + +# Other useful IPv6 addresses +fe00::0 ip6-localnet +ff00::0 ip6-mcastprefix +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters diff --git a/cookbooks/networking/templates/default/interfaces.erb b/cookbooks/networking/templates/default/interfaces.erb new file mode 100644 index 000000000..89fc316eb --- /dev/null +++ b/cookbooks/networking/templates/default/interfaces.erb @@ -0,0 +1,35 @@ +# DO NOT EDIT - This file is being maintained by Chef + +iface lo inet loopback +<% node[:networking][:interfaces].each do |name,interface| -%> + +iface <%= interface[:interface] %> <%= interface[:family] %> static + address <%= interface[:address] %> +<% if interface[:family] == "inet" -%> + netmask <%= interface[:netmask] %> +<% elsif interface[:family] == "inet6" -%> + netmask <%= interface[:prefix] %> +<% end -%> +<% if interface[:hwaddress] -%> + hwaddress <%= interface[:hwaddress] %> +<% end -%> +<% if interface[:gateway] -%> +<% if interface[:network].include?(interface[:gateway]) or IPAddr.new("fe80::/64").include?(interface[:gateway]) -%> + gateway <%= interface[:gateway] %> + metric <%= interface[:metric] %> +<% else -%> + post-up /sbin/ip -f <%= interface[:family] %> route add <%= interface[:gateway] %> dev <%= interface[:interface] %> + post-up /sbin/ip -f <%= interface[:family] %> route add default metric <%= interface[:metric] %> via <%= interface[:gateway] %> + pre-down /sbin/ip -f <%= interface[:family] %> route del default metric <%= interface[:metric] %> via <%= interface[:gateway] %> + pre-down /sbin/ip -f <%= interface[:family] %> route del <%= interface[:gateway] %> dev <%= interface[:interface] %> +<% end -%> +<% end -%> +<% if interface[:mtu] -%> + mtu <%= interface[:mtu] %> +<% end -%> +<% if interface[:family] == "inet6" -%> + autoconf 0 +<% end -%> +<% end -%> + +auto lo <%= node[:networking][:interfaces].collect { |n,i| i[:interface] }.sort.uniq.join(" ") %> diff --git a/cookbooks/networking/templates/default/resolv.conf.erb b/cookbooks/networking/templates/default/resolv.conf.erb new file mode 100644 index 000000000..c857ff84a --- /dev/null +++ b/cookbooks/networking/templates/default/resolv.conf.erb @@ -0,0 +1,7 @@ +# DO NOT EDIT - This file is being maintained by Chef +<% unless node[:networking][:search].empty? -%> +search <%= node[:networking][:search].join(" ") %> +<% end -%> +<% node[:networking][:nameservers].each do |nameserver| -%> +nameserver <%= nameserver %> +<% end -%> diff --git a/cookbooks/networking/templates/default/shorewall-default.erb b/cookbooks/networking/templates/default/shorewall-default.erb new file mode 100644 index 000000000..03f3ffcdb --- /dev/null +++ b/cookbooks/networking/templates/default/shorewall-default.erb @@ -0,0 +1,7 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# Allow shorewall to start +startup=1 + +# Program options +OPTIONS="" diff --git a/cookbooks/networking/templates/default/shorewall-hosts.erb b/cookbooks/networking/templates/default/shorewall-hosts.erb new file mode 100644 index 000000000..76160b060 --- /dev/null +++ b/cookbooks/networking/templates/default/shorewall-hosts.erb @@ -0,0 +1,12 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# ZONE HOST OPTIONS +<% node.interfaces(:family => :inet, :role => :external).each do |interface| -%> +<% @zones.keys.sort.each do |zone| -%> +<% if @zones[zone]["inet"] -%> +<% @zones[zone]["inet"].sort.each do |ra| -%> +<%= zone %> <%= interface[:interface] %>:<%= ra %> +<% end -%> +<% end -%> +<% end -%> +<% end -%> diff --git a/cookbooks/networking/templates/default/shorewall-interfaces.erb b/cookbooks/networking/templates/default/shorewall-interfaces.erb new file mode 100644 index 000000000..89d8a2d54 --- /dev/null +++ b/cookbooks/networking/templates/default/shorewall-interfaces.erb @@ -0,0 +1,13 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# ZONE INTERFACE BROADCAST OPTIONS +<% node[:networking][:interfaces].each do |name,interface| -%> +<% if interface[:family] == "inet" -%> +<% if interface[:role] == "internal" -%> +loc <%= interface[:interface] %> detect nosmurfs,tcpflags +<% elsif interface[:role] == "external" -%> +net <%= interface[:interface] %> detect nosmurfs,tcpflags +<% end -%> +<% end -%> +<% end -%> +loc tun+ detect nosmurfs,tcpflags diff --git a/cookbooks/networking/templates/default/shorewall-masq.erb b/cookbooks/networking/templates/default/shorewall-masq.erb new file mode 100644 index 000000000..856f60e56 --- /dev/null +++ b/cookbooks/networking/templates/default/shorewall-masq.erb @@ -0,0 +1,8 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# INTERFACE SOURCE ADDRESS +<% node.interfaces(:role => :external).each do |external| -%> +<% node.interfaces(:role => :internal).each do |internal| -%> +<%= external[:interface] %> <%= internal[:network] %>/<%= internal[:prefix] %> detect +<% end -%> +<% end -%> diff --git a/cookbooks/networking/templates/default/shorewall-policy.erb b/cookbooks/networking/templates/default/shorewall-policy.erb new file mode 100644 index 000000000..4f29377d8 --- /dev/null +++ b/cookbooks/networking/templates/default/shorewall-policy.erb @@ -0,0 +1,5 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# FROM TO POLICY LOG LEVEL BURST:LIMIT +net all DROP +all all ACCEPT diff --git a/cookbooks/networking/templates/default/shorewall-rules.erb b/cookbooks/networking/templates/default/shorewall-rules.erb new file mode 100644 index 000000000..ffa55a9be --- /dev/null +++ b/cookbooks/networking/templates/default/shorewall-rules.erb @@ -0,0 +1,9 @@ +# DO NOT EDIT - This file is being maintained by Chef + +SECTION NEW + +# ACTION SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE +# PORTS PORTS DEST LIMIT +<% @rules.each do |r| -%> +<%= r[:action] %> <%= r[:source] %> <%= r[:dest] %> <%= r[:proto] %> <%= r[:dest_ports] %> <%= r[:source_ports] %> - <%= r[:rate_limit] %> +<% end -%> diff --git a/cookbooks/networking/templates/default/shorewall-zones.erb b/cookbooks/networking/templates/default/shorewall-zones.erb new file mode 100644 index 000000000..0af666a46 --- /dev/null +++ b/cookbooks/networking/templates/default/shorewall-zones.erb @@ -0,0 +1,20 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# ZONE TYPE OPTIONS IN OPTIONS OUT OPTIONS +fw firewall +loc <%= @type %> +net <%= @type %> +osm:net <%= @type %> +ucl:osm <%= @type %> +ic:osm <%= @type %> +bm:osm <%= @type %> +ts:osm <%= @type %> +yx:osm <%= @type %> +ra:osm <%= @type %> +pa:osm <%= @type %> +bx:osm <%= @type %> +ff:osm <%= @type %> +pr:osm <%= @type %> +ly:osm <%= @type %> +ov:osm <%= @type %> +hz:osm <%= @type %> diff --git a/cookbooks/networking/templates/default/shorewall.conf.erb b/cookbooks/networking/templates/default/shorewall.conf.erb new file mode 100644 index 000000000..14e0779db --- /dev/null +++ b/cookbooks/networking/templates/default/shorewall.conf.erb @@ -0,0 +1,192 @@ +# DO NOT EDIT - This file is being maintained by Chef + +############################################################################### +# S T A R T U P E N A B L E D +############################################################################### + +STARTUP_ENABLED=Yes + +############################################################################### +# V E R B O S I T Y +############################################################################### + +VERBOSITY=1 + +############################################################################### +# L O G G I N G +############################################################################### + +LOGFILE=/var/log/messages + +STARTUP_LOG=/var/log/shorewall-init.log + +LOG_VERBOSITY=2 + +LOGFORMAT="Shorewall:%s:%s:" + +LOGTAGONLY=No + +LOGRATE= + +LOGBURST= + +LOGALLNEW= + +BLACKLIST_LOGLEVEL= + +MACLIST_LOG_LEVEL=info + +TCP_FLAGS_LOG_LEVEL=info + +SMURF_LOG_LEVEL=info + +LOG_MARTIANS=Yes + +############################################################################### +# L O C A T I O N O F F I L E S A N D D I R E C T O R I E S +############################################################################### + +IPTABLES= + +IP= + +TC= + +IPSET= + +PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin + +SHOREWALL_SHELL=/bin/sh + +SUBSYSLOCK="" + +MODULESDIR= + +CONFIG_PATH=/etc/shorewall:/usr/share/shorewall + +RESTOREFILE= + +IPSECFILE=zones + +LOCKFILE= + +############################################################################### +# D E F A U L T A C T I O N S / M A C R O S +############################################################################### + +DROP_DEFAULT="Drop" +REJECT_DEFAULT="Reject" +ACCEPT_DEFAULT="none" +QUEUE_DEFAULT="none" +NFQUEUE_DEFAULT="none" + +############################################################################### +# R S H / R C P C O M M A N D S +############################################################################### + +RSH_COMMAND='ssh ${root}@${system} ${command}' +RCP_COMMAND='scp ${files} ${root}@${system}:${destination}' + +############################################################################### +# F I R E W A L L O P T I O N S +############################################################################### + +IP_FORWARDING=Keep + +ADD_IP_ALIASES=Yes + +ADD_SNAT_ALIASES=No + +RETAIN_ALIASES=No + +TC_ENABLED=Internal + +TC_EXPERT=No + +CLEAR_TC=Yes + +MARK_IN_FORWARD_CHAIN=No + +CLAMPMSS=No + +ROUTE_FILTER=Yes + +DETECT_DNAT_IPADDRS=No + +MUTEX_TIMEOUT=60 + +ADMINISABSENTMINDED=Yes + +BLACKLISTNEWONLY=Yes + +DELAYBLACKLISTLOAD=No + +MODULE_SUFFIX=ko + +DISABLE_IPV6=No + +BRIDGING=No + +DYNAMIC_ZONES=No + +PKTTYPE=Yes + +NULL_ROUTE_RFC1918=No + +MACLIST_TABLE=filter + +MACLIST_TTL= + +SAVE_IPSETS=No + +MAPOLDACTIONS=No + +FASTACCEPT=No + +IMPLICIT_CONTINUE=Yes + +HIGH_ROUTE_MARKS=No + +USE_ACTIONS=Yes + +OPTIMIZE=1 + +EXPORTPARAMS=Yes + +EXPAND_POLICIES=Yes + +KEEP_RT_TABLES=No + +DELETE_THEN_ADD=Yes + +MULTICAST=No + +DONT_LOAD= + +AUTO_COMMENT=Yes + +MANGLE_ENABLED=Yes + +USE_DEFAULT_RT=No + +RESTORE_DEFAULT_ROUTE=Yes + +AUTOMAKE=No + +WIDE_TC_MARKS=No + +TRACK_PROVIDERS=No + +ZONE2ZONE=2 + +############################################################################### +# P A C K E T D I S P O S I T I O N +############################################################################### + +BLACKLIST_DISPOSITION=DROP + +MACLIST_DISPOSITION=REJECT + +TCP_FLAGS_DISPOSITION=DROP + +#LAST LINE -- DO NOT REMOVE diff --git a/cookbooks/networking/templates/default/shorewall6-hosts.erb b/cookbooks/networking/templates/default/shorewall6-hosts.erb new file mode 100644 index 000000000..c2ac66356 --- /dev/null +++ b/cookbooks/networking/templates/default/shorewall6-hosts.erb @@ -0,0 +1,12 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# ZONE HOST OPTIONS +<% node.interfaces(:family => :inet6, :role => :external).each do |interface| -%> +<% @zones.keys.sort.each do |zone| -%> +<% if @zones[zone]["inet6"] -%> +<% @zones[zone]["inet6"].sort.each do |ra| -%> +<%= zone %> <%= interface[:interface] %>:[<%= ra %>] +<% end -%> +<% end -%> +<% end -%> +<% end -%> diff --git a/cookbooks/networking/templates/default/shorewall6-interfaces.erb b/cookbooks/networking/templates/default/shorewall6-interfaces.erb new file mode 100644 index 000000000..d2b4a3d91 --- /dev/null +++ b/cookbooks/networking/templates/default/shorewall6-interfaces.erb @@ -0,0 +1,12 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# ZONE INTERFACE UNICAST OPTIONS +<% node[:networking][:interfaces].each do |name,interface| -%> +<% if interface[:family] == "inet6" -%> +<% if interface[:role] == "internal" -%> +loc <%= interface[:interface] %> - +<% elsif interface[:role] == "external" -%> +net <%= interface[:interface] %> - +<% end -%> +<% end -%> +<% end -%> diff --git a/cookbooks/networking/templates/default/shorewall6.conf.erb b/cookbooks/networking/templates/default/shorewall6.conf.erb new file mode 100644 index 000000000..008fc6a9f --- /dev/null +++ b/cookbooks/networking/templates/default/shorewall6.conf.erb @@ -0,0 +1,146 @@ +# DO NOT EDIT - This file is being maintained by Chef + +############################################################################### +# S T A R T U P E N A B L E D +############################################################################### + +STARTUP_ENABLED=Yes + +############################################################################### +# V E R B O S I T Y +############################################################################### + +VERBOSITY=1 + +############################################################################### +# L O G G I N G +############################################################################### + +LOGFILE=/var/log/messages + +STARTUP_LOG=/var/log/shorewall6-init.log + +LOG_VERBOSITY=2 + +LOGFORMAT="Shorewall:%s:%s:" + +LOGTAGONLY=No + +LOGRATE= + +LOGBURST= + +LOGALLNEW= + +BLACKLIST_LOGLEVEL= + +TCP_FLAGS_LOG_LEVEL=info + +SMURF_LOG_LEVEL=info + +############################################################################### +# L O C A T I O N O F F I L E S A N D D I R E C T O R I E S +############################################################################### + +IP6TABLES= + +IP= + +TC= + +IPSET= + +PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin + +SHOREWALL_SHELL=/bin/sh + +SUBSYSLOCK="" + +MODULESDIR= + +CONFIG_PATH=/etc/shorewall6:/usr/share/shorewall6:/usr/share/shorewall + +RESTOREFILE= + +LOCKFILE= + +############################################################################### +# D E F A U L T A C T I O N S / M A C R O S +############################################################################### + +DROP_DEFAULT="Drop" +REJECT_DEFAULT="Reject" +ACCEPT_DEFAULT="none" +QUEUE_DEFAULT="none" +NFQUEUE_DEFAULT="none" + +############################################################################### +# R S H / R C P C O M M A N D S +############################################################################### + +RSH_COMMAND='ssh ${root}@${system} ${command}' +RCP_COMMAND='scp ${files} ${root}@${system}:${destination}' + +############################################################################### +# F I R E W A L L O P T I O N S +############################################################################### + +IP_FORWARDING=Off + +TC_ENABLED=No + +TC_EXPERT=No + +CLEAR_TC=No + +MARK_IN_FORWARD_CHAIN=No + +CLAMPMSS=No + +MUTEX_TIMEOUT=60 + +ADMINISABSENTMINDED=Yes + +BLACKLISTNEWONLY=Yes + +MODULE_SUFFIX=ko + +FASTACCEPT=No + +IMPLICIT_CONTINUE=Yes + +HIGH_ROUTE_MARKS=No + +OPTIMIZE=1 + +EXPORTPARAMS=Yes + +EXPAND_POLICIES=Yes + +KEEP_RT_TABLES=Yes + +DELETE_THEN_ADD=Yes + +DONT_LOAD= + +AUTO_COMMENT=Yes + +MANGLE_ENABLED=Yes + +AUTOMAKE=No + +WIDE_TC_MARKS=No + +TRACK_PROVIDERS=No + +ZONE2ZONE=2 + +############################################################################### +# P A C K E T D I S P O S I T I O N +############################################################################### + +BLACKLIST_DISPOSITION=DROP + +TCP_FLAGS_DISPOSITION=DROP + +#LAST LINE -- DO NOT REMOVE diff --git a/cookbooks/nfs/README.rdoc b/cookbooks/nfs/README.rdoc new file mode 100644 index 000000000..3de2ec7a3 --- /dev/null +++ b/cookbooks/nfs/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/cookbooks/nfs/metadata.rb b/cookbooks/nfs/metadata.rb new file mode 100644 index 000000000..7deebd5d1 --- /dev/null +++ b/cookbooks/nfs/metadata.rb @@ -0,0 +1,6 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Installs and configures nfs" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "1.0.0" diff --git a/cookbooks/nfs/recipes/default.rb b/cookbooks/nfs/recipes/default.rb new file mode 100644 index 000000000..0b4c9ffe4 --- /dev/null +++ b/cookbooks/nfs/recipes/default.rb @@ -0,0 +1,44 @@ +# +# Cookbook Name:: nfs +# Recipe:: default +# +# Copyright 2010, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package "nfs-common" + +node[:nfs].each do |mountpoint,details| + if details[:readonly] + mount_options = "ro,bg,soft,udp,rsize=8192,wsize=8192,nfsvers=3" + else + mount_options = "rw,bg,udp,rsize=8192,wsize=8192,nfsvers=3" + end + + directory mountpoint do + owner "root" + group "root" + mode 0755 + recursive true + not_if { File.exists?(mountpoint) } + end + + mount mountpoint do + action [ :mount, :enable ] + device "#{details[:host]}:#{details[:path]}" + fstype "nfs" + options mount_options + ignore_failure true + end +end diff --git a/cookbooks/nfs/recipes/server.rb b/cookbooks/nfs/recipes/server.rb new file mode 100644 index 000000000..3e13507f1 --- /dev/null +++ b/cookbooks/nfs/recipes/server.rb @@ -0,0 +1,64 @@ +# +# Cookbook Name:: nfs +# Recipe:: server +# +# Copyright 2010, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package "nfs-kernel-server" + +service "portmap" do + action [ :enable, :start ] + supports :status => true, :restart => true, :reload => true +end + +#service "nfs-kernel-server" do +# action [ :enable, :start ] +# supports :status => true, :restart => true, :reload => true +#end + +exports = {} + +search(:node, "*:*") do |client| + if client[:nfs] + client[:nfs].each_value do |mount| + if mount[:host] == node[:hostname] + client.ipaddresses do |address| + exports[mount[:path]] ||= {} + + if mount[:readonly] + exports[mount[:path]][address] = "ro" + else + exports[mount[:path]][address] = "rw" + end + end + end + end + end +end + +execute "exportfs" do + action :nothing + command "/usr/sbin/exportfs -ra" +end + +template "/etc/exports" do + source "exports.erb" + owner "root" + group "root" + mode 0644 + variables :exports => exports + notifies :run, resources(:execute => "exportfs") +end diff --git a/cookbooks/nfs/templates/default/exports.erb b/cookbooks/nfs/templates/default/exports.erb new file mode 100644 index 000000000..ba812c7c6 --- /dev/null +++ b/cookbooks/nfs/templates/default/exports.erb @@ -0,0 +1,6 @@ +# DO NOT EDIT - This file is being maintained by Chef + +<% @exports.each do |directory,clients| -%> +<%= directory -%> -sync,subtree_check<% clients.each do |address,options| -%> <%= address -%>(<%= options -%>)<% end %> +<% end -%> +/store/planet -sync,subtree_check 146.179.159.168(rw) 146.179.159.170(rw) 128.40.168.104(ro) 128.40.168.103(ro) 128.40.168.100(ro) diff --git a/cookbooks/openvpn/README.rdoc b/cookbooks/openvpn/README.rdoc new file mode 100644 index 000000000..3de2ec7a3 --- /dev/null +++ b/cookbooks/openvpn/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/cookbooks/openvpn/attributes/default.rb b/cookbooks/openvpn/attributes/default.rb new file mode 100644 index 000000000..af20e4e4c --- /dev/null +++ b/cookbooks/openvpn/attributes/default.rb @@ -0,0 +1,2 @@ +default[:openvpn][:tunnels] = {} +default[:openvpn][:keys] = {} diff --git a/cookbooks/openvpn/metadata.rb b/cookbooks/openvpn/metadata.rb new file mode 100644 index 000000000..9197554fc --- /dev/null +++ b/cookbooks/openvpn/metadata.rb @@ -0,0 +1,6 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Installs and configures OpenVPN" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "1.0.0" diff --git a/cookbooks/openvpn/recipes/default.rb b/cookbooks/openvpn/recipes/default.rb new file mode 100644 index 000000000..cbd45ee65 --- /dev/null +++ b/cookbooks/openvpn/recipes/default.rb @@ -0,0 +1,79 @@ +# +# Cookbook Name:: openvpn +# Recipe:: default +# +# Copyright 2012, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package "openvpn" + +service "openvpn" do + action [ :enable, :start ] + supports :status => true, :restart => true, :reload => true + ignore_failure true +end + +node[:openvpn][:tunnels].each do |name,details| + if peer = search(:node, "fqdn:#{details[:peer][:host]}").first + if peer[:openvpn] and not details[:peer][:address] + node.default[:openvpn][:tunnels][name][:peer][:address] = peer[:openvpn][:address] + end + + node.default[:openvpn][:tunnels][name][:peer][:networks] = peer.interfaces(:role => :internal).collect do |interface| + { :address => interface[:network], :netmask => interface[:netmask] } + end + else + node.default[:openvpn][:tunnels][name][:peer][:networks] = [] + end + + if details[:mode] == "client" + execute "openvpn-genkey-#{name}" do + command "openvpn --genkey --secret /etc/openvpn/#{name}.key" + user "root" + group "root" + creates "/etc/openvpn/#{name}.key" + end + + if File.exists?("/etc/openvpn/#{name}.key") + node.set[:openvpn][:keys][name] = IO.read("/etc/openvpn/#{name}.key") + end + elsif peer and peer[:openvpn] + file "/etc/openvpn/#{name}.key" do + owner "root" + group "root" + mode 0600 + content peer[:openvpn][:keys][name] + end + end + + if node[:openvpn][:tunnels][name][:peer][:address] + template "/etc/openvpn/#{name}.conf" do + source "tunnel.conf.erb" + owner "root" + group "root" + mode 0644 + variables :name => name, + :address => node[:openvpn][:address], + :port => node[:openvpn][:tunnels][name][:port], + :mode => node[:openvpn][:tunnels][name][:mode], + :peer => node[:openvpn][:tunnels][name][:peer] + notifies :restart, resources(:service => "openvpn") + end + else + file "/etc/openvpn/#{name}.conf" do + action :delete + end + end +end diff --git a/cookbooks/openvpn/templates/default/tunnel.conf.erb b/cookbooks/openvpn/templates/default/tunnel.conf.erb new file mode 100644 index 000000000..748f96993 --- /dev/null +++ b/cookbooks/openvpn/templates/default/tunnel.conf.erb @@ -0,0 +1,47 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# Set the local port to use +port <%= @port %> + +# Use UDP +proto udp + +# Use routed IP tunnels +dev tun + +# Use shared secret authentication +secret <%= @name %>.key + +# Run in peer-to-peer mode +mode p2p +<% if @mode == "client" -%> + +# Connect to the remote machine +remote <%= @peer[:host] %> <%= @peer[:port] %> +<% end -%> + +# Configure interface and routing +ifconfig <%= @address %> <%= @peer[:address] %> +<% @peer[:networks].each do |network| -%> +route <%= network[:address] %> <%= network[:netmask] %> +<% end -%> + +# Keepalive - check every 10 seconds and reset after 2 minutes +keepalive 10 120 + +# Use AES-128 as the cipher +cipher AES-128-CBC + +# Enable compression +comp-lzo + +# Run unprivileged +user nobody +group nogroup + +# Reuse resources on restart to avoid privilege problems +persist-key +persist-tun + +# Set log verbosity +verb 3 diff --git a/cookbooks/osqa/README.rdoc b/cookbooks/osqa/README.rdoc new file mode 100644 index 000000000..3de2ec7a3 --- /dev/null +++ b/cookbooks/osqa/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/cookbooks/osqa/attributes/default.rb b/cookbooks/osqa/attributes/default.rb new file mode 100644 index 000000000..fb20a4d47 --- /dev/null +++ b/cookbooks/osqa/attributes/default.rb @@ -0,0 +1,7 @@ +default[:osqa][:revision] = "1284" +default[:osqa][:user] = "osqa" +default[:osqa][:group] = nil +default[:osqa][:database_name] = "osqa" +default[:osqa][:database_user] = "osqa" +default[:osqa][:database_password] = "" +default[:osqa][:sites] = [] diff --git a/cookbooks/osqa/files/default/osmauth/__init__.py b/cookbooks/osqa/files/default/osmauth/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/cookbooks/osqa/files/default/osmauth/authentication.py b/cookbooks/osqa/files/default/osmauth/authentication.py new file mode 100644 index 000000000..7c8e70279 --- /dev/null +++ b/cookbooks/osqa/files/default/osmauth/authentication.py @@ -0,0 +1,21 @@ +from forum.authentication.base import AuthenticationConsumer, ConsumerTemplateContext, InvalidAuthentication +from forms import OpenStreetMapLoginForm + +class OpenStreetMapAuthConsumer(AuthenticationConsumer): + def process_authentication_request(self, request): + form_auth = OpenStreetMapLoginForm(request.POST) + + if form_auth.is_valid(): + request.session["auth_consumer_data"] = form_auth.get_user_data() + return form_auth.get_user() + else: + raise InvalidAuthentication(" ".join(form_auth.errors.values()[0])) + + def get_user_data(self, key): + return {} + +class OpenStreetMapAuthContext(ConsumerTemplateContext): + mode = 'TOP_STACK_ITEM' + weight = 0 + human_name = 'OpenStreetMap Login' + stack_item_template = 'modules/osmauth/loginform.html' diff --git a/cookbooks/osqa/files/default/osmauth/forms.py b/cookbooks/osqa/files/default/osmauth/forms.py new file mode 100644 index 000000000..c59475e9a --- /dev/null +++ b/cookbooks/osqa/files/default/osmauth/forms.py @@ -0,0 +1,72 @@ +from osm import OpenStreetMapAPI +from forum.forms import NextUrlField, UserNameField, SetPasswordForm +from django.utils.translation import ugettext as _ +from django import forms + +class OpenStreetMapLoginForm(forms.Form): + """ osm account signin form """ + next = NextUrlField() + username = UserNameField(required=False, skip_clean=True) + password = forms.CharField(max_length=128, + widget=forms.widgets.PasswordInput(attrs={'class':'required login'}), + required=False) + + def __init__(self, data=None, files=None, auto_id='id_%s', + prefix=None, initial=None): + super(OpenStreetMapLoginForm, self).__init__(data, files, auto_id, + prefix, initial) + self.user_details = None + + def _clean_nonempty_field(self, field): + value = None + if field in self.cleaned_data: + value = self.cleaned_data[field].strip() + if value == '': + value = None + self.cleaned_data[field] = value + return value + + def clean_username(self): + return self._clean_nonempty_field('username') + + def clean_password(self): + return self._clean_nonempty_field('password') + + def clean(self): + error_list = [] + username = self.cleaned_data['username'] + password = self.cleaned_data['password'] + + self.user_details = None + if username and password: + api = OpenStreetMapAPI(username, password) + + try: + self.user_details = api.user_details() + except: + del self.cleaned_data['username'] + del self.cleaned_data['password'] + error_list.insert(0, (_("Please enter valid username and password " + "(both are case-sensitive)."))) + error_list.insert(0, _('Login failed.')) + + elif password == None and username == None: + error_list.append(_('Please enter username and password')) + elif password == None: + error_list.append(_('Please enter your password')) + elif username == None: + error_list.append(_('Please enter user name')) + if len(error_list) > 0: + self._errors['__all__'] = forms.util.ErrorList(error_list) + + return self.cleaned_data + + def get_user(self): + """ get authenticated user """ + return "http://www.openstreetmap.org/user/%s" % self.user_details["id"] + + def get_user_data(self): + """ get user data for authenticated user """ + return { + "username": self.user_details["display_name"] + } diff --git a/cookbooks/osqa/files/default/osmauth/osm.py b/cookbooks/osqa/files/default/osmauth/osm.py new file mode 100644 index 000000000..94dcd13bf --- /dev/null +++ b/cookbooks/osqa/files/default/osmauth/osm.py @@ -0,0 +1,19 @@ +from xml.etree.ElementTree import ElementTree +import urllib2 + +class OpenStreetMapAPI: + def __init__(self, username, password): + passman = urllib2.HTTPPasswordMgr() + passman.add_password("Web Password", "https://api.openstreetmap.org/api/0.6", username, password) + authhandler = urllib2.HTTPBasicAuthHandler(passman) + self.opener = urllib2.build_opener(authhandler) + + def user_details(self): + response = self.opener.open("https://api.openstreetmap.org/api/0.6/user/details") + tree = ElementTree() + root = tree.parse(response) + user = root.find("user") + return { + "id": user.attrib["id"], + "display_name": user.attrib["display_name"] + } diff --git a/cookbooks/osqa/files/default/osmauth/templates/loginform.html b/cookbooks/osqa/files/default/osmauth/templates/loginform.html new file mode 100644 index 000000000..5091dfa38 --- /dev/null +++ b/cookbooks/osqa/files/default/osmauth/templates/loginform.html @@ -0,0 +1,31 @@ +{% load i18n %} + +
+

{% trans 'Enter your OpenStreetMap username and password' %}
({% trans 'or select your external provider below' %})

+ + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + {% trans 'Create account' %} | {% trans 'Forgot your password?' %} +
+
diff --git a/cookbooks/osqa/files/default/osmauth/urls.py b/cookbooks/osqa/files/default/osmauth/urls.py new file mode 100644 index 000000000..62581f005 --- /dev/null +++ b/cookbooks/osqa/files/default/osmauth/urls.py @@ -0,0 +1,8 @@ +from django.conf.urls.defaults import * +from django.views.generic.simple import direct_to_template +from django.utils.translation import ugettext as _ +import views as app + +urlpatterns = patterns('', + url(r'^%s%s%s$' % (_('account/'), _('openstreetmap/'), _('register/')), app.register, name='auth_openstreetmap_register'), +) diff --git a/cookbooks/osqa/metadata.rb b/cookbooks/osqa/metadata.rb new file mode 100644 index 000000000..da3014e8c --- /dev/null +++ b/cookbooks/osqa/metadata.rb @@ -0,0 +1,48 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Installs and configures OSQA" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "1.0.0" +depends "apache" +depends "memcached" + +attribute "osqa", + :display_name => "OSQA", + :description => "Hash of OSQA attributes", + :type => "hash" + +attribute "osqa/revision", + :display_name => "OSQA Revision", + :description => "Default revision of OSQA to use", + :default => "703" + +attribute "osqa/user", + :display_name => "User", + :description => "Default user to run OSQA as", + :default => "osqa" + +attribute "osqa/group", + :display_name => "Group", + :description => "Default group to run OSQA ad", + :default => nil + +attribute "osqa/database_name", + :display_name => "Database Name", + :description => "Default database to run OSQA against", + :default => "osqa" + +attribute "osqa/database_user", + :display_name => "Database User", + :description => "Default user for OSQA to connect to the database as", + :default => "osqa" + +attribute "osqa/database_password", + :display_name => "Database Password", + :description => "Default password for OSQA to authenticate to the database with", + :default => "" + +attribute "osqa/sites", + :display_name => "Sites", + :description => "Array of OSQA sites to setup", + :default => [] diff --git a/cookbooks/osqa/recipes/default.rb b/cookbooks/osqa/recipes/default.rb new file mode 100644 index 000000000..2ed82d269 --- /dev/null +++ b/cookbooks/osqa/recipes/default.rb @@ -0,0 +1,113 @@ +# +# Cookbook Name:: osqa +# Recipe:: default +# +# Copyright 2011, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include_recipe "tools" +include_recipe "apache::ssl" +include_recipe "memcached" + +package "python-django" +package "python-html5lib" +package "python-markdown" +package "python-memcache" +package "python-openid" +package "python-mysqldb" +package "python-psycopg2" +package "python-setuptools" + +easy_install_package "South" do + package_name "south" +end + +apache_module "rewrite" +apache_module "wsgi" + +node[:osqa][:sites].each do |site| + name = site[:name] + directory = site[:directory] || "/var/www/#{name}" + osqa_revision = site[:revision] || node[:osqa][:revision] + site_user = site[:user] || node[:osqa][:user] + site_user = Etc.getpwuid(site_user).name if site_user.is_a?(Integer) + site_group = site[:group] || node[:osqa][:group] || Etc.getpwnam(site_user).gid + site_group = Etc.getgrgid(site_group).name if site_group.is_a?(Integer) + database_name = site[:database_name] || node[:osqa][:database_name] + database_user = site[:database_user] || node[:osqa][:database_user] + database_password = site[:database_user] || node[:osqa][:database_password] + + apache_site name do + template "apache.erb" + directory "#{directory}/osqa" + variables :user => site_user, :group => site_group + end + + execute "osqa-migrate" do + action :nothing + command "python manage.py migrate forum" + cwd "#{directory}/osqa" + user site_user + group site_group + notifies :reload, resources(:service => "apache2") + end + + subversion "#{directory}/osqa" do + action :sync + repository "http://svn.osqa.net/svnroot/osqa/trunk" + revision osqa_revision + user site_user + group site_group + notifies :run, resources(:execute => "osqa-migrate") + end + + remote_directory "#{directory}/osqa/forum_modules/osmauth" do + source "osmauth" + owner site_user + group site_group + mode 0755 + files_owner site_user + files_group site_group + files_mode 0644 + end + + template "#{directory}/osqa/osqa.wsgi" do + source "osqa.wsgi.erb" + owner site_user + group site_group + mode 0644 + variables :directory => directory + notifies :reload, resources(:service => "apache2") + end + + file "#{directory}/osqa/settings_local.py" do + owner site_user + group site_group + mode 0644 + content_from_file "#{directory}/osqa/settings_local.py.dist" do |line| + line.gsub!(/^( *)'ENGINE': '.*',/, "\\1'ENGINE': 'django.db.backends.postgresql_psycopg2',") + line.gsub!(/^( *)'NAME': '.*',/, "\\1'NAME': '#{database_name}',") + line.gsub!(/^( *)'USER': '.*',/, "\\1'USER': '#{database_user}',") + line.gsub!(/^( *)'PASSWORD': '.*',/, "\\1'PASSWORD': '#{database_password}',") + line.gsub!(/^CACHE_BACKEND = .*/, "CACHE_BACKEND = 'memcached://127.0.0.1:11211/'") + line.gsub!(/^APP_URL = 'http:\/\/'/, "APP_URL = 'http://#{name}'") + line.gsub!(/^TIME_ZONE = 'America\/New_York'/, "TIME_ZONE = 'Europe/London'") + line.gsub!(/^DISABLED_MODULES = \[([^\]]+)\]/, "DISABLED_MODULES = [\\1, 'localauth', 'facebookauth', 'oauthauth']") + + line + end + notifies :reload, resources(:service => "apache2") + end +end diff --git a/cookbooks/osqa/templates/default/apache.erb b/cookbooks/osqa/templates/default/apache.erb new file mode 100644 index 000000000..ad9850162 --- /dev/null +++ b/cookbooks/osqa/templates/default/apache.erb @@ -0,0 +1,31 @@ +# DO NOT EDIT - This file is being maintained by Chef + +WSGIDaemonProcess <%= @name %> user=<%= @user %> group=<%= @group %> processes=4 threads=4 + + + ServerName <%= @name %> + ServerAdmin webmaster@openstreetmap.org + + CustomLog /var/log/apache2/<%= @name %>-access.log combined + ErrorLog /var/log/apache2/<%= @name %>-error.log + + RedirectPermanent / https://<%= @name %>/ + + + + ServerName <%= @name %> + ServerAdmin webmaster@openstreetmap.org + + CustomLog /var/log/apache2/<%= @name %>-access.log combined + ErrorLog /var/log/apache2/<%= @name %>-error.log + + DocumentRoot <%= @directory %> + Alias /m/ <%= @directory %>/forum/skins/ + Alias /upfiles/ <%= @directory %>/forum/upfiles/ + Alias /admin_media/ /usr/share/pyshared/django/contrib/admin/media/ + WSGIScriptAlias / <%= @directory %>/osqa.wsgi + + WSGIProcessGroup <%= @name %> + + SSLEngine on + diff --git a/cookbooks/osqa/templates/default/osqa.wsgi.erb b/cookbooks/osqa/templates/default/osqa.wsgi.erb new file mode 100644 index 000000000..04487d562 --- /dev/null +++ b/cookbooks/osqa/templates/default/osqa.wsgi.erb @@ -0,0 +1,11 @@ +# DO NOT EDIT - This file is being maintained by Chef + +import os +import sys +import django.core.handlers.wsgi + +sys.path.append('<%= @directory %>') +sys.path.append('<%= @directory %>/osqa') +os.environ['DJANGO_SETTINGS_MODULE'] = 'osqa.settings' + +application = django.core.handlers.wsgi.WSGIHandler() diff --git a/cookbooks/otrs/README.rdoc b/cookbooks/otrs/README.rdoc new file mode 100644 index 000000000..3de2ec7a3 --- /dev/null +++ b/cookbooks/otrs/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/cookbooks/otrs/attributes/default.rb b/cookbooks/otrs/attributes/default.rb new file mode 100644 index 000000000..b6edde202 --- /dev/null +++ b/cookbooks/otrs/attributes/default.rb @@ -0,0 +1,8 @@ +default[:otrs][:version] = "3.1.5" +default[:otrs][:user] = "otrs" +default[:otrs][:group] = nil +default[:otrs][:database_cluster] = "9.1/main" +default[:otrs][:database_name] = "otrs" +default[:otrs][:database_user] = "otrs" +default[:otrs][:database_password] = "" +default[:otrs][:site] = nil diff --git a/cookbooks/otrs/metadata.rb b/cookbooks/otrs/metadata.rb new file mode 100644 index 000000000..562783630 --- /dev/null +++ b/cookbooks/otrs/metadata.rb @@ -0,0 +1,53 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Installs and configures OTRS" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "1.0.0" +depends "apache" +depends "postgresql" + +attribute "otrs", + :display_name => "OTRS", + :description => "Hash of OTRS attributes", + :type => "hash" + +attribute "otrs/version", + :display_name => "OTRS Version", + :description => "Version of OTRS to use", + :default => "3.1.5" + +attribute "otrs/user", + :display_name => "User", + :description => "Iser to run OTRS as", + :default => "otrs" + +attribute "otrs/group", + :display_name => "Group", + :description => "Group to run OTRS as", + :default => nil + +attribute "otrs/database_cluster", + :display_name => "Database Cluster", + :description => "Database cluster to run OTRS against", + :default => "8.4/main" + +attribute "otrs/database_name", + :display_name => "Database Name", + :description => "Database to run OTRS against", + :default => "otrs" + +attribute "otrs/database_user", + :display_name => "Database User", + :description => "User for OTRS to connect to the database as", + :default => "otrs" + +attribute "otrs/database_password", + :display_name => "Database Password", + :description => "Password for OTRS to authenticate to the database with", + :default => "" + +attribute "otrs/site", + :display_name => "Site", + :description => "Name of OTRS site", + :default => nil diff --git a/cookbooks/otrs/recipes/default.rb b/cookbooks/otrs/recipes/default.rb new file mode 100644 index 000000000..731bdf273 --- /dev/null +++ b/cookbooks/otrs/recipes/default.rb @@ -0,0 +1,144 @@ +# +# Cookbook Name:: otrs +# Recipe:: default +# +# Copyright 2012, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include_recipe "tools" +include_recipe "apache::ssl" + +package "libapache2-mod-perl2" +package "libapache2-reload-perl" + +package "libgd-gd2-perl" +package "libgd-graph-perl" +package "libgd-text-perl" +package "libjson-xs-perl" +package "libmail-imapclient-perl" +package "libnet-ldap-perl" +package "libpdf-api2-perl" +package "libsoap-lite-perl" + +apache_module "headers" + +version = node[:otrs][:version] +user = node[:otrs][:user] +group = node[:otrs][:group] +database_cluster = node[:otrs][:database_cluster] +database_name = node[:otrs][:database_name] +database_user = node[:otrs][:database_user] +database_password = node[:otrs][:database_password] +site = node[:otrs][:site] + +remote_file "/tmp/otrs-#{version}.tar.bz2" do + source "http://ftp.otrs.org/pub/otrs/otrs-#{version}.tar.bz2" + not_if { File.exist?("/opt/otrs-#{version}") } +end + +execute "untar-otrs-#{version}" do + command "tar jxf /tmp/otrs-#{version}.tar.bz2" + cwd "/opt" + user "root" + group "root" + not_if { File.exist?("/opt/otrs-#{version}") } +end + +file "/opt/otrs-#{version}/Kernel/Config.pm" do + owner user + group "www-data" + mode 0664 + content_from_file "/opt/otrs-#{version}/Kernel/Config.pm.dist" do |line| + line.gsub!(/^( *)\$Self->{Database} = 'otrs'/, "\\1$Self->{Database} = '#{database_name}'") + line.gsub!(/^( *)\$Self->{DatabaseUser} = 'otrs'/, "\\1$Self->{DatabaseUser} = '#{database_user}'") + line.gsub!(/^( *)\$Self->{DatabasePw} = 'some-pass'/, "\\1$Self->{DatabasePw} = '#{database_password}'") + line.gsub!(/^( *)\$Self->{Database} = 'otrs'/, "\\1$Self->{Database} = '#{database_name}'") + line.gsub!(/^( *\$Self->{DatabaseDSN} = "DBI:mysql:)/, "#\\1") + line.gsub!(/^#( *\$Self->{DatabaseDSN} = "DBI:Pg:.*;host=)/, "\\1") + + line + end +end + +file "/opt/otrs-#{version}/Kernel/Config/GenericAgent.pm" do + owner user + group "www-data" + mode 0664 + content_from_file "/opt/otrs-#{version}/Kernel/Config/GenericAgent.pm.dist" do |line| + line + end +end + +link "/opt/otrs" do + to "/opt/otrs-#{version}" +end + +execute "/opt/otrs/bin/otrs.SetPermissions.pl" do + action :run + command "/opt/otrs/bin/otrs.SetPermissions.pl --otrs-user=#{user} --web-user=www-data --otrs-group=www-data --web-group=www-data /opt/otrs-#{version}" + user "root" + group "root" + not_if { File.stat("/opt/otrs/README").uid != Etc.getpwnam("otrs").uid } +end + +execute "/opt/otrs/bin/otrs.RebuildConfig.pl" do + action :run + command "/opt/otrs/bin/otrs.RebuildConfig.pl" + user "root" + group "root" + not_if { File.exist?("/opt/otrs/Kernel/Config/Files/ZZZAAuto.pm") } +end + +if node[:postgresql][:clusters][database_cluster] + postgresql_user database_user do + cluster database_cluster + password database_password + end + + postgresql_database database_name do + cluster database_cluster + owner database_user + end +end + +execute "/opt/otrs/bin/Cron.sh" do + action :nothing + command "/opt/otrs/bin/Cron.sh restart" + user "otrs" + group "otrs" +end + +Dir.glob("/opt/otrs/var/cron/*.dist") do |distname| + name = distname.sub(".dist", "") + + file name do + owner "otrs" + group "www-data" + mode 0664 + content IO.read(distname) + notifies :run, resources(:execute => "/opt/otrs/bin/Cron.sh") + end +end + +apache_site site do + template "apache.erb" +end + +template "/etc/sudoers.d/otrs" do + source "sudoers.erb" + owner "root" + group "root" + mode 0440 +end diff --git a/cookbooks/otrs/templates/default/apache.erb b/cookbooks/otrs/templates/default/apache.erb new file mode 100644 index 000000000..da5a60d2f --- /dev/null +++ b/cookbooks/otrs/templates/default/apache.erb @@ -0,0 +1,72 @@ +# DO NOT EDIT - This file is being maintained by Chef + + + ServerName <%= @name %> + ServerAdmin webmaster@openstreetmap.org + + CustomLog /var/log/apache2/<%= @name %>-access.log combined + ErrorLog /var/log/apache2/<%= @name %>-error.log + + RedirectPermanent / https://otrs.openstreetmap.org/ + + + + ServerName <%= @name %> + ServerAdmin webmaster@openstreetmap.org + + CustomLog /var/log/apache2/<%= @name %>-access.log combined + ErrorLog /var/log/apache2/<%= @name %>-error.log + + SSLEngine on + + ScriptAlias /otrs/ /opt/otrs/bin/cgi-bin/ + Alias /otrs-web/ /opt/otrs/var/httpd/htdocs/ + RedirectMatch ^/$ /otrs/index.pl + + PerlRequire /opt/otrs/scripts/apache2-perl-startup.pl + + PerlModule Apache2::Reload + PerlInitHandler Apache2::Reload + PerlModule Apache2::RequestRec + + + ErrorDocument 403 /otrs/index.pl + ErrorDocument 404 /otrs/index.pl + SetHandler perl-script + PerlResponseHandler ModPerl::Registry + Options +ExecCGI + PerlOptions +ParseHeaders + PerlOptions +SetupEnv + Order allow,deny + Allow from all + + + + PerlOptions -ParseHeaders + + + + + AllowOverride None + Options +ExecCGI -Includes + Order allow,deny + Allow from all + + + + AllowOverride None + Order allow,deny + Allow from all + + + + + Header set Cache-Control "max-age=2592000 must-revalidate" + + + + + + Header set Cache-Control "max-age=2592000 must-revalidate" + + diff --git a/cookbooks/otrs/templates/default/sudoers.erb b/cookbooks/otrs/templates/default/sudoers.erb new file mode 100644 index 000000000..91c73e9e0 --- /dev/null +++ b/cookbooks/otrs/templates/default/sudoers.erb @@ -0,0 +1,4 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# Allow exim to deliver mail into OTRS +Debian-exim ALL=(otrs) NOPASSWD: /usr/share/otrs/bin/PostMaster.pl diff --git a/cookbooks/piwik/README.rdoc b/cookbooks/piwik/README.rdoc new file mode 100644 index 000000000..3de2ec7a3 --- /dev/null +++ b/cookbooks/piwik/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/cookbooks/piwik/metadata.rb b/cookbooks/piwik/metadata.rb new file mode 100644 index 000000000..31d80cec1 --- /dev/null +++ b/cookbooks/piwik/metadata.rb @@ -0,0 +1,8 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Installs and configures Piwik" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "1.0.0" +depends "apache" +depends "mysql" diff --git a/cookbooks/piwik/recipes/default.rb b/cookbooks/piwik/recipes/default.rb new file mode 100644 index 000000000..02fb7a860 --- /dev/null +++ b/cookbooks/piwik/recipes/default.rb @@ -0,0 +1,73 @@ +# +# Cookbook Name:: piwik +# Recipe:: default +# +# Copyright 2011, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include_recipe "apache::ssl" +include_recipe "mysql" + +passwords = data_bag_item("piwik", "passwords") + +package "php5" +package "php5-cli" +package "php5-curl" +package "php5-mysql" +package "php5-gd" + +package "php-apc" + +package "geoip-database-contrib" + +apache_module "php5" +apache_module "geoip" + +apache_site "piwik.openstreetmap.org" do + template "apache.erb" +end + +directory "/srv/piwik.openstreetmap.org" do + owner "root" + group "root" + mode "0755" +end + +directory "/srv/piwik.openstreetmap.org/config" do + owner "www-data" + group "www-data" + mode "0755" +end + +directory "/srv/piwik.openstreetmap.org/tmp" do + owner "www-data" + group "www-data" + mode "0755" +end + +template "/etc/cron.d/piwiki" do + source "cron.erb" + owner "root" + group "root" + mode "0644" +end + +mysql_user "piwik@localhost" do + password passwords["database"] +end + +mysql_database "piwik" do + permissions "piwik@localhost" => :all +end diff --git a/cookbooks/piwik/templates/default/apache.erb b/cookbooks/piwik/templates/default/apache.erb new file mode 100644 index 000000000..522935880 --- /dev/null +++ b/cookbooks/piwik/templates/default/apache.erb @@ -0,0 +1,28 @@ +# DO NOT EDIT - This file is being maintained by Chef + + + ServerName piwik.openstreetmap.org + ServerAlias piwik.osm.org + ServerAdmin webmaster@openstreetmap.org + + CustomLog /var/log/apache2/piwik.openstreetmap.org-access.log combined + ErrorLog /var/log/apache2/piwik.openstreetmap.org-error.log + + DocumentRoot /srv/piwik.openstreetmap.org + + + + ServerName piwik.openstreetmap.org + ServerAdmin webmaster@openstreetmap.org + + SSLEngine on + SSLProtocol all -SSLv2 + SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW + SSLCertificateFile /etc/ssl/certs/openstreetmap.pem + SSLCertificateKeyFile /etc/ssl/private/openstreetmap.key + + CustomLog /var/log/apache2/piwik.openstreetmap.org-access.log combined + ErrorLog /var/log/apache2/piwik.openstreetmap.org-error.log + + DocumentRoot /srv/piwik.openstreetmap.org + diff --git a/cookbooks/piwik/templates/default/cron.erb b/cookbooks/piwik/templates/default/cron.erb new file mode 100644 index 000000000..7bf54843b --- /dev/null +++ b/cookbooks/piwik/templates/default/cron.erb @@ -0,0 +1 @@ +5 * * * * www-data /usr/bin/php5 /srv/piwik.openstreetmap.org/misc/cron/archive.php --url=http://piwik.openstreetmap.org/ > /dev/null diff --git a/cookbooks/postgresql/README.rdoc b/cookbooks/postgresql/README.rdoc new file mode 100644 index 000000000..3de2ec7a3 --- /dev/null +++ b/cookbooks/postgresql/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/cookbooks/postgresql/attributes/default.rb b/cookbooks/postgresql/attributes/default.rb new file mode 100644 index 000000000..1bfdb836a --- /dev/null +++ b/cookbooks/postgresql/attributes/default.rb @@ -0,0 +1,30 @@ +default[:postgresql][:versions] = [] +default[:postgresql][:clusters] = {} +default[:postgresql][:settings][:defaults][:port] = "5432" +default[:postgresql][:settings][:defaults][:max_connections] = "100" +default[:postgresql][:settings][:defaults][:shared_buffers] = "32MB" +default[:postgresql][:settings][:defaults][:temp_buffers] = "8MB" +default[:postgresql][:settings][:defaults][:work_mem] = "1MB" +default[:postgresql][:settings][:defaults][:maintenance_work_mem] = "16MB" +default[:postgresql][:settings][:defaults][:max_stack_depth] = "2MB" +default[:postgresql][:settings][:defaults][:wal_level] = "minimal" +default[:postgresql][:settings][:defaults][:fsync] = "on" +default[:postgresql][:settings][:defaults][:synchronous_commit] = "on" +default[:postgresql][:settings][:defaults][:wal_buffers] = "-1" +default[:postgresql][:settings][:defaults][:wal_writer_delay] = "200ms" +default[:postgresql][:settings][:defaults][:commit_delay] = "0" +default[:postgresql][:settings][:defaults][:checkpoint_segments] = "3" +default[:postgresql][:settings][:defaults][:checkpoint_timeout] = "5min" +default[:postgresql][:settings][:defaults][:checkpoint_completion_target] = "0.5" +default[:postgresql][:settings][:defaults][:archive_mode] = "off" +default[:postgresql][:settings][:defaults][:max_wal_senders] = "0" +default[:postgresql][:settings][:defaults][:hot_standby] = "off" +default[:postgresql][:settings][:defaults][:hot_standby_feedback] = "off" +default[:postgresql][:settings][:defaults][:random_page_cost] = "4.0" +default[:postgresql][:settings][:defaults][:effective_cache_size] = "128MB" +default[:postgresql][:settings][:defaults][:log_min_duration_statement] = "-1" +default[:postgresql][:settings][:defaults][:autovacuum_max_workers] = "3" +default[:postgresql][:settings][:defaults][:user_name_maps] = {} +default[:postgresql][:settings][:defaults][:early_authentication_rules] = [] +default[:postgresql][:settings][:defaults][:late_authentication_rules] = [] +default[:postgresql][:settings][:defaults][:standby_mode] = "off" diff --git a/cookbooks/postgresql/definitions/postgresql_munin.rb b/cookbooks/postgresql/definitions/postgresql_munin.rb new file mode 100644 index 000000000..8062044f7 --- /dev/null +++ b/cookbooks/postgresql/definitions/postgresql_munin.rb @@ -0,0 +1,94 @@ +# +# Cookbook Name:: postgresql +# Definition:: postgresql_munin +# +# Copyright 2012, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +define :postgresql_munin, :action => :create do + cluster = params[:cluster] + suffix = cluster.tr("/", ":") + database = params[:database] + + if node[:postgresql][:clusters] and node[:postgresql][:clusters][cluster] + munin_plugin "postgres_cache_#{database}:#{suffix}" do + action params[:action] + target "postgres_cache_" + conf "munin.erb" + conf_cookbook "postgresql" + conf_variables :port => node[:postgresql][:clusters][cluster][:port] + end + + munin_plugin "postgres_connections_#{database}:#{suffix}" do + action params[:action] + target "postgres_connections_" + conf "munin.erb" + conf_cookbook "postgresql" + conf_variables :port => node[:postgresql][:clusters][cluster][:port] + end + + munin_plugin "postgres_locks_#{database}:#{suffix}" do + action params[:action] + target "postgres_locks_" + conf "munin.erb" + conf_cookbook "postgresql" + conf_variables :port => node[:postgresql][:clusters][cluster][:port] + end + + munin_plugin "postgres_querylength_#{database}:#{suffix}" do + action params[:action] + target "postgres_querylength_" + conf "munin.erb" + conf_cookbook "postgresql" + conf_variables :port => node[:postgresql][:clusters][cluster][:port] + end + + munin_plugin "postgres_scans_#{database}:#{suffix}" do + action params[:action] + target "postgres_scans_" + conf "munin.erb" + conf_cookbook "postgresql" + conf_variables :port => node[:postgresql][:clusters][cluster][:port] + end + + munin_plugin "postgres_size_#{database}:#{suffix}" do + action params[:action] + target "postgres_size_" + conf "munin.erb" + conf_cookbook "postgresql" + conf_variables :port => node[:postgresql][:clusters][cluster][:port] + end + + munin_plugin "postgres_transactions_#{database}:#{suffix}" do + action params[:action] + target "postgres_transactions_" + conf "munin.erb" + conf_cookbook "postgresql" + conf_variables :port => node[:postgresql][:clusters][cluster][:port] + end + + munin_plugin "postgres_tuples_#{database}:#{suffix}" do + action params[:action] + target "postgres_tuples_" + conf "munin.erb" + conf_cookbook "postgresql" + conf_variables :port => node[:postgresql][:clusters][cluster][:port] + end + else + log "Postgres cluster #{cluster} not found" do + level :warn + end + end +end diff --git a/cookbooks/postgresql/libraries/postgresql.rb b/cookbooks/postgresql/libraries/postgresql.rb new file mode 100644 index 000000000..bd10a0233 --- /dev/null +++ b/cookbooks/postgresql/libraries/postgresql.rb @@ -0,0 +1,130 @@ +require 'chef/mixin/command' + +class Chef + class PostgreSQL + include Chef::Mixin::Command + + TABLE_PRIVILEGES = [ + :select, :insert, :update, :delete, :truncate, :references, :trigger + ] + + def initialize(cluster) + @cluster = cluster + end + + def execute(options) + # Create argument array + args = [] + + # Build the arguments + args.push("--command=\"#{options[:command].gsub('"', '\\"')}\"") if options[:command] + args.push("--file=#{options[:file]}") if options[:file] + + # Get the database to use + database = options[:database] || "template1" + + # Build the command to run + command = "/usr/bin/psql --cluster #{@cluster} #{args.join(' ')} #{database}" + + # Get the user and group to run as + user = options[:user] || "postgres" + group = options[:group] || "postgres" + + # Run the command + run_command(:command => command, :user => user, :group => group) + end + + def query(sql, options = {}) + # Get the database to use + database = options[:database] || "template1" + + # Construct the command string + command = "/usr/bin/psql --cluster #{@cluster} --no-align --command='#{sql}' #{database}" + + # Run the query + status, stdout, stderr = output_of_command(command, :user => "postgres", :group => "postgres") + handle_command_failures(status, "STDOUT: #{stdout}\nSTDERR: #{stderr}", :output_on_failure => true) + + # Split the output into lines + lines = stdout.split("\n") + + # Remove the "(N rows)" line from the end + lines.pop + + # Get the field names + fields = lines.shift.split("|") + + # Extract the record data + lines.collect do |line| + record = {} + fields.zip(line.split("|")) { |name,value| record[name.to_sym] = value } + record + end + end + + def users + @users ||= query("SELECT * FROM pg_user").inject({}) do |users,user| + users[user[:usename]] = { + :superuser => user[:usesuper] == "t", + :createdb => user[:usercreatedb] == "t", + :createrole => user[:usecatupd] == "t", + :replication => user[:userepl] == "t" + } + users + end + end + + def databases + @databases ||= query("SELECT d.datname, u.usename, d.encoding FROM pg_database AS d INNER JOIN pg_user AS u ON d.datdba = u.usesysid").inject({}) do |databases,database| + databases[database[:datname]] = { + :owner => database[:usename], + :encoding => database[:encoding] + } + databases + end + end + + def extensions(database) + @extensions ||= {} + @extensions[database] ||= query("SELECT extname, extversion FROM pg_extension", :database => database).inject({}) do |extensions,extension| + extensions[extension[:extname]] = { + :version => extension[:extversion] + } + databases + end + end + + def tables(database) + @tables ||= {} + @tables[database] ||= query("SELECT n.nspname, c.relname, u.usename, c.relacl FROM pg_class AS c INNER JOIN pg_user AS u ON c.relowner = u.usesysid INNER JOIN pg_namespace AS n ON c.relnamespace = n.oid", :database => database).inject({}) do |tables,table| + name = "#{table[:nspname]}.#{table[:relname]}" + + tables[name] = { + :owner => table[:usename], + :permissions => parse_acl(table[:relacl] || "{}") + } + + tables + end + end + + private + + def parse_acl(acl) + acl.sub(/^\{(.*)\}$/, "\\1").split(",").inject({}) do |permissions, entry| + entry = entry.sub(/^"(.*)"$/) { $1.gsub(/\\"/, '"') }.sub(/\/.*$/, "") + user, privileges = entry.split("=") + + user = user.sub(/^"(.*)"$/, "\\1") + user = "public" if user == "" + + permissions[user] = { + "a" => :insert, "r" => :select, "w" => :update, "d" => :delete, + "D" => :truncate, "x" => :references, "t" => :trigger + }.values_at(*(privileges.chars)).compact + + permissions + end + end + end +end diff --git a/cookbooks/postgresql/metadata.rb b/cookbooks/postgresql/metadata.rb new file mode 100644 index 000000000..f2ad1943b --- /dev/null +++ b/cookbooks/postgresql/metadata.rb @@ -0,0 +1,18 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Installs and configures postgresql" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "1.0.0" +depends "chef" + +attribute "postgresql", + :display_name => "PostgreSQL", + :description => "Hash of PostgreSQL configuration details", + :type => "hash" + +attribute "postgresql/versions", + :display_name => "Versions", + :description => "List of versions to install", + :type => "array", + :default => [] diff --git a/cookbooks/postgresql/providers/database.rb b/cookbooks/postgresql/providers/database.rb new file mode 100644 index 000000000..eee79031d --- /dev/null +++ b/cookbooks/postgresql/providers/database.rb @@ -0,0 +1,50 @@ +# +# Cookbook Name:: postgresql +# Provider:: postgresql_database +# +# Copyright 2012, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +def load_current_resource + @pg = Chef::PostgreSQL.new(new_resource.cluster) + + @current_resource = Chef::Resource::PostgresqlDatabase.new(new_resource.name) + @current_resource.database(new_resource.database) + @current_resource.cluster(new_resource.cluster) + if pg_database = @pg.databases[@current_resource.database] + @current_resource.owner(pg_database[:owner]) + @current_resource.encoding(pg_database[:encoding]) + end + @current_resource +end + +action :create do + unless @pg.databases.include?(new_resource.database) + @pg.execute(:command => "CREATE DATABASE #{new_resource.database} OWNER #{new_resource.owner} ENCODING '#{new_resource.encoding}'") + new_resource.updated_by_last_action(true) + else + if new_resource.owner != @current_resource.owner + @pg.execute(:command => "ALTER DATABASE #{new_resource.database} OWNER TO #{new_resource.owner}") + new_resource.updated_by_last_action(true) + end + end +end + +action :drop do + if @pg.databases.include?(new_resource.database) + @pg.execute(:command => "DROP DATABASE #{new_resource.database}") + new_resource.updated_by_last_action(true) + end +end diff --git a/cookbooks/postgresql/providers/execute.rb b/cookbooks/postgresql/providers/execute.rb new file mode 100644 index 000000000..2b7bd5ff9 --- /dev/null +++ b/cookbooks/postgresql/providers/execute.rb @@ -0,0 +1,42 @@ +# +# Cookbook Name:: postgresql +# Provider:: postgresql_execute +# +# Copyright 2012, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +def load_current_resource + @pg = Chef::PostgreSQL.new(new_resource.cluster) + + @current_resource = Chef::Resource::PostgresqlExecute.new(new_resource.name) + @current_resource.cluster(new_resource.cluster) + @current_resource.database(new_resource.database) + @current_resource +end + +action :nothing do +end + +action :run do + options = { :database => new_resource.database, :user => new_resource.user, :group => new_resource.group } + + if ::File.exist?(new_resource.command) + @pg.execute(options.merge(:file => new_resource.command)) + else + @pg.execute(options.merge(:command => new_resource.command)) + end + + new_resource.updated_by_last_action(true) +end diff --git a/cookbooks/postgresql/providers/extension.rb b/cookbooks/postgresql/providers/extension.rb new file mode 100644 index 000000000..81a976004 --- /dev/null +++ b/cookbooks/postgresql/providers/extension.rb @@ -0,0 +1,42 @@ +# +# Cookbook Name:: postgresql +# Provider:: postgresql_extension +# +# Copyright 2012, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +def load_current_resource + @pg = Chef::PostgreSQL.new(new_resource.cluster) + + @current_resource = Chef::Resource::PostgresqlExtension.new(new_resource.name) + @current_resource.extension(new_resource.extension) + @current_resource.cluster(new_resource.cluster) + @current_resource.database(new_resource.database) + @current_resource +end + +action :create do + unless @pg.extensions(new_resource.database).include?(new_resource.extension) + @pg.execute(:command => "CREATE EXTENSION #{new_resource.extension}", :database => new_resource.database) + new_resource.updated_by_last_action(true) + end +end + +action :drop do + if @pg.extensions(new_resource.database).include?(new_resource.extension) + @pg.execute(:command => "DROP EXTENSION #{new_resource.extension}", :database => new_resource.database) + new_resource.updated_by_last_action(true) + end +end diff --git a/cookbooks/postgresql/providers/table.rb b/cookbooks/postgresql/providers/table.rb new file mode 100644 index 000000000..4a2b43f5d --- /dev/null +++ b/cookbooks/postgresql/providers/table.rb @@ -0,0 +1,90 @@ +# +# Cookbook Name:: postgresql +# Provider:: postgresql_table +# +# Copyright 2013, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +def load_current_resource + @pg = Chef::PostgreSQL.new(new_resource.cluster) + @tables = @pg.tables(new_resource.database) + @name = "#{new_resource.schema}.#{new_resource.name}" + + @current_resource = Chef::Resource::PostgresqlTable.new(new_resource.name) + @current_resource.cluster(new_resource.cluster) + @current_resource.database(new_resource.database) + @current_resource.schema(new_resource.schema) + if pg_table = @tables[@name] + @current_resource.owner(pg_table[:owner]) + @current_resource.permissions(pg_table[:permissions]) + end + @current_resource +end + +action :create do + if @tables.include?(@name) + if new_resource.owner != @current_resource.owner + converge_by("set owner for #{new_resource} to #{new_resource.owner}") do + Chef::Log.info("Setting owner for #{new_resource} to #{new_resource.owner}") + @pg.execute(:command => "ALTER TABLE #{@name} OWNER TO \"#{new_resource.owner}\"", :database => new_resource.database) + end + end + + @current_resource.permissions.each do |user,privileges| + unless new_resource.permissions[user] + converge_by("revoke all for #{user} on #{new_resource}") do + Chef::Log.info("Revoking all for #{user} on #{new_resource}") + @pg.execute(:command => "REVOKE ALL ON #{@name} FROM \"#{user}\"", :database => new_resource.database) + end + end + end + + new_resource.permissions.each do |user,new_privileges| + current_privileges = @current_resource.permissions[user] || {} + new_privileges = Array(new_privileges) + + if new_privileges.include?(:all) + new_privileges |= Chef::PostgreSQL::TABLE_PRIVILEGES + end + + Chef::PostgreSQL::TABLE_PRIVILEGES.each do |privilege| + if new_privileges.include?(privilege) + unless current_privileges.include?(privilege) + converge_by("grant #{privilege} for #{user} on #{new_resource}") do + Chef::Log.info("Granting #{privilege} for #{user} on #{new_resource}") + @pg.execute(:command => "GRANT #{privilege.to_s.upcase} ON #{@name} TO \"#{user}\"", :database => new_resource.database) + end + end + else + if current_privileges.include?(privilege) + converge_by("revoke #{privilege} for #{user} on #{new_resource}") do + Chef::Log.info("Revoking #{privilege} for #{user} on #{new_resource}") + @pg.execute(:command => "REVOKE #{privilege.to_s.upcase} ON #{@name} FROM \"#{user}\"", :database => new_resource.database) + end + end + end + end + end + end +end + +action :drop do + if @tables.include?(@name) + converge_by("drop #{new_resource}") do + Chef::Log.info("Dropping #{new_resource}") + @pg.execute(:command => "DROP TABLE #{@name}", :database => new_resource.database) + end + end +end diff --git a/cookbooks/postgresql/providers/user.rb b/cookbooks/postgresql/providers/user.rb new file mode 100644 index 000000000..11c783e22 --- /dev/null +++ b/cookbooks/postgresql/providers/user.rb @@ -0,0 +1,75 @@ +# +# Cookbook Name:: postgresql +# Provider:: postgresql_user +# +# Copyright 2012, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +def load_current_resource + @pg = Chef::PostgreSQL.new(new_resource.cluster) + + @current_resource = Chef::Resource::PostgresqlUser.new(new_resource.name) + @current_resource.user(new_resource.user) + @current_resource.cluster(new_resource.cluster) + if pg_user = @pg.users[@current_resource.user] + @current_resource.superuser(pg_user[:superuser]) + @current_resource.createdb(pg_user[:createdb]) + @current_resource.createrole(pg_user[:createrole]) + @current_resource.replication(pg_user[:replication]) + end + @current_resource +end + +action :create do + password = new_resource.password ? "ENCRYPTED PASSWORD '#{new_resource.password}'" : "" + superuser = new_resource.superuser ? "SUPERUSER" : "NOSUPERUSER" + createdb = new_resource.createdb ? "CREATEDB" : "NOCREATEDB" + createrole = new_resource.createrole ? "CREATEROLE" : "NOCREATEROLE" + replication = new_resource.replication ? "REPLICATION" : "NOREPLICATION" + + unless @pg.users.include?(new_resource.user) + @pg.execute(:command => "CREATE ROLE \"#{new_resource.user}\" LOGIN #{password} #{superuser} #{createdb} #{createrole}") + new_resource.updated_by_last_action(true) + else + if new_resource.superuser != @current_resource.superuser + @pg.execute(:command => "ALTER ROLE \"#{new_resource.user}\" #{superuser}") + new_resource.updated_by_last_action(true) + end + + unless new_resource.superuser + if new_resource.createdb != @current_resource.createdb + @pg.execute(:command => "ALTER ROLE \"#{new_resource.user}\" #{createdb}") + new_resource.updated_by_last_action(true) + end + + if new_resource.createrole != @current_resource.createrole + @pg.execute(:command => "ALTER ROLE \"#{new_resource.user}\" #{createrole}") + new_resource.updated_by_last_action(true) + end + + if new_resource.replication != @current_resource.replication + @pg.execute(:command => "ALTER ROLE \"#{new_resource.user}\" #{replication}") + new_resource.updated_by_last_action(true) + end + end + end +end + +action :drop do + if @pg.users.include?(new_resource.user) + @pg.execute(:command => "DROP ROLE \"#{new_resource.user}\"") + new_resource.updated_by_last_action(true) + end +end diff --git a/cookbooks/postgresql/recipes/default.rb b/cookbooks/postgresql/recipes/default.rb new file mode 100644 index 000000000..c054a138b --- /dev/null +++ b/cookbooks/postgresql/recipes/default.rb @@ -0,0 +1,168 @@ +# +# Cookbook Name:: postgresql +# Recipe:: default +# +# Copyright 2012, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +if File.exists?("/etc/init.d/postgresql") + service "postgresql" do + action [ :enable, :start ] + supports :status => true, :restart => true, :reload => true + end +end + +node[:postgresql][:versions].each do |version| + package "postgresql-#{version}" + package "postgresql-client-#{version}" + package "postgresql-contrib-#{version}" + package "postgresql-server-dev-#{version}" + + if File.exists?("/etc/init.d/postgresql-#{version}") + service "postgresql-#{version}" do + action [ :enable, :start ] + supports :status => true, :restart => true, :reload => true + end + end + + defaults = node[:postgresql][:settings][:defaults] || {} + settings = node[:postgresql][:settings][version] || {} + + template "/etc/postgresql/#{version}/main/postgresql.conf" do + source "postgresql.conf.erb" + owner "postgres" + group "postgres" + mode 0644 + variables :version => version, :defaults => defaults, :settings => settings + if File.exists?("/etc/init.d/postgresql-#{version}") + notifies :reload, resources(:service => "postgresql-#{version}") + else + notifies :reload, resources(:service => "postgresql") + end + end + + template "/etc/postgresql/#{version}/main/pg_hba.conf" do + source "pg_hba.conf.erb" + owner "postgres" + group "postgres" + mode 0640 + variables :early_rules => settings[:early_authentication_rules] || defaults[:early_authentication_rules], + :late_rules => settings[:late_authentication_rules] || defaults[:late_authentication_rules] + if File.exists?("/etc/init.d/postgresql-#{version}") + notifies :reload, resources(:service => "postgresql-#{version}") + else + notifies :reload, resources(:service => "postgresql") + end + end + + template "/etc/postgresql/#{version}/main/pg_ident.conf" do + source "pg_ident.conf.erb" + owner "postgres" + group "postgres" + mode 0640 + variables :maps => settings[:user_name_maps] || defaults[:user_name_maps] + if File.exists?("/etc/init.d/postgresql-#{version}") + notifies :reload, resources(:service => "postgresql-#{version}") + else + notifies :reload, resources(:service => "postgresql") + end + end + + link "/var/lib/postgresql/#{version}/main/server.crt" do + to "/etc/ssl/certs/ssl-cert-snakeoil.pem" + end + + link "/var/lib/postgresql/#{version}/main/server.key" do + to "/etc/ssl/private/ssl-cert-snakeoil.key" + end + + restore_command = settings[:restore_command] || defaults[:restore_command] + standby_mode = settings[:standby_mode] || defaults[:standby_mode] + + if restore_command || standby_mode == "on" + template "/var/lib/postgresql/#{version}/main/recovery.conf" do + source "recovery.conf.erb" + owner "postgres" + group "postgres" + mode 0640 + variables :defaults => defaults, :settings => settings + if File.exists?("/etc/init.d/postgresql-#{version}") + notifies :reload, resources(:service => "postgresql-#{version}") + else + notifies :reload, resources(:service => "postgresql") + end + end + else + template "/var/lib/postgresql/#{version}/main/recovery.conf" do + action :delete + if File.exists?("/etc/init.d/postgresql-#{version}") + notifies :reload, resources(:service => "postgresql-#{version}") + else + notifies :reload, resources(:service => "postgresql") + end + end + end +end + +ohai_plugin "postgresql" do + template "ohai.rb.erb" +end + +package "ptop" +package "libdbd-pg-perl" + +clusters = node[:postgresql][:clusters] || [] + +clusters.each do |name,details| + suffix = name.tr("/", ":") + + munin_plugin "postgres_bgwriter_#{suffix}" do + target "postgres_bgwriter" + conf "munin.erb" + conf_variables :port => details[:port] + end + + munin_plugin "postgres_checkpoints_#{suffix}" do + target "postgres_checkpoints" + conf "munin.erb" + conf_variables :port => details[:port] + end + + munin_plugin "postgres_connections_db_#{suffix}" do + target "postgres_connections_db" + conf "munin.erb" + conf_variables :port => details[:port] + end + + munin_plugin "postgres_users_#{suffix}" do + target "postgres_users" + conf "munin.erb" + conf_variables :port => details[:port] + end + + munin_plugin "postgres_xlog_#{suffix}" do + target "postgres_xlog" + conf "munin.erb" + conf_variables :port => details[:port] + end + + if File.exist?("/var/lib/postgresql/#{details[:version]}/main/recovery.conf") + munin_plugin "postgres_replication_#{suffix}" do + target "postgres_replication" + conf "munin.erb" + conf_variables :port => details[:port] + end + end +end diff --git a/cookbooks/postgresql/resources/database.rb b/cookbooks/postgresql/resources/database.rb new file mode 100644 index 000000000..039c12467 --- /dev/null +++ b/cookbooks/postgresql/resources/database.rb @@ -0,0 +1,30 @@ +# +# Cookbook Name:: postgresql +# Resource:: postgresql_database +# +# Copyright 2012, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +actions :create, :drop + +attribute :database, :kind_of => String, :name_attribute => true +attribute :cluster, :kind_of => String, :required => true +attribute :owner, :kind_of => String, :required => true +attribute :encoding, :kind_of => String, :default => "UTF8" + +def initialize(*args) + super + @action = :create +end diff --git a/cookbooks/postgresql/resources/execute.rb b/cookbooks/postgresql/resources/execute.rb new file mode 100644 index 000000000..49ff80e4f --- /dev/null +++ b/cookbooks/postgresql/resources/execute.rb @@ -0,0 +1,31 @@ +# +# Cookbook Name:: postgresql +# Resource:: postgresql_execute +# +# Copyright 2012, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +actions :nothing, :run + +attribute :command, :kind_of => String, :name_attribute => true +attribute :cluster, :kind_of => String, :required => true +attribute :database, :kind_of => String, :required => true +attribute :user, :default => "postgres" +attribute :group, :default => "postgres" + +def initialize(*args) + super + @action = :run +end diff --git a/cookbooks/postgresql/resources/extension.rb b/cookbooks/postgresql/resources/extension.rb new file mode 100644 index 000000000..8c876f473 --- /dev/null +++ b/cookbooks/postgresql/resources/extension.rb @@ -0,0 +1,29 @@ +# +# Cookbook Name:: postgresql +# Resource:: postgresql_extension +# +# Copyright 2012, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +actions :create, :drop + +attribute :extension, :kind_of => String, :name_attribute => true +attribute :cluster, :kind_of => String, :required => true +attribute :database, :kind_of => String, :required => true + +def initialize(*args) + super + @action = :create +end diff --git a/cookbooks/postgresql/resources/table.rb b/cookbooks/postgresql/resources/table.rb new file mode 100644 index 000000000..9bf1fe1cd --- /dev/null +++ b/cookbooks/postgresql/resources/table.rb @@ -0,0 +1,28 @@ +# +# Cookbook Name:: postgresql +# Resource:: postgresql_table +# +# Copyright 2013, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +actions :create, :drop +default_action :create + +attribute :table, :kind_of => String, :name_attribute => true +attribute :cluster, :kind_of => String, :required => true +attribute :database, :kind_of => String, :required => true +attribute :schema, :kind_of => String, :default => "public" +attribute :owner, :kind_of => String, :required => true +attribute :permissions, :kind_of => Hash, :default => {} diff --git a/cookbooks/postgresql/resources/user.rb b/cookbooks/postgresql/resources/user.rb new file mode 100644 index 000000000..f5fefa35a --- /dev/null +++ b/cookbooks/postgresql/resources/user.rb @@ -0,0 +1,33 @@ +# +# Cookbook Name:: postgresql +# Resource:: postgresql_user +# +# Copyright 2012, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +actions :create, :drop + +attribute :user, :kind_of => String, :name_attribute => true +attribute :cluster, :kind_of => String, :required => true +attribute :password, :kind_of => String +attribute :superuser, :default => false +attribute :createdb, :default => false +attribute :createrole, :default => false +attribute :replication, :default => false + +def initialize(*args) + super + @action = :create +end diff --git a/cookbooks/postgresql/templates/default/munin.erb b/cookbooks/postgresql/templates/default/munin.erb new file mode 100644 index 000000000..fd08870d4 --- /dev/null +++ b/cookbooks/postgresql/templates/default/munin.erb @@ -0,0 +1,6 @@ +# DO NOT EDIT - This file is being maintained by Chef + +[<%= @name %>] +user postgres +env.PGUSER postgres +env.PGPORT <%= @port %> diff --git a/cookbooks/postgresql/templates/default/ohai.rb.erb b/cookbooks/postgresql/templates/default/ohai.rb.erb new file mode 100644 index 000000000..e3eca3a35 --- /dev/null +++ b/cookbooks/postgresql/templates/default/ohai.rb.erb @@ -0,0 +1,17 @@ +provides "postgresql" + +postgresql Mash.new + +Dir.glob("/etc/postgresql/*/*/postgresql.conf").each do |conf| + cluster = conf.sub("/etc/postgresql/", "").sub("/postgresql.conf", "") + + postgresql[:clusters] = Mash.new unless postgresql[:clusters] + postgresql[:clusters][cluster] = Mash.new unless postgresql[:clusters][cluster] + postgresql[:clusters][cluster][:version] = cluster.split("/").first.to_f + + IO.foreach(conf) do |line| + if line =~ /^ *port *= *([0-9]+)\s+/ + postgresql[:clusters][cluster][:port] = $1 + end + end +end diff --git a/cookbooks/postgresql/templates/default/pg_hba.conf.erb b/cookbooks/postgresql/templates/default/pg_hba.conf.erb new file mode 100644 index 000000000..18b490c03 --- /dev/null +++ b/cookbooks/postgresql/templates/default/pg_hba.conf.erb @@ -0,0 +1,12 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# TYPE DATABASE USER ADDRESS METHOD +<% @early_rules.each do |rule| -%> +<%= rule[:type] || "host" %> <%= rule[:database] || "all" %> <%= rule[:user] || "all" %> <%= rule[:address] %> <%= rule[:method] || "md5" %> <%= (rule[:options] || {}).collect { |k,v| "#{k}=#{v}" }.join(" ") %> +<% end -%> +local all all peer +host all all 127.0.0.1/32 md5 +host all all ::1/128 md5 +<% @late_rules.each do |rule| -%> +<%= rule[:type] || "host" %> <%= rule[:database] || "all" %> <%= rule[:user] || "all" %> <%= rule[:address] %> <%= rule[:method] || "md5" %> <%= (rule[:options] || {}).collect { |k,v| "#{k}=#{v}" }.join(" ") %> +<% end -%> diff --git a/cookbooks/postgresql/templates/default/pg_ident.conf.erb b/cookbooks/postgresql/templates/default/pg_ident.conf.erb new file mode 100644 index 000000000..d46a05fc3 --- /dev/null +++ b/cookbooks/postgresql/templates/default/pg_ident.conf.erb @@ -0,0 +1,8 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# MAPNAME SYSTEM-USERNAME PG-USERNAME +<% @maps.keys.each do |name| -%> +<% @maps[name].each do |user| -%> +<%= name %> <%= user[:system] %> <%= user[:postgres] %> +<% end -%> +<% end -%> diff --git a/cookbooks/postgresql/templates/default/postgresql.conf.erb b/cookbooks/postgresql/templates/default/postgresql.conf.erb new file mode 100644 index 000000000..01b796862 --- /dev/null +++ b/cookbooks/postgresql/templates/default/postgresql.conf.erb @@ -0,0 +1,119 @@ +# DO NOT EDIT - This file is being maintained by Chef + +#------------------------------------------------------------------------------ +# FILE LOCATIONS +#------------------------------------------------------------------------------ + +data_directory = '/var/lib/postgresql/<%= @version %>/main' +hba_file = '/etc/postgresql/<%= @version %>/main/pg_hba.conf' +ident_file = '/etc/postgresql/<%= @version %>/main/pg_ident.conf' +external_pid_file = '/var/run/postgresql/<%= @version %>-main.pid' + +#------------------------------------------------------------------------------ +# CONNECTIONS AND AUTHENTICATION +#------------------------------------------------------------------------------ + +# - Connection Settings - + +<% if @settings[:listen_addresses] || @defaults[:listen_addresses] -%> +listen_addresses = '<%= @settings[:listen_addresses] || @defaults[:listen_addresses] %>' +<% end -%> +port = <%= @settings[:port] || @defaults[:port] %> +max_connections = <%= @settings[:max_connections] || @defaults[:max_connections] %> +unix_socket_directory = '/var/run/postgresql' + +# - Security and Authentication - + +ssl = true +ssl_renegotiation_limit = 0 + +#------------------------------------------------------------------------------ +# RESOURCE USAGE (except WAL) +#------------------------------------------------------------------------------ + +# - Memory - + +shared_buffers = <%= @settings[:shared_buffers] || @defaults[:shared_buffers] %> +temp_buffers = <%= @settings[:temp_buffers] || @defaults[:temp_buffers] %> +work_mem = <%= @settings[:work_mem] || @defaults[:work_mem] %> +maintenance_work_mem = <%= @settings[:maintenance_work_mem] || @defaults[:maintenance_work_mem] %> +max_stack_depth = <%= @settings[:max_stack_depth] || @defaults[:max_stack_depth] %> + +#------------------------------------------------------------------------------ +# WRITE AHEAD LOG +#------------------------------------------------------------------------------ + +# - Settings - + +wal_level = <%= @settings[:wal_level] || @defaults[:wal_level] %> +fsync = <%= @settings[:fsync] || @defaults[:fsync] %> +synchronous_commit = <%= @settings[:synchronous_commit] || @defaults[:synchronous_commit] %> +wal_buffers = <%= @settings[:wal_buffers] || @defaults[:wal_buffers] %> +wal_writer_delay = <%= @settings[:wal_writer_delay] || @defaults[:wal_writer_delay] %> +commit_delay = <%= @settings[:commit_delay] || @defaults[:commit_delay] %> + +# - Checkpoints - + +checkpoint_segments = <%= @settings[:checkpoint_segments] || @defaults[:checkpoint_segments] %> +checkpoint_timeout = <%= @settings[:checkpoint_timeout] || @defaults[:checkpoint_timeout] %> +checkpoint_completion_target = <%= @settings[:checkpoint_completion_target] || @defaults[:checkpoint_completion_target] %> + +# - Archiving - + +archive_mode = <%= @settings[:archive_mode] || @defaults[:archive_mode] %> +<% if @settings[:archive_command] || @defaults[:archive_command] -%> +archive_command = '<%= @settings[:archive_command] || @defaults[:archive_command] %>' +<% end -%> + +#------------------------------------------------------------------------------ +# REPLICATION +#------------------------------------------------------------------------------ + +# - Sending Server(s) - + +max_wal_senders = <%= @settings[:max_wal_senders] || @defaults[:max_wal_senders] %> + +# - Standby Servers - + +hot_standby = <%= @settings[:hot_standby] || @defaults[:hot_standby] %> +hot_standby_feedback = <%= @settings[:hot_standby_feedback] || @defaults[:hot_standby_feedback] %> + +#------------------------------------------------------------------------------ +# QUERY TUNING +#------------------------------------------------------------------------------ + +# - Planner Cost Constants - + +random_page_cost = <%= @settings[:random_page_cost] || @defaults[:random_page_cost] %> +effective_cache_size = <%= @settings[:effective_cache_size] || @defaults[:effective_cache_size] %> + +#------------------------------------------------------------------------------ +# ERROR REPORTING AND LOGGING +#------------------------------------------------------------------------------ + +# - When to Log - + +log_min_duration_statement = <%= @settings[:log_min_duration_statement] || @defaults[:log_min_duration_statement] %> + +# - What to Log - + +log_line_prefix = '%t ' + +#------------------------------------------------------------------------------ +# AUTOVACUUM PARAMETERS +#------------------------------------------------------------------------------ + +autovacuum_max_workers = <%= @settings[:autovacuum_max_workers] || @defaults[:autovacuum_max_workers] %> + +#------------------------------------------------------------------------------ +# CLIENT CONNECTION DEFAULTS +#------------------------------------------------------------------------------ + +# - Locale and Formatting - + +datestyle = 'iso, dmy' +lc_messages = 'en_GB.UTF-8' +lc_monetary = 'en_GB.UTF-8' +lc_numeric = 'en_GB.UTF-8' +lc_time = 'en_GB.UTF-8' +default_text_search_config = 'pg_catalog.english' diff --git a/cookbooks/postgresql/templates/default/recovery.conf.erb b/cookbooks/postgresql/templates/default/recovery.conf.erb new file mode 100644 index 000000000..f7628906c --- /dev/null +++ b/cookbooks/postgresql/templates/default/recovery.conf.erb @@ -0,0 +1,9 @@ +# DO NOT EDIT - This file is being maintained by Chef + +standby_mode = <%= @settings[:standby_mode] || @defaults[:standby_mode] %> +<% if @settings[:primary_conninfo] || @defaults[:primary_conninfo] -%> +primary_conninfo = '<%= @settings[:primary_conninfo] || @defaults[:primary_conninfo] %>' +<% end -%> +<% if @settings[:restore_command] || @defaults[:restore_command] -%> +restore_command = '<%= @settings[:restore_command] || @defaults[:restore_command] %>' +<% end -%> diff --git a/cookbooks/rsyncd/README.md b/cookbooks/rsyncd/README.md new file mode 100644 index 000000000..6b087690a --- /dev/null +++ b/cookbooks/rsyncd/README.md @@ -0,0 +1,57 @@ +DESCRIPTION +=========== + +Configures networking. + +USAGE +===== + +Set the networking attributes in a role, for example from my base.rb: + + :networking => { + :nameservers => [ "10.13.37.120", "10.13.37.40" ], + :search => [ "int.example.org". "example.org" ] + } + +The resulting /etc/resolv.conf will look like: + + search int.example.org example.org + nameserver 10.13.37.120 + nameserver 10.13.37.40 + +LICENSE AND AUTHOR +================== + +Author:: OpenStreetMap Administrators () + +Copyright 2010, OpenStreetMap Foundation. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Based on resolver cookbook: + +Author:: Joshua Timberman () + +Copyright 2009, Opscode, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/cookbooks/rsyncd/attributes/default.rb b/cookbooks/rsyncd/attributes/default.rb new file mode 100644 index 000000000..55bd9a78d --- /dev/null +++ b/cookbooks/rsyncd/attributes/default.rb @@ -0,0 +1 @@ +default[:rsyncd][:modules] = [ ] diff --git a/cookbooks/rsyncd/metadata.rb b/cookbooks/rsyncd/metadata.rb new file mode 100644 index 000000000..790d94648 --- /dev/null +++ b/cookbooks/rsyncd/metadata.rb @@ -0,0 +1,17 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Configures rsyncd" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) +version "1.0.0" +depends "networking" + +attribute "rsyncd", + :display_name => "rsyncd", + :description => "Hash of rsyncd attributes", + :type => "hash" + +attribute "rsyncd/modules", + :display_name => "rsyncd", + :description => "Hash of rsyncd modules to configure", + :type => "hash" diff --git a/cookbooks/rsyncd/recipes/default.rb b/cookbooks/rsyncd/recipes/default.rb new file mode 100644 index 000000000..5f090d1ce --- /dev/null +++ b/cookbooks/rsyncd/recipes/default.rb @@ -0,0 +1,51 @@ +# +# Cookbook Name:: rsyncd +# Recipe:: default +# +# Copyright 2011, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include_recipe "networking" + +package "rsync" + +service "rsync" do + action [ :enable, :start ] + supports :status => true, :restart => true +end + +template "/etc/default/rsync" do + source "rsync.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "rsync") +end + +template "/etc/rsyncd.conf" do + source "rsyncd.conf.erb" + owner "root" + group "root" + mode 0644 +end + +firewall_rule "accept-rsync" do + action :accept + source "net" + dest "fw" + proto "tcp:syn" + dest_ports "rsync" + source_ports "1024:" +end diff --git a/cookbooks/rsyncd/templates/default/rsync.erb b/cookbooks/rsyncd/templates/default/rsync.erb new file mode 100644 index 000000000..013f02914 --- /dev/null +++ b/cookbooks/rsyncd/templates/default/rsync.erb @@ -0,0 +1,43 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# defaults file for rsync daemon mode + +# start rsync in daemon mode from init.d script? +# only allowed values are "true", "false", and "inetd" +# Use "inetd" if you want to start the rsyncd from inetd, +# all this does is prevent the init.d script from printing a message +# about not starting rsyncd (you still need to modify inetd's config yourself). +RSYNC_ENABLE=true + +# which file should be used as the configuration file for rsync. +# This file is used instead of the default /etc/rsyncd.conf +# Warning: This option has no effect if the daemon is accessed +# using a remote shell. When using a different file for +# rsync you might want to symlink /etc/rsyncd.conf to +# that file. +# RSYNC_CONFIG_FILE= + +# what extra options to give rsync --daemon? +# that excludes the --daemon; that's always done in the init.d script +# Possibilities are: +# --address=123.45.67.89 (bind to a specific IP address) +# --port=8730 (bind to specified port; default 873) +RSYNC_OPTS='' + +# run rsyncd at a nice level? +# the rsync daemon can impact performance due to much I/O and CPU usage, +# so you may want to run it at a nicer priority than the default priority. +# Allowed values are 0 - 19 inclusive; 10 is a reasonable value. +RSYNC_NICE='10' + +# run rsyncd with ionice? +# "ionice" does for IO load what "nice" does for CPU load. +# As rsync is often used for backups which aren't all that time-critical, +# reducing the rsync IO priority will benefit the rest of the system. +# See the manpage for ionice for allowed options. +# -c3 is recommended, this will run rsync IO at "idle" priority. Uncomment +# the next line to activate this. +RSYNC_IONICE='-c3' + +# Don't forget to create an appropriate config file, +# else the daemon will not start. diff --git a/cookbooks/rsyncd/templates/default/rsyncd.conf.erb b/cookbooks/rsyncd/templates/default/rsyncd.conf.erb new file mode 100644 index 000000000..adc04a899 --- /dev/null +++ b/cookbooks/rsyncd/templates/default/rsyncd.conf.erb @@ -0,0 +1,43 @@ +# DO NOT EDIT - This file is being maintained by Chef +<% node[:rsyncd][:modules].each do |name,details| -%> + +[<%= name %>] + comment = <%= details[:comment] %> + path = <%= details[:path] %> + use chroot = yes + read only = <%= details[:read_only] %> + write only = <%= details[:write_only] %> + list = <%= details[:list] %> + uid = <%= details[:uid] %> + gid = <%= details[:gid] %> + transfer logging = <%= details[:transfer_logging] %> +<% if details[:include] -%> + include = <%= details[:include].join(" ") %> +<% end -%> +<% if details[:exclude] -%> + exclude = <%= details[:exclude].join(" ") %> +<% end -%> +<% if details[:max_connections] -%> + max connections = <%= details[:max_connections] %> + lock file = /var/run/rsyncd.<%= name %>.lock +<% end -%> +<% if details[:ignore_errors] -%> + ignore errors = true +<% end -%> +<% if details[:ignore_nonreadable] -%> + ignore nonreadable = true +<% end -%> +<% if details[:timeout] -%> + timeout = <%= details[:timeout] %> +<% end -%> +<% if details[:refuse_options] -%> + refuse options = <%= details[:refuse_options].join(" ") %> +<% end -%> +<% if details[:hosts_allow] -%> + hosts allow = <%= details[:hosts_allow].join(",") %> +<% end -%> +<% if details[:hosts_deny] -%> + hosts deny = <%= details[:hosts_deny].join(",") %> +<% end -%> + dont compress = *.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz *.7z +<% end -%> diff --git a/cookbooks/spamassassin/README.rdoc b/cookbooks/spamassassin/README.rdoc new file mode 100644 index 000000000..3de2ec7a3 --- /dev/null +++ b/cookbooks/spamassassin/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/cookbooks/spamassassin/metadata.rb b/cookbooks/spamassassin/metadata.rb new file mode 100644 index 000000000..d662a9250 --- /dev/null +++ b/cookbooks/spamassassin/metadata.rb @@ -0,0 +1,6 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Installs and configures spamassassin" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "1.0.0" diff --git a/cookbooks/spamassassin/recipes/default.rb b/cookbooks/spamassassin/recipes/default.rb new file mode 100644 index 000000000..ec1109c76 --- /dev/null +++ b/cookbooks/spamassassin/recipes/default.rb @@ -0,0 +1,52 @@ +# +# Cookbook Name:: spamassassin +# Recipe:: default +# +# Copyright 2011, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package "spamassassin" + +service "spamassassin" do + action [ :enable, :start ] + supports :status => true, :restart => true, :reload => true +end + +template "/etc/default/spamassassin" do + source "spamassassin.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "spamassassin") +end + +trusted_networks = node[:exim][:relay_from_hosts] + +if node[:exim][:smarthost_name] + search(:node, "exim_smarthost_via:#{node[:exim][:smarthost_name]}\\:*").each do |host| + trusted_networks = trusted_networks | host.ipaddresses(:role => :external) + end +end + +trusted_networks = trusted_networks - [ "127.0.0.1", "::1" ] + +template "/etc/spamassassin/local.cf" do + source "local.cf.erb" + owner "root" + group "root" + mode 0644 + variables :trusted_networks => trusted_networks.sort + notifies :restart, resources(:service => "spamassassin") +end diff --git a/cookbooks/spamassassin/templates/default/local.cf.erb b/cookbooks/spamassassin/templates/default/local.cf.erb new file mode 100644 index 000000000..be8b7736a --- /dev/null +++ b/cookbooks/spamassassin/templates/default/local.cf.erb @@ -0,0 +1,7 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# Set the threshold at which a message is considered spam +required_score 5.0 + +# Set which networks or hosts are considered 'trusted' +trusted_networks <%= @trusted_networks.join(" ") %> diff --git a/cookbooks/spamassassin/templates/default/spamassassin.erb b/cookbooks/spamassassin/templates/default/spamassassin.erb new file mode 100644 index 000000000..e64c19be9 --- /dev/null +++ b/cookbooks/spamassassin/templates/default/spamassassin.erb @@ -0,0 +1,27 @@ +# DO NOT EDIT - This file is being maintained by Chef + +# Change to one to enable spamd +ENABLED=1 + +# Options +# See man spamd for possible options. The -d option is automatically added. + +# SpamAssassin uses a preforking model, so be careful! You need to +# make sure --max-children is not set to anything higher than 5, +# unless you know what you're doing. + +OPTIONS="--username mail --nouser-config" + +# Pid file +# Where should spamd write its PID to file? If you use the -u or +# --username option above, this needs to be writable by that user. +# Otherwise, the init script will not be able to shut spamd down. +PIDFILE="/var/run/spamd.pid" + +# Set nice level of spamd +#NICE="--nicelevel 15" + +# Cronjob +# Set to anything but 0 to enable the cron job to automatically update +# spamassassin's rules on a nightly basis +CRON=1 diff --git a/cookbooks/switch2osm/README.rdoc b/cookbooks/switch2osm/README.rdoc new file mode 100644 index 000000000..3de2ec7a3 --- /dev/null +++ b/cookbooks/switch2osm/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/cookbooks/switch2osm/metadata.rb b/cookbooks/switch2osm/metadata.rb new file mode 100644 index 000000000..a73dbb8f5 --- /dev/null +++ b/cookbooks/switch2osm/metadata.rb @@ -0,0 +1,7 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Installs and configures servers for switch2osm" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "1.0.0" +depends "wordpress" diff --git a/cookbooks/switch2osm/recipes/default.rb b/cookbooks/switch2osm/recipes/default.rb new file mode 100644 index 000000000..d394d7e58 --- /dev/null +++ b/cookbooks/switch2osm/recipes/default.rb @@ -0,0 +1,36 @@ +# +# Cookbook Name:: switch2osm +# Recipe:: default +# +# Copyright 2013, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include_recipe "wordpress" + +passwords = data_bag_item("switch2osm", "passwords") + +wordpress_site "switch2osm.org" do + aliases "www.switch2osm.org", "switch2osm.com", "www.switch2osm.com" + directory "/srv/switch2osm.org" + database_name "switch2osm-blog" + database_user "switch2osm-user" + database_password passwords["switch2osm-user"] +end + +wordpress_theme "picolight" do + site "switch2osm.org" + repository "git://github.com/Firefishy/picolight-s2o.git" + revision "master" +end diff --git a/cookbooks/thinkup/README.rdoc b/cookbooks/thinkup/README.rdoc new file mode 100644 index 000000000..3de2ec7a3 --- /dev/null +++ b/cookbooks/thinkup/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/cookbooks/thinkup/metadata.rb b/cookbooks/thinkup/metadata.rb new file mode 100644 index 000000000..1ef9c8c0f --- /dev/null +++ b/cookbooks/thinkup/metadata.rb @@ -0,0 +1,8 @@ +maintainer "OpenStreetMap Administrators" +maintainer_email "admins@openstreetmap.org" +license "Apache 2.0" +description "Installs and configures ThinkUp" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "1.0.0" +depends "apache" +depends "mysql" diff --git a/cookbooks/thinkup/recipes/default.rb b/cookbooks/thinkup/recipes/default.rb new file mode 100644 index 000000000..ab85e645e --- /dev/null +++ b/cookbooks/thinkup/recipes/default.rb @@ -0,0 +1,116 @@ +# +# Cookbook Name:: thinkup +# Recipe:: default +# +# Copyright 2011, OpenStreetMap Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include_recipe "apache" +include_recipe "mysql" + +passwords = data_bag_item("thinkup", "passwords") + +package "php5" +package "php5-cli" +package "php5-curl" +package "php5-mysql" +package "php5-gd" + +package "php-apc" + +apache_module "php5" + +apache_site "thinkup.openstreetmap.org" do + template "apache.erb" +end + +mysql_user "thinkup@localhost" do + password passwords["database"] +end + +mysql_database "thinkup" do + permissions "thinkup@localhost" => :all +end + +git "/srv/thinkup.openstreetmap.org" do + action :sync + repository "git://github.com/ginatrapani/ThinkUp.git" + revision "v1.2.1" + user "root" + group "root" + notifies :reload, resources(:service => "apache2") +end + +directory "/srv/thinkup.openstreetmap.org/logs" do + owner "thinkup" + group "thinkup" + mode "0755" +end + +directory "/srv/thinkup.openstreetmap.org/logs/archive" do + owner "thinkup" + group "thinkup" + mode "0755" +end + +directory "/srv/thinkup.openstreetmap.org/webapp/data" do + owner "www-data" + group "www-data" + mode "0755" +end + +directory "/srv/thinkup.openstreetmap.org/webapp/_lib/view/compiled_view" do + owner "www-data" + group "www-data" + mode "0755" +end + +file "/srv/thinkup.openstreetmap.org/webapp/config.inc.php" do + owner "root" + group "root" + mode 0644 + content_from_file "/srv/thinkup.openstreetmap.org/webapp/config.sample.inc.php" do |line| + line.gsub!(/^(\$THINKUP_CFG\['site_root_path'\] *=) '[^']*';$/, "\\1 '/';") + line.gsub!(/^(\$THINKUP_CFG\['timezone'\] *=) '[^']*';$/, "\\1 'Europe/London';") + line.gsub!(/^(\$THINKUP_CFG\['db_user'\] *=) '[^']*';$/, "\\1 'thinkup';") + line.gsub!(/^(\$THINKUP_CFG\['db_password'\] *=) '[^']*';$/, "\\1 '#{passwords["database"]}';") + line.gsub!(/^(\$THINKUP_CFG\['db_name'\] *=) '[^']*';$/, "\\1 'thinkup';") + + line + end + notifies :reload, resources(:service => "apache2") +end + +file "/srv/thinkup.openstreetmap.org/extras/cron/config" do + owner "root" + group "thinkup" + mode 0640 + content_from_file "/srv/thinkup.openstreetmap.org/extras/cron/config.sample" do |line| + line.gsub!(/^thinkup="[^"]*"$/, "thinkup=\"/srv/thinkup.openstreetmap.org\"") + line.gsub!(/^thinkup_username="[^"]*"$/, "thinkup_username=\"openstreetmap@jonno.cix.co.uk\"") + line.gsub!(/^thinkup_password="[^"]*"$/, "thinkup_password=\"#{passwords["admin"]}\"") + line.gsub!(/^php="[^"]*"$/, "php=\"/usr/bin/php\"") + line.gsub!(/^#crawl_interval=[0-9]+$/, "crawl_interval=30") + + line + end +end + +template "/etc/cron.d/thinkup" do + source "cron.erb" + owner "root" + group "root" + mode "0644" +end diff --git a/cookbooks/thinkup/templates/default/apache.erb b/cookbooks/thinkup/templates/default/apache.erb new file mode 100644 index 000000000..fa40d7f8a --- /dev/null +++ b/cookbooks/thinkup/templates/default/apache.erb @@ -0,0 +1,12 @@ +# DO NOT EDIT - This file is being maintained by Chef + + + ServerName thinkup.openstreetmap.org + ServerAlias thinkup.osm.org + ServerAdmin webmaster@openstreetmap.org + + CustomLog /var/log/apache2/thinkup.openstreetmap.org-access.log combined + ErrorLog /var/log/apache2/thinkup.openstreetmap.org-error.log + + DocumentRoot /srv/thinkup.openstreetmap.org/webapp + diff --git a/cookbooks/thinkup/templates/default/cron.erb b/cookbooks/thinkup/templates/default/cron.erb new file mode 100644 index 000000000..b0b4d09ae --- /dev/null +++ b/cookbooks/thinkup/templates/default/cron.erb @@ -0,0 +1 @@ +0 * * * * thinkup /srv/thinkup.openstreetmap.org/extras/cron/cron > /srv/thinkup.openstreetmap.org/logs/crawler-$(date +\%Y\%m\%d\%H\%M\%S).log 2>&1