2016/08/31

[作業記録]Ubuntu on Windows で Autoware を動かしたかった

前回の投稿から引き続き、 Autoware を動かすのに挑戦する。
2016/9/1 追記 : Quick Start の途中でエラーになる。詳細は末尾に追加

環境構築

sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu trusty main" > /etc/apt/sources.list.d/ros-latest.list'
wget http://packages.ros.org/ros.key
sudo apt-key add ./ros.key
sudo apt update
sudo apt install ros-indigo-desktop-full ros-indigo-nmea-msgs ros-indigo-nmea-navsat-driver ros-indigo-sound-play ros-indigo-jsk-visualization libnlopt-dev freeglut3-dev qtbase5-dev libqt5opengl5-dev libssh2-1-dev libarmadillo-dev libpcap-dev gksu

ビルド

# 本来は .bashrc とかに追加する
source /opt/ros/indigo/setup.bash

mkdir -p ~/project
cd ~/project
git clone https://github.com/CPFL/Autoware.git
cd Autoware/ros/src
catkin_init_workspace
cd ..
./catkin_make_release

実行(失敗)

# 必要に応じて。
# 本来は .bashrc とかに追加する
source /opt/ros/indigo/setup.bash

cd ~/project/Autoware/ros

Process Manager

(gksudo:9442): Gtk-WARNING **: cannot open display:
./run: 行 41: --geometry=50x10+0+0: コマンドが見つかりません
./run: 行 44: --geometry=50x10+500+0: コマンドが見つかりません
./run
ディスプレイとターミナルがないのでエラー。 方針としては下記。
  1. lxterminal をインストールする
  2. Windows に xserver 立てる

必要な環境を追加

lxterminal

sudo apt install lxterminal

xserver

Xming をインストールする。
インストールするファイルは下記。
  • Xming-6-9-0-31-setup.exe

実行リベンジ

export DISPLAY=localhost:0.0
./run
だめだった...。



文字化けについては、 export LC_ALL=C で回避。
.Xauthority は touch で作ってしまう。 

実行リベンジ2

export LC_ALL=C
touch ~/.Xauthority
./run
が、ダメ。



cap_last_cap が権限関係の何からしいので、とりあえずコメントアウトしてみる。
※これで大丈夫な根拠ない。だれかよい方法おしえて...。

実行リベンジ3

# drop_capabilities() をコメントアウトする。
vim ~/project/Autoware/ros/src/util/packages/runtime_manager/scripts/proc_manager.py

こうなった。


内部で roscore が動いているみたいなので実行してみる。

実験

$ roscore
... logging to /home/mikoto/.ros/log/5330c532-6f82-11e6-a03c-74d02b272f3b/roslaunch-MNHOMEWIN-3539.log
Checking log directory for disk usage. This may take awhile.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.

started roslaunch server http://MNHOMEWIN:53403/
ros_comm version 1.11.20


SUMMARY
========

PARAMETERS
 * /rosdistro: indigo
 * /rosversion: 1.11.20

NODES

Traceback (most recent call last):
  File "/opt/ros/indigo/lib/python2.7/dist-packages/roslaunch/__init__.py", line 307, in main
    p.start()
  File "/opt/ros/indigo/lib/python2.7/dist-packages/roslaunch/parent.py", line 279, in start
    self.runner.launch()
  File "/opt/ros/indigo/lib/python2.7/dist-packages/roslaunch/launch.py", line 654, in launch
    self._setup()
  File "/opt/ros/indigo/lib/python2.7/dist-packages/roslaunch/launch.py", line 630, in _setup
    self._launch_master()
  File "/opt/ros/indigo/lib/python2.7/dist-packages/roslaunch/launch.py", line 394, in _launch_master
    validate_master_launch(m, self.is_core, self.is_rostest)
  File "/opt/ros/indigo/lib/python2.7/dist-packages/roslaunch/launch.py", line 83, in validate_master_launch
    if not rosgraph.network.is_local_address(m.get_host()):
  File "/opt/ros/indigo/lib/python2.7/dist-packages/rosgraph/network.py", line 176, in is_local_address
    local_addresses = ['localhost'] + get_local_addresses()
  File "/opt/ros/indigo/lib/python2.7/dist-packages/rosgraph/network.py", line 219, in get_local_addresses
    for iface in netifaces.interfaces():
OSError: [Errno 22] Invalid argument
調べてみると、https://github.com/gavanderhoorn/getifaddrs_preload を導入するとうまくいくらしい。

実行リベンジ4

cd ~/project
git clone https://github.com/gavanderhoorn/getifaddrs_preload
cd getifaddrs_preload
make
export LD_PRELOAD=~/project/getifaddrs_preload/_getifaddrs.so
cd ~/project/Autoware/ros/
./run
動いた。Quick Start を試すのはまた今度。


2016/9/1 追記
Quick Start してみたらうまく動かなかった...。悲しい。

参考資料

[作業記録]Ubuntu on Windows を導入して mintty から操作できるようにする

Autoware という、Linux ソフトウェア動かしたい。 しかし、これを VM で動かすのは厳しいのでは...? との思いから、使えたらラッキーくらいの気持ちで試してみる。

CPFL/Autoware: Open-source software for urban autonomous driving : https://github.com/CPFL/Autoware/

前提条件

  • OS : Windows 10 Home Edition
  • msys2 導入済み

必要な手順

  1. Windows10 Anniversary Update の導入
  2. Windows Subsystem for Linux の有効化
  3. wslbridge のビルド
  4. 起動用の設定

Windows Subsystem for Linux の有効化

Windows10 Anniversary Update を導入していれば、 「Windows の機能の有効化または無効化」から有効化できる。

有効化したうえで、コマンドプロンプトから bash.exe を起動し、インストールを行い、初期設定する。

有効化

  1. 「スタートメニュー右クリック -> プログラムと機能」
  2. ウィンドウ左の「Windows の機能の有効化または無効化」リンクをクリック
  3. 「Windows の機能」の一覧から、「Windows Subsystem for Linux」を探してチェックを入れる
  4. OK 押して再起動
  5. 「スタートメニュー -> 設定 -> 更新とセキュリティ -> 開発者向け -> 開発者モードを選択」
  6. 再起動
  7. コマンドプロンプト

インストール

コマンドプロンプトで C:\Windows\System32\bash.exe を起動する。

Microsoft Windows [Version 10.0.14393]
(c) 2016 Microsoft Corporation. All rights reserved.

C:\Users\mikoto>C:\Windows\System32\bash.exe
-- ベータ機能 --
これにより Windows に Ubuntu がインストールされます。Ubuntu は Canonical によって配布される製品であり、
次のサイトに示される条件に基づいてライセンスされています。
https://aka.ms/uowterms

続行するには、"y" を入力してください: y
Windows ストアからダウンロードしています... 100%
ファイル システムを展開しています。この処理には数分かかります...
既定の UNIX ユーザー アカウントを作成してください。ユーザー名は、Windows のユーザー名と一致する必要はあり ません。
詳細: https://aka.ms/wslusers を参照してください
新しい UNIX ユーザー名を入力してください: mikoto
新しい UNIX パスワードを入力してください:
新しい UNIX パスワードを再入力してください:
passwd: password updated successfully
インストールが正常に終了しました
環境が間もなく開始されます...
ドキュメントを参照できる場所: https://aka.ms/wsldocs
mikoto@MNHOMEWIN:/mnt/c/Users/mikoto$

初期設定

sudo cp /etc/hosts /etc/hosts.bkup
sudo sh -c 'echo 127.0.1.1 $(hostname) >> /etc/hosts'
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bkup
sudo sed -i -e 's%http://.*.ubuntu.com%http://ftp.jaist.ac.jp/pub/Linux%g' /etc/apt/sources.list
sudo apt update
sudo apt upgrade

Windows Subsystem for Linux の導入は以上。

wslbridge のビルド

windows 側

Bash on Ubuntu on Windows の最高の端末環境らしいので導入する。 msys2 環境を開いてそこで git clone and make.

$ cd /c/Users/mikoto/project/
$ git clone https://github.com/rprichard/wslbridge.git
Cloning into 'wslbridge'...
remote: Counting objects: 156, done.
Receiving objects:  82remote: Total 156 (delta 0), reused 0 (delta 0), pack-reused 156
Receiving objects: 100% (156/156), 54.63 KiB | 0 bytes/s, done.
Resolving deltas: 100% (66/66), done.
Checking connectivity... done.
cd wslbridge/frontend
$ make
mkdir -p ../out
g++ -std=c++11 -fno-exceptions \
        -static -static-libgcc -static-libstdc++ \
        -D_GNU_SOURCE -DWSLBRIDGE_VERSION=0.1.1-dev \
        -Wall -O2 wslbridge.cc ../common/SocketIo.cc -o ../out/wslbridge.exe

Ubuntu 側

sudo apt install git g++ make
cd /mnt/c/Users/mikoto/project/wslbridge/backend/
make

起動用の設定

「wslbridge のビルド」の成果物 wslbridge.exe, wslbridge-backend を Windows のパスの通った場所にコピーする。

ショートカットを作成する。/PATH/TO/mintty.exe -e wslbridge.exe

以上。

参考資料

2015/11/10

[作業記録]Mikutter on JRuby on Debian 環境構築手順メモ

目次

環境

  • OS: Debian 8 minimal インストールから、ssh, sudo をインストールした状態。

手順

### 必要なパッケージのインストール
sudo aptitude update
sudo aptitude install git default-jdk

### jruby の準備(apt のパッケージが古くて?gem install に失敗するため、新しいのを持ってくる)
mkdir develop
cd develop
wget https://s3.amazonaws.com/jruby.org/downloads/9.0.3.0/jruby-bin-9.0.3.0.tar.gz
tar zxfv jruby-bin-9.0.3.0.tar.gz
PATH=$PATH:~/develop/jruby-9.0.3.0/bin/

mkdir -p ~/project
cd ~/project
git clone git://toshia.dip.jp/mikutter.git
cd mikutter

### プラグイン調整開始
cd core/plugin

# 不要なプラグインを削除
rm -rf achievement activity alsa aspectframe bitly bugreport change_account command console direct_message display_requirements extract followingcontrol gtk gui home_timeline image_file_cache libnotify list list_for_profile list_settings mentions notify openimg photo_support profile proxy ratelimit saved_search search set_input set_view settings shortcutkey skin smartthread sound user_filesystem_cache

# CUI で streaming が有効になるように、依存関係から gui を外す
sed -e "s/  - gui//g" streaming/.mikutter.yml > streaming/.mikutter.yml_; mv streaming/.mikutter.yml_ streaming/.mikutter.yml

# CUI 用のプラグインを入れる
mkdir -p ~/.mikutter/plugin
cd ~/.mikutter/plugin
git clone git://github.com/mikoto2000/mikutter_stdout.git stdout
git clone git://github.com/mikoto2000/mikutter_cui_account_register.git cui_account_register

### 実行
cd ~/project/mikutter
jruby -S gem install bundle
jruby -S bundle install --path=vendor/bundle
jruby -S bundle exec jruby mikutter.rb

2015/10/28

[Tomcat][鯖]Tomcat でクライアント認証

概要

環境構築

作業ディレクトリ作成

$ cd ~/tmp/ssl
$ mkdir ca
$ mkdir ca/newcerts ca/crl ca/private client
$ touch ca/index.txt
$ echo 00 > ca/serial
$ echo 00 > ca/crlnumber
$ cp /usr/ssl/openssl.cnf ./

dir を ca の絶対パスに修正

$ vim ./openssl.cnf

CA 環境構築

CA 秘密鍵を作成

$ openssl genrsa -out ca/private/cakey.pem 2048 -config openssl.cnf

CA 証明書要求を作成

$ openssl req -new -key ca/private/cakey.pem -out ca/cacsr.pem -config openssl.cnf
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:Minato-ku
Organization Name (eg, company) [Internet Widgits Pty Ltd]:foo
Organizational Unit Name (eg, section) []:bar
Common Name (e.g. server FQDN or YOUR name) []:localhost
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

CA 証明書を作成

$ openssl x509 -req -in ca/cacsr.pem -signkey ca/private/cakey.pem -out ca/cacert.pem

クライアント環境構築

クライアント秘密鍵作成

$ openssl genrsa -out client/clientkey.pem 2048 -config ./openssl.cnf

クライアント証明書要求を作成

$ openssl req -new -key client/clientkey.pem -out client/clientcsr.pem -config ./openssl.cnf
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:Minato-ku
Organization Name (eg, company) [Internet Widgits Pty Ltd]:foo
Organizational Unit Name (eg, section) []:bar
Common Name (e.g. server FQDN or YOUR name) []:localhost
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

クライアント証明書作成

クライアントから csr を受け取った CA がやる作業。

$ openssl ca -config ./openssl.cnf -out client/client.crt -infiles client/clientcsr.pem
Using configuration from ./openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 0 (0x0)
        Validity
            Not Before: Oct 27 17:33:35 2015 GMT
            Not After : Oct 26 17:33:35 2016 GMT
        Subject:
            countryName               = JP
            stateOrProvinceName       = Tokyo
            organizationName          = foo
            organizationalUnitName    = bar
            commonName                = localhost
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                E1:44:51:CF:68:FC:3D:E1:52:59:F3:C3:E9:09:B4:64:CC:81:47:7C
            X509v3 Authority Key Identifier:
                DirName:/C=JP/ST=Tokyo/L=Minato-ku/O=foo/OU=bar/CN=localhost
                serial:E3:E6:4D:2B:0C:20:5A:E2

Certificate is to be certified until Oct 26 17:33:35 2016 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

サーバー環境構築

サーバー秘密鍵とキーストア作成

$ keytool -genkey -alias tomcat -keyalg RSA -keystore ../../.keystore
キーストアのパスワードを入力してください:  changeit
新規パスワードを再入力してください: changeit
姓名は何ですか。
  [Unknown]:  localhost
組織単位名は何ですか。
  [Unknown]:  bar
組織名は何ですか。
  [Unknown]:  foo
都市名または地域名は何ですか。
  [Unknown]:  Minato-ku
都道府県名または州名は何ですか。
  [Unknown]:  Tokyo
この単位に該当する2文字の国コードは何ですか。
  [Unknown]:  JP
CN=localhost, OU=bar, O=foo, L=Minato-ku, ST=Tokyo, C=JPでよろしいですか。
  [いいえ]:  y

<tomcat>の鍵パスワードを入力してください
        (キーストアのパスワードと同じ場合はRETURNを押してください):

サーバー証明書要求作成

$ keytool -certreq -alias tomcat -file tomcat.csr -keystore ../../.keystore

サーバー証明書作成

サーバーから csr を受け取った CA がやる作業。

$ openssl ca -policy policy_anything -config ./openssl.cnf -out tomcat.crt -infiles tomcat.csr
Using configuration from ./openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: Oct 27 17:47:23 2015 GMT
            Not After : Oct 26 17:47:23 2016 GMT
        Subject:
            countryName               = JP
            stateOrProvinceName       = Tokyo
            localityName              = Minato-ku
            organizationName          = foo
            organizationalUnitName    = bar
            commonName                = localhost
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                5A:E0:56:79:25:16:46:39:DD:33:89:59:67:91:0F:5F:96:49:CB:10
            X509v3 Authority Key Identifier:
                DirName:/C=JP/ST=Tokyo/L=Minato-ku/O=foo/OU=bar/CN=localhost
                serial:E3:E6:4D:2B:0C:20:5A:E2

Certificate is to be certified until Oct 26 17:47:23 2016 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

サーバーキーストアにCA証明書をインポート

$ keytool -import -alias ca -trustcacerts -file ./ca/cacert.pem -keystore ../../.keystore
キーストアのパスワードを入力してください:  changeit
所有者: CN=localhost, OU=bar, O=foo, L=Minato-ku, ST=Tokyo, C=JP
発行者: CN=localhost, OU=bar, O=foo, L=Minato-ku, ST=Tokyo, C=JP
シリアル番号: e3e64d2b0c205ae2
有効期間の開始日: Wed Oct 28 02:28:40 JST 2015終了日: Fri Nov 27 02:28:40 JST 2015
証明書のフィンガプリント:
         MD5:  5C:16:AC:D6:25:3D:59:23:1B:C1:CF:F1:51:A1:6A:4B
         SHA1: 4B:C2:E7:3D:21:71:6E:C7:29:5A:34:67:9A:0C:E1:30:E8:B2:C2:19
         SHA256: DA:4B:2C:07:86:D3:93:2C:A9:74:28:54:D5:5D:77:83:3F:85:D9:01:8D:34:98:99:BD:BF:51:AC:84:59:10:91
         署名アルゴリズム名: SHA256withRSA
         バージョン: 1
この証明書を信頼しますか。 [いいえ]:  y
証明書がキーストアに追加されました

サーバーキーストアにサーバー証明書をインポート

$ keytool -import -alias tomcat -trustcacerts -file ./tomcat.crt -keystore ../../.keystore
キーストアのパスワードを入力してください:  changeit
証明書応答がキーストアにインストールされました

Tomcat 設定

server.xml

redirectPort を削除。

    <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1"/>

追加。

    <Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
               clientAuth="true" sslProtocol="TLS" truststoreFile= "C:/Users/mikoto/.keystore"
               truststorePass="changeit"/>

web.xml

web-app タグの末尾に追加。

<login-config>
    <auth-method>CLIENT-CERT</auth-method>
</login-config>

wget してみる

$ # クライアント証明書による認証で失敗する
$ wget https://localhost:8443/
--2015-10-28 03:05:42--  https://localhost:8443/
localhost (localhost) をDNSに問いあわせています... ::1, 127.0.0.1
localhost (localhost)|::1|:8443 に接続しています... 接続しました。
OpenSSL: error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate
SSL による接続が確立できません。
$
$
$ # クライアント証明書を指定して接続しに行く。
$ # サーバ証明書が信用できない証明書なので失敗する
$ wget https://localhost:8443/ --private-key=client/clientkey.pem --certificate=client/client.crt
--2015-10-28 03:07:46--  https://localhost:8443/
localhost (localhost) をDNSに問いあわせています... ::1, 127.0.0.1
localhost (localhost)|::1|:8443 に接続しています... 接続しました。
エラー: localhost の証明書(発行者: `CN=localhost,OU=bar,O=foo,L=Minato-ku,ST=Tokyo,C=JP')の検証に失敗しました:
  自己署名証明書です。
localhost に安全の確認をしないで接続するには、`--no-check-certificate' を使ってください。
$
$
$ # クライアント証明書とCA証明書を指定して接続しに行く
$ # サーバ証明書がCAに信用されているので接続できる
$ wget https://localhost:8443/ --private-key=client/clientkey.pem --certificate=client/client.crt --ca-certificate=ca/cacert.pem
--2015-10-28 03:09:41--  https://localhost:8443/
localhost (localhost) をDNSに問いあわせています... ::1, 127.0.0.1
localhost (localhost)|::1|:8443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 404 Not Found
2015-10-28 03:09:41 エラー 404: Not Found。

2015/08/30

[作業記録]curl を使って Web API の挙動を確かめる

Lingr の Web API の挙動を調べるために curl を使用したのでメモ。

cURL - How To Use (マニュアルページ日本語訳)

$ curl http://lingr.com/api/session/create -d user=mikoto2000@gmail.com -d password=MY_PASSWORD
{"status":"ok","session":"sVe3d6","public_id":"9a5w2p","nickname":"mikoto2000","user":{"username":"mikoto2000","name":"mikoto2000"}}

$ curl http://lingr.com/api/user/get_rooms -d session=5adYDm
{"status":"ok","rooms":["golang","vim"]}

$ curl http://lingr.com/api/room/show -d session=5adYDm -d rooms=vim
...(snip)

2015/08/29

[Git]fork したリポジトリに fork 元の変更を取り込む

この話題。 リモートを追加して、 fetch, merge --ff でいけるようだ。

git remote add upstream [fork元リポジトリ]
git fetch upstream
git merge upstream/master --ff

2015/08/24

[Embulk]embulk-input-salesforce_bulk の next config を試す

昨日の下記記事の続き。 next config がうまくいくかどうか確認していなかったのでそのあたりを確認。

親知らずの日記: [Embulk] Embulk で Salesforce から PostgreSQL にデータを転送してみた

設定変更

startRowMarkerName を追加。 更新するたびに増えていく値であれば何でもよい。 とはいえ一番簡単なのは最終更新日であろう。

in:
  type: salesforce_bulk
  userName: USERNAME
  password: PASSWORD+TOKEN
  authEndpointUrl: https://login.salesforce.com/services/Soap/u/34.0
  objectType: Account
  pollingIntervalMillisecond: 2500
  querySelectFrom: SELECT Id,Name,LastModifiedDate FROM Account
  columns:
  - {type: string, name: Id}
  - {type: string, name: Name}
  - {type: timestamp, name: LastModifiedDate, format: '%FT%T.%L%Z'}
  startRowMarkerName: LastModifiedDate
out: {type: postgresql, host: 192.168.11.207, user: from_sfdc, password: testing,
  database: from_sfdc, table: account_t, mode: merge}

初回実行

$ ./bin/embulk run -L ../embulk-input-salesforce_bulk/ ./sfdc_postgresql.yml -o ./sfdc_postgresql.yml
2015-08-24 22:39:52.733 +0900: Embulk v0.7.3
2015-08-24 22:39:54.269 +0900 [INFO] (transaction): Loaded plugin embulk-input-salesforce_bulk (0.1.0)
2015-08-24 22:39:54.309 +0900 [INFO] (transaction): Loaded plugin embulk-output-postgresql (0.4.1)
2015-08-24 22:39:54.372 +0900 [INFO] (transaction): Connecting to jdbc:postgresql://192.168.11.207:5432/from_sfdc options {user=from_sfdc, tcpKeepAlive=true, loginTimeout=300, socketTimeout=1800}
2015-08-24 22:39:54.425 +0900 [INFO] (transaction): SQL: SET search_path TO "public"
2015-08-24 22:39:54.427 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:39:54.427 +0900 [INFO] (transaction): Using merge mode
2015-08-24 22:39:54.446 +0900 [INFO] (transaction): SQL: DROP TABLE IF EXISTS "account_t_aa0b9f76c0_bl_tmp000"
2015-08-24 22:39:54.447 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:39:54.455 +0900 [INFO] (transaction): SQL: CREATE TABLE IF NOT EXISTS "account_t_aa0b9f76c0_bl_tmp000" ("Id" VARCHAR(20), "Name" VARCHAR(100), "LastModifiedDate" TIMESTAMP)
2015-08-24 22:39:54.457 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:39:54.468 +0900 [INFO] (transaction): Using merge keys: [Id]
2015-08-24 22:39:54.488 +0900 [INFO] (transaction): {done:  0 / 1, running: 0}
2015-08-24 22:39:54.511 +0900 [INFO] (task-0000): Connecting to jdbc:postgresql://192.168.11.207:5432/from_sfdc options {user=from_sfdc, tcpKeepAlive=true, loginTimeout=300, socketTimeout=1800}
2015-08-24 22:39:54.521 +0900 [INFO] (task-0000): SQL: SET search_path TO "public"
2015-08-24 22:39:54.522 +0900 [INFO] (task-0000): > 0.00 seconds
2015-08-24 22:39:54.523 +0900 [INFO] (task-0000): Copy SQL: COPY "account_t_aa0b9f76c0_bl_tmp000" ("Id", "Name", "LastModifiedDate") FROM STDIN
2015-08-24 22:39:54.525 +0900 [WARN] (task-0000): An output plugin is compiled with old Embulk plugin API. Please update the plugin version using "embulk gem install" command, or contact a developer of the plugin to upgrade the plugin code using "embulk migrate" command: class org.embulk.output.jdbc.AbstractJdbcOutputPlugin$PluginPageOutput
2015-08-24 22:39:54.548 +0900 [INFO] (task-0000): Try login to 'https://login.salesforce.com/services/Soap/u/34.0'.
2015-08-24 22:39:55.016 +0900 [INFO] (task-0000): Login success.
2015-08-24 22:39:55.017 +0900 [INFO] (task-0000): Send request : 'SELECT Id,Name,LastModifiedDate FROM Account'
2015-08-24 22:39:58.396 +0900 [INFO] (task-0000): Loading 30 rows (1,903 bytes)
2015-08-24 22:39:58.399 +0900 [INFO] (task-0000): > 0.00 seconds (loaded 30 rows in total)
2015-08-24 22:39:58.524 +0900 [INFO] (transaction): {done:  1 / 1, running: 0}
2015-08-24 22:39:58.525 +0900 [INFO] (transaction): Connecting to jdbc:postgresql://192.168.11.207:5432/from_sfdc options {user=from_sfdc, tcpKeepAlive=true, loginTimeout=300, socketTimeout=28800}
2015-08-24 22:39:58.719 +0900 [INFO] (transaction): SQL: SET search_path TO "public"
2015-08-24 22:39:58.720 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:39:58.720 +0900 [INFO] (transaction): SQL: WITH updated AS (UPDATE "account_t" SET "Id" = S."Id", "Name" = S."Name", "LastModifiedDate" = S."LastModifiedDate" FROM (SELECT "Id", "Name", "LastModifiedDate" FROM "account_t_aa0b9f76c0_bl_tmp000") S WHERE "account_t"."Id" = S."Id" RETURNING S."Id") INSERT INTO "account_t" ("Id", "Name", "LastModifiedDate") SELECT DISTINCT ON ("Id") * FROM (SELECT "Id", "Name", "LastModifiedDate" FROM "account_t_aa0b9f76c0_bl_tmp000") S WHERE NOT EXISTS (SELECT 1 FROM updated WHERE S."Id" = updated."Id")
2015-08-24 22:39:58.723 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:39:58.729 +0900 [INFO] (transaction): Connecting to jdbc:postgresql://192.168.11.207:5432/from_sfdc options {user=from_sfdc, tcpKeepAlive=true, loginTimeout=300, socketTimeout=1800}
2015-08-24 22:39:58.735 +0900 [INFO] (transaction): SQL: SET search_path TO "public"
2015-08-24 22:39:58.736 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:39:58.736 +0900 [INFO] (transaction): SQL: DROP TABLE IF EXISTS "account_t_aa0b9f76c0_bl_tmp000"
2015-08-24 22:39:58.738 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:39:58.740 +0900 [INFO] (main): Committed.
2015-08-24 22:39:58.741 +0900 [INFO] (main): Next config diff: {"in":{"start_row_marker":"2015-08-24T13:31:58.000Z"},"out":{}}

ちゃんと 30 行ロードされたようだ。

2015-08-24 22:39:58.396 +0900 [INFO] (task-0000): Loading 30 rows (1,903 bytes)
2015-08-24 22:39:58.399 +0900 [INFO] (task-0000): > 0.00 seconds (loaded 30 rows in total)

そして更新された設定ファイルがこちら。

in:
  type: salesforce_bulk
  userName: USERNAME
  password: PASSWORD+TOKEN
  authEndpointUrl: https://login.salesforce.com/services/Soap/u/34.0
  objectType: Account
  pollingIntervalMillisecond: 2500
  querySelectFrom: SELECT Id,Name,LastModifiedDate FROM Account
  columns:
  - {type: string, name: Id}
  - {type: string, name: Name}
  - {type: timestamp, name: LastModifiedDate, format: '%FT%T.%L%Z'}
  startRowMarkerName: LastModifiedDate
  start_row_marker: '2015-08-24T13:31:58.000Z'
out: {type: postgresql, host: 192.168.11.207, user: from_sfdc, password: testing,
  database: from_sfdc, table: account_t, mode: merge}

2 回目実行

Salesforce 側を何も更新せずに実行。

$ ./bin/embulk run -L ../embulk-input-salesforce_bulk/ ./sfdc_postgresql.yml -o ./sfdc_postgresql.yml
2015-08-24 22:42:51.365 +0900: Embulk v0.7.3
2015-08-24 22:42:52.903 +0900 [INFO] (transaction): Loaded plugin embulk-input-salesforce_bulk (0.1.0)
2015-08-24 22:42:52.930 +0900 [INFO] (transaction): Loaded plugin embulk-output-postgresql (0.4.1)
2015-08-24 22:42:52.991 +0900 [INFO] (transaction): Connecting to jdbc:postgresql://192.168.11.207:5432/from_sfdc options {user=from_sfdc, tcpKeepAlive=true, loginTimeout=300, socketTimeout=1800}
2015-08-24 22:42:53.040 +0900 [INFO] (transaction): SQL: SET search_path TO "public"
2015-08-24 22:42:53.043 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:42:53.043 +0900 [INFO] (transaction): Using merge mode
2015-08-24 22:42:53.072 +0900 [INFO] (transaction): SQL: DROP TABLE IF EXISTS "account_t_5c31b5d480_bl_tmp000"
2015-08-24 22:42:53.074 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:42:53.081 +0900 [INFO] (transaction): SQL: CREATE TABLE IF NOT EXISTS "account_t_5c31b5d480_bl_tmp000" ("Id" VARCHAR(20), "Name" VARCHAR(100), "LastModifiedDate" TIMESTAMP)
2015-08-24 22:42:53.104 +0900 [INFO] (transaction): > 0.02 seconds
2015-08-24 22:42:53.121 +0900 [INFO] (transaction): Using merge keys: [Id]
2015-08-24 22:42:53.145 +0900 [INFO] (transaction): {done:  0 / 1, running: 0}
2015-08-24 22:42:53.170 +0900 [INFO] (task-0000): Connecting to jdbc:postgresql://192.168.11.207:5432/from_sfdc options {user=from_sfdc, tcpKeepAlive=true, loginTimeout=300, socketTimeout=1800}
2015-08-24 22:42:53.179 +0900 [INFO] (task-0000): SQL: SET search_path TO "public"
2015-08-24 22:42:53.180 +0900 [INFO] (task-0000): > 0.00 seconds
2015-08-24 22:42:53.181 +0900 [INFO] (task-0000): Copy SQL: COPY "account_t_5c31b5d480_bl_tmp000" ("Id", "Name", "LastModifiedDate") FROM STDIN
2015-08-24 22:42:53.183 +0900 [WARN] (task-0000): An output plugin is compiled with old Embulk plugin API. Please update the plugin version using "embulk gem install" command, or contact a developer of the plugin to upgrade the plugin code using "embulk migrate" command: class org.embulk.output.jdbc.AbstractJdbcOutputPlugin$PluginPageOutput
2015-08-24 22:42:53.203 +0900 [INFO] (task-0000): Try login to 'https://login.salesforce.com/services/Soap/u/34.0'.
2015-08-24 22:42:53.653 +0900 [INFO] (task-0000): Login success.
2015-08-24 22:42:53.654 +0900 [INFO] (task-0000): Send request : 'SELECT Id,Name,LastModifiedDate FROM Account WHERE LastModifiedDate > 2015-08-24T13:31:58.000Z'
2015-08-24 22:42:57.647 +0900 [INFO] (transaction): {done:  1 / 1, running: 0}
2015-08-24 22:42:57.648 +0900 [INFO] (transaction): Connecting to jdbc:postgresql://192.168.11.207:5432/from_sfdc options {user=from_sfdc, tcpKeepAlive=true, loginTimeout=300, socketTimeout=28800}
2015-08-24 22:42:57.651 +0900 [INFO] (transaction): SQL: SET search_path TO "public"
2015-08-24 22:42:57.652 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:42:57.652 +0900 [INFO] (transaction): SQL: WITH updated AS (UPDATE "account_t" SET "Id" = S."Id", "Name" = S."Name", "LastModifiedDate" = S."LastModifiedDate" FROM (SELECT "Id", "Name", "LastModifiedDate" FROM "account_t_5c31b5d480_bl_tmp000") S WHERE "account_t"."Id" = S."Id" RETURNING S."Id") INSERT INTO "account_t" ("Id", "Name", "LastModifiedDate") SELECT DISTINCT ON ("Id") * FROM (SELECT "Id", "Name", "LastModifiedDate" FROM "account_t_5c31b5d480_bl_tmp000") S WHERE NOT EXISTS (SELECT 1 FROM updated WHERE S."Id" = updated."Id")
2015-08-24 22:42:57.654 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:42:57.660 +0900 [INFO] (transaction): Connecting to jdbc:postgresql://192.168.11.207:5432/from_sfdc options {user=from_sfdc, tcpKeepAlive=true, loginTimeout=300, socketTimeout=1800}
2015-08-24 22:42:57.668 +0900 [INFO] (transaction): SQL: SET search_path TO "public"
2015-08-24 22:42:57.669 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:42:57.669 +0900 [INFO] (transaction): SQL: DROP TABLE IF EXISTS "account_t_5c31b5d480_bl_tmp000"
2015-08-24 22:42:57.672 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:42:57.675 +0900 [INFO] (main): Committed.
2015-08-24 22:42:57.676 +0900 [INFO] (main): Next config diff: {"in":{"start_row_marker":"2015-08-24T13:31:58.000Z"},"out":{}}

「Loading XXX rows」がない。何も読み込まれなかったようだ。

3 回目実行

取引先を一つ修正してから実行。

$ ./bin/embulk run -L ../embulk-input-salesforce_bulk/ ./sfdc_postgresql.yml -o ./sfdc_postgresql.yml
2015-08-24 22:45:26.724 +0900: Embulk v0.7.3
2015-08-24 22:45:28.289 +0900 [INFO] (transaction): Loaded plugin embulk-input-salesforce_bulk (0.1.0)
2015-08-24 22:45:28.321 +0900 [INFO] (transaction): Loaded plugin embulk-output-postgresql (0.4.1)
2015-08-24 22:45:28.392 +0900 [INFO] (transaction): Connecting to jdbc:postgresql://192.168.11.207:5432/from_sfdc options {user=from_sfdc, tcpKeepAlive=true, loginTimeout=300, socketTimeout=1800}
2015-08-24 22:45:28.448 +0900 [INFO] (transaction): SQL: SET search_path TO "public"
2015-08-24 22:45:28.450 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:45:28.450 +0900 [INFO] (transaction): Using merge mode
2015-08-24 22:45:28.468 +0900 [INFO] (transaction): SQL: DROP TABLE IF EXISTS "account_t_f80c474f80_bl_tmp000"
2015-08-24 22:45:28.470 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:45:28.476 +0900 [INFO] (transaction): SQL: CREATE TABLE IF NOT EXISTS "account_t_f80c474f80_bl_tmp000" ("Id" VARCHAR(20), "Name" VARCHAR(100), "LastModifiedDate" TIMESTAMP)
2015-08-24 22:45:28.477 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:45:28.523 +0900 [INFO] (transaction): Using merge keys: [Id]
2015-08-24 22:45:28.542 +0900 [INFO] (transaction): {done:  0 / 1, running: 0}
2015-08-24 22:45:28.561 +0900 [INFO] (task-0000): Connecting to jdbc:postgresql://192.168.11.207:5432/from_sfdc options {user=from_sfdc, tcpKeepAlive=true, loginTimeout=300, socketTimeout=1800}
2015-08-24 22:45:28.569 +0900 [INFO] (task-0000): SQL: SET search_path TO "public"
2015-08-24 22:45:28.570 +0900 [INFO] (task-0000): > 0.00 seconds
2015-08-24 22:45:28.570 +0900 [INFO] (task-0000): Copy SQL: COPY "account_t_f80c474f80_bl_tmp000" ("Id", "Name", "LastModifiedDate") FROM STDIN
2015-08-24 22:45:28.572 +0900 [WARN] (task-0000): An output plugin is compiled with old Embulk plugin API. Please update the plugin version using "embulk gem install" command, or contact a developer of the plugin to upgrade the plugin code using "embulk migrate" command: class org.embulk.output.jdbc.AbstractJdbcOutputPlugin$PluginPageOutput
2015-08-24 22:45:28.587 +0900 [INFO] (task-0000): Try login to 'https://login.salesforce.com/services/Soap/u/34.0'.
2015-08-24 22:45:29.355 +0900 [INFO] (task-0000): Login success.
2015-08-24 22:45:29.355 +0900 [INFO] (task-0000): Send request : 'SELECT Id,Name,LastModifiedDate FROM Account WHERE LastModifiedDate > 2015-08-24T13:31:58.000Z'
2015-08-24 22:45:32.773 +0900 [INFO] (task-0000): Loading 1 rows (57 bytes)
2015-08-24 22:45:32.777 +0900 [INFO] (task-0000): > 0.00 seconds (loaded 1 rows in total)
2015-08-24 22:45:32.958 +0900 [INFO] (transaction): {done:  1 / 1, running: 0}
2015-08-24 22:45:32.959 +0900 [INFO] (transaction): Connecting to jdbc:postgresql://192.168.11.207:5432/from_sfdc options {user=from_sfdc, tcpKeepAlive=true, loginTimeout=300, socketTimeout=28800}
2015-08-24 22:45:32.964 +0900 [INFO] (transaction): SQL: SET search_path TO "public"
2015-08-24 22:45:32.965 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:45:32.965 +0900 [INFO] (transaction): SQL: WITH updated AS (UPDATE "account_t" SET "Id" = S."Id", "Name" = S."Name", "LastModifiedDate" = S."LastModifiedDate" FROM (SELECT "Id", "Name", "LastModifiedDate" FROM "account_t_f80c474f80_bl_tmp000") S WHERE "account_t"."Id" = S."Id" RETURNING S."Id") INSERT INTO "account_t" ("Id", "Name", "LastModifiedDate") SELECT DISTINCT ON ("Id") * FROM (SELECT "Id", "Name", "LastModifiedDate" FROM "account_t_f80c474f80_bl_tmp000") S WHERE NOT EXISTS (SELECT 1 FROM updated WHERE S."Id" = updated."Id")
2015-08-24 22:45:32.967 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:45:32.973 +0900 [INFO] (transaction): Connecting to jdbc:postgresql://192.168.11.207:5432/from_sfdc options {user=from_sfdc, tcpKeepAlive=true, loginTimeout=300, socketTimeout=1800}
2015-08-24 22:45:32.978 +0900 [INFO] (transaction): SQL: SET search_path TO "public"
2015-08-24 22:45:32.979 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-24 22:45:32.980 +0900 [INFO] (transaction): SQL: DROP TABLE IF EXISTS "account_t_f80c474f80_bl_tmp000"
2015-08-24 22:45:32.993 +0900 [INFO] (transaction): > 0.01 seconds
2015-08-24 22:45:32.997 +0900 [INFO] (main): Committed.
2015-08-24 22:45:32.997 +0900 [INFO] (main): Next config diff: {"in":{"start_row_marker":"2015-08-24T13:45:28.000Z"},"out":{}}

うむ、良いのではないだろうか。

PostgreSQL のカラムが更新されていることも確認。embulk-input-postgresql の mode も merge で良いようだ。

2015/08/23

[Embulk] Embulk で Salesforce から PostgreSQL にデータを転送してみた

使用するプラグイン

salesforce_bulk は、自作プラグイン。設定方法などまだまだいろいろ変わりそうなので gem 化は考えていない。

Embulk に embulk-output-postgresql を入れる

$ ./bin/embulk gem install embulk-output-postgresql
2015-08-22 22:24:01.986 +0900: Embulk v0.7.2
Successfully installed embulk-output-postgresql-0.4.1
1 gem installed

PostgreSQL を準備する

VirtualBox に Debian minimal をインストール

...(略)

Debian に PostgreSQL 環境を構築

aptitude update
aptitude full-upgrade
aptitude install postgresql

su - postgres
psql

create database from_sfdc;
\c from_sfdc
create role from_sfdc with login;
alter user from_sfdc with password 'testing';

create table account_t("Id" varchar(20) primary key, "Name" varchar(100), "LastModifiedDate" timestamp);

exit
echo "listen_addresses = '*'" >> /etc/postgresql/9.4/main/postgres.conf
echo "host from_sfdc from_sfdc xxx.xxx.xxx.xxx/xx md5" >> /etc/postgresql/9.4/main/pg_hba.conf
service postgresql restart

Embulk 設定ファイルを作成

in:
  type: salesforce_bulk
  userName: USERNAME
  password: PASSWORD+TOKEN
  authEndpointUrl: https://login.salesforce.com/services/Soap/u/34.0
  objectType: Account
  pollingIntervalMillisecond: 2500
  querySelectFrom: SELECT Id,Name,LastModifiedDate FROM Account
  columns:
  - {type: string, name: Id}
  - {type: string, name: Name}
  - {type: timestamp, name: LastModifiedDate, format: '%FT%T.%L%Z'}
out:
  type: postgresql
  host: 192.168.11.207
  user: from_sfdc
  password: "testing"
  database: from_sfdc
  table: account_t
  mode: merge

実行

$ ./bin/embulk run -L ../embulk-input-salesforce_bulk/ ./sfdc_postgresql.yml
2015-08-23 03:08:56.728 +0900: Embulk v0.7.2
2015-08-23 03:08:58.254 +0900 [INFO] (transaction): Loaded plugin embulk-input-salesforce_bulk (0.1.0)
2015-08-23 03:08:58.289 +0900 [INFO] (transaction): Loaded plugin embulk-output-postgresql (0.4.1)
2015-08-23 03:08:58.356 +0900 [INFO] (transaction): Connecting to jdbc:postgresql://192.168.11.207:5432/from_sfdc options {user=from_sfdc, tcpKeepAlive=true, loginTimeout=300, socketTimeout=1800}
2015-08-23 03:08:58.406 +0900 [INFO] (transaction): SQL: SET search_path TO "public"
2015-08-23 03:08:58.408 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-23 03:08:58.408 +0900 [INFO] (transaction): Using merge mode
2015-08-23 03:08:58.427 +0900 [INFO] (transaction): SQL: DROP TABLE IF EXISTS "account_t_ba0b162280_bl_tmp000"
2015-08-23 03:08:58.429 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-23 03:08:58.435 +0900 [INFO] (transaction): SQL: CREATE TABLE IF NOT EXISTS "account_t_ba0b162280_bl_tmp000" ("Id" VARCHAR(20), "Name" VARCHAR(100), "LastModifiedDate" TIMESTAMP)
2015-08-23 03:08:58.436 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-23 03:08:58.466 +0900 [INFO] (transaction): Using merge keys: [Id]
2015-08-23 03:08:58.482 +0900 [INFO] (transaction): {done:  0 / 1, running: 0}
2015-08-23 03:08:58.500 +0900 [INFO] (task-0000): Connecting to jdbc:postgresql://192.168.11.207:5432/from_sfdc options {user=from_sfdc, tcpKeepAlive=true, loginTimeout=300, socketTimeout=1800}
2015-08-23 03:08:58.506 +0900 [INFO] (task-0000): SQL: SET search_path TO "public"
2015-08-23 03:08:58.507 +0900 [INFO] (task-0000): > 0.00 seconds
2015-08-23 03:08:58.508 +0900 [INFO] (task-0000): Copy SQL: COPY "account_t_ba0b162280_bl_tmp000" ("Id", "Name", "LastModifiedDate") FROM STDIN
2015-08-23 03:08:58.509 +0900 [WARN] (task-0000): An output plugin is compiled with old Embulk plugin API. Please update the plugin version using "embulk gem install" command, or contact a developer of the plugin to upgrade the plugin code using "embulk migrate" command: class org.embulk.output.jdbc.AbstractJdbcOutputPlugin$PluginPageOutput
2015-08-23 03:08:58.524 +0900 [INFO] (task-0000): Try login to 'https://login.salesforce.com/services/Soap/u/34.0'.
2015-08-23 03:08:58.960 +0900 [INFO] (task-0000): Login success.
2015-08-23 03:08:58.960 +0900 [INFO] (task-0000): Send request : 'SELECT Id,Name,LastModifiedDate FROM Account'
2015-08-23 03:09:02.660 +0900 [INFO] (task-0000): Loading 30 rows (1,903 bytes)
2015-08-23 03:09:02.663 +0900 [INFO] (task-0000): > 0.00 seconds (loaded 30 rows in total)
2015-08-23 03:09:02.730 +0900 [INFO] (transaction): {done:  1 / 1, running: 0}
2015-08-23 03:09:02.731 +0900 [INFO] (transaction): Connecting to jdbc:postgresql://192.168.11.207:5432/from_sfdc options {user=from_sfdc, tcpKeepAlive=true, loginTimeout=300, socketTimeout=28800}
2015-08-23 03:09:02.735 +0900 [INFO] (transaction): SQL: SET search_path TO "public"
2015-08-23 03:09:02.736 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-23 03:09:02.736 +0900 [INFO] (transaction): SQL: WITH updated AS (UPDATE "account_t" SET "Id" = S."Id", "Name" = S."Name", "LastModifiedDate" = S."LastModifiedDate" FROM (SELECT "Id", "Name", "LastModifiedDate" FROM "account_t_ba0b162280_bl_tmp000") S WHERE "account_t"."Id" = S."Id" RETURNING S."Id") INSERT INTO "account_t" ("Id", "Name", "LastModifiedDate") SELECT DISTINCT ON ("Id") * FROM (SELECT "Id", "Name", "LastModifiedDate" FROM "account_t_ba0b162280_bl_tmp000") S WHERE NOT EXISTS (SELECT 1 FROM updated WHERE S."Id" = updated."Id")
2015-08-23 03:09:02.739 +0900 [INFO] (transaction): > 0.00 seconds (30 rows)
2015-08-23 03:09:02.746 +0900 [INFO] (transaction): Connecting to jdbc:postgresql://192.168.11.207:5432/from_sfdc options {user=from_sfdc, tcpKeepAlive=true, loginTimeout=300, socketTimeout=1800}
2015-08-23 03:09:02.751 +0900 [INFO] (transaction): SQL: SET search_path TO "public"
2015-08-23 03:09:02.752 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-23 03:09:02.752 +0900 [INFO] (transaction): SQL: DROP TABLE IF EXISTS "account_t_ba0b162280_bl_tmp000"
2015-08-23 03:09:02.755 +0900 [INFO] (transaction): > 0.00 seconds
2015-08-23 03:09:02.759 +0900 [INFO] (main): Committed.
2015-08-23 03:09:02.759 +0900 [INFO] (main): Next config diff: {"in":{},"out":{}}

無事、PostgreSQL に格納された。よかった。

こんな感じのこともありました。『中の処理がわからんとシンタックスエラーっていわれても...』ってなって割と苦戦してました。

2014/12/28

[Android][Arch] Xperia Z2 Tablet に chroot Arch Linux 環境を入れた

前提条件

  • Xperia Z2 Tablet の root 化済み
  • BusyBox インストール済み

自分が入れた BusyBox はこれ。BusyBox - Google Play の Android アプリ

やったこと

sd カードに arch 用のパーティションを作る

busybox の fdisk, mkfs を使用。詳細は略す。

arch 格納用のディレクトリ準備

# 読み書きできるように再マウント
mount -o rw,remount /

# マウントポイントを作成
mkdir /mnt/arch

# sd カードの arch 用パーティションをマウント
cd /mnt
mount -t ext2 /dev/block/mmcblk1p2 arch

arch のベースシステム(?)を配置

cd /mnt/arch

# ベースシステムが格納されたファイルをダウンロード
wget http://os.archlinuxarm.org/os/ArchLinuxARM-armv7-latest.tar.gz

# 解凍
tar zxfv ArchLinuxARM-armv7-latest.tar.gz

[2015/01/6更新]:armv7でなく、armv5だったので修正。

[2015/01/7更新]:やっぱりarmv7だったので修正。

chroot しても問題なく動くように設定を書き換える

# dns につながるように設定を書き換える
rm /mnt/arch/etc/resolv.conf
echo 'nameserver 8.8.8.8' > /mnt/arch/etc/resolv.conf

# chroot 環境から proc が見えるようにする
mount -t proc /proc /mnt/arch/proc

# /dev が必要なプログラムも多いので bind しておく
mount -o bind /dev /mnt/arch

arch 環境を整える

# 既存パッケージのアップグレード
pacman -Syu

# 必要なパッケージをインストール
pacman -S vim
pacman -S git
pacman -S ghc
pacman -S cabal-install
cabal update
cabal install cabal-install
cabal install pandoc
pacman -S graphviz
pacman -S go
pacman -S base-devel

pacman -S imagemagick
pacman -S otf-ipafont

とりあえず、 golang と imagemagick が動くことは確認できた。

2014/11/08

[Vim, Ubuntu]Ubuntu1204 での vim ビルドメモ

忘れないように。 Ubuntu1204 をインストールして、 aptitude で build-essential を入れたくらいのはず。

sudo aptitude install libncurses5-dev
sudo aptitude install liblua5.2-dev
sudo aptitude install liblua5.1-0-dev
sudo aptitude install luajit libluajit-5.1-dev

cd ~/project/vimsrc/

hg pull
hg update

./configure --enable-luainterp --with-luajit --prefix=/home/mikoto/app/vim/ --enable-fail-if-missing
make -j8
make install

2014/10/03

[Mikutter] mikutter の change_account プラグインの interactive 機能を使ってみる

mikutter で、クリック一発でイベント発行出来る方法無いかなぁと考えていたら、 mikutter-adventure を思い出したので、参照しながらボタンクリックでイベント発火の練習をしてみる。

こんな感じでメッセージ内に表示されたボタンに応じたイベントを発行できるようだ。

多分コマンドでも代用できるけど、いちいち右クリックして選択とかしたくない・させたくない場合に使えそう。 (多用してボタンが並ぶとちょうどよいタイミングで画面がスクロールしてひどいことになったりしそうですが...)

タスク管理プラグイン作って、完了ボタンを押すとみくったーちゃんが褒めてくれる感じのプラグインなんてどうだろうか?

参考文献

mikutter-adventure/mikutter-adventure.rb at master · moguno/mikutter-adventure

2014/09/27

[作業記録, Debian] tmux をビルドした

早速ダウンロード・ビルド

git clone git://git.code.sf.net/p/tmux/tmux-code tmux-tmux-code

./configure
-bash: ./configure: No such file or directory

あ、configure ない。 README 見よう。

...(抜粋)
    $ git clone git://git.code.sf.net/p/tmux/tmux-code tmux
    $ cd tmux
    $ sh autogen.sh
    $ ./configure && make

autogen が必要みたい。

sh autogen.sh
autogen.sh: 16: autogen.sh: aclocal: not found
aclocal failed

aclocal とな。 automake がいるのか。というか入れてなかったっけ?

sudo aptitude install automake
sh autogen.sh
./configure
checking for library containing event_init... !!!configure: error: "libevent not found"!!!

こんどは libevent だ。

sudo aptitude install libevent-dev
./configure --prefix=/home/mikoto/opt/tmux
make -j8
make install

うん、できたっぽい。作業記録なので動作確認は割愛。あと、ビルドのためのパッケージはほぼすべてインストール済みだったのでそれも省略。

2014/09/20

[Debian, Ruby]Debian(wheezy) に rbenv で ruby2.1.3 をインストール

これだけ。

# 必要パッケージ取得
sudo apt-get install autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev rbenv ruby-build

# rbenv 初期設定
rbenv init
echo eval "$(rbenv init -)" >> .bashrc

# 2.1.3 のパッケージ URL を指定したファイルを作成
vim 2.1.3
cat ./2.1.3
install_package "yaml-0.1.4" "http://pyyaml.org/download/libyaml/yaml-0.1.4.tar.gz"
install_package "ruby-2.1.3" "http://ftp.ruby-lang.org/pub/ruby/2.1/ruby-2.1.3.tar.gz"

# 2.1.3 インストール
rbenv install ./2.1.3

# ruby コマンドで 2.1.3 が呼び出されるようにする。
rbenv global 2.1.3

2014/09/19

[Mikutter] UserConfig に連想配列を格納して、設定画面から変更できるようにしたい

UserConfig に連想配列を格納して、設定画面から変更できるようにしたかったので挑戦してみた。

実現方針は下記。

  • 設定画面の設定値を連想配列に紐付ける
  • 連想配列に変更があったら UserConfig を更新する

設定画面の設定値を連想配列に紐付ける

Settings の各関数にリスナを渡せるので、リスナ内で連想配列に出し入れするよう頑張ってもらう。

select は、 3.0.5 の時点ではリスナを渡せない。 3.0.6 くらいでフィックスされるのではないだろうか。

連想配列に変更があったら UserConfig を更新する

UserConfig[key] で取得できる値はコピーなので、 格納した連想配列に変更があった場合には連想配列自体を入れ替える。

上述のリスナの set 処理の最後に、連想配列をごっそり入れ替える処理を入れる感じ。

コードと、その結果の設定は下記の通り。

設定項目がゴチャッとしてきたらそれなりにわかりよくなるのではないでしょうか。

書きながら思ったけど、何かやるたびに連想配列全体のコピーが走るんだな、これ。 性能が気になる場合は、更新・取得にさらなる工夫が必要ですね。

参考文献

2014/08/14

[Mikutter, 作業記録] mikutter を Windows8 にインストールした

Windows8 に mikutter をインストールしたい

まずは ggr.

MikutterInstallBattleForWindows - mikutter Wiki(http://yuzuki.hachune.net/wiki/MikutterInstallBattleForWindows)

ふむ。やるか。

ruby のインストール

wiki の指示通りに rubyinstaller-2.0/0-p481.exe をダウンロードしてインストールした。

mikutter のダウンロード

都合のよいことに、すでに git 導入済みだったので、リポジトリからクローンして とってきた。

vimshell% mkdir develop
vimshell% cd develop
vimshell% git clone git://toshia.dip.jp/mikutter.git
!!!Cloning into 'mikutter'...!!!
!!!Checking out files: 100% (672/672), done.!!!

windows 用パッチブラグインの展開

こちらも git で。

vimshell% cd ~/develop/mikutter/plugin
vimshell% git clone https://github.com/moguno/mikutter-windows.git mikutter-windows

セットアップスクリプトの実行

vimshell% cd ~/develop/mikutter/plugin/mikutter-windows/
vimshell% c:/Ruby200/bin/ruby.exe ./setup.rb

...何も起きなかった。さすがにだめか。普通にダブルクリックする。おぉ、bundler のフェッチとインストールがはじまった。

コマンドプロンプトが閉じないと思っていたら、ショートカットできてた。コマンドプロンプトは開きっぱなしなのかな? 反応なし。コマンドプロンプトで「ruby mikutter」やってみたら gem が足りないって怒られた。やはりあれは途中だったのか...。しまった。 setup.rb をやり直す。

今度はちゃんと complete って表示されるまで待ったよ。

そのあと、「ruby mikutter.rb」でできました。

デスクトップにできたショートカットでも問題なし。

2014/08/12

[Mikutter] データソースを作ってみたい!

データソースの作成がしてみたいので、ホームタイムラインと同じ物を表示するだけのデータソースを定義してみる。

そもそもデータソースって何?

「抽出タブ」で選択できるデータの取得元。抽出タブの設定でチェックを入れると、そのデータソースのメッセージがタブに表示されるようになる。

「抽出タブ」を全く使っていなかったので、自分にとって「得体のしれない何か」であったが、今回の勉強でこんなもんかと解った気がしますわ。

「抽出タブで対応できないような特定のツイートを抽出する」、「外から情報撮ってきて表示する」ような機能はデータソース使うのがスマートっぽいですね。

じゃあ作ってみる

はい、やっていきましょう。

前準備

勉強用プラグイン作成。

cd ~/.mikutter/plugin/
mikutter.rb generate study_datasource
mikutter.rb spec study_datasource

コーディング

データソースを作成するにあたり、最低限必要な作業は下記の通り。

  1. 提供するデータソースの宣言(登録)
  2. 1 で宣言したデータソースにメッセージを追加する

これだけ。以下、今回作った具体的なコード。

.mikutter.yml

---
slug: :study_datasource
depends:
  mikutter: 3.0.4
  plugin: []
version: '1.0'
author: 
name: study_datasource
description: データソースの勉強するよー

study_datasource.rb

# -*- coding: utf-8 -*-
# mikutter datasource の勉強。
# ホームタイムラインのクローンデータソースを作成する。
#
# データソース作成手順としては、
#     1. filter_extract_datasources で、「こんなデータソースを作るよー」と宣言
#     2. データソースにメッセージを追加したいタイミングで
#        「:extract_receive_message」を呼ぶ。
#         その際、引数に「データソースに紐付くシンボル」を渡す。
# という感じ良いみたい。
#
# 既存タイムラインからの抽出でない場合は、
#     1. 自前でデータ取得ループ作成
#     2. 自前でメッセージ作成
#     3. 「:extract_receive_message」を呼ぶ
# となる感じですね。

Plugin.create(:study_datasource) do
    DATASOURCE_NAME = 'clone_home_timeline'

    # このプラグインが提供するデータソースの定義を組み立てて返却
    def datasources
        ds = {clone_home_timeline: "ホームタイムラインのクローン".freeze}
        ds[DATASOURCE_NAME.to_sym] = DATASOURCE_NAME
        ds
    end

    # 提供するデータソースの登録
    # 登録は、このプラグインで定義したデータソースを
    # 引数で渡ってきたデータソースにマージすることで行う。
    filter_extract_datasources { |ds|
        p "Add My Datasources"
        [ds.merge(datasources)]
    }

    # データソースにメッセージを追加
    # on_update で受け取ったメッセージ全てをデータソースに突っ込んでいる。
    on_update do |service, messages|
        messages.each do |message|
            p "Add message to #{DATASOURCE_NAME}"
            Plugin.call(:extract_receive_message, DATASOURCE_NAME.to_sym, [message])
        end
    end
end

参考文献

2014/07/30

[Mikutter] イベント定義を試した

イベントを定義したい

リストに所属している人のツイートがあった場合に発火するイベントが欲しくなったので、勉強がてら作って見る。

イベント定義の手順

  1. defevent で下記項目を定義
    • イベント名
    • 優先度
    • 引数の型
  2. Plugin.call(イベント名, 引数) でイベント発火

これだけ。

確認用コード

.mikutter.yml

---
slug: :studyEvent
depends:
  mikutter: 3.0.3
  plugin: []
version: '1.0'
author: 
name: studyEvent
description: イベントの勉強。

studyEvent.rb

# -*- coding: utf-8 -*-

Plugin.create(:studyEvent) do
    defevent :list_tweet_receive,  priority: :routine_passive, prototype: [UserList, Message]

    onboot do |service|
        Open3.capture3("echo 'start' > ~/tmp/ttt.txt")
    end

    # リストのツイート受信毎に list_tweet_receive イベントを発行する
    on_appear do |messages|
        messages.each{ |message|
            Plugin[:list].timelines.each{ |slug, list|
                if list.related?(message)
                    Plugin.call(:list_tweet_receive, list, message)
                end
            }
        }
    end

    # イベント発火をトリガに処理を行う
    on_list_tweet_receive do |list, message|
        Open3.capture3("echo '#{list.user}/#{list[:name]}' >> ~/tmp/ttt.txt")
        if list.user === 'mikoto2000' && list[:name] === 'News' then
            Open3.capture3("echo '#{message}' >> ~/tmp/ttt.txt")
        end
    end
end

イベント発火の部分だけ抜き出すと以下な感じか?

# -*- coding: utf-8 -*-

Plugin.create(:studyEvent) do
    defevent :list_tweet_receive,  priority: :routine_passive, prototype: [UserList, Message]

    # リストのツイート受信毎に list_tweet_receive イベントを発行する
    on_appear do |messages|
        messages.each{ |message|
            Plugin[:list].timelines.each{ |slug, list|
                if list.related?(message)
                    Plugin.call(:list_tweet_receive, list, message)
                end
            }
        }
    end
end

「リストイベントを追加するプラグイン」として単体で提供して、 このイベントが欲しかったら依存関係に入れろみたいな感じでどうか?

依存関係に入れなくても、プラグインが入っている時だけリスト系の機能が使えます的な使い方できるか?

-> 公開した。

mikoto2000/mikutter-list-event : https://github.com/mikoto2000/mikutter-list-event

2014/07/21

[Ruby, Mikutter] mikutter プラグイン「ゆかりが読む」を作った

mikutter プラグイン「ゆかりが読む」を作った

mikoto2000/mikutter-yukari : https://github.com/mikoto2000/mikutter-yukari

requirements 厳しすぎるけどまぁそれはそれ。

とりあえず自分の環境で動いたので公開。 ツイートを、音声配信サーバに投げて音声化し、再生します。

音声配信サーバとしては「VOICEROID+ 結月ゆかり」がインストールされた Windows7 端末を想定。

TODO

  • 先頭の twitter id とか末尾のハッシュタグとかは、読み上げ的には必要ないので無視するのがよいかなぁ。
  • ニュースツイート(nhk_news とか) のリンクは、リンク先をスクレイピングして読みあげたい。

mikutter plugin tips

本プラグインを作るにあたって、設定のデフォルト値の指定方法について調べたのでメモ。

プラグインのデフォルト値

プラグインのデフォルト設定値を作りたい場合、「on_boot」内で空チェックして、空ならデフォルト値設定とするのが良いようだ。

参考資料

VLC の曲名を nowplaying できる mikutter プラグイン書いた - polamjaggy : http://polamjag.hatenablog.jp/entry/2013/11/18/035402

2014/07/19

[Ruby, Mikutter] Mikutter プラグインを作ってみる。

はじめに

プラグインの書き方解説ページの「5 STOT 形式でコピー」を写経。

参考資料

Writing mikutter plugin : http://toshia.github.io/writing-mikutter-plugin/#sec-5

$ cd ~/.mikutter/plugin
$ mikutter.rb generate stot
$ mikutter.rb spec stot/
$ cd stot
$ vim stot.rb

...で、こんな感じ。

$ cat .mikutter.yml
---
slug: :stot
depends:
  mikutter: 3.0.3
  plugin: []
version: '1.0'
author: 
name: stot
description: Copy to clipboard with STOT format.
$ cat stot.rb
# -*- coding: utf-8 -*-

Plugin.create(:stot) do
  command(:copy_as_stot,
    name: 'STOT形式でコピー',
    condition: Plugin::Command[:HasOneMessage],
    visible: true,
    role: :timeline) do |opt|
      message = opt.messages.first
      screen_name = message.user[:idname]
      Gtk::Clipboard.copy("#{screen_name}: #{message.to_s} [https://twitter.com/#{screen_name}/status/#{message.id}]")
  end
end

つぎに

ツイートの本文を外部プログラムに渡すプラグインを作ってみる。

探せば有りそうと考えてはいけない。

参考資料

Rubyから外部プログラムを起動 - None is None is None : http://doloopwhile.hatenablog.com/entry/2014/02/04/213641

$ cd ~/.mikutter/plugin
$ mikutter.rb generate runWith
$ mikutter.rb spec runWith/
$ cd runWith
$ vim runWith.rb

...で、こうなる。

$ cat .mikutter.yml 
---
slug: :runWith
depends:
  mikutter: 3.0.3
  plugin: []
version: '1.0'
author: 
name: runWith
description: ツイートの内容を外部プログラムに、実行する。
$ cat runWith.rb 
# -*- coding: utf-8 -*-

require "open3"

Plugin.create(:runWith) do
  command(:run_with,
    name: 'echo to ~/tmp/echo.txt',
    condition: Plugin::Command[:HasOneMessage],
    visible: true,
    role: :timeline) do |opt|
      message = opt.messages.first
      Open3.capture3("echo '#{message.to_s}' > ~/tmp/echo.txt")
    end
end

とりあえず echo で試した。 あとはコマンドと引数を変更すればよいだけ。 外部プログラムが呼べてしまえば、もう何でも出来ますね!

2014/05/11

[作業記録][Debian]ALminium を導入しようとしてみた


下準備

仮想マシン再作成

# ホストPCで
sudo virsh destroy alminium
sudo virsh undefine alminium
sudo virsh vol-delete --pool default alminium.img
sudo rm /var/lib/libvirt/images/alminium.img
sudo virt-clone -o debian_org -n alminium --file /var/lib/libvirt/images/alminium.img
sudo virsh setmaxmem alminium 2048000
sudo virsh start alminium
sudo virsh setmem alminium 2048000
# 下記確認・設定を行う
# ホスト名修正
# IP アドレス確認
sudo virsh console alminium

ベースは ssh, git 導入済みなので ssh で接続。 次に、 Jenkins のインストールと、ベース URL の設定を行う。

Jenkins のインストール・設定

# ゲストPCで
sudo aptitude update && sudo aptitude -y dist-upgrade
# Debian では Jenkins インストールしてくれなかったのでインストールする
wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
echo 'deb http://pkg.jenkins-ci.org/debian binary/' | sudo tee -a /etc/apt/sources.list
sudo aptitude update && sudo aptitude install jenkins
sudo service jenkins restart

ベース URL の設定。

/etc/default/jenkins の JENKINS_ARGS の末尾に "--prefix=$PREFIX" を追加する。

本番

ALMinium のインストール

cd ~/work
git clone https://github.com/alminium/alminium.git
cd alminium
sudo bash ./smelt
Debian / Ubuntu が検出されました。
インストールに失敗するかも知れませんが、お許しくださいm(__)m

途中MySQLのパスワードを聞かれたら空のままエンターキーを押してください。
MySQLのパスワードを設定するとインストールに失敗します。
パスワードを設定したい場合は、ALMiniumのインストール完了後行ってください
*******************************************************
  ホスト名の設定
*******************************************************
ホスト名(IPアドレスもしくはDNS名)を入力してください。ホスト名はApacheのバーチャルホストで利用されます。
例えば、192.168.1.4をホスト名で入力すると、http://192.168.1.4/でアクセスすることになります。
(上記の設定ではhttp://localhost/では接続できないのでご注意ください)
ホスト名: 192.168.11.209


*******************************************************
  SSLのサポート
*******************************************************
SSLのサポートを有効にすると、httpsのみの接続を許可します。
httpでのアクセスは、全てhttpsのポートへ転送されるようになります。
SSLの証明書は認証機関により署名されたものではありません。通信の暗号化のみ
に利用します。
gitの利用では、

  $ git config --global http.sslVerify false

などのコマンドで、SSLの証明書を無効にする必要があります。

SSL(https)サポートを有効にしますか?(y/N) N


*******************************************************
  メール設定
*******************************************************
Redmineのシステムメールを送信するための設定を行います。

<利用する上での注意>
・利用したいメールシステムと通信可能なことをご確認ください。ファイアーウォールなどで遮断されている場合は管理者にお問い合わせください。
・Sendmailコマンドを利用する場合、別途Sendmailの設定を行う必要があります。
・G-Mail/Hotmailを利用する場合、ユーザー名とパスワードがあれば利用可能です。

次の中から、使いたいメールシステムを選択してください。
ここでメール設定を行わない場合は「N」を選択してください。

0. 独自のメールサーバーを設定する
1. Linux内のSendmailコマンドを使用する
2. G-Mail/Google Apps
3. Windows Live Hotmail

N. メール設定をしない

番号選択: N


メール設定を行いません。


継続的インテグレーションツールのJenkinsのインストール・設定を行うことができます。デフォルトはインストールしません。よく分からなければNを選択してください。Jenkinsをインストールしますか?[y/N]y

※ ここで、MySQL のルートパスワード入力になるが、空ですすめる。

... (snip)

Enabling site jenkins.
To activate the new configuration, you need to run:
  service apache2 reload
mkdir: cannot create directory `/var/lib/jenkins/plugins': File exists
[ ok ] Restarting Jenkins Continuous Integration Server: jenkins.
--2014-05-10 10:20:28--  http://localhost:8080/jenkins/jnlpJars/jenkins-cli.jar
Resolving localhost (localhost)... ::1, 127.0.0.1
Connecting to localhost (localhost)|::1|:8080... connected.
HTTP request sent, awaiting response... 503 Service Unavailable
2014-05-10 10:20:32 ERROR 503: Service Unavailable.
...(snip)

こんな感じのエラーで無限ループになるので、 Jenkins の設定を頑張る。

cd /var/lib/jenkins
mv config.xml _config.xml
sudo service jenkins restart

先には進むが、いろいろ残念なことになるので解消する。

[....] Starting web server: apache2apache2: Syntax error on line 268 of /etc/apache2/apache2.conf: Syntax error on line 1 of /etc/apache2/sites-enabled/redmine: Cannot load /usr/lib/ruby/gems/1.9.1/gems/passenger-4.0.42/buildout/apache2/mod_passenger.so into server: /usr/lib/ruby/gems/1.9.1/gems/passenger-4.0.42/buildout/apache2/mod_passenger.so: cannot open shared object file: No such file or directory
Action 'start' failed.
The Apache error log may have more information.
 failed!

Jenkins から。

cd /var/lib/jenkins
mv _config.xml config.xml
sudo service jenkins restart

その後、 Jenkins にアクセスし、アップデート等行う。

次、 apache2。これは、 mod_passenger が無いと言っているようなので apt でインストールする。

sudo aptitude install libapache2-mod-passenger
sudo service apache2 restart

apache2 のページを開くと、 gem 'thin (>=0) ruby' が無いって怒られた。 thin をインストールする。

sudo gem install thin rubu

...まだたりないらしい。

gem パッケージが足りないとすると、Gemfile.local あたり探せば良いかな。あった。

cd /opt/alminium
bundle update
...(snip)

いろいろインストールされた。 ALMinium のホーム画面は表示されたけれど、エラーだか警告だかのメッセージが表示されている。

バックログが設定されていません。設定画面 管理 > プラグイン, からリンク 設定 をクリックして設定してください。フィールドを設定後、このページへ戻りツールを利用してください。

ログを見てみる。 (/opt/alminium/log/production.log)

~ { .log } DEPRECATION WARNING: Passing a template handler in the template name is deprecated. You can simply remove the handler name or pass render :handlers => [:erb] instead. (called from realtime at /usr/lib/ruby/1.9.1/benchmark.rb:295) }

バックログの設定の警告とは関係ないログっぽい。 /opt/alminium/plugins/redmine_backlogs/app/controllers/rb_server_variables_controller.rb を修正。

---    format.js { render :file => 'rb_server_variables/show.js.erb', :layout => false }
+++    format.js { render :file => 'rb_server_variables/show', :layout => false }

バックログの DB マイグレーションがうまくいっていなかったらしい。

Support - "Plugin migrations have not been executed" after successfull installation

cd /opt/alminium
sudo rake redmine:plugins:migrate RAILS_ENV=production

とりあえずホーム画面は映った。

残課題

  • Jenkins の認証がおかしい。
    • ログインユーザが「(null)」になっている。
    • 「Jenkinsの管理」画面に「リバースプロキシーの設定がおかしいようです。」と表示される。

あと、インストールスクリプトちょっと見る限り、 Jenkins はリポジトリの登録さえしておけば apt-get でインストールはしてくれそう。その後の設定がどうなるかは読んでないけれど。

apache2, redmine, jenkins あたりの認証共通化の仕組みを勉強しないことにはこれ以上ダメそうね。どうしたものか。