]> git.openstreetmap.org Git - chef.git/blob - cookbooks/nominatim/recipes/default.rb
nominatim: reorganise recipe for Debian installation
[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
23 if platform?("debian")
24   include_recipe "postgresql"
25   include_recipe "python"
26   include_recipe "nginx"
27   include_recipe "git"
28   include_recipe "fail2ban"
29
30   basedir = data_bag_item("accounts", "nominatim")["home"]
31   project_directory = "#{basedir}/planet-project"
32   bin_directory = "#{basedir}/bin"
33   cfg_directory = "#{basedir}/etc"
34   ui_directory = "#{basedir}/ui"
35   qa_bin_directory = "#{basedir}/Nominatim-Data-Analyser"
36   qa_data_directory = "#{basedir}/qa-data"
37
38   directory basedir do
39     owner "nominatim"
40     group "nominatim"
41     mode "755"
42     recursive true
43   end
44
45   [basedir, bin_directory, cfg_directory, project_directory, ui_directory].each do |path|
46     directory path do
47       owner "nominatim"
48       group "nominatim"
49       mode "755"
50     end
51   end
52
53   if node[:nominatim][:flatnode_file]
54     directory File.dirname(node[:nominatim][:flatnode_file]) do
55       recursive true
56     end
57   end
58
59   directory "#{bin_directory}/maintenance" do
60     owner "nominatim"
61     group "nominatim"
62     mode "775"
63   end
64
65   ## Log directory setup
66
67   directory node[:nominatim][:logdir] do
68     owner "nominatim"
69     group "nominatim"
70     mode "755"
71     recursive true
72   end
73
74   file "#{node[:nominatim][:logdir]}/query.log" do
75     action :create_if_missing
76     owner "www-data"
77     group "adm"
78     mode "664"
79   end
80
81   ### Postgresql
82
83   postgresql_version = node[:nominatim][:dbcluster].split("/").first
84   postgis_version = node[:nominatim][:postgis]
85
86   package "postgresql-#{postgresql_version}-postgis-#{postgis_version}"
87
88   node[:nominatim][:dbadmins].each do |user|
89     postgresql_user user do
90       cluster node[:nominatim][:dbcluster]
91       superuser true
92     end
93   end
94
95   postgresql_user "nominatim" do
96     cluster node[:nominatim][:dbcluster]
97     superuser true
98   end
99
100   postgresql_user "www-data" do
101     cluster node[:nominatim][:dbcluster]
102   end
103
104   ### Nominatim
105
106   python_directory = "#{basedir}/venv"
107
108   package %w[
109     libicu-dev
110     python3-dev
111     pkg-config
112     osm2pgsql
113   ]
114
115   python_virtualenv python_directory do
116     interpreter "/usr/bin/python3"
117   end
118
119   # These are updated during the database update.
120   python_package "nominatim-db" do
121     python_virtualenv python_directory
122     extra_index_url node[:nominatim][:pip_index]
123   end
124
125   python_package "nominatim-api" do
126     python_virtualenv python_directory
127     extra_index_url node[:nominatim][:pip_index]
128   end
129
130   remote_directory "#{project_directory}/static-website" do
131     source "website"
132     owner "nominatim"
133     group "nominatim"
134     mode "755"
135     files_owner "nominatim"
136     files_group "nominatim"
137     files_mode "644"
138     purge false
139   end
140
141   template "#{project_directory}/.env" do
142     source "nominatim.env.erb"
143     owner "nominatim"
144     group "nominatim"
145     mode "664"
146     variables :base_url => node[:nominatim][:state] == "off" ? node[:fqdn] : "nominatim.openstreetmap.org",
147               :dbname => node[:nominatim][:dbname],
148               :flatnode_file => node[:nominatim][:flatnode_file],
149               :log_file => "#{node[:nominatim][:logdir]}/query.log",
150               :pool_size => node[:nominatim][:api_pool_size],
151               :query_timeout => node[:nominatim][:api_query_timeout],
152               :request_timeout => node[:nominatim][:api_request_timeout]
153   end
154
155   remote_file "#{project_directory}/secondary_importance.sql.gz" do
156     action :create_if_missing
157     source "https://nominatim.org/data/wikimedia-secondary-importance.sql.gz"
158     owner "nominatim"
159     group "nominatim"
160     mode "644"
161   end
162
163   remote_file "#{project_directory}/wikimedia-importance.csv.gz" do
164     action :create_if_missing
165     source "https://nominatim.org/data/wikimedia-importance.csv.gz"
166     owner "nominatim"
167     group "nominatim"
168     mode "644"
169   end
170
171   %w[gb_postcodes.csv.gz us_postcodes.csv.gz].each do |fname|
172     remote_file "#{project_directory}/#{fname}" do
173       action :create
174       source "https://nominatim.org/data/#{fname}"
175       owner "nominatim"
176       group "nominatim"
177       mode "644"
178     end
179   end
180
181   # Webserver + frontend
182
183   %w[user_agent referrer email generic].each do |name|
184     file "#{cfg_directory}/nginx_blocked_#{name}.conf" do
185       action :create_if_missing
186       owner "nominatim"
187       group "adm"
188       mode "664"
189     end
190   end
191
192   systemd_service "nominatim" do
193     description "Nominatim running as a gunicorn application"
194     user "www-data"
195     group "www-data"
196     working_directory project_directory
197     standard_output "append:#{node[:nominatim][:logdir]}/gunicorn.log"
198     standard_error "inherit"
199     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()'"
200     exec_reload "/bin/kill -s HUP $MAINPID"
201     kill_mode "mixed"
202     timeout_stop_sec 5
203     private_tmp true
204     requires "nominatim.socket"
205     after "network.target"
206   end
207
208   systemd_socket "nominatim" do
209     description "Gunicorn socket for Nominatim"
210     listen_stream "/run/gunicorn-nominatim.openstreetmap.org.sock"
211     socket_user "www-data"
212   end
213
214   ssl_certificate node[:fqdn] do
215     domains [node[:fqdn],
216              "nominatim.openstreetmap.org",
217              "nominatim.osm.org",
218              "nominatim.openstreetmap.com",
219              "nominatim.openstreetmap.net",
220              "nominatim.openstreetmaps.org",
221              "nominatim.openmaps.org",
222              "nominatim.qgis.org"]
223     notifies :reload, "service[nginx]"
224   end
225
226   nginx_site "default" do
227     action [:delete]
228   end
229
230   frontends = search(:node, "recipes:web\\:\\:frontend").sort_by(&:name)
231
232   nginx_site "nominatim" do
233     template "nginx.erb"
234     directory project_directory
235     variables :pools => node[:nominatim][:fpm_pools],
236               :frontends => frontends,
237               :confdir => "#{basedir}/etc",
238               :ui_directory => ui_directory
239   end
240
241   template "/etc/logrotate.d/nginx" do
242     source "logrotate.nginx.erb"
243     owner "root"
244     group "root"
245     mode "644"
246   end
247
248   ### Import, update and maintenance scripts
249
250   %w[nominatim-update
251      nominatim-update-data
252      nominatim-update-refresh-db
253      nominatim-daily-maintenance].each do |fname|
254     template "#{bin_directory}/#{fname}" do
255       source "#{fname}.erb"
256       owner "nominatim"
257       group "nominatim"
258       mode "554"
259       variables :bindir => bin_directory,
260                 :projectdir => project_directory,
261                 :venvprefix => "#{python_directory}/bin/",
262                 :qadatadir => qa_data_directory
263     end
264   end
265
266   systemd_service "nominatim-update" do
267     description "Update the Nominatim database"
268     exec_start "#{bin_directory}/nominatim-update"
269     restart "on-success"
270     standard_output "journal"
271     standard_error "inherit"
272     working_directory project_directory
273   end
274
275   systemd_service "nominatim-update-maintenance-trigger" do
276     description "Trigger daily maintenance tasks for Nominatim DB"
277     exec_start "ln -sf #{bin_directory}/nominatim-daily-maintenance #{bin_directory}/maintenance/"
278     user "nominatim"
279   end
280
281   systemd_timer "nominatim-update-maintenance-trigger" do
282     action node[:nominatim][:state] != "off" ? :create : :delete
283     description "Schedule daily maintenance tasks for Nominatim DB"
284     on_calendar "*-*-* 02:03:00 UTC"
285   end
286
287   service "nominatim-update-maintenance-trigger" do
288     action node[:nominatim][:state] != "off" ? :enable : :disable
289   end
290
291   ## Nominatim UI
292
293   git ui_directory do
294     action :sync
295     repository node[:nominatim][:ui_repository]
296     revision node[:nominatim][:ui_revision]
297     user "nominatim"
298     group "nominatim"
299   end
300
301   template "#{ui_directory}/dist/theme/config.theme.js" do
302     source "ui-config.js.erb"
303     owner "nominatim"
304     group "nominatim"
305     mode "664"
306   end
307
308   ## Nominatim QA
309
310   if node[:nominatim][:enable_qa_tiles]
311     python_package "nominatim-data-analyser" do
312       python_virtualenv python_directory
313       extra_index_url node[:nominatim][:pip_index]
314     end
315
316     directory qa_data_directory do
317       owner "nominatim"
318       group "nominatim"
319       mode "755"
320       recursive true
321     end
322
323     template "#{project_directory}/qa-config.yaml" do
324       source "qa_config.erb"
325       owner "nominatim"
326       group "nominatim"
327       mode "755"
328       variables :outputdir => "#{qa_data_directory}/new"
329     end
330
331     ssl_certificate "qa-tile.nominatim.openstreetmap.org" do
332       domains ["qa-tile.nominatim.openstreetmap.org"]
333       notifies :reload, "service[nginx]"
334     end
335
336     nginx_site "qa-tiles.nominatim" do
337       template "nginx-qa-tiles.erb"
338       directory qa_data_directory
339       variables :qa_data_directory => qa_data_directory
340     end
341   end
342
343   ## Logging and monitoring
344
345   template "/etc/logrotate.d/nominatim" do
346     source "logrotate.nominatim.erb"
347     owner "root"
348     group "root"
349     mode "644"
350   end
351
352   prometheus_exporter "nominatim" do
353     port 8082
354     user "www-data"
355     restrict_address_families "AF_UNIX"
356     options [
357       "--nominatim.query-log=#{node[:nominatim][:logdir]}/query.log",
358       "--nominatim.database-name=#{node[:nominatim][:dbname]}"
359     ]
360   end
361
362 ################################# END OF DEBIAN #############################
363
364 else
365
366   if node[:nominatim][:api_flavour] == "php"
367     include_recipe "php::fpm"
368   end
369
370   basedir = data_bag_item("accounts", "nominatim")["home"]
371   email_errors = data_bag_item("accounts", "lonvia")["email"]
372
373   directory basedir do
374     owner "nominatim"
375     group "nominatim"
376     mode "755"
377     recursive true
378   end
379
380   ## Log directory setup
381
382   directory node[:nominatim][:logdir] do
383     owner "nominatim"
384     group "nominatim"
385     mode "755"
386     recursive true
387   end
388
389   file "#{node[:nominatim][:logdir]}/query.log" do
390     action :create_if_missing
391     owner "www-data"
392     group "adm"
393     mode "664"
394   end
395
396   file "#{node[:nominatim][:logdir]}/update.log" do
397     action :create_if_missing
398     owner "nominatim"
399     group "adm"
400     mode "664"
401   end
402
403   ## Postgresql
404
405   include_recipe "postgresql"
406
407   postgresql_version = node[:nominatim][:dbcluster].split("/").first
408   postgis_version = node[:nominatim][:postgis]
409
410   package "postgresql-#{postgresql_version}-postgis-#{postgis_version}"
411
412   node[:nominatim][:dbadmins].each do |user|
413     postgresql_user user do
414       cluster node[:nominatim][:dbcluster]
415       superuser true
416       only_if { node[:nominatim][:state] != "slave" }
417     end
418   end
419
420   postgresql_user "nominatim" do
421     cluster node[:nominatim][:dbcluster]
422     superuser true
423     only_if { node[:nominatim][:state] != "slave" }
424   end
425
426   postgresql_user "www-data" do
427     cluster node[:nominatim][:dbcluster]
428     only_if { node[:nominatim][:state] != "slave" }
429   end
430
431   directory "#{basedir}/tablespaces" do
432     owner "postgres"
433     group "postgres"
434     mode "700"
435   end
436
437   # NOTE: tablespaces must be exactly in the same location on each
438   #       Nominatim instance when replication is in use. Therefore
439   #       use symlinks to canonical directory locations.
440   node[:nominatim][:tablespaces].each do |name, location|
441     directory location do
442       owner "postgres"
443       group "postgres"
444       mode "700"
445       recursive true
446     end
447
448     link "#{basedir}/tablespaces/#{name}" do
449       to location
450     end
451
452     postgresql_tablespace name do
453       cluster node[:nominatim][:dbcluster]
454       location "#{basedir}/tablespaces/#{name}"
455     end
456   end
457
458   ## Nominatim backend
459
460   include_recipe "git"
461   include_recipe "python"
462
463   python_directory = "#{basedir}/venv"
464
465   package %w[
466     build-essential
467     cmake
468     g++
469     libboost-dev
470     libboost-system-dev
471     libboost-filesystem-dev
472     libexpat1-dev
473     zlib1g-dev
474     libbz2-dev
475     libpq-dev
476     libproj-dev
477     liblua5.3-dev
478     libluajit-5.1-dev
479     libicu-dev
480     nlohmann-json3-dev
481     lua5.3
482     python3-pyosmium
483     python3-psycopg2
484     python3-dotenv
485     python3-psutil
486     python3-jinja2
487     python3-icu
488     python3-datrie
489     python3-yaml
490     python3-sqlalchemy-ext
491     python3-geoalchemy2
492     python3-asyncpg
493     python3-dev
494     pkg-config
495     ruby
496     ruby-file-tail
497     ruby-pg
498     ruby-webrick
499   ]
500
501   if node[:nominatim][:api_flavour] == "php"
502     package %w[
503       php-pgsql
504       php-intl
505     ]
506   elsif node[:nominatim][:api_flavour] == "python"
507
508     python_virtualenv python_directory do
509       interpreter "/usr/bin/python3"
510     end
511
512     python_package "SQLAlchemy" do
513       python_virtualenv python_directory
514       version "2.0.32"
515     end
516
517     python_package "PyICU" do
518       python_virtualenv python_directory
519       version "2.13.1"
520     end
521
522     python_package "psycopg[binary]" do
523       python_virtualenv python_directory
524       version "3.2.1"
525     end
526
527     python_package "psycopg2-binary" do
528       python_virtualenv python_directory
529       version "2.9.9"
530     end
531
532     python_package "python-dotenv" do
533       python_virtualenv python_directory
534       version "1.0.1"
535     end
536
537     python_package "pygments" do
538       python_virtualenv python_directory
539       version "2.18.0"
540     end
541
542     python_package "PyYAML" do
543       python_virtualenv python_directory
544       version "6.0.2"
545     end
546
547     python_package "falcon" do
548       python_virtualenv python_directory
549       version "3.1.3"
550     end
551
552     python_package "uvicorn" do
553       python_virtualenv python_directory
554       version "0.30.5"
555     end
556
557     python_package "gunicorn" do
558       python_virtualenv python_directory
559       version "22.0.0"
560     end
561
562     python_package "jinja2" do
563       python_virtualenv python_directory
564       version "3.1.4"
565     end
566
567     python_package "datrie" do
568       python_virtualenv python_directory
569       version "0.8.2"
570     end
571
572     python_package "psutil" do
573       python_virtualenv python_directory
574       version "6.0.0"
575     end
576
577     python_package "osmium" do
578       python_virtualenv python_directory
579       version "3.7.0"
580     end
581   end
582
583   source_directory = "#{basedir}/src/nominatim"
584   build_directory = "#{basedir}/src/build"
585   project_directory = "#{basedir}/planet-project"
586   bin_directory = "#{basedir}/bin"
587   cfg_directory = "#{basedir}/etc"
588   ui_directory = "#{basedir}/ui"
589   qa_bin_directory = "#{basedir}/src/Nominatim-Data-Analyser"
590   qa_data_directory = "#{basedir}/qa-data"
591
592   [basedir, "#{basedir}/src", cfg_directory, bin_directory, build_directory, project_directory].each do |path|
593     directory path do
594       owner "nominatim"
595       group "nominatim"
596       mode "755"
597       recursive true
598     end
599   end
600
601   directory "#{bin_directory}/maintenance" do
602     owner "nominatim"
603     group "nominatim"
604     mode "775"
605   end
606
607   if node[:nominatim][:flatnode_file]
608     directory File.dirname(node[:nominatim][:flatnode_file]) do
609       recursive true
610     end
611   end
612
613   remote_directory "#{project_directory}/static-website" do
614     source "website"
615     owner "nominatim"
616     group "nominatim"
617     mode "755"
618     files_owner "nominatim"
619     files_group "nominatim"
620     files_mode "644"
621     purge false
622   end
623
624   # Normally syncing via chef is a bad idea because syncing might involve
625   # an update of database functions which should not be done while an update
626   # is ongoing. Therefore we sync in between update cycles. There is an
627   # exception for slaves: they get DB function updates from the master, so
628   # only the source code needs to be updated, which chef may do.
629   git source_directory do
630     action node[:nominatim][:state] == "slave" ? :sync : :checkout
631     repository node[:nominatim][:repository]
632     revision node[:nominatim][:revision]
633     enable_submodules true
634     user "nominatim"
635     group "nominatim"
636     not_if { node[:nominatim][:state] != "slave" && File.exist?("#{source_directory}/README.md") }
637     notifies :run, "execute[compile_nominatim]"
638   end
639
640   remote_file "#{source_directory}/data/country_osm_grid.sql.gz" do
641     action :create_if_missing
642     source "https://nominatim.org/data/country_grid.sql.gz"
643     owner "nominatim"
644     group "nominatim"
645     mode "644"
646   end
647
648   execute "compile_nominatim" do
649     action :nothing
650     user "nominatim"
651     cwd build_directory
652     command "cmake #{source_directory} && make"
653     notifies :run, "execute[install_nominatim]"
654   end
655
656   execute "install_nominatim" do
657     action :nothing
658     cwd build_directory
659     command "make install"
660   end
661
662   # Project directory
663
664   template "#{project_directory}/.env" do
665     source "nominatim.env.erb"
666     owner "nominatim"
667     group "nominatim"
668     mode "664"
669     variables :base_url => node[:nominatim][:state] == "off" ? node[:fqdn] : "nominatim.openstreetmap.org",
670               :dbname => node[:nominatim][:dbname],
671               :flatnode_file => node[:nominatim][:flatnode_file],
672               :log_file => "#{node[:nominatim][:logdir]}/query.log",
673               :tokenizer => node[:nominatim][:config][:tokenizer],
674               :forward_dependencies => node[:nominatim][:config][:forward_dependencies],
675               :pool_size => node[:nominatim][:api_pool_size],
676               :query_timeout => node[:nominatim][:api_query_timeout],
677               :request_timeout => node[:nominatim][:api_request_timeout]
678   end
679
680   remote_file "#{project_directory}/secondary_importance.sql.gz" do
681     action :create_if_missing
682     source "https://nominatim.org/data/wikimedia-secondary-importance.sql.gz"
683     owner "nominatim"
684     group "nominatim"
685     mode "644"
686   end
687
688   remote_file "#{project_directory}/wikimedia-importance.sql.gz" do
689     action :create_if_missing
690     source "https://nominatim.org/data/wikimedia-importance.sql.gz"
691     owner "nominatim"
692     group "nominatim"
693     mode "644"
694   end
695
696   %w[gb_postcodes.csv.gz us_postcodes.csv.gz].each do |fname|
697     remote_file "#{project_directory}/#{fname}" do
698       action :create
699       source "https://nominatim.org/data/#{fname}"
700       owner "nominatim"
701       group "nominatim"
702       mode "644"
703     end
704   end
705
706   # Webserver + frontend
707
708   %w[user_agent referrer email generic].each do |name|
709     file "#{cfg_directory}/nginx_blocked_#{name}.conf" do
710       action :create_if_missing
711       owner "nominatim"
712       group "adm"
713       mode "664"
714     end
715   end
716
717   if node[:nominatim][:api_flavour] == "php"
718     node[:nominatim][:fpm_pools].each do |name, data|
719       php_fpm name do
720         port data[:port]
721         pm data[:pm]
722         pm_max_children data[:max_children]
723         pm_start_servers 20
724         pm_min_spare_servers 10
725         pm_max_spare_servers 20
726         pm_max_requests 10000
727         prometheus_port data[:prometheus_port]
728       end
729     end
730   elsif node[:nominatim][:api_flavour] == "python"
731     systemd_service "nominatim" do
732       description "Nominatim running as a gunicorn application"
733       user "www-data"
734       group "www-data"
735       working_directory project_directory
736       standard_output "append:#{node[:nominatim][:logdir]}/gunicorn.log"
737       standard_error "inherit"
738       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"
739       exec_reload "/bin/kill -s HUP $MAINPID"
740       environment :PYTHONPATH => "/usr/local/lib/nominatim/lib-python/"
741       kill_mode "mixed"
742       timeout_stop_sec 5
743       private_tmp true
744       requires "nominatim.socket"
745       after "network.target"
746     end
747
748     systemd_socket "nominatim" do
749       description "Gunicorn socket for Nominatim"
750       listen_stream "/run/gunicorn-nominatim.openstreetmap.org.sock"
751       socket_user "www-data"
752     end
753   end
754
755   ssl_certificate node[:fqdn] do
756     domains [node[:fqdn],
757              "nominatim.openstreetmap.org",
758              "nominatim.osm.org",
759              "nominatim.openstreetmap.com",
760              "nominatim.openstreetmap.net",
761              "nominatim.openstreetmaps.org",
762              "nominatim.openmaps.org",
763              "nominatim.qgis.org"]
764     notifies :reload, "service[nginx]"
765   end
766
767   include_recipe "nginx"
768
769   nginx_site "default" do
770     action [:delete]
771   end
772
773   frontends = search(:node, "recipes:web\\:\\:frontend").sort_by(&:name)
774
775   nginx_site "nominatim" do
776     template "nginx.erb"
777     directory project_directory
778     variables :pools => node[:nominatim][:fpm_pools],
779               :frontends => frontends,
780               :confdir => "#{basedir}/etc",
781               :ui_directory => ui_directory
782   end
783
784   template "/etc/logrotate.d/nginx" do
785     source "logrotate.nginx.erb"
786     owner "root"
787     group "root"
788     mode "644"
789   end
790
791   # Updates
792
793   %w[nominatim-update
794      nominatim-update-source
795      nominatim-update-refresh-db
796      nominatim-update-data
797      nominatim-daily-maintenance].each do |fname|
798     template "#{bin_directory}/#{fname}" do
799       source "#{fname}.erb"
800       owner "nominatim"
801       group "nominatim"
802       mode "554"
803       variables :bindir => bin_directory,
804                 :srcdir => source_directory,
805                 :builddir => build_directory,
806                 :projectdir => project_directory,
807                 :qabindir => qa_bin_directory,
808                 :qadatadir => qa_data_directory
809     end
810   end
811
812   systemd_service "nominatim-update" do
813     description "Update the Nominatim database"
814     exec_start "#{bin_directory}/nominatim-update"
815     restart "on-success"
816     standard_output "append:#{node[:nominatim][:logdir]}/update.log"
817     standard_error "inherit"
818     working_directory project_directory
819   end
820
821   systemd_service "nominatim-update-maintenance-trigger" do
822     description "Trigger daily maintenance tasks for Nominatim DB"
823     exec_start "ln -sf #{bin_directory}/nominatim-daily-maintenance #{bin_directory}/maintenance/"
824     user "nominatim"
825   end
826
827   systemd_timer "nominatim-update-maintenance-trigger" do
828     action node[:nominatim][:state] != "off" ? :create : :delete
829     description "Schedule daily maintenance tasks for Nominatim DB"
830     on_calendar "*-*-* 02:03:00 UTC"
831   end
832
833   service "nominatim-update-maintenance-trigger" do
834     action node[:nominatim][:state] != "off" ? :enable : :disable
835   end
836
837   # Nominatim UI
838
839   git ui_directory do
840     action :sync
841     repository node[:nominatim][:ui_repository]
842     revision node[:nominatim][:ui_revision]
843     user "nominatim"
844     group "nominatim"
845   end
846
847   template "#{ui_directory}/dist/theme/config.theme.js" do
848     source "ui-config.js.erb"
849     owner "nominatim"
850     group "nominatim"
851     mode "664"
852   end
853
854   # Nominatim QA
855
856   if node[:nominatim][:enable_qa_tiles]
857     package "python3-geojson"
858
859     git qa_bin_directory do
860       repository node[:nominatim][:qa_repository]
861       revision node[:nominatim][:qa_revision]
862       enable_submodules true
863       user "nominatim"
864       group "nominatim"
865       notifies :run, "execute[compile_qa]"
866     end
867
868     execute "compile_qa" do
869       action :nothing
870       user "nominatim"
871       cwd "#{qa_bin_directory}/clustering-vt"
872       command "make"
873     end
874
875     directory qa_data_directory do
876       owner "nominatim"
877       group "nominatim"
878       mode "755"
879       recursive true
880     end
881
882     template "#{qa_bin_directory}/analyser/config/config.yaml" do
883       source "qa_config.erb"
884       owner "nominatim"
885       group "nominatim"
886       mode "755"
887       variables :outputdir => "#{qa_data_directory}/new"
888     end
889
890     ssl_certificate "qa-tile.nominatim.openstreetmap.org" do
891       domains ["qa-tile.nominatim.openstreetmap.org"]
892       notifies :reload, "service[nginx]"
893     end
894
895     nginx_site "qa-tiles.nominatim" do
896       template "nginx-qa-tiles.erb"
897       directory build_directory
898       variables :qa_data_directory => qa_data_directory
899     end
900
901   end
902
903   # Replication
904
905   cron_d "nominatim-clean-db" do
906     action node[:nominatim][:state] == "master" ? :create : :delete
907     minute "5"
908     hour "*/4"
909     user "postgres"
910     command "#{bin_directory}/clean-db-nominatim"
911     mailto email_errors
912   end
913
914   if node[:nominatim][:state] == "master"
915     postgresql_user "replication" do
916       cluster node[:nominatim][:dbcluster]
917       password data_bag_item("nominatim", "passwords")["replication"]
918       replication true
919     end
920
921     directory node[:rsyncd][:modules][:archive][:path] do
922       owner "postgres"
923       group "postgres"
924       mode "700"
925     end
926
927     template "#{bin_directory}/clean-db-nominatim" do
928       source "clean-db-nominatim.erb"
929       owner "nominatim"
930       group "nominatim"
931       mode "755"
932       variables :archive_dir => node[:rsyncd][:modules][:archive][:path],
933                 :update_stop_file => "#{basedir}/status/updates_disabled",
934                 :streaming_clients => search(:node, "nominatim_state:slave").map { |slave| slave[:fqdn] }.join(" ")
935     end
936   end
937
938   # Maintenance
939
940   cron_d "nominatim-backup" do
941     action (node[:nominatim][:enable_backup] && node[:nominatim][:state] != "off") ? :create : :delete
942     minute "0"
943     hour "3"
944     day "1"
945     user "nominatim"
946     command "#{bin_directory}/backup-nominatim"
947     mailto email_errors
948   end
949
950   cron_d "nominatim-vacuum-db" do
951     action node[:nominatim][:state] != "off" ? :create : :delete
952     minute "20"
953     hour "0"
954     user "postgres"
955     command "#{bin_directory}/vacuum-db-nominatim"
956     mailto email_errors
957   end
958
959   %w[backup-nominatim vacuum-db-nominatim].each do |fname|
960     template "#{bin_directory}/#{fname}" do
961       source "#{fname}.erb"
962       owner "nominatim"
963       group "nominatim"
964       mode "755"
965       variables :db => node[:nominatim][:dbname]
966     end
967   end
968
969   # Logging
970
971   template "/etc/logrotate.d/nominatim" do
972     source "logrotate.nominatim.erb"
973     owner "root"
974     group "root"
975     mode "644"
976   end
977
978   # Monitoring
979   prometheus_exporter "nominatim" do
980     port 8082
981     user "www-data"
982     restrict_address_families "AF_UNIX"
983     options [
984       "--nominatim.query-log=#{node[:nominatim][:logdir]}/query.log",
985       "--nominatim.database-name=#{node[:nominatim][:dbname]}"
986     ]
987   end
988
989   include_recipe "fail2ban"
990 end # platform?('debian')
991
992 frontend_addresses = frontends.collect { |f| f.ipaddresses(:role => :external) }
993
994 fail2ban_jail "nominatim_limit_req" do
995   filter "nginx-limit-req"
996   logpath "#{node[:nominatim][:logdir]}/nominatim.openstreetmap.org-error.log"
997   ports [80, 443]
998   maxretry 20
999   ignoreips frontend_addresses.flatten.sort
1000 end