- name: trac
run_list:
- recipe[trac::default]
+ - name: vectortile
+ run_list:
+ - recipe[vectortile::default]
- name: web-cgimap
run_list:
- recipe[web::cgimap]
class PostgreSQL
include Chef::Mixin::ShellOut
+ SCHEMA_PRIVILEGES = [
+ :create, :usage
+ ].freeze
+
TABLE_PRIVILEGES = [
:select, :insert, :update, :delete, :truncate, :references, :trigger
].freeze
end
end
+ def schemas(database)
+ @schemas ||= {}
+ @schemas[database] ||= query("SELECT n.nspname, pg_catalog.pg_get_userbyid(n.nspowner) AS usename, n.nspacl FROM pg_namespace AS n WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'", :database => database).each_with_object({}) do |schema, schemas|
+ name = "#{schema[:nspname]}"
+
+ schemas[name] = {
+ :owner => schema[:usename],
+ :permissions => parse_acl(schema[:nspacl] || "{}")
+ }
+ end
+ end
+
def tables(database)
@tables ||= {}
- @tables[database] ||= query("SELECT n.nspname, c.relname, u.usename, c.relacl FROM pg_class AS c INNER JOIN pg_user AS u ON c.relowner = u.usesysid INNER JOIN pg_namespace AS n ON c.relnamespace = n.oid WHERE n.nspname NOT IN ('pg_catalog', 'information_schema') AND c.relkind = 'r'", :database => database).each_with_object({}) do |table, tables|
+ @tables[database] ||= query("SELECT n.nspname, c.relname, u.usename, c.relacl FROM pg_class AS c INNER JOIN pg_user AS u ON c.relowner = u.usesysid INNER JOIN pg_namespace AS n ON c.relnamespace = n.oid WHERE n.nspname NOT IN ('pg_catalog', 'information_schema') AND c.relkind IN ('r', 'p')", :database => database).each_with_object({}) do |table, tables|
name = "#{table[:nspname]}.#{table[:relname]}"
tables[name] = {
--- /dev/null
+#
+# Cookbook:: postgresql
+# Resource:: postgresql_schema
+#
+# Copyright:: 2024, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+unified_mode true
+
+default_action :create
+
+property :schema, :kind_of => String, :name_property => true
+property :cluster, :kind_of => String, :required => true
+property :database, :kind_of => String, :required => true
+property :owner, :kind_of => String, :required => [:create]
+property :permissions, :kind_of => Hash, :default => {}
+
+action :create do
+ if schemas.include?(qualified_name)
+ # Handle the case of an existing schema
+ if new_resource.owner != schemas[qualified_name][:owner]
+ converge_by("set owner for #{new_resource} to #{new_resource.owner}") do
+ Chef::Log.info("Setting owner for #{new_resource} to #{new_resource.owner}")
+ cluster.execute(:command => "ALTER SCHEMA #{qualified_name} OWNER TO \"#{new_resource.owner}\"", :database => new_resource.database)
+ end
+ end
+
+ schemas[qualified_name][:permissions].each_key do |user|
+ next if new_resource.permissions[user]
+ # Remove permissions from users who no longer have them
+ converge_by("revoke all for #{user} on #{new_resource}") do
+ Chef::Log.info("Revoking all for #{user} on #{new_resource}")
+ cluster.execute(:command => "REVOKE ALL ON SCHEMA #{qualified_name} FROM \"#{user}\"", :database => new_resource.database)
+ end
+ end
+ new_resource.permissions.each do |user, new_privileges|
+ current_privileges = schemas[qualified_name][:permissions][user] || {}
+ new_privileges = Array(new_privileges)
+
+ if new_privileges.include?(:all)
+ new_privileges |= OpenStreetMap::PostgreSQL::SCHEMA_PRIVILEGES
+ end
+
+ OpenStreetMap::PostgreSQL::SCHEMA_PRIVILEGES.each do |privilege|
+ if new_privileges.include?(privilege)
+ unless current_privileges.include?(privilege)
+ converge_by("grant #{privilege} for #{user} on #{new_resource}") do
+ Chef::Log.info("Granting #{privilege} for #{user} on #{new_resource}")
+ cluster.execute(:command => "GRANT #{privilege.to_s.upcase} ON SCHEMA #{qualified_name} TO \"#{user}\"", :database => new_resource.database)
+ end
+ end
+ elsif current_privileges.include?(privilege)
+ converge_by("revoke #{privilege} for #{user} on #{new_resource}") do
+ Chef::Log.info("Revoking #{privilege} for #{user} on #{new_resource}")
+ cluster.execute(:command => "REVOKE #{privilege.to_s.upcase} ON SCHEMA #{qualified_name} FROM \"#{user}\"", :database => new_resource.database)
+ end
+ end
+ end
+ end
+ else
+ converge_by "create schema #{new_resource.schema}" do
+ cluster.execute(:command => "CREATE SCHEMA #{new_resource.schema} AUTHORIZATION #{new_resource.owner}", :database => new_resource.database)
+ # Because the schema is new, we don't have to worry about revoking or checking current permissions
+ new_resource.permissions.each do |user, new_privileges|
+ new_privileges = Array(new_privileges)
+ if new_privileges.include?(:all)
+ new_privileges |= OpenStreetMap::PostgreSQL::SCHEMA_PRIVILEGES
+ end
+ OpenStreetMap::PostgreSQL::SCHEMA_PRIVILEGES.each do |privilege|
+ next unless new_privileges.include?(privilege)
+ converge_by("grant #{privilege} for #{user} on #{new_resource}") do
+ Chef::Log.info("Granting #{privilege} for #{user} on #{new_resource}")
+ cluster.execute(:command => "GRANT #{privilege.to_s.upcase} ON SCHEMA #{qualified_name} TO \"#{user}\"", :database => new_resource.database)
+ end
+ end
+ end
+ end
+ end
+end
+
+action :drop do
+ if schemas.include?(qualified_name)
+ converge_by("drop #{new_resource}") do
+ Chef::Log.info("Dropping #{new_resource}")
+ cluster.execute(:command => "DROP SCHEMA #{qualified_name}", :database => new_resource.database)
+ end
+ end
+end
+
+action_class do
+ def cluster
+ @cluster ||= OpenStreetMap::PostgreSQL.new(new_resource.cluster)
+ end
+
+ def schemas
+ @schemas ||= cluster.schemas(new_resource.database)
+ end
+
+ def qualified_name
+ "#{new_resource.name}"
+ end
+end
--- /dev/null
+# vectortile cookbook
+
+This cookbook installs and configures the tilekiln based tileservers
+
+## Accounts
+The following accounts are used
+- `www-data` for nginx serving static files and proxying
+- `tilekiln` for the process serving tiles
+- `tileupdate` for the process running osm2pgsql and tilekiln on updates
--- /dev/null
+default[:vectortile][:database][:cluster] = "16/main"
+default[:vectortile][:database][:postgis] = "3"
+default[:vectortile][:database][:nodes_store] = :flat
+default[:vectortile][:serve][:threads] = node.cpu_cores
+default[:vectortile][:serve][:mode] = :live
+default[:vectortile][:replication][:url] = "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet/replication/minute"
+default[:vectortile][:replication][:status] = :enabled
+default[:vectortile][:replication][:tileupdate] = :enabled
+default[:vectortile][:replication][:threads] = node.cpu_cores
+
+default[:postgresql][:versions] |= [node[:vectortile][:database][:cluster].split("/").first]
+default[:postgresql][:monitor_database] = "tiles"
+default[:postgresql][:settings][:defaults][:max_connections] = (node.cpu_cores * 4 + 20).to_s
+default[:accounts][:users][:tileupdate][:status] = :role
+default[:accounts][:users][:tilekiln][:status] = :role
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<access-policy>
+ <cross-domain-access>
+ <policy>
+ <allow-from http-request-headers="*">
+ <domain uri="*"/>
+ </allow-from>
+ <grant-to>
+ <resource path="/" include-subpaths="true"/>
+ </grant-to>
+ </policy>
+ </cross-domain-access>
+</access-policy>
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
+<cross-domain-policy>
+ <allow-access-from domain="*" secure="false" />
+</cross-domain-policy>
--- /dev/null
+User-agent: *
+Disallow: /12/
+Disallow: /13/
+Disallow: /14/
+Disallow: /15/
+Disallow: /16/
+Disallow: /17/
+Disallow: /18/
+Disallow: /19/
+Disallow: /20/
+Disallow: /21/
+Disallow: /22/
+Disallow: /23/
--- /dev/null
+name "vectortile"
+maintainer "OpenStreetMap Administrators"
+maintainer_email "admins@openstreetmap.org"
+license "Apache-2.0"
+description "Installs and configures vector tile servers"
+
+version "1.0.0"
+supports "ubuntu"
+depends "accounts"
+depends "git"
+depends "nginx"
+depends "postgresql"
+depends "prometheus"
+depends "python"
+depends "systemd"
+depends "tools"
--- /dev/null
+#
+# Cookbook:: vectortile
+# Recipe:: default
+#
+# Copyright:: 2024, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "accounts"
+include_recipe "git"
+include_recipe "nginx"
+include_recipe "postgresql"
+include_recipe "prometheus"
+include_recipe "python"
+include_recipe "tools"
+
+directory "/srv/vector.openstreetmap.org" do
+ user "tileupdate"
+ group "tileupdate"
+ mode "755"
+end
+
+nginx_site "default" do
+ action [:delete]
+end
+
+nginx_site "vector.openstreetmap.org" do
+ template "nginx.erb"
+end
+
+ssl_certificate node[:fqdn] do
+ domains [node[:fqdn], "vector.openstreetmap.org"]
+ notifies :reload, "service[nginx]"
+end
+
+remote_directory "/srv/vector.openstreetmap.org/html" do
+ source "html"
+ owner "www-data"
+ group "www-data"
+ mode "755"
+ files_owner "www-data"
+ files_group "www-data"
+ files_mode "644"
+end
+
+template "/srv/vector.openstreetmap.org/html/index.html" do
+ source "index.html.erb"
+ owner "www-data"
+ group "www-data"
+ mode "644"
+end
+
+postgresql_version = node[:vectortile][:database][:cluster].split("/").first
+postgis_version = node[:vectortile][:database][:postgis]
+
+package "postgresql-#{postgresql_version}-postgis-#{postgis_version}"
+
+# Spirit dependencies
+package %w[
+ osm2pgsql
+ gdal-bin
+ python3-yaml
+ python3-psycopg2
+]
+
+style_directory = "/srv/vector.openstreetmap.org/spirit"
+git style_directory do
+ repository "https://github.com/pnorman/spirit.git"
+ user "tileupdate"
+ group "tileupdate"
+end
+
+shortbread_config = "#{style_directory}/shortbread.yaml"
+
+themepark_directory = "/srv/vector.openstreetmap.org/osm2pgsql-themepark"
+git themepark_directory do
+ repository "https://github.com/osm2pgsql-dev/osm2pgsql-themepark.git"
+ user "tileupdate"
+ group "tileupdate"
+end
+
+tilekiln_directory = "/opt/tilekiln"
+
+python_virtualenv tilekiln_directory do
+ interpreter "/usr/bin/python3"
+end
+
+python_package "tilekiln" do
+ python_virtualenv tilekiln_directory
+ python_version "3"
+ version "0.5.1"
+end
+
+template "/srv/vector.openstreetmap.org/html/index.html" do
+ source "index.html.erb"
+ owner "www-data"
+ group "www-data"
+ mode "644"
+end
+
+directory "/srv/vector.openstreetmap.org/data" do
+ user "tileupdate"
+ group "tileupdate"
+ mode "755"
+end
+
+node_store_options = node[:vectortile][:database][:nodes_store] == :flat ? "--flat-nodes '/srv/vector.openstreetmap.org/data/nodes.bin'" : ""
+template "/usr/local/bin/import-planet" do
+ source "import-planet.erb"
+ owner "root"
+ group "root"
+ mode "755"
+ variables :node_store_options => "#{node_store_options}"
+end
+
+template "/usr/local/bin/tilekiln-storage-init" do
+ source "tilekiln-storage-init.erb"
+ owner "root"
+ group "root"
+ mode "755"
+ variables :tilekiln_bin => "#{tilekiln_directory}/bin/tilekiln", :storage_database => "tiles", :config_path => "#{shortbread_config}"
+end
+
+postgresql_user "tomh" do
+ cluster node[:vectortile][:database][:cluster]
+ superuser true
+end
+
+postgresql_user "pnorman" do
+ cluster node[:vectortile][:database][:cluster]
+ superuser true
+end
+
+postgresql_user "tilekiln" do
+ cluster node[:vectortile][:database][:cluster]
+end
+
+postgresql_user "tileupdate" do
+ cluster node[:vectortile][:database][:cluster]
+end
+
+postgresql_database "tiles" do
+ cluster node[:vectortile][:database][:cluster]
+ owner "tileupdate"
+end
+
+postgresql_database "spirit" do
+ cluster node[:vectortile][:database][:cluster]
+ owner "tileupdate"
+end
+
+postgresql_extension "postgis" do
+ cluster node[:vectortile][:database][:cluster]
+ database "spirit"
+end
+
+postgresql_schema "tilekiln" do
+ cluster node[:vectortile][:database][:cluster]
+ database "tiles"
+ owner "tileupdate"
+ permissions "tileupdate" => :all, "tilekiln" => :usage
+ notifies :run, "execute[tilekiln-storage-init]", :immediately
+end
+
+execute "tilekiln-storage-init" do
+ action :nothing
+ command "/usr/local/bin/tilekiln-storage-init"
+ user "tileupdate"
+end
+
+%w[metadata shortbread_v1].each do |table|
+ postgresql_table table do
+ cluster node[:vectortile][:database][:cluster]
+ database "tiles"
+ schema "tilekiln"
+ owner "tileupdate"
+ permissions "tileupdate" => :all, "tilekiln" => :select
+ end
+end
+
+(0..14).each do |zoom|
+ postgresql_table "shortbread_v1_z#{zoom}" do
+ cluster node[:vectortile][:database][:cluster]
+ database "tiles"
+ schema "tilekiln"
+ owner "tileupdate"
+ permissions "tileupdate" => :all, "tilekiln" => node[:vectortile][:serve][:mode] == :live ? [:select, :insert, :update] : :select
+ end
+end
+
+%w[addresses aerialways aeroways boundaries boundary_labels bridges buildings
+dam_lines dam_polygons ferries land pier_lines pier_polygons place_labels
+planet_osm_nodes planet_osm_rels planet_osm_ways pois public_transport railways
+road_routes roads sites street_polygons streets_labels_points
+streets_polygons_labels water_area_labels water_areas water_lines water_lines_labels].each do |table|
+ postgresql_table table do
+ cluster node[:vectortile][:database][:cluster]
+ database "spirit"
+ schema "public"
+ owner "tileupdate"
+ permissions "tileupdate" => :all, "tilekiln" => :select
+ end
+end
+
+tilekiln_mode = node[:vectortile][:serve][:mode] == :live ? "live --config #{shortbread_config} --source-dbname spirit" : "static"
+
+systemd_service "tilekiln" do
+ description "Tilekiln vector tile server"
+ user "tilekiln"
+ after "postgresql.service"
+ wants "postgresql.service"
+ sandbox :enable_network => true
+ restrict_address_families "AF_UNIX"
+ exec_start "#{tilekiln_directory}/bin/tilekiln serve #{tilekiln_mode} --storage-dbname tiles --num-threads #{node[:vectortile][:serve][:threads]}"
+end
+
+service "tilekiln" do
+ action [:enable, :start]
+end
+
+execute "/srv/vector.openstreetmap.org/spirit/scripts/get-external-data.py" do
+ command "/srv/vector.openstreetmap.org/spirit/scripts/get-external-data.py -R tilekiln"
+ cwd "/srv/vector.openstreetmap.org/spirit"
+ user "tileupdate"
+ group "tileupdate"
+ ignore_failure true
+end
+
+template "/usr/local/bin/vector-update" do
+ source node[:vectortile][:replication][:tileupdate] == :enabled ? "vector-update-tile.erb" : "vector-update-notile.erb"
+ owner "root"
+ group "root"
+ mode "755"
+ variables :tilekiln_bin => "#{tilekiln_directory}/bin/tilekiln", :source_database => "spirit", :config_path => "#{shortbread_config}", :diff_size => "1000", :tiles_file => "/srv/vector.openstreetmap.org/data/tiles.txt", :post_processing => "/usr/local/bin/tiles-rerender"
+end
+
+template "/usr/local/bin/tiles-rerender" do
+ source "tiles-rerender.erb"
+ owner "root"
+ group "root"
+ mode "755"
+ variables :tilekiln_bin => "#{tilekiln_directory}/bin/tilekiln", :source_database => "spirit", :storage_database => "tiles", :config_path => "#{shortbread_config}", :tiles_file => "/srv/vector.openstreetmap.org/data/tiles.txt", :update_threads => 4
+end
+
+systemd_service "replicate" do
+ description "Get replication updates"
+ user "tileupdate"
+ after "postgresql.service"
+ wants "postgresql.service"
+ sandbox :enable_network => true
+ restrict_address_families "AF_UNIX"
+ read_write_paths ["/srv/vector.openstreetmap.org/data/"]
+ exec_start "/usr/local/bin/vector-update"
+end
+
+systemd_timer "replicate" do
+ description "Get replication updates"
+ on_boot_sec 60
+ on_unit_active_sec 30
+ accuracy_sec 5
+end
+
+if node[:vectortile][:replication][:status] == :enabled
+ service "replicate.timer" do
+ action [:enable, :start]
+ end
+else
+ service "replicate.timer" do
+ action [:stop, :disable]
+ end
+end
--- /dev/null
+#!/bin/sh
+
+# Usage
+# sudo -u tileupdate import-planet osmfile.osm.pbf
+# sudo -u tileupdate import-planet --cache 50000 osmfile.osm.pbf
+# This script sets the appropriate Lua and style paths for the osm2pgsql import
+
+set -e
+
+export LUA_PATH='/srv/vector.openstreetmap.org/osm2pgsql-themepark/lua/?.lua;/srv/vector.openstreetmap.org/spirit/?.lua;;'
+
+# Import the osm2pgsql file specified as an argument, using the locations for spirit
+osm2pgsql \
+ --output flex \
+ --style '/srv/vector.openstreetmap.org/spirit/shortbread.lua' \
+ --slim \
+ <%= @node_store_options %> \
+ -d spirit \
+ $@
+
+# Set up replication. This doesn't specify the replication server, so it will use planet.osm.org on extracts
+osm2pgsql-replication init \
+ -d spirit \
+ --server '<%= node[:vectortile][:replication][:url] %>'
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>vector.openstreetmap.org</title>
+<!-- MANAGED VIA CHEF -->
+<meta name="robots" content="noindex">
+<meta http-equiv="cache-control" content="no-cache">
+<meta http-equiv="pragma" content="no-cache">
+</head>
+<body>
+You've reached the OpenStreetMap.org vector tile server (<%= node['fqdn'] %>)<br />
+<dl>
+<dt>If you are a user...</dt>
+<dd>You probably want <a href="https://www.openstreetmap.org/">OpenStreetMap</a> itself.</dd>
+<dt>If you are a developer...</dt>
+<dd>Please be aware of the <a href="https://operations.osmfoundation.org/policies/tiles/">tile usage policy</a>.</dd>
+</dl>
+</body>
+</html>
--- /dev/null
+upstream tilekiln {
+ server 127.0.0.1:8000;
+}
+
+server {
+ listen 80 default_server;
+ listen [::]:80 default_server;
+
+ location /nginx_status {
+ stub_status on;
+ access_log off;
+ allow 127.0.0.1;
+ allow ::1;
+ deny all;
+ }
+
+ rewrite ^/\.well-known/acme-challenge/(.*)$ http://acme.openstreetmap.org/.well-known/acme-challenge/$1 permanent;
+
+ location / {
+ return 301 https://$host$request_uri;
+ }
+}
+
+server {
+ # IPv4
+ listen 443 ssl default_server;
+ # IPv6
+ listen [::]:443 ssl default_server;
+ http2 on;
+ server_name localhost;
+
+ ssl_certificate /etc/ssl/certs/<%= node[:fqdn] %>.pem;
+ ssl_certificate_key /etc/ssl/private/<%= node[:fqdn] %>.key;
+
+ location /nginx_status {
+ stub_status on;
+ access_log off;
+ allow 127.0.0.1;
+ allow ::1;
+ deny all;
+ }
+ location /shortbread_v1/ {
+ proxy_pass http://tilekiln;
+ }
+ root /srv/vector.openstreetmap.org/html;
+}
--- /dev/null
+#!/bin/sh
+
+# Usage
+# sudo -u tileupdate tilekiln-storage-init
+
+<%= @tilekiln_bin %> storage init \
+ --storage-dbname <%= @storage_database %> \
+ --config <%= @config_path %>
--- /dev/null
+#!/bin/sh
+set -eu
+<%= @tilekiln_bin %> generate tiles \
+--source-dbname "<%= @source_database %>" \
+--storage-dbname "<%= @storage_database %>" \
+--num-threads "<%= node[:vectortile][:replication][:threads] %>" \
+--config <%= @config_path %> < <%= @tiles_file %>
--- /dev/null
+#!/bin/sh
+
+# Usage
+# sudo -u tilekiln vector-update
+
+set -eu
+
+export LUA_PATH='/srv/vector.openstreetmap.org/osm2pgsql-themepark/lua/?.lua;/srv/vector.openstreetmap.org/spirit/?.lua;;'
+
+osm2pgsql-replication update \
+ -d "<%= @source_database %>" \
+ --max-diff-size "<%= @diff_size %>"
--- /dev/null
+#!/bin/sh
+
+# Usage
+# sudo -u tilekiln vector-update
+
+set -eu
+
+export LUA_PATH='/srv/vector.openstreetmap.org/osm2pgsql-themepark/lua/?.lua;/srv/vector.openstreetmap.org/spirit/?.lua;;'
+
+osm2pgsql-replication update \
+ -d "<%= @source_database %>" \
+ --max-diff-size "<%= @diff_size %>" \
+ --post-processing "<%= @post_processing %>" \
+ -- --expire-tiles=10-14 \
+ --expire-output="<%= @tiles_file %>"
)
run_list(
- "role[cloudferro-waw3-2]"
+ "role[cloudferro-waw3-2]",
+ "role[vectortile]"
)
--- /dev/null
+name "vectortile"
+description "Role applied to all vector tile servers"
+
+default_attributes(
+ :accounts => {
+ :users => {
+ :pnorman => { :status => :administrator },
+ :tile => {
+ :members => [:tomh, :pnorman]
+ }
+ }
+ },
+ :postgresql => {
+ :settings => {
+ :defaults => {
+ :max_connections => "250",
+ :shared_buffers => "16GB",
+ :work_mem => "128MB",
+ :maintenance_work_mem => "8GB",
+ :max_parallel_workers_per_gather => "0",
+ :wal_level => "minimal",
+ :wal_buffers => "1024kB",
+ :wal_writer_delay => "500ms",
+ :checkpoint_timeout => "60min",
+ :commit_delay => "10000",
+ :max_wal_size => "10GB",
+ :max_wal_senders => "0",
+ :jit => "off",
+ :track_activity_query_size => "16384",
+ :autovacuum_vacuum_scale_factor => "0.05",
+ :autovacuum_analyze_scale_factor => "0.02"
+ }
+ }
+ },
+ :sysctl => {
+ :sockets => {
+ :comment => "Increase size of connection queue",
+ :parameters => {
+ "net.core.somaxconn" => 10000
+ }
+ },
+ :network_conntrack_time_wait => {
+ :comment => "Only track completed connections for 30 seconds",
+ :parameters => {
+ "net.netfilter.nf_conntrack_tcp_timeout_time_wait" => "30"
+ }
+ },
+ :network_conntrack_max => {
+ :comment => "Increase max number of connections tracked",
+ :parameters => {
+ "net.netfilter.nf_conntrack_max" => "524288"
+ }
+ },
+ :no_tcp_slow_start => {
+ :comment => "Disable TCP slow start",
+ :parameters => {
+ "net.ipv4.tcp_slow_start_after_idle" => "0"
+ }
+ },
+ :tcp_use_bbr => {
+ :comment => "Use TCP BBR Congestion Control",
+ :parameters => {
+ "net.core.default_qdisc" => "fq",
+ "net.ipv4.tcp_congestion_control" => "bbr"
+ }
+ }
+ }
+)
+
+run_list(
+ "recipe[vectortile]"
+)
--- /dev/null
+{
+ "id": "tilekiln",
+ "uid": "532",
+ "comment": "vectortile.openstreetmap.org",
+ "manage_home": false
+}
--- /dev/null
+{
+ "id": "tileupdate",
+ "uid": "531",
+ "comment": "vectortile.openstreetmap.org",
+ "manage_home": false
+}
--- /dev/null
+describe file("/usr/local/bin/import-planet") do
+ it { should be_executable.by_user("tileupdate") }
+end
--- /dev/null
+describe package("nginx") do
+ it { should be_installed }
+end
+
+describe service("nginx") do
+ it { should be_enabled }
+ it { should be_running }
+end
+
+describe port(80) do
+ it { should be_listening }
+ its("protocols") { should cmp %w[tcp tcp6] }
+end
+
+describe port(443) do
+ it { should be_listening }
+ its("protocols") { should cmp %w[tcp tcp6] }
+end
+
+describe http("http://localhost") do
+ its("status") { should cmp 301 }
+end
+
+describe http("https://localhost", :ssl_verify => false) do
+ its("status") { should cmp 200 }
+end
--- /dev/null
+describe package("osm2pgsql") do
+ it { should be_installed }
+ its("version") { should cmp >= "1.11.0" }
+end
--- /dev/null
+describe package("postgresql-16") do
+ it { should be_installed }
+end
+
+describe service("postgresql@16-main") do
+ it { should be_enabled }
+ it { should be_running }
+end
+
+describe port(5432) do
+ it { should be_listening }
+ its("protocols") { should cmp %w[tcp tcp6] }
+end
--- /dev/null
+describe file("/usr/local/bin/tilekiln-storage-init") do
+ it { should be_executable.by_user("tileupdate") }
+end
--- /dev/null
+describe file("/srv/vector.openstreetmap.org/osm2pgsql-themepark/lua/themepark.lua") do
+ it { should exist }
+end
+
+describe file("/srv/vector.openstreetmap.org/spirit/spirit.lua") do
+ it { should exist }
+end
--- /dev/null
+describe pip("tilekiln", "/opt/tilekiln/bin/pip") do
+ it { should be_installed }
+ its("version") { should cmp >= "0.5.0" }
+end
+
+describe service("tilekiln") do
+ it { should be_enabled }
+ it { should be_running }
+end
+
+describe port(8000) do
+ it { should be_listening }
+ its("protocols") { should cmp %w[tcp] }
+end
+
+describe http("http://localhost:8000") do
+ its("status") { should cmp 404 }
+end
+
+describe http("https://localhost/shortbread_v1/tilejson.json", :ssl_verify => false) do
+ its("status") { should cmp 200 }
+end
+
+# There are no tiles so everything should return a 404
+describe http("https://localhost/shortbread_v1/0/0/0.mvt", :ssl_verify => false) do
+ its("status") { should cmp 404 }
+end
+describe http("https://localhost/shortbread_v1/16/0/0.mvt", :ssl_verify => false) do
+ its("status") { should cmp 404 }
+end