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