Service Request should be written in JSON

※ カスタマーからリクエストを受ける仕組みを、改善する画面を書いたので、一筆

状況

エンドユーザーからServiceRequest(以下、SR) を受け取る場合、可能であれば、Webから受け取って、受け取った値をそのままDBに反映したり、fabricコマンドを発行したりしたいのだが、SRの受け取り方によって、そう出来ないケースがある。
ひっかかっているのは、"SR の受け取り方が承認フローとして固定されており、かつ、承認に使用している画面が変更できない場合" となる。
※ 承認された際に担当者にメールが飛んで担当者がコマンドを発行する。ツールから直接fabricコマンドを発行して欲しいのだが、、

現状、SR の本体(このSQLを発行して欲しい、ここにファイルを置いてほしい、など) は、エクセルに記述しており、条件付き書式等を使って入力をチェックしたりしているのだが、エクセル(Windows)からfabric(RHEL)を呼び出すところの書き方が微妙だったり、JavaScriptほどチェックが書きやすくなかったりで、今後のことを考えると、どこかでこの仕組みをWeb化しておきたいところだった。

対応

対応として、入力したフォームをJSONとしてエクスポートするための、新規のWeb画面を作ってみた。
新規フローは以下となる。

  1. 画面から作業内容を記述 -> JSONとしてエクスポート。
  2. エクセルの代わりにJSONを添付。承認フローを通す。
  3. オペレーターが、JSONRHELの某ディレクトリに配置。常駐ジョブが、JSONを解釈してfabricを呼び出す(ジョブが多数定義されている場合も、そのまま続けて呼び出す)

※ 作業用のweb画面

※ 上記画面に対応するJSON

効果

今までエクセルの内容をコピペしてfabricコマンドを作ったりしていたので、オペレーターの作業が非常に大変だったのだが、今後は、そのまま流せるのでだいぶ作業が楽になりそうだ、、
※ 当初 rundeckやjenkinsを使って上記を実現しようとしていたのだが、どちらもコマンドを自由に書けてしまうため、採用出来なかった、、(各種事前チェックの実装がDev任せになってしまう、リリースロジックの出来にムラあり)

(参考)作り

画面本体はDjangoJQueryを組み合わせて書いている。(fabfileを除くと600行くらい)
githubに上げてみようとしたのだが、コード内に固有名詞がありすぎて難しかった、、 orz



2016/2/28追記
-> githubにアップしました
https://github.com/aaabbb200909/execjson

2013年04月07日のツイート

qpid+gluster-swift でファイル転送

元々qpidはMQでファイル転送等の大量データのやりとりのツールではないので、、大容量データ転送ともろもろの後続ジョブ制御を兼ねて、qpidとgluster-swift(gluster UFO)を組み合わせてみた。

実現したい内容

実現したい内容は以下になる。

  • 1. 巨大ファイル(数GB程度を想定)の転送に対応出来る
  • 2. 送信元は、送信先の後処理が終わったかを確認せずに、次の処理に移れる
  • 3. 送信先は、ファイルが到着したらすぐに、事後処理を始める
  • (4: オプション)各計算ノードは巨大ファイルを載せられるだけのローカルディスクは持たず、直接glusterをマウントして使用する
  • 5. 計算ノードが停止していても、送信元はファイル送信を完了出来る

※ 1, 4, 5を実現するために、gluster-swift, 2, 3, 5 を実施するためにqpidを使う形になる。

実施方法

次の順で実施する。

  • 1. 送信元はgluster-swiftに対して HTTPでアップロードする。この後、qpidの特定のキューに対して、contentにglusterのファイルパスを指定したメッセージを書き込む。(ファイルパスはその時の時刻等を含めて、重複しないようにしておく)
  • 3. 送信先は事後処理を書き込んだスクリプトをqpidに対してアタッチしておく。(メッセージが届くと、MQの消費処理の一環として、事後処理が流れる)

※ ただし、実際に使ってみたところ、gluster-swiftでアップロードしたファイルが必ず 600, rootで設定されるため、その他のユーザーで事後処理を行うために、次の処理も必要になった。(計算ノードのジョブをrootで動かす場合は不要, また、gluster-swift経由でchmodが出来ればこの処理は不要になるはず。。)

  • 2. gluster-swift のノードで、 glusterfsに置かれたファイルにchmodを行うプロセスをqpidのserver 処理として稼働させておく。このプロセスは1のキューにアタッチしておき、chmodを実施したあと、3のキューにメッセージを配送する。

なお、テスト環境では次の3つのスクリプトで実施している。

  • 1: transferfile.sh
  • 2: peformchown.py
  • 3: consumefile.py

※ サンプルファイルはブログの後半に添付
※ 同じディレクトリに python-qpidサンプルのspout を置かないと上手く動かない。(swiftコマンドも必要)

まとめ

オープンソースだけだと、ファイル転送/その後の事後処理(非同期) を上手く実施するための仕組みがあまりなかった気がするが(知らないだけかも)、さしあたりこの組み合わせで動くものが出来そうな気がしている。
プロプライエタリ製品を含めると結構ある
価格も安く済みそうだし、おすすめかも。

スクリプトサンプル

transferfile.sh

起動方法:
 $ ./transferfile.sh
////
filename=aaa
container=container$(date +%s)
queuename=myqueuepre
replyto=myqueue

# upload file
swift --auth=https://localhost/auth/v1.0 --user=test:tester --key=testing  upload ${container} ${filename}
if [[ 0 -ne $? ]]
then
 echo "Cant upload file"
 exit 31
fi

# Then say that I uploaded file
./spout --reply-to=${replyto} ${queuename} ${container}/${filename}
if [[ 0 -ne $? ]]
then
 echo "Cant MQ"
 exit 32
fi

performchown.py(serverからの差分のみ):

起動方法:
 (root)# ./performchown.py myqueuepre
////

$ diff -u server performchown.py 
--- server      2013-04-06 19:26:30.089313772 +0900
+++ performchown.py     2013-04-06 20:41:20.259411750 +0900
@@ -18,7 +18,7 @@
 # under the License.
 #
 
-import optparse, sys, traceback
+import optparse, sys, traceback, os
 from qpid.messaging import *
 from qpid.util import URL
 from subprocess import Popen, STDOUT, PIPE
@@ -68,6 +68,13 @@
     result = Message(content)
   else:
     result = Message("unrecognized message type: %s" % msg_type)
+    #######
+    accountname='test'
+    print 'Use this:', msg.content
+    filepath='/mnt/gluster-object/AUTH_%s/%s' % (accountname, msg.content)
+    os.chmod(filepath, 0644)
+    result=msg
+    #######
   return result
 
 try:
@@ -87,7 +94,7 @@
     if snd is not None:
       snd.close()
     ssn.acknowledge()
-except ReceiveError, e:
+except ReceiverError, e:
   print e
 except KeyboardInterrupt:
   pass


consumefile.py(drainからの差分のみ):

起動方法:
 $ ./consumefile.py -f myqueue
////
$ diff -u drain consumefile.py 
--- drain       2013-04-06 19:26:30.084988056 +0900
+++ consumefile.py      2013-04-06 21:00:45.910323049 +0900
@@ -18,7 +18,7 @@
 # under the License.
 #
 
-import optparse
+import optparse, os
 from qpid.messaging import *
 from qpid.util import URL
 from qpid.log import enable, DEBUG, WARN
@@ -85,6 +85,16 @@
     try:
       msg = rcv.fetch(timeout=timeout)
       print opts.format % Formatter(msg)
+      #######
+      accountname='test'
+      print 'Use this:', msg.content
+      filepath='/mnt/gluster-object/AUTH_%s/%s' % (accountname, msg.content)
+      f=file(filepath)
+      print f.read()
+      f.close()
+      ##
+      os.system('swift --auth=https://localhost/auth/v1.0 --user=test:tester --key=testing delete %s' % msg.content.split('/')[0])
+      #######
       count += 1
       ssn.acknowledge()
     except Empty:

swiftコマンドのメモ

準備

export ST_AUTH=https://localhost/auth/v1.0
export ST_USER=test:tester
export ST_KEY=testing

実コマンド

swift list
swift upload hello mmm
swift download hello
swift upload hello2 mmm
swift delete hello2

環境変数を使わない場合は

swift --auth=https://localhost/auth/v1.0 --user=test:tester --key=testing list

gluster objectストレージを試してみた

Glusterfsではバージョン3.3以降でHTTPで読み書きが出来る機能(Objectストレージ, 以下UFO) が追加されている。
これについて、Scientific linux 6.3 + glusterfs 3.3.1 (ノード名: scfc-virt2)で確認した。

基本的には本家(?)の記事が参考になるが、パッケージ置き場の追加は手動で行う必要があるので注意。
https://access.redhat.com/site/documentation/en-US/Red_Hat_Storage/2.0/html/Administration_Guide/chap-User_Guide-UFO.html

パッケージ置き場としては、こちらを使用した。
http://download.gluster.org/pub/gluster/glusterfs/3.3/3.3.1/EPEL.repo/glusterfs-epel.repo

パッケージインストール

yum install glusterfs-server glusterfs-swift glusterfs-swift-proxy glusterfs-swift-account glusterfs-swift-container glusterfs-swift-object glusterfs-swift-plugin
※ swift関連のパッケージは全てインストールしないと上手く動作しないので注意

ボリューム作成

まずボリュームを作成する。ボリューム名は後で使用するUFOの設定と合わせる必要があるので注意。(ここでは"test"を使用)

service glusterd start
mkdir /root/glusterfs/
cd /root/glusterfs/
mkdir test
gluster volume create test scfc-virt2:/root/glusterfs/test/
gluster volume list
gluster volume start test
mount -t glusterfs localhost:/test /mnt/
ls /mnt/
umount /mnt

Swift部分の設定変更

まずSSL設定とユーザー設定を実施した。(SSL設定はオプションと思われる)

/etc/swift以下のdiff はこちらになる。

 diff --git a/proxy-server.conf b/proxy-server.conf
 index 1fcde8e..61e14d0 100644
 --- a/proxy-server.conf
 +++ b/proxy-server.conf
 @@ -3,6 +3,12 @@ bind_port = 8080
 user = root
 log_facility = LOG_LOCAL1
 
 +bind_port = 443
 +cert_file = /etc/swift/cert.crt
 +key_file = /etc/swift/cert.key
 +
 +
 +
 [pipeline:main]
 pipeline = healthcheck cache tempauth proxy-server
 
 @@ -14,6 +20,10 @@ account_autocreate = true
 [filter:tempauth]
 use = egg:swift#tempauth
 
 +
 +user_test_tester = testing .admin
 +
 +
 [filter:healthcheck]
 use = egg:swift#healthcheck

※ 事前にSSL鍵を作っておく必要あり

# cd /etc/swift
# openssl req -new -x509 -nodes -out cert.crt -keyout cert.key

Swift 起動

[root@scfc-virt2 ~]# swift-init main start
Starting proxy-server...(/etc/swift/proxy-server.conf)
Starting container-server...(/etc/swift/container-server/1.conf)
Starting account-server...(/etc/swift/account-server/1.conf)
Starting object-server...(/etc/swift/object-server/1.conf)
[root@scfc-virt2 ~]# 

※ 上手くいかない場合 /var/log/messages を確認する。。

動作確認

認証を実施:
# curl -v -H 'X-Storage-User: test:tester' -H 'X-Storage-Pass:testing' -k https://localhost:443/auth/v1.0
 ///
 < HTTP/1.1 200 OK
 < X-Storage-Url: https://127.0.0.1:443/v1/AUTH_test
 < X-Storage-Token: AUTH_tkbf93f02e7e6842bb98374849cedcb6d1
 < X-Auth-Token: AUTH_tkbf93f02e7e6842bb98374849cedcb6d1
 < Content-Length: 0
 < Date: Sat, 30 Mar 2013 09:38:43 GMT
 < 
 * Connection #0 to host localhost left intact
 * Closing connection #0
 ///

コンテナー名を列記:
# curl -v -X GET -H 'X-Auth-Token: AUTH_tkbf93f02e7e6842bb98374849cedcb6d1' https://localhost:443/v1/AUTH_test -k
///
 < HTTP/1.1 204 No Content
 < X-Account-Container-Count: 0
 < X-Account-Object-Count: 0
 < X-Bytes-Used: 0
 < X-Object-Count: 0
 < X-Account-Bytes-Used: 0
 < X-Type: Account
 < X-Container-Count: 0
 < Accept-Ranges: bytes
 < Content-Length: 0
 < Date: Sat, 30 Mar 2013 10:05:14 GMT
 < 
 * Connection #0 to host localhost left intact
 * Closing connection #0
///
※ "test"という名前のvolumeが無いと、ここで503エラーが発生。

ファイル作成:
# curl -T /tmp/mmm -X PUT -k -H 'X-Auth-Token: AUTH_tkbf93f02e7e6842bb98374849cedcb6d1' -H 'transfer-encoding: chunked' https://localhost:443/v1/AUTH_test/hello/aaa
※ ファイルが作成されているかの確認は、/mnt/gluster-objects かbrickの置き場所(/root/glusterfs/test)で実施する。 

まとめ

差し当たりGlusterのUFOを動かすことが出来た。実際に実施していることはHTTPでファイルGET/PUTを受けてプロキシ上にマウントされた glusterfsに読み書きしているだけのようなので、あまり新しいことはないが、、セグメントを越えたりリバースプロキシ経由でglusterに読み書き出来たりするので、オンプレミスの環境ではかなり使い勝手がよくなる気がしている。。(特にセグメント越えでCIFSが遅い場合や、、閲覧元がWindowsUnixでない場合)

※ 今のところ、ユーザー名が proxy-server.conf に直書きするしかなく、かつ、反映時に再起動が必要なのが運用上少々辛い気がする(ロードバランサーを使えば出来なくはないかもしれないが)

qpidでルーティングを作るときのメモ

qpidでルーティングを作るとき、QueueからQueueにルートを作るようにしないと、送り元で一度受け取って、送り先が起動したタイミングで再送、という動作が実施できない。
しかし、qpid-configでqueueルートを作る場合、指定できるのが送り元のqueueと送り先のexchangeとなっており、queueからqueueへのルートを作るには工夫が必要となる。

上手くいった構成としては、次の順で、Queue,Exchange,QueueをQueueルート、およびbindでつないだときだった。
※ メッセージの送信/受信は、サンプルのspout/drain で実施
hello2(queue, centos-virt12) -> (routing) -> helloexch(exchange, centos-virt11) -> (bind) -> hello(queue, centos-virt11)

事前準備

(centos-virt11)$ qpid-config add queue hello
(centos-virt12)$ qpid-config add queue hello2
(centos-virt11)$ qpid-config add exchange fanout helloexch
(centos-virt11)$ qpid-config bind helloexch hello
(centos-virt11)$ qpid-route queue add centos-virt11 centos-virt12 helloexch hello2
※ $ qpid-route route map で確認可能

確認

(centos-virt12)$ spout hello2
(centos-virt11)$ drain -f -r hello
※ centos-virt11上でメッセージが表示されることを確認する

なお、ルーティングのテストをする場合、同じブローカー内ではルートが作れないので注意。。

$ qpid-route queue add localhost localhost hello2 hello
Failed: Exception - Linking broker to itself is not permitted

追記:
※ bind があるかどうかを確認するには

$ qpid-tool
> list exchange
> list queue
から接続元/接続先 を調べて、
> list binding
> show (bindID)
exchangeRef
queueRef
を調べていくしかなさそう。。

PythonでExcelを操作する時のメモ

Windows版のPythonとwin32com モジュールを使うことで、VBAからしか使用出来ないような機能が Pythonからも使用できるようになる。
Git等と連携できる点や、普通のPythonモジュール(正規表現XML/JSON処理等)が使える点が圧倒的に便利で、、もはやVBAには戻れない。

インストール

本体とモジュールをインストールする(Windowsのみに対応)

http://www.python.org/ftp/python/2.7.3/python-2.7.3.msi

  • win32comモジュール:

http://sourceforge.net/projects/pywin32/files/pywin32/Build%20218/

役に立つリソース

  • 全般的:

http://mono-comp.com/programming/python-win-excel
https://sites.google.com/site/pythoncasestudy/home/pywin32kara-comwo-tsuka-tsu-te-excelwo-sousa-suru-houhou

  • セル数が多いときの必須テクニック:

http://d.hatena.ne.jp/Wacky/20091011/1255259575

https://github.com/aaabbb200909/test01/blob/master/win32excel.py

  • 追記: Oreilly本(特にmakepy.py の使い方)

http://oreilly.com/catalog/pythonwin32/chapter/ch12.html


※ ちなみにPerl/Ruby等でも類似のモジュールがあるようなので、お好みで