Browse Source

Добавил возможность обновления локального файла .osm.pbf

master
Vitaliy Filippov 4 years ago
parent
commit
5729dc92eb
  1. 18
      Dockerfile
  2. 7
      README.md
  3. 2
      etc/locale.gen
  4. 129
      home/osm-loader.pl

18
Dockerfile

@ -1,10 +1,14 @@
FROM debian:sid AS build
MAINTAINER Vitaliy Filippov <vitalif@mail.ru>
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 <vitalif@mail.ru>
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

7
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
```

2
etc/locale.gen

@ -0,0 +1,2 @@
en_US.UTF-8 UTF-8
ru_RU.UTF-8 UTF-8

129
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 = <FD>;
close FD;
$state = { map { (split /\s*=\s*/, $_, 2) } grep { !/^\s*(#.*)?$/so && /=/so } split /\n/, $state };
if (!$state->{timestamp} || !$state->{sequenceNumber})
{
local $/ = undef;
$state = <FD>;
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=<ISO8601 date> and sequenceNumber=<integer>");
}
$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,8 +286,28 @@ 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");
}
}

Loading…
Cancel
Save