]> git.openstreetmap.org Git - chef.git/blob - cookbooks/tile/recipes/default.rb
28d51bc20b9671593b160925c2210686c0cd22e4
[chef.git] / cookbooks / tile / recipes / default.rb
1 #
2 # Cookbook:: tile
3 # Recipe:: default
4 #
5 # Copyright:: 2013, 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 "apache"
22 include_recipe "git"
23 include_recipe "munin"
24 include_recipe "nodejs"
25 include_recipe "postgresql"
26 include_recipe "prometheus"
27 include_recipe "python"
28 include_recipe "ruby"
29 include_recipe "tools"
30
31 blocks = data_bag_item("tile", "blocks")
32 admins = data_bag_item("apache", "admins")
33 web_passwords = data_bag_item("web", "passwords")
34
35 apache_module "alias"
36 apache_module "cgi"
37 apache_module "expires"
38 apache_module "headers"
39 apache_module "remoteip"
40 apache_module "rewrite"
41
42 apache_module "tile" do
43   conf "tile.conf.erb"
44 end
45
46 apache_conf "renderd" do
47   action :disable
48 end
49
50 ssl_certificate node[:fqdn] do
51   domains [node[:fqdn], "tile.openstreetmap.org", "render.openstreetmap.org"]
52   notifies :reload, "service[apache2]"
53 end
54
55 remote_file "#{Chef::Config[:file_cache_path]}/fastly-ip-list.json" do
56   source "https://api.fastly.com/public-ip-list"
57   compile_time true
58   ignore_failure true
59 end
60
61 fastlyips = JSON.parse(IO.read("#{Chef::Config[:file_cache_path]}/fastly-ip-list.json"))
62
63 remote_file "#{Chef::Config[:file_cache_path]}/statuscake-locations.json" do
64   source "https://app.statuscake.com/Workfloor/Locations.php?format=json"
65   compile_time true
66   ignore_failure true
67 end
68
69 statuscakelocations = JSON.parse(IO.read("#{Chef::Config[:file_cache_path]}/statuscake-locations.json"))
70
71 apache_site "default" do
72   action :disable
73 end
74
75 apache_site "tileserver_site" do
76   action :disable
77 end
78
79 apache_site "tile.openstreetmap.org" do
80   template "apache.erb"
81   variables :fastly => fastlyips["addresses"] + fastlyips["ipv6_addresses"],
82             :statuscake => statuscakelocations.flat_map { |_, v| [v["ip"], v["ipv6"]] },
83             :admins => admins["hosts"]
84 end
85
86 template "/etc/logrotate.d/apache2" do
87   source "logrotate.apache.erb"
88   owner "root"
89   group "root"
90   mode "644"
91 end
92
93 directory "/srv/tile.openstreetmap.org" do
94   owner "tile"
95   group "tile"
96   mode "755"
97 end
98
99 tile_directories = node[:tile][:styles].collect do |_, style|
100   style[:tile_directories].collect { |directory| directory[:name] }
101 end.flatten.sort.uniq
102
103 package %w[
104   renderd
105   libgoogle-perftools4
106 ]
107
108 systemd_service "renderd" do
109   dropin "chef"
110   after "postgresql.service"
111   wants "postgresql.service"
112   environment "LD_PRELOAD" => "libtcmalloc.so.4"
113   limit_nofile 4096
114   memory_high "80%"
115   memory_max "90%"
116   sandbox true
117   restrict_address_families "AF_UNIX"
118   read_write_paths tile_directories
119   system_call_filter ["@system-service", "mincore"]
120   restart "on-failure"
121 end
122
123 service "renderd" do
124   action [:enable, :start]
125   subscribes :restart, "systemd_service[renderd]"
126 end
127
128 directory "/srv/tile.openstreetmap.org/tiles" do
129   owner "tile"
130   group "tile"
131   mode "755"
132 end
133
134 template "/etc/renderd.conf" do
135   source "renderd.conf.erb"
136   owner "root"
137   group "root"
138   mode "644"
139   notifies :reload, "service[apache2]"
140   notifies :restart, "service[renderd]"
141 end
142
143 remote_directory "/srv/tile.openstreetmap.org/html" do
144   source "html"
145   owner "tile"
146   group "tile"
147   mode "755"
148   files_owner "tile"
149   files_group "tile"
150   files_mode "644"
151 end
152
153 template "/srv/tile.openstreetmap.org/html/index.html" do
154   source "index.html.erb"
155   owner "tile"
156   group "tile"
157   mode "644"
158 end
159
160 package %w[
161   python3-cairo
162   python3-mapnik
163   python3-pyproj
164   python3-setuptools
165 ]
166
167 python_package "pyotp" do
168   python_version "3"
169 end
170
171 directory "/srv/tile.openstreetmap.org/cgi-bin" do
172   owner "tile"
173   group "tile"
174   mode "755"
175 end
176
177 template "/srv/tile.openstreetmap.org/cgi-bin/export" do
178   source "export.erb"
179   owner "tile"
180   group "tile"
181   mode "755"
182   variables :blocks => blocks, :totp_key => web_passwords["totp_key"]
183 end
184
185 template "/srv/tile.openstreetmap.org/cgi-bin/debug" do
186   source "debug.erb"
187   owner "tile"
188   group "tile"
189   mode "755"
190 end
191
192 systemd_service "export-cleanup" do
193   description "Cleanup stale export temporary files"
194   joins_namespace_of "apache2.service"
195   exec_start "find /tmp -ignore_readdir_race -name 'export??????' -mmin +60 -delete"
196   user "www-data"
197   sandbox true
198 end
199
200 systemd_timer "export-cleanup" do
201   description "Cleanup stale export temporary files"
202   on_boot_sec "60m"
203   on_unit_inactive_sec "60m"
204 end
205
206 service "export-cleanup.timer" do
207   action [:enable, :start]
208 end
209
210 directory "/srv/tile.openstreetmap.org/data" do
211   owner "tile"
212   group "tile"
213   mode "755"
214 end
215
216 package %w[
217   mapnik-utils
218   tar
219   unzip
220 ]
221
222 node[:tile][:data].each_value do |data|
223   url = data[:url]
224   file = "/srv/tile.openstreetmap.org/data/#{File.basename(url)}"
225
226   if data[:directory]
227     directory = "/srv/tile.openstreetmap.org/data/#{data[:directory]}"
228
229     directory directory do
230       owner "tile"
231       group "tile"
232       mode "755"
233     end
234   else
235     directory = "/srv/tile.openstreetmap.org/data"
236   end
237
238   if file =~ /\.tgz$/
239     execute file do
240       action :nothing
241       command "tar -zxf #{file} -C #{directory}"
242       user "tile"
243       group "tile"
244     end
245   elsif file =~ /\.tar\.bz2$/
246     execute file do
247       action :nothing
248       command "tar -jxf #{file} -C #{directory}"
249       user "tile"
250       group "tile"
251     end
252   elsif file =~ /\.zip$/
253     execute file do
254       action :nothing
255       command "unzip -qq -o #{file} -d #{directory}"
256       user "tile"
257       group "tile"
258     end
259   end
260
261   execute "#{file}_shapeindex" do
262     action :nothing
263     command "find #{directory} -type f -iname '*.shp' -print0 | xargs -0 --no-run-if-empty shapeindex --shape_files"
264     user "tile"
265     group "tile"
266     subscribes :run, "execute[#{file}]", :immediately
267   end
268
269   remote_file file do
270     if data[:refresh]
271       action :create
272       use_conditional_get true
273       ignore_failure true
274     else
275       action :create_if_missing
276     end
277
278     source url
279     owner "tile"
280     group "tile"
281     mode "644"
282     backup false
283     notifies :run, "execute[#{file}]", :immediately
284     notifies :restart, "service[renderd]"
285   end
286 end
287
288 nodejs_package "carto"
289
290 lowzoom_threads = [node.cpu_cores - 1, node[:memory][:total].to_f / 6291456].min.floor
291
292 systemd_service "update-lowzoom@" do
293   description "Low zoom tile update service for %i layer"
294   user "tile"
295   exec_start_pre "+/bin/systemctl stop render-lowzoom.service"
296   exec_start "/bin/bash /usr/local/bin/update-lowzoom-%i"
297   runtime_directory "update-lowzoom-%i"
298   sandbox true
299   restrict_address_families "AF_UNIX"
300   read_write_paths [
301     "/srv/tile.openstreetmap.org/tiles/%i",
302     "/var/log/tile"
303   ]
304   restart "on-failure"
305 end
306
307 directory "/srv/tile.openstreetmap.org/styles" do
308   owner "tile"
309   group "tile"
310   mode "755"
311 end
312
313 node[:tile][:styles].each do |name, details|
314   style_directory = "/srv/tile.openstreetmap.org/styles/#{name}"
315   tile_directory = "/srv/tile.openstreetmap.org/tiles/#{name}"
316
317   template "/usr/local/bin/update-lowzoom-#{name}" do
318     source "update-lowzoom.erb"
319     owner "root"
320     group "root"
321     mode "755"
322     variables :style => name, :threads => lowzoom_threads
323   end
324
325   service "update-lowzoom@#{name}" do
326     action :disable
327     supports :restart => true
328   end
329
330   directory tile_directory do
331     owner "tile"
332     group "tile"
333     mode "755"
334   end
335
336   details[:tile_directories].each do |directory|
337     directory directory[:name] do
338       owner "_renderd"
339       group "_renderd"
340       mode "755"
341     end
342
343     directory[:min_zoom].upto(directory[:max_zoom]) do |zoom|
344       directory "#{directory[:name]}/#{zoom}" do
345         owner "_renderd"
346         group "_renderd"
347         mode "755"
348       end
349
350       link "#{tile_directory}/#{zoom}" do
351         to "#{directory[:name]}/#{zoom}"
352         owner "tile"
353         group "tile"
354       end
355     end
356   end
357
358   file "#{tile_directory}/planet-import-complete" do
359     action :create_if_missing
360     owner "tile"
361     group "tile"
362     mode "444"
363   end
364
365   git style_directory do
366     action :sync
367     repository details[:repository]
368     revision details[:revision]
369     user "tile"
370     group "tile"
371   end
372
373   link "#{style_directory}/data" do
374     to "/srv/tile.openstreetmap.org/data"
375     owner "tile"
376     group "tile"
377   end
378
379   if details[:fonts_script]
380     execute details[:fonts_script] do
381       action :nothing
382       command details[:fonts_script]
383       cwd style_directory
384       user "tile"
385       group "tile"
386       subscribes :run, "git[#{style_directory}]"
387     end
388   end
389
390   execute "#{style_directory}/project.mml" do
391     action :nothing
392     command "carto -a 3.0.22 project.mml > project.xml"
393     cwd style_directory
394     user "tile"
395     group "tile"
396     subscribes :run, "git[#{style_directory}]"
397     notifies :restart, "service[renderd]", :immediately
398     notifies :restart, "service[update-lowzoom@#{name}]"
399   end
400 end
401
402 postgresql_version = node[:tile][:database][:cluster].split("/").first
403 postgis_version = node[:tile][:database][:postgis]
404
405 package "postgresql-#{postgresql_version}-postgis-#{postgis_version}"
406
407 postgresql_user "jburgess" do
408   cluster node[:tile][:database][:cluster]
409   superuser true
410 end
411
412 postgresql_user "tomh" do
413   cluster node[:tile][:database][:cluster]
414   superuser true
415 end
416
417 postgresql_user "pnorman" do
418   cluster node[:tile][:database][:cluster]
419   superuser true
420 end
421
422 postgresql_user "tile" do
423   cluster node[:tile][:database][:cluster]
424 end
425
426 postgresql_user "www-data" do
427   cluster node[:tile][:database][:cluster]
428 end
429
430 postgresql_user "_renderd" do
431   cluster node[:tile][:database][:cluster]
432 end
433
434 postgresql_database "gis" do
435   cluster node[:tile][:database][:cluster]
436   owner "tile"
437 end
438
439 postgresql_extension "postgis" do
440   cluster node[:tile][:database][:cluster]
441   database "gis"
442 end
443
444 postgresql_extension "hstore" do
445   cluster node[:tile][:database][:cluster]
446   database "gis"
447   only_if { node[:tile][:database][:hstore] }
448 end
449
450 %w[geography_columns planet_osm_nodes planet_osm_rels planet_osm_ways raster_columns raster_overviews].each do |table|
451   postgresql_table table do
452     cluster node[:tile][:database][:cluster]
453     database "gis"
454     owner "tile"
455     permissions "tile" => :all
456   end
457 end
458
459 %w[geometry_columns planet_osm_line planet_osm_point planet_osm_polygon planet_osm_roads spatial_ref_sys].each do |table|
460   postgresql_table table do
461     cluster node[:tile][:database][:cluster]
462     database "gis"
463     owner "tile"
464     permissions "tile" => :all, "www-data" => :select, "_renderd" => :select
465   end
466 end
467
468 package %w[
469   gdal-bin
470   python3-yaml
471   python3-psycopg2
472 ]
473
474 if node[:tile][:database][:external_data_script]
475   execute node[:tile][:database][:external_data_script] do
476     command "#{node[:tile][:database][:external_data_script]} -R _renderd"
477     cwd "/srv/tile.openstreetmap.org"
478     user "tile"
479     group "tile"
480     ignore_failure true
481   end
482
483   Array(node[:tile][:database][:external_data_tables]).each do |table|
484     postgresql_table table do
485       cluster node[:tile][:database][:cluster]
486       database "gis"
487       owner "tile"
488       permissions "tile" => :all, "www-data" => :select, "_renderd" => :select
489     end
490   end
491 end
492
493 postgresql_munin "gis" do
494   cluster node[:tile][:database][:cluster]
495   database "gis"
496 end
497
498 directory File.dirname(node[:tile][:database][:node_file]) do
499   owner "root"
500   group "root"
501   mode "755"
502   recursive true
503 end
504
505 file node[:tile][:database][:node_file] do
506   owner "tile"
507   group "_renderd"
508   mode "660"
509 end
510
511 directory "/var/log/tile" do
512   owner "tile"
513   group "tile"
514   mode "755"
515 end
516
517 package %w[
518   osm2pgsql
519   osmium-tool
520   pyosmium
521 ]
522
523 directory "/var/lib/replicate" do
524   owner "tile"
525   group "tile"
526   mode "755"
527 end
528
529 template "/usr/local/bin/expire-tiles" do
530   source "expire-tiles.erb"
531   owner "root"
532   group "root"
533   mode "755"
534 end
535
536 directory "/var/lib/replicate/expire-queue" do
537   owner "tile"
538   group "_renderd"
539   mode "775"
540 end
541
542 template "/usr/local/bin/replicate" do
543   source "replicate.erb"
544   owner "root"
545   group "root"
546   mode "755"
547 end
548
549 systemd_service "expire-tiles" do
550   description "Tile dirtying service"
551   type "simple"
552   user "_renderd"
553   exec_start "/usr/local/bin/expire-tiles"
554   nice 10
555   sandbox true
556   restrict_address_families "AF_UNIX"
557   read_write_paths tile_directories + [
558                      "/var/lib/replicate/expire-queue"
559                    ]
560 end
561
562 systemd_path "expire-tiles" do
563   description "Tile dirtying trigger"
564   directory_not_empty "/var/lib/replicate/expire-queue"
565 end
566
567 service "expire-tiles.path" do
568   action [:enable, :start]
569   subscribes :restart, "systemd_path[expire-tiles]"
570 end
571
572 template "/usr/local/bin/replicate-post" do
573   source "replicate-post.erb"
574   owner "root"
575   group "root"
576   mode "755"
577 end
578
579 osm2pgsql_arguments = %w[
580     --number-processes=1
581     --log-progress=false
582     --expire-tiles=13-19
583     --expire-output=/var/lib/replicate/dirty-tiles.txt
584   ]
585
586 osm2pgsql_arguments.append("--multi-geometry") if node[:tile][:database][:multi_geometry]
587 osm2pgsql_arguments.append("--hstore") if node[:tile][:database][:hstore]
588 osm2pgsql_arguments.append("--tag-transform-script=#{node[:tile][:database][:tag_transform_script]}") if node[:tile][:database][:tag_transform_script]
589
590 systemd_service "replicate" do
591   description "Rendering database replication service"
592   after "postgresql.service"
593   wants "postgresql.service"
594   user "tile"
595   exec_start "/usr/local/bin/replicate"
596   sandbox :enable_network => true
597   restrict_address_families "AF_UNIX"
598   read_write_paths [
599     "/store/database/nodes",
600     "/var/lib/replicate"
601   ]
602   restart "on-failure"
603 end
604
605 service "replicate" do
606   action [:enable, :start]
607   subscribes :restart, "template[/usr/local/bin/replicate]"
608   subscribes :restart, "systemd_service[replicate]"
609 end
610
611 template "/usr/local/bin/render-lowzoom" do
612   source "render-lowzoom.erb"
613   owner "root"
614   group "root"
615   mode "755"
616   variables :threads => lowzoom_threads
617 end
618
619 systemd_service "render-lowzoom" do
620   description "Render low zoom tiles"
621   condition_path_exists_glob "!/run/update-lowzoom-*"
622   user "tile"
623   exec_start "/usr/local/bin/render-lowzoom"
624   sandbox true
625   restrict_address_families "AF_UNIX"
626   read_write_paths "/var/log/tile"
627 end
628
629 systemd_timer "render-lowzoom" do
630   description "Render low zoom tiles"
631   on_calendar "23:00 #{node[:timezone]}"
632 end
633
634 service "render-lowzoom.timer" do
635   action [:enable, :start]
636 end
637
638 package "liblockfile-simple-perl"
639 package "libfilesys-df-perl"
640
641 template "/usr/local/bin/cleanup-tiles" do
642   source "cleanup-tiles.erb"
643   owner "root"
644   group "root"
645   mode "755"
646 end
647
648 systemd_service "cleanup-tiles@" do
649   description "Cleanup old tiles for /%I"
650   exec_start "/usr/local/bin/cleanup-tiles /%I"
651   user "_renderd"
652   io_scheduling_class "idle"
653   sandbox true
654   read_write_paths "/%I"
655 end
656
657 systemd_timer "cleanup-tiles@" do
658   description "Cleanup old tiles for /%I"
659   on_boot_sec "30m"
660   on_unit_inactive_sec "60m"
661   randomized_delay_sec "10m"
662 end
663
664 tile_directories.each do |directory|
665   label = directory[1..].gsub("/", "-")
666
667   service "cleanup-tiles@#{label}.timer" do
668     action [:enable, :start]
669   end
670 end
671
672 munin_plugin "mod_tile_fresh"
673 munin_plugin "mod_tile_latency"
674 munin_plugin "mod_tile_response"
675 munin_plugin "mod_tile_zoom"
676
677 munin_plugin "renderd_processed"
678 munin_plugin "renderd_queue"
679 munin_plugin "renderd_queue_time"
680 munin_plugin "renderd_zoom"
681 munin_plugin "renderd_zoom_time"
682
683 munin_plugin "replication_delay"
684
685 package "ruby-webrick"
686
687 prometheus_exporter "modtile" do
688   port 9494
689 end
690
691 prometheus_exporter "renderd" do
692   port 9393
693 end