]> git.openstreetmap.org Git - chef.git/blob - cookbooks/nominatim/recipes/default.rb
46a03fc9148ade9af1003d54adb77b82144389de
[chef.git] / cookbooks / nominatim / recipes / default.rb
1 #
2 # Cookbook:: nominatim
3 # Recipe:: base
4 #
5 # Copyright:: 2015, OpenStreetMap Foundation
6 #
7 # Licensed under the Apache License, Version 2.0 (the "License");
8 # you may not use this file except in compliance with the License.
9 # You may obtain a copy of the License at
10 #
11 #     https://www.apache.org/licenses/LICENSE-2.0
12 #
13 # Unless required by applicable law or agreed to in writing, software
14 # distributed under the License is distributed on an "AS IS" BASIS,
15 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 # See the License for the specific language governing permissions and
17 # limitations under the License.
18 #
19
20 include_recipe "accounts"
21 include_recipe "munin"
22
23 basedir = data_bag_item("accounts", "nominatim")["home"]
24 email_errors = data_bag_item("accounts", "lonvia")["email"]
25
26 directory basedir do
27   owner "nominatim"
28   group "nominatim"
29   mode 0o755
30   recursive true
31 end
32
33 directory node[:nominatim][:logdir] do
34   owner "nominatim"
35   group "nominatim"
36   mode 0o755
37   recursive true
38 end
39
40 file "#{node[:nominatim][:logdir]}/query.log" do
41   action :create_if_missing
42   owner "www-data"
43   group "adm"
44   mode 0o664
45 end
46
47 file "#{node[:nominatim][:logdir]}/update.log" do
48   action :create_if_missing
49   owner "nominatim"
50   group "adm"
51   mode 0o664
52 end
53
54 # exception granted for a limited time so that they can set up their own server
55 firewall_rule "increase-limits-gnome-proxy" do
56   action :accept
57   family "inet"
58   source "net:8.43.85.23"
59   dest "fw"
60   proto "tcp:syn"
61   dest_ports "https"
62   rate_limit "s:10/sec:30"
63 end
64
65 ## Postgresql
66
67 include_recipe "postgresql"
68
69 postgresql_version = node[:nominatim][:dbcluster].split("/").first
70 postgis_version = node[:nominatim][:postgis]
71
72 package "postgresql-#{postgresql_version}-postgis-#{postgis_version}"
73
74 node[:nominatim][:dbadmins].each do |user|
75   postgresql_user user do
76     cluster node[:nominatim][:dbcluster]
77     superuser true
78     only_if { node[:nominatim][:state] != "slave" }
79   end
80 end
81
82 postgresql_user "nominatim" do
83   cluster node[:nominatim][:dbcluster]
84   superuser true
85   only_if { node[:nominatim][:state] != "slave" }
86 end
87
88 postgresql_user "www-data" do
89   cluster node[:nominatim][:dbcluster]
90   only_if { node[:nominatim][:state] != "slave" }
91 end
92
93 postgresql_munin "nominatim" do
94   cluster node[:nominatim][:dbcluster]
95   database node[:nominatim][:dbname]
96 end
97
98 directory "#{basedir}/tablespaces" do
99   owner "postgres"
100   group "postgres"
101   mode 0o700
102 end
103
104 # Note: tablespaces must be exactly in the same location on each
105 #       Nominatim instance when replication is in use. Therefore
106 #       use symlinks to canonical directory locations.
107 node[:nominatim][:tablespaces].each do |name, location|
108   directory location do
109     owner "postgres"
110     group "postgres"
111     mode 0o700
112     recursive true
113   end
114
115   link "#{basedir}/tablespaces/#{name}" do
116     to location
117   end
118
119   postgresql_tablespace name do
120     cluster node[:nominatim][:dbcluster]
121     location "#{basedir}/tablespaces/#{name}"
122   end
123 end
124
125 if node[:nominatim][:state] == "master"
126   postgresql_user "replication" do
127     cluster node[:nominatim][:dbcluster]
128     password data_bag_item("nominatim", "passwords")["replication"]
129     replication true
130   end
131
132   directory node[:rsyncd][:modules][:archive][:path] do
133     owner "postgres"
134     group "postgres"
135     mode 0o700
136   end
137
138   template "/usr/local/bin/clean-db-nominatim" do
139     source "clean-db-nominatim.erb"
140     owner "root"
141     group "root"
142     mode 0o755
143     variables :archive_dir => node[:rsyncd][:modules][:archive][:path],
144               :update_stop_file => "#{basedir}/status/updates_disabled",
145               :streaming_clients => search(:node, "nominatim_state:slave").map { |slave| slave[:fqdn] }.join(" ")
146   end
147 end
148
149 ## Nominatim backend
150
151 include_recipe "git"
152
153 package %w[
154   build-essential
155   cmake
156   g++
157   libboost-dev
158   libboost-system-dev
159   libboost-filesystem-dev
160   libexpat1-dev
161   zlib1g-dev
162   libxml2-dev
163   libbz2-dev
164   libpq-dev
165   libgeos++-dev
166   libproj-dev
167   python3-pyosmium
168   pyosmium
169   python3-psycopg2
170   php
171   php-fpm
172   php-pgsql
173   php-intl
174 ]
175
176 source_directory = "#{basedir}/nominatim"
177 build_directory = "#{basedir}/bin"
178
179 directory build_directory do
180   owner "nominatim"
181   group "nominatim"
182   mode 0o755
183   recursive true
184 end
185
186 # Normally syncing via chef is a bad idea because syncing might involve
187 # an update of database functions which should not be done while an update
188 # is ongoing. Therefore we sync in between update cycles. There is an
189 # exception for slaves: they get DB function updates from the master, so
190 # only the source code needs to be updated, which chef may do.
191 git source_directory do
192   action node[:nominatim][:state] == "slave" ? :sync : :checkout
193   repository node[:nominatim][:repository]
194   revision node[:nominatim][:revision]
195   enable_submodules true
196   user "nominatim"
197   group "nominatim"
198   not_if { node[:nominatim][:state] != "slave" && File.exist?("#{source_directory}/README.md") }
199   notifies :run, "execute[compile_nominatim]", :immediately
200 end
201
202 execute "compile_nominatim" do
203   action :nothing
204   user "nominatim"
205   cwd build_directory
206   command "cmake #{source_directory} && make"
207 end
208
209 template "#{source_directory}/.git/hooks/post-merge" do
210   source "git-post-merge-hook.erb"
211   owner "nominatim"
212   group "nominatim"
213   mode 0o755
214   variables :srcdir => source_directory,
215             :builddir => build_directory,
216             :dbname => node[:nominatim][:dbname]
217 end
218
219 template "#{build_directory}/settings/local.php" do
220   source "settings.erb"
221   owner "nominatim"
222   group "nominatim"
223   mode 0o664
224   variables :base_url => node[:nominatim][:state] == "off" ? node[:fqdn] : "nominatim.openstreetmap.org",
225             :dbname => node[:nominatim][:dbname],
226             :flatnode_file => node[:nominatim][:flatnode_file],
227             :log_file => "#{node[:nominatim][:logdir]}/query.log"
228 end
229
230 if node[:nominatim][:flatnode_file]
231   directory File.dirname(node[:nominatim][:flatnode_file]) do
232     recursive true
233   end
234 end
235
236 template "/etc/logrotate.d/nominatim" do
237   source "logrotate.nominatim.erb"
238   owner "root"
239   group "root"
240   mode 0o644
241 end
242
243 external_data = [
244   "wikimedia-importance.sql.gz",
245   "gb_postcode_data.sql.gz"
246 ]
247
248 external_data.each do |fname|
249   remote_file "#{source_directory}/data/#{fname}" do
250     action :create_if_missing
251     source "https://www.nominatim.org/data/#{fname}"
252     owner "nominatim"
253     group "nominatim"
254     mode 0o644
255   end
256 end
257
258 remote_file "#{source_directory}/data/country_osm_grid.sql.gz" do
259   action :create_if_missing
260   source "https://www.nominatim.org/data/country_grid.sql.gz"
261   owner "nominatim"
262   group "nominatim"
263   mode 0o644
264 end
265
266 template "/etc/cron.d/nominatim" do
267   action node[:nominatim][:state] == "off" ? :delete : :create
268   source "nominatim.cron.erb"
269   owner "root"
270   group "root"
271   mode "0644"
272   variables :bin_directory => "#{source_directory}/utils",
273             :mailto => email_errors,
274             :update_maintenance_trigger => "#{basedir}/status/update_maintenance"
275 end
276
277 template "#{source_directory}/utils/nominatim-update" do
278   source "updater.erb"
279   user "nominatim"
280   group "nominatim"
281   mode 0o755
282   variables :bindir => build_directory,
283             :srcdir => source_directory,
284             :logfile => "#{node[:nominatim][:logdir]}/update.log",
285             :branch => node[:nominatim][:revision],
286             :update_stop_file => "#{basedir}/status/updates_disabled",
287             :update_maintenance_trigger => "#{basedir}/status/update_maintenance"
288 end
289
290 template "/etc/init.d/nominatim-update" do
291   source "updater.init.erb"
292   user "nominatim"
293   group "nominatim"
294   mode 0o755
295   variables :source_directory => source_directory
296 end
297
298 %w[backup-nominatim vacuum-db-nominatim].each do |fname|
299   template "/usr/local/bin/#{fname}" do
300     source "#{fname}.erb"
301     owner "root"
302     group "root"
303     mode 0o755
304     variables :db => node[:nominatim][:dbname]
305   end
306 end
307
308 ## webserver frontend
309
310 directory "#{basedir}/etc" do
311   owner "nominatim"
312   group "adm"
313   mode 0o775
314 end
315
316 %w[user_agent referrer email].each do |name|
317   file "#{basedir}/etc/nginx_blocked_#{name}.conf" do
318     action :create_if_missing
319     owner "nominatim"
320     group "adm"
321     mode 0o664
322   end
323 end
324
325 service "php7.2-fpm" do
326   action [:enable, :start]
327   supports :status => true, :restart => true, :reload => true
328 end
329
330 node[:nominatim][:fpm_pools].each do |name, data|
331   template "/etc/php/7.2/fpm/pool.d/#{name}.conf" do
332     source "fpm.conf.erb"
333     owner "root"
334     group "root"
335     mode 0o644
336     variables data.merge(:name => name)
337     notifies :reload, "service[php7.2-fpm]"
338   end
339 end
340
341 ssl_certificate node[:fqdn] do
342   domains [node[:fqdn],
343            "nominatim.openstreetmap.org",
344            "nominatim.osm.org",
345            "nominatim.openstreetmap.com",
346            "nominatim.openstreetmap.net",
347            "nominatim.openstreetmaps.org",
348            "nominatim.openmaps.org"]
349   notifies :reload, "service[nginx]"
350 end
351
352 package "apache2" do
353   action :remove
354 end
355
356 include_recipe "nginx"
357
358 nginx_site "default" do
359   action [:delete]
360 end
361
362 nginx_site "nominatim" do
363   template "nginx.erb"
364   directory build_directory
365   variables :pools => node[:nominatim][:fpm_pools],
366             :frontends => search(:node, "recipes:web\\:\\:frontend"),
367             :confdir => "#{basedir}/etc"
368 end
369
370 template "/etc/logrotate.d/nginx" do
371   source "logrotate.nginx.erb"
372   owner "root"
373   group "root"
374   mode 0o644
375 end
376
377 munin_plugin_conf "nominatim" do
378   template "munin.erb"
379   variables :db => node[:nominatim][:dbname],
380             :querylog => "#{node[:nominatim][:logdir]}/query.log"
381 end
382
383 munin_plugin "nominatim_importlag" do
384   target "#{source_directory}/munin/nominatim_importlag"
385 end
386
387 munin_plugin "nominatim_query_speed" do
388   target "#{source_directory}/munin/nominatim_query_speed_querylog"
389 end
390
391 munin_plugin "nominatim_requests" do
392   target "#{source_directory}/munin/nominatim_requests_querylog"
393 end
394
395 directory "#{basedir}/status" do
396   owner "nominatim"
397   group "postgres"
398   mode 0o775
399 end
400
401 include_recipe "fail2ban"
402
403 fail2ban_jail "nominatim_limit_req" do
404   filter "nginx-limit-req"
405   logpath "#{node[:nominatim][:logdir]}/nominatim.openstreetmap.org-error.log"
406   ports [80, 443]
407   maxretry 5
408 end