OSMI simple views をビルドしてローカルで OSM データのエラーを確認する

OpenStreetMap のエラー訂正をするにあたって、エラーの確認と編集のスタートを OSM Inspector で行っています。
しばらく前から OSM Inspector で表示されているエラーを検出するためのプログラム OSMI Simple Views が GitHub公開されていて、これを使えば不定期に更新される OSM Inspector からではなく、自分で任意に更新できるローカルデータベースからエラー訂正できると思いビルドを試してみました。

ビルドを試した環境は docker の ubuntu:latest で、実行時は Ubuntu 16.04.2 LTS でした。
横着して全部 root で実行しています。

環境構築

最初に必要なパッケージ類をインストールします。

# apt-get update
# apt-get install wget git build-essential cmake libexpat1-dev zlib1g-dev libbz2-dev libsparsehash-dev libboost-dev libgdal-dev libproj-dev doxygen graphviz libsqlite3-dev sqlite3 cppcheck -y

osmium のビルド

OSMI Simple Views のバックエンドで動く osmium をビルドします。

# cd /mnt
# git clone https://github.com/osmcode/libosmium.git
# cd libosmium
# mkdir build
# cd  build
# cmake ..
# make

cd ../../

osmi_simple_views のビルド

続いて osmi_simple_views をビルドします。

# git clone https://github.com/geofabrik/osmi_simple_views.git
# cd osmi_simple_views
# ln -s ../libosmium/include libosmium
# mkdir build
# cd build
# cmake ..
# make

make した時にいくつか hpp ファイルが見つからなくてビルドが停止することがありましたが、この手順で入れるとビルドが通りました。
よくわかりません。

osmi_simple_views/build/src に実行ファイルがあるので、それを叩くとエラー情報の入った SQLite のファイルが出来上がります。

# cd src
# wget http://download.geofabrik.de/asia/japan/kanto-latest.osm.pbf
# ./osmi_simple_views -t geometry kanto-latest.osm.pbf kanto_error.sqlite

出来上がった kanto_error.sqliteQGIS にツッコむとエラーが出ているポイントやウェイを表示することができました。

d3-hexbin でポイントデータを表示する

ポイントの点密度を六角形で表示してくれる d3 のプラグインがあったので試してみました。

今回は OpenStreetMap から埼玉県内のコンビニのデータを取り出して表示しました。

コードなんかはこちら

なんかカッコイイから使ってみたんですが、冷静に考えて自分の用途ではこのプラグインを使うことはなさそうですね…。

ローカルサーバに Gogs をインストールする

ちょっとローカルに Git のリポジトリを置いておくサーバが欲しかったので docker コンテナにインストールしました。
今回は http によるアクセスのみで、SSH によるアクセスはできない設定です。

# cat /etc/debian_version
8.8

コンテナの3000ポートとホストの3000ポートを繋いでいます。

Gogs のインストールはドキュメントを読むと楽勝です。
今回はバイナリ版を入れています。

ざっくり環境を整える

sudo と vimwget を入れておきます。なぜか curl も気分で入れました。

# apt-get install sudo vim wget curl -y
# adduser zoar
# usermod -aG sudo zoar
# su zoar

MySQL Server のインストー

データベースとして MySQL を使うのでインストール。

$ sudo apt-get install mysql-server -y
$ sudo /etc/init.d/mysql start

コントロールするユーザーとデータを格納するデータベースを作ります。

$ mysql -uroot -p
mysql> CREATE DATABASE gogs;
mysql> CREATE USER zoar@localhost IDENTIFIED BY '%パスワード%';
mysql> use mysql
mysql> SELECT User FROM user WHERE User = 'zoar';
+------+
| User |
+------+
| zoar |
+------+
mysql> GRANT all ON gogs.* TO zoar@localhost;
mysql> \q  

Go言語のインストー

apt-get で入れようとすると 1.3 が落ちてくるので godeb を使って 1.8 をインストールします。

$ cd /tmp
$ wget https://godeb.s3.amazonaws.com/godeb-amd64.tar.gz
$ tar xvf godeb-amd64.tar.gz
$ sudo mv godeb /usr/local/bin/

godeb から Go 言語をインストールする。

$ godeb list | more
$ godeb install 1.8

Gogs バイナリのインストー

バイナリを落としてきて展開すればOK。
横着なのでホームディレクトリに直接展開しています。

$ cd /tmp
$ wget https://cdn.gogs.io/0.11.19/linux_amd64.tar.gz
$ cd ~
$ tar xvf /tmp/linux_amd64.tar.gz

Gogs を起動してウェブインターフェイスにアクセスすれば完了

$ cd gogs
$ ./gogs web

変更したのは次の部分。

  • データベース設定

    • ユーザ:zoar
    • パスワード:%パスワード%
  • Gogs の全般設定

    • 実行ユーザ:zoar
    • SSHポート:%空白%
    • アプリケーションのURL:http://%サーバIP%:3000/

最後に Gogs をインストール をクリックしておしまい。

最初に作成したユーザーが Gogs のサイト管理もできる権限に設定されます。

普通の(?) http で接続できるようにする

操作するときに :3000 を付けるのが面倒な感じだったので docker ホストで動いてる apache2 にプロキシ設定を追加して /gogs でもアクセスできるようにしました。

まずはコンテナにアタッチして設定を変更します。

host$ docker attach %hash%
container$ vi ./custom/conf/app.ini
ROOT_URL     = http://%サーバーIP%:3000
↓
ROOT_URL     = http://%サーバーIP%/gogs

再度起動しておく

container$ ./gogs web

Ctrl+p q でデタッチしてホストの設定をいじる

host$ sudo vi /etc/apache2/mods-enabled/proxy.conf 
        ProxyPass /gogs http://%サーバーIP%:3000
        ProxyPassReverse /gogs http://%サーバーIP%:3000
host $ sudo service apache2 reload

これで http://%サーバーIP%/gogs にアクセスして gogs を使えるようになりました。

SELinux を有効にしたまま CentOS 7 で OpenStreetMap のタイルサーバを構築する

Qiita で OpenStreetMap のタイルサーバを構築する記事が公開されていました。

OS が CentOS なので SELinux を無効にする記述がありましたので、とりあえず SELinux を有効にしたままタイルサーバを動かせないか試してみました。
とりあえず動くことは動いたんですが、rendoer.sockSELinux コンテキストを意義的に正しく設定できてないのでセキュリティホールになっている可能性が否めません。
目的を達成できているか不明確ですが、隠して置いても正しい設定が見つかるわけじゃないのでとりあえず公開してみます。

最初には SELinux を有効にして動かす差分的なもの、後半には自分が試した記録を載せています。

SELinux の設定

先の設定方法でブラウザから地図を確認できたら SELinux を再度有効にします。

$ sudo vi /etc/selinux/config
SELINUX=enforcing
#SELINUX=disabled

再起動すると /var/run に作成したディレクトリが消されてしまうので設定ファイルを書きます。

$ sudo vi /etc/tmpfiles.d/renderd.conf
d /var/run/renderd 0777 root root

再起動

$ sudo reboot

サーバが上がってきたら動作確認のために一時的に SELinux の状態を確認して Permissive にします。

$ getenforce
Enforcing
$ sudo setenforce 0
$ getenforce
Permissive

フォアグランドで動かして試します。

$ sudo /usr/local/bin/renderd -f

http://%サーバーIP%/ へアクセスして地図が表示されれば OK。

動作していることがわかったら SELinux を Enforcing に戻します。

$ sudo setenforce 1
$ getenforce
Enforcing

そのまま http://%サーバーIP%/ へアクセスするとタイル画像へアクセスできない Openlayers の地図もどきが表示されます。

audit.log の中で `type=AVC‘ から始まる denied された renderd のログを確認できるはずです。

$ sudo cat /var/log/audit/audit.log | grep renderd

renderd.sock へのアクセスが制限されないように SELinux への登録を行います。
まずは必要なパッケージのインストー

$ sudo yum -y install policycoreutils-python

ログから renderd に関する記述を抜き出して audit2allow で設定ファイルを作成します。
できた設定ファイルを semodule に食わせると SELinux 側に登録されます。

$ cd ~/src
$ sudo ausearch -m avc | grep renderd | audit2allow -M renderd
$ sudo semodule -i renderd.pp

もう一度 renderd を動かしてタイルが表示されるか確認します。

$ sudo /usr/local/bin/renderd -f

タイルが表示されたら renderd をバックグラウンドで走らせておけばOKです。

$ sudo sh -c "/usr/local/bin/renderd -f > /var/log/renderd.log 2> /var/log/renderd.log &"

こんな感じで SELinux が有効でもタイルサーバを動かすことができました。

試した記録

ここからは自分が今回テストした環境と設定の全部です。全部見る必要はないです、長いし。
VirtualBox で新しい CentOS をセットして試しています。

続きを読む

Ruby から Slack の WebHooks URI を叩いてメッセージをポストする

Ruby スクリプトで Slack の WebHooks URI を叩いてスクリプトの実行結果などをポストさせたかった時に調べました。
Ruby Gems には WebHooks を叩くための gems がいくつかあります。例えば slcak-notifier などなど。

今回は本当にスクリプトから Slack に対してポストできれば良かったので

res = Net::HTTP.post_form(URI.parse('http://www.example.com/'), {'payload'=> %JSON%})

とかやっちゃえばおしまいです。

実際に実装した時はクラスとか作りましたがこんな雰囲気で。

WebHooks は URI 叩けば反応してくれるので楽でいいですね。

コマンドの終了を通知(?)してくれるコマンド

1000個ある Excel のファイルを PDF に変換するとか結構時間かかるんだけど、それが終わったら別のコマンド実行したいとかたまにあるので、コマンドレットの後ろに付けて一連の実行終了を教えてくれるような PowerShell スクリプトです。

Push-Notification を実行すると Invoke-RestMethod で Slack の Webhook を殴ってるだけです。
Slack 側の設定でスマホなりデスクトップ通知なりをやっておけばコマンドの終了を知ることができるはず。

PS> . .\Push-Notification.ps1
PS> Get-ChildItem -Recurse | Out-File ..\list.txt -Encoding utf8 | Push-Notification

あー、終了時刻を入れさせたけど Slack のタイムスタンプ見れば一目瞭然かー。

自分の管理下にある Tasking Manager でログインできなくなった話

OpenStreetMap でそれなりに広いエリアを編集したい時は HOT の Tasking Manager を利用しています。

http://osmtm.pgw.jp/

OSC 2017 Tokyo Spring で出展中にこの自分の管理下にある Tasking Manager を使って編集をしようと思いましたが、ログインしようとするとエラーになるので使うのを一時的にあきらめました。

原因の調査

落ち着いて作業できる状況になったところで動作のログを確認すると次のようなものが表示されていました。

SSLHandshakeError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)

SSL の証明書関係でエラーが出ているようです。
そういえば先月あたりに OpenStreetMap Foundation が管理する Web サイトの証明書が Let’s Encrypt のものになったというニュースがありました。きっとこれです。

問題の修正

Tasking Manager のリポジトリでも同じエラーによる issue が上がっていて解決法も示されていました。
virtualenv の環境で pip パッケージの更新をすればよいようです。

$ ./env/bin/pip install --upgrade httplib2
$ ./env/bin/pip install --upgrade urllib3[secure]

さらに起こった悲劇(?)

これで無事にログインできるようになったのですが、ここで「Tasking Manager も更新しちゃえ」と git pull したのが運の尽き、今度は Tasking Manager 自体が動かなくなってしまいました。
git pull 以後のログを確認すると「project テーブルに requires_validator_role カラムなんてねーよ」という感じのエラーが出ていました。

解決方法の模索

カラムがないならカラムを追加すればいいじゃないと思ったのですが、カラムの型がわからないので手の出し様がありません。
仕方なく docker で一時的な Tasking Manager を立ち上げてデータベースを比較します。構造の比較方法なんて知らないので手動で確認しました。

ざっくり次のような形で新しい Tasking Manager で使われている project テーブルを確認しました。

new$ sudo -u postgres psql -d newosmtm
newosmtm=# \d project;
<snip>
 id                               | integer                     | not null default nextval('project_id_seq'::regclass)
 status                           | integer                     |
 area_id                          | integer                     |
 created                          | timestamp without time zone | 
 author_id                        | bigint                      | 
 last_update                      | timestamp without time zone | 
 license_id                       | integer                     | 
 zoom                             | integer                     | 
 imagery                          | character varying           | 
 priority                         | integer                     | 
 done                             | double precision            | 
 validated                        | double precision            | 
 entities_to_map                  | character varying           | 
 changeset_comment                | character varying           | 
 private                          | boolean                     | 
 josm_preset                      | character varying           | 
 due_date                         | timestamp without time zone | 
 requires_validator_role          | boolean                     | not null default false  
 requires_experienced_mapper_role | boolean                     | not null default false
<snip>

既存の Tasking Manager には requires_validator_rolerequires_experienced_mapper_role のカラムがありません、これを boolean で false を持った状態で追加させればなんとかなりそうです。

current$ sudo -u postgres psql -d osmtm
osmtm=# ALTER TABLE project ADD requires_validator_role boolean DEFAULT false NOT NULL, ADD requires_experienced_mapper_role boolean DEFAULT false NOT NULL;

\dt; を実行したところ新しい方の Tasking Manager ではテーブルも3つ増えていました。
プロジェクトへラベルを付与できるようになったのかそんな感じの名前のテーブルがありました。これらのテーブルスキーマを取り出してやればよさそうです。

new$ sudo -u postgres pg_dump -d osmtm -s -t project_labels > project_labels.sql
new$ sudo -u postgres pg_dump -d osmtm -s -t labels > labels.sql
new$ sudo -u postgres pg_dump -d osmtm -s -t labels_translation > labels_translation.sql

3つのファイルをどうにかして既存のサーバーにコピーして取り込みます。

current$ sudo -u postgres psql -d osmtm < project_labels.sql
current$ sudo -u postgres psql -d osmtm < labels.sql
current$ sudo -u postgres psql -d osmtm < labels_translation.sql

これでやっと動くようになりました。ながかった…。