]> git.openstreetmap.org Git - chef.git/blob - cookbooks/nominatim/recipes/default.rb
bc7e542a7992e09f31e030c4e6742d2635b8e4c2
[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 "prometheus"
22 include_recipe "postgresql"
23 include_recipe "python"
24 include_recipe "nginx"
25 include_recipe "git"
26 include_recipe "fail2ban"
27
28 basedir = data_bag_item("accounts", "nominatim")["home"]
29 project_directory = "#{basedir}/planet-project"
30 bin_directory = "#{basedir}/bin"
31 cfg_directory = "#{basedir}/etc"
32 ui_directory = "#{basedir}/ui"
33 qa_bin_directory = "#{basedir}/Nominatim-Data-Analyser"
34 qa_data_directory = "#{basedir}/qa-data"
35
36 directory basedir do
37   owner "nominatim"
38   group "nominatim"
39   mode "755"
40   recursive true
41 end
42
43 [basedir, bin_directory, cfg_directory, project_directory, ui_directory].each do |path|
44   directory path do
45     owner "nominatim"
46     group "nominatim"
47     mode "755"
48   end
49 end
50
51 if node[:nominatim][:flatnode_file]
52   directory File.dirname(node[:nominatim][:flatnode_file]) do
53     recursive true
54   end
55 end
56
57 directory "#{bin_directory}/maintenance" do
58   owner "nominatim"
59   group "nominatim"
60   mode "775"
61 end
62
63 ## Log directory setup
64
65 directory node[:nominatim][:logdir] do
66   owner "nominatim"
67   group "nominatim"
68   mode "755"
69   recursive true
70 end
71
72 file "#{node[:nominatim][:logdir]}/query.log" do
73   action :create_if_missing
74   owner "www-data"
75   group "adm"
76   mode "664"
77 end
78
79 ### Postgresql
80
81 postgresql_version = node[:nominatim][:dbcluster].split("/").first
82 postgis_version = node[:nominatim][:postgis]
83
84 package "postgresql-#{postgresql_version}-postgis-#{postgis_version}"
85
86 node[:nominatim][:dbadmins].each do |user|
87   postgresql_user user do
88     cluster node[:nominatim][:dbcluster]
89     superuser true
90   end
91 end
92
93 postgresql_user "nominatim" do
94   cluster node[:nominatim][:dbcluster]
95   superuser true
96 end
97
98 postgresql_user "www-data" do
99   cluster node[:nominatim][:dbcluster]
100 end
101
102 ### Nominatim
103
104 python_directory = "#{basedir}/venv"
105
106 package %w[
107   build-essential
108   libicu-dev
109   python3-dev
110   pkg-config
111   osm2pgsql
112   ruby
113   ruby-file-tail
114   ruby-pg
115   ruby-webrick
116 ]
117
118 python_virtualenv python_directory do
119   interpreter "/usr/bin/python3"
120 end
121
122 # These are updated during the database update.
123 python_package "nominatim-db" do
124   python_virtualenv python_directory
125   extra_index_url node[:nominatim][:pip_index]
126 end
127
128 python_package "nominatim-api" do
129   python_virtualenv python_directory
130   extra_index_url node[:nominatim][:pip_index]
131 end
132
133 remote_directory "#{project_directory}/static-website" do
134   source "website"
135   owner "nominatim"
136   group "nominatim"
137   mode "755"
138   files_owner "nominatim"
139   files_group "nominatim"
140   files_mode "644"
141   purge false
142 end
143
144 template "#{project_directory}/.env" do
145   source "nominatim.env.erb"
146   owner "nominatim"
147   group "nominatim"
148   mode "664"
149   variables :base_url => "nominatim.openstreetmap.org",
150             :dbname => node[:nominatim][:dbname],
151             :flatnode_file => node[:nominatim][:flatnode_file],
152             :log_file => "#{node[:nominatim][:logdir]}/query.log",
153             :pool_size => node[:nominatim][:api_pool_size],
154             :query_timeout => node[:nominatim][:api_query_timeout],
155             :request_timeout => node[:nominatim][:api_request_timeout]
156 end
157
158 remote_file "#{project_directory}/secondary_importance.sql.gz" do
159   action :create_if_missing
160   source "https://nominatim.org/data/wikimedia-secondary-importance.sql.gz"
161   owner "nominatim"
162   group "nominatim"
163   mode "644"
164 end
165
166 remote_file "#{project_directory}/wikimedia-importance.csv.gz" do
167   action :create_if_missing
168   source "https://nominatim.org/data/wikimedia-importance.csv.gz"
169   owner "nominatim"
170   group "nominatim"
171   mode "644"
172 end
173
174 %w[gb_postcodes.csv.gz us_postcodes.csv.gz].each do |fname|
175   remote_file "#{project_directory}/#{fname}" do
176     action :create
177     source "https://nominatim.org/data/#{fname}"
178     owner "nominatim"
179     group "nominatim"
180     mode "644"
181   end
182 end
183
184 # Webserver + frontend
185
186 %w[user_agent referrer email generic].each do |name|
187   file "#{cfg_directory}/nginx_blocked_#{name}.conf" do
188     action :create_if_missing
189     owner "nominatim"
190     group "adm"
191     mode "664"
192   end
193 end
194
195 systemd_service "nominatim" do
196   description "Nominatim running as a gunicorn application"
197   user "www-data"
198   group "www-data"
199   working_directory project_directory
200   standard_output "append:#{node[:nominatim][:logdir]}/gunicorn.log"
201   standard_error "inherit"
202   exec_start "#{python_directory}/bin/gunicorn --max-requests 200000 -b unix:/run/gunicorn-nominatim.openstreetmap.org.sock -w #{node[:nominatim][:api_workers]} -k uvicorn.workers.UvicornWorker 'nominatim_api.server.falcon.server:run_wsgi()'"
203   exec_reload "/bin/kill -s HUP $MAINPID"
204   kill_mode "mixed"
205   timeout_stop_sec 5
206   private_tmp true
207   requires "nominatim.socket"
208   after "network.target"
209 end
210
211 systemd_socket "nominatim" do
212   description "Gunicorn socket for Nominatim"
213   listen_stream "/run/gunicorn-nominatim.openstreetmap.org.sock"
214   socket_user "www-data"
215 end
216
217 ssl_certificate node[:fqdn] do
218   domains [node[:fqdn],
219            "nominatim.openstreetmap.org",
220            "nominatim.osm.org",
221            "nominatim.openstreetmap.com",
222            "nominatim.openstreetmap.net",
223            "nominatim.openstreetmaps.org",
224            "nominatim.openmaps.org",
225            "nominatim.qgis.org"]
226   notifies :reload, "service[nginx]"
227 end
228
229 nginx_site "default" do
230   action [:delete]
231 end
232
233 frontends = search(:node, "recipes:web\\:\\:frontend").sort_by(&:name)
234
235 nginx_site "nominatim" do
236   template "nginx.erb"
237   directory project_directory
238   variables :pools => node[:nominatim][:fpm_pools],
239             :frontends => frontends,
240             :confdir => "#{basedir}/etc",
241             :ui_directory => ui_directory
242 end
243
244 template "/etc/logrotate.d/nginx" do
245   source "logrotate.nginx.erb"
246   owner "root"
247   group "root"
248   mode "644"
249 end
250
251 ### Import, update and maintenance scripts
252
253 %w[nominatim-update
254    nominatim-update-data
255    nominatim-update-refresh-db
256    nominatim-daily-maintenance].each do |fname|
257   template "#{bin_directory}/#{fname}" do
258     source "#{fname}.erb"
259     owner "nominatim"
260     group "nominatim"
261     mode "554"
262     variables :bindir => bin_directory,
263               :projectdir => project_directory,
264               :venvprefix => "#{python_directory}/bin/",
265               :qadatadir => qa_data_directory
266   end
267 end
268
269 systemd_service "nominatim-update" do
270   description "Update the Nominatim database"
271   exec_start "#{bin_directory}/nominatim-update"
272   restart "on-success"
273   standard_output "journal"
274   standard_error "inherit"
275   working_directory project_directory
276 end
277
278 systemd_service "nominatim-update-maintenance-trigger" do
279   description "Trigger daily maintenance tasks for Nominatim DB"
280   exec_start "ln -sf #{bin_directory}/nominatim-daily-maintenance #{bin_directory}/maintenance/"
281   user "nominatim"
282 end
283
284 systemd_timer "nominatim-update-maintenance-trigger" do
285   action :create
286   description "Schedule daily maintenance tasks for Nominatim DB"
287   on_calendar "*-*-* 02:03:00 UTC"
288 end
289
290 service "nominatim-update-maintenance-trigger" do
291   action :enable
292 end
293
294 ## Nominatim UI
295
296 git ui_directory do
297   action :sync
298   repository node[:nominatim][:ui_repository]
299   revision node[:nominatim][:ui_revision]
300   user "nominatim"
301   group "nominatim"
302 end
303
304 template "#{ui_directory}/dist/theme/config.theme.js" do
305   source "ui-config.js.erb"
306   owner "nominatim"
307   group "nominatim"
308   mode "664"
309 end
310
311 ## Nominatim QA
312
313 if node[:nominatim][:enable_qa_tiles]
314   python_package "nominatim-data-analyser" do
315     python_virtualenv python_directory
316     extra_index_url node[:nominatim][:pip_index]
317   end
318
319   directory qa_data_directory do
320     owner "nominatim"
321     group "nominatim"
322     mode "755"
323     recursive true
324   end
325
326   template "#{project_directory}/qa-config.yaml" do
327     source "qa_config.erb"
328     owner "nominatim"
329     group "nominatim"
330     mode "755"
331     variables :outputdir => "#{qa_data_directory}/new"
332   end
333
334   ssl_certificate "qa-tile.nominatim.openstreetmap.org" do
335     domains ["qa-tile.nominatim.openstreetmap.org"]
336     notifies :reload, "service[nginx]"
337   end
338
339   nginx_site "qa-tiles.nominatim" do
340     template "nginx-qa-tiles.erb"
341     directory qa_data_directory
342     variables :qa_data_directory => qa_data_directory
343   end
344 end
345
346 ## Logging and monitoring
347
348 template "/etc/logrotate.d/nominatim" do
349   source "logrotate.nominatim.erb"
350   owner "root"
351   group "root"
352   mode "644"
353 end
354
355 prometheus_exporter "nominatim" do
356   port 8082
357   user "www-data"
358   restrict_address_families "AF_UNIX"
359   options [
360     "--nominatim.query-log=#{node[:nominatim][:logdir]}/query.log",
361     "--nominatim.database-name=#{node[:nominatim][:dbname]}"
362   ]
363 end
364
365 frontend_addresses = frontends.collect { |f| f.ipaddresses(:role => :external) }
366
367 fail2ban_jail "nominatim_limit_req" do
368   filter "nginx-limit-req"
369   logpath "#{node[:nominatim][:logdir]}/nominatim.openstreetmap.org-error.log"
370   ports [80, 443]
371   maxretry 20
372   ignoreips frontend_addresses.flatten.sort
373 end