From 5729dc92eb6a9a6e63386c0fcea1ab53cf512548 Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Sat, 8 Dec 2018 18:57:09 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BB=D0=BE=D0=BA=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B0=20.osm.pbf?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 18 +++++-- README.md | 7 +-- etc/locale.gen | 2 + home/osm-loader.pl | 129 ++++++++++++++++++++++++++++++--------------- 4 files changed, 105 insertions(+), 51 deletions(-) create mode 100644 etc/locale.gen diff --git a/Dockerfile b/Dockerfile index 66e9553..d62d813 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,14 @@ FROM debian:sid AS build MAINTAINER Vitaliy Filippov -ADD etc /etc +# Используем одинаковое начало для ускорения сборки +ADD [ "etc/apt/apt.conf", "/etc/apt/" ] +ADD etc/locale.gen /etc/locale.gen +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y -q \ + less wget sudo curl unzip git mc ca-certificates gnupg2 && \ + apt-get clean && rm -rf /var/lib/apt/lists/* RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y -q \ - less wget sudo curl unzip git mc ca-certificates \ build-essential golang-go libleveldb-dev libgeos-dev && \ apt-get clean && rm -rf /var/lib/apt/lists/* @@ -20,13 +24,17 @@ RUN dpkg -l | grep libgeos | awk '{print $2}' >> /root/pkg.lst FROM debian:sid AS run MAINTAINER Vitaliy Filippov -ADD etc /etc +# Используем одинаковое начало для ускорения сборки +ADD [ "etc/apt/apt.conf", "/etc/apt/" ] +ADD etc/locale.gen /etc/locale.gen +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y -q \ + less wget sudo curl unzip git mc ca-certificates gnupg2 && \ + apt-get clean && rm -rf /var/lib/apt/lists/* COPY --from=build /root/pkg.lst /root/ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y -q \ - less wget sudo curl unzip git mc \ - `cat /root/pkg.lst` libleveldb1v5 libdbd-pg-perl && \ + osmctools `cat /root/pkg.lst` libleveldb1v5 libdbd-pg-perl && \ apt-get clean && rm -rf /var/lib/apt/lists/* COPY --from=build /root/go/src/github.com/omniscale/imposm3/imposm /usr/bin/imposm3 diff --git a/README.md b/README.md index 6e6116a..2b1290f 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ docker build -t imposm3 . ## Running ``` -docker run -it -d --restart always \ - -v /home/test/russia-latest.osm.pbf:/home/valhalla/data.osm.pbf \ - --name valhalla -p 8002:8002 valhalla +docker run -t --rm=true \ + -e OSM_CACHE_DIR=/home/data \ + -v /home/data/osm:/home/data \ + --name imposm3 imposm3 ``` diff --git a/etc/locale.gen b/etc/locale.gen new file mode 100644 index 0000000..0c8fc3f --- /dev/null +++ b/etc/locale.gen @@ -0,0 +1,2 @@ +en_US.UTF-8 UTF-8 +ru_RU.UTF-8 UTF-8 diff --git a/home/osm-loader.pl b/home/osm-loader.pl index bfb65e7..e376e15 100755 --- a/home/osm-loader.pl +++ b/home/osm-loader.pl @@ -1,6 +1,19 @@ #!/usr/bin/perl -# Configuration in env: OSM_CACHE_DIR, OSM_CARTO_VERSION, URL_LATEST, URL_UPDATES, -# plus PG_ENV_OSM_{DB,HOST,PORT,USER,PASSWORD} like in README for the render server itself +# Конфигурация в переменных окружения: +# +# OSM_CACHE_DIR - путь к директории с временными и загружаемыми файлами +# OSM_INIT - если 1, то при пустой базе инициализировать базу +# OSM_UPDATE_FILE - если 1, то обновлять локальный файл osm.pbf до актуального состояния путём наката дельт +# OSM_EXPIRE - если 1, то вызывать утилиту render_expired +# OSM_METHOD - режим загрузки: osm2pgsql-carto или imposm3-all +# OSM_CARTO_VERSION - для режима osm2pgsql-carto - версия osm-carto. Файлы должны быть в /usr/share/mapnik/openstreetmap-carto-ВЕРСИЯ +# URL_LATEST - URL последней версии .osm.pbf экспортного файла +# URL_UPDATES - URL директории с обновлениями (должна содержать state.txt и дельты) +# PG_ENV_OSM_DB - БД PostGIS +# PG_ENV_OSM_HOST - хост/сокет БД +# PG_ENV_OSM_PORT - порт БД (по умолчанию 5432) +# PG_ENV_OSM_USER - пользователь БД +# PG_ENV_OSM_PASSWORD - пароль пользователя БД use strict; use DBI; @@ -14,22 +27,19 @@ my $url_updates = $ENV{URL_UPDATES} || 'http://download.geofabrik.de/russia-upda if (!$ENV{PG_ENV_OSM_DB}) { - fatal("OSM database not specified"); + fatal("Не задана БД OSM"); } - -info("Started OSM update for database: $ENV{PG_ENV_OSM_DB}"); - +info("Начато обновлением OSM базы данных: $ENV{PG_ENV_OSM_DB}"); if ($method ne 'osm2pgsql-carto' && $method ne 'imposm3-all') { - fatal("Incorrect OSM update mode: $method"); + fatal("Некорректный режим обновления: $method (поддерживаются только osm2pgsql-carto и imposm3-all)"); } - -e $dir || mkdir($dir); -chdir $dir or fatal("Failed to chdir $dir"); +chdir $dir or fatal("Директория $dir не существует"); eval { run_update() }; if ($@) { - fatal("$@"); + fatal("Ошибка кода: $@"); } exit(0); @@ -47,7 +57,7 @@ sub run_update { if (!$ENV{OSM_INIT}) { - fatal("Current OSM version missing, run with OSM_INIT=1 environment variable to initialize"); + fatal("БД OSM не инициализирована, запустите скрипт с переменной окружения OSM_INIT=1 для инициализации"); } $dbh->rollback; # иначе postgresql пишет "statements until the end ignored" # создаём таблицу и оставляем её заблокированной @@ -56,13 +66,13 @@ sub run_update $dbh->do('CREATE EXTENSION IF NOT EXISTS hstore'); # качаем дамп my ($fn) = $url_latest =~ /([^\/]+)$/so; - $fn =~ s/^([^\.]+)/$1-$state->{timestamp}/; - info("Downloading $url_latest"); + info("Скачивается файл $url_latest"); system("curl -s -C - -f '$url_latest' -o $dir/$fn"); if ($? || !-e "$dir/$fn") { - fatal("Failed to download $url_latest"); + fatal("Не удалось скачать файл $url_latest"); } + system("cp $dir/state.txt $dir/$fn.state.txt"); if ($method eq 'osm2pgsql-carto') { init_osm2pgsql($dbh, $state->{timestamp} . ' ' . $state->{sequenceNumber}, "$dir/$fn"); @@ -72,10 +82,12 @@ sub run_update init_imposm3($dbh, $state->{timestamp} . ' ' . $state->{sequenceNumber}, "$dir/$fn"); } $dbh->commit; - info("OSM database initialized with version: ".$state->{timestamp}); + info("База данных OSM $ENV{PG_ENV_OSM_DB} инициализирована версией: ".$state->{timestamp}); } else { + $version = [ split /\s+/, $version ]; + $version = { timestamp => $version->[0], sequenceNumber => $version->[1] }; my $apply = load_geofabrik_deltas($version, $state, $url_updates, $dir); chdir($dir); if ($method eq 'osm2pgsql-carto') @@ -88,53 +100,63 @@ sub run_update } update_state($dbh, $state); $dbh->commit; - info("OSM database updated to version: ".$state->{timestamp}); + info("База данных OSM $ENV{PG_ENV_OSM_DB} обновлена до версии: ".$state->{timestamp}); if ($ENV{OSM_EXPIRE}) { system("cat $dir/expire.list | render_expired --map=osm_carto --touch-from=11"); system("cat $dir/expire.list | render_expired --map=osm_bright --touch-from=11"); } } + if ($ENV{OSM_UPDATE_FILE}) + { + apply_deltas_file($url_latest, $url_updates, $dir); + } } sub parse_geofabrik_state { my ($url_updates, $dir) = @_; system("curl -s -f '$url_updates/state.txt' -o $dir/state.txt"); - if (!-r "$dir/state.txt") + if (-r "$dir/state.txt") { - fatal("Error downloading $url_updates/state.txt"); + return parse_geofabrik_state_file("$dir/state.txt"); } - else + fatal("Не удалось скачать файл $url_updates/state.txt"); +} + +sub parse_geofabrik_state_file +{ + my ($file) = @_; + my $state; + if (open FD, "<$file") { - my $state; - if (open FD, "<$dir/state.txt") + local $/ = undef; + $state = ; + close FD; + $state = { map { (split /\s*=\s*/, $_, 2) } grep { !/^\s*(#.*)?$/so && /=/so } split /\n/, $state }; + if (!$state->{timestamp} || !$state->{sequenceNumber}) { - local $/ = undef; - $state = ; - close FD; - $state = { map { (split /\s*=\s*/, $_, 2) } grep { !/^\s*(#.*)?$/so && /=/so } split /\n/, $state }; - if (!$state->{timestamp} || !$state->{sequenceNumber}) - { - fatal("State file incorrect, should have timestamp= and sequenceNumber="); - } - $state->{timestamp} =~ s/\\//g; - return $state; + fatal("Файл состояния репликации OSM некорректный, должен содержать строки timestamp=<дата_ISO8601> и sequenceNumber=<число>"); } + $state->{timestamp} =~ s/\\//g; + return $state; } - fatal("Error downloading $url_updates/state.txt"); + return undef; } sub load_geofabrik_deltas { - my ($version, $state, $url_updates, $dir) = @_; - my ($timestamp, $i) = split /\s+/, $version; + my ($old_state, $state, $url_updates, $dir) = @_; + my $i = $old_state->{sequenceNumber}; my $apply = []; - while ($i <= $state->{sequenceNumber}) + while ($i < $state->{sequenceNumber}) { my $subdir = sprintf("%03d/%03d", $i / 1000000, ($i / 1000) % 1000); my $fn = sprintf("%03d.osc.gz", $i % 1000); - info("Downloading $url_updates/$subdir/$fn"); + if (!-e "$dir/$subdir/$fn") + { + info("Скачивается файл дельты $url_updates/$subdir/$fn"); + } system("mkdir -p $dir/$subdir && curl -C - -s -f '$url_updates/$subdir/$fn' -o $dir/$subdir/$fn"); if (-e "$dir/$subdir/$fn") { @@ -142,7 +164,8 @@ sub load_geofabrik_deltas } else { - fatal("Delta not available: $url_updates/$subdir/$fn\n"); + unlink("$dir/$subdir/$fn") if -e "$dir/$subdir/$fn"; + fatal("Не удалось скачать файл дельты $url_updates/$subdir/$fn\n"); } $i++; } @@ -174,7 +197,7 @@ sub init_osm2pgsql my $carto_dir = '/usr/share/mapnik/openstreetmap-carto-'.$ENV{OSM_CARTO_VERSION}; if (!$ENV{OSM_CARTO_VERSION}) { - fatal("osm-carto path not specified"); + fatal("Не задан путь к osm-carto"); } my $cmd = "PGPASSWORD='".$ENV{PG_ENV_OSM_PASSWORD}."' osm2pgsql -I -s -c --hstore". @@ -185,7 +208,7 @@ sub init_osm2pgsql system($cmd); if ($?) { - fatal("$cmd failed"); + fatal("Загрузка полного дампа с помощью osm2pgsql не удалась"); } local $/ = undef; my $fd; @@ -208,7 +231,7 @@ sub init_imposm3 system($cmd); if ($?) { - fatal("$cmd failed"); + fatal("Загрузка полного дампа с помощью imposm3 не удалась"); } my $indexes = "SET SEARCH_PATH TO import, public; CREATE INDEX IF NOT EXISTS osm_polygon_area ON osm_polygon (st_area(geometry)); @@ -240,7 +263,7 @@ sub apply_deltas_osm2pgsql system($cmd); if ($?) { - fatal("$cmd failed"); + fatal("Загрузка дельт osm2pgsql не удалась"); } } } @@ -251,7 +274,7 @@ sub apply_deltas_imposm3 my $carto_dir = '/usr/share/mapnik/openstreetmap-carto-'.$ENV{OSM_CARTO_VERSION}; if (!$ENV{OSM_CARTO_VERSION}) { - fatal("osm-carto path not specified"); + fatal("Не задан путь к osm-carto"); } if (@$apply) { @@ -263,11 +286,31 @@ sub apply_deltas_imposm3 system($cmd); if ($?) { - fatal("$cmd failed"); + fatal("Загрузка дельт imposm3 не удалась"); } } } +sub apply_deltas_file +{ + my ($url_latest, $url_updates, $dir) = @_; + my ($full_fn) = $url_latest =~ /([^\/]+)$/so; + my $old_state = parse_geofabrik_state_file("$dir/$full_fn.state.txt"); + my $state = parse_geofabrik_state($url_updates, $dir); + my $apply = load_geofabrik_deltas($old_state, $state, $url_updates, $dir); + if (@$apply) + { + my $cmd = "osmconvert $dir/$full_fn '".join("' '", @$apply)."' -o $dir/new-$full_fn"; + system($cmd); + if ($?) + { + fatal("Обновление локального файла .osm.pbf не удалось"); + } + system("mv $dir/new-$full_fn $dir/$full_fn"); + system("cp $dir/state.txt $full_fn.state.txt"); + } +} + sub info { my ($msg) = @_;