主にプログラミングに関して。Python, .NET Framework(C#), JavaScript, その他いくらか。
記事にあるサンプルやコードは要検証。使用に際しては責任を負いかねます

foo

                
tags:
 一か月ブログを更新してないのでFC2のルールとしてトップに広告が出るようになってしまった・・・ので今後いじりたいものを適当に書いて、広告に引っ込んでもらうことにする。

・MongoDB
今年のメジャーバージョンアップで「クリティカルなものにも使える」というデータベースになったらしい。どういうことか調べつつ追加機能をいじっておく。

・ASP.NET MVC
.NET Coreのオープンソース化でLinuxでも動くようになっている。Pythonで作ってあったブログをこれで作り直して、VPS借りてそこにのっけたい。Pythonで作ったブログはGAEにのっけてあるが、いまだにPython2.7なのとデータベースがオリジナルなのでもっと一般的なものを使いたく、GAE脱却計画中。
スポンサーサイト



Windows 10: Boot2Docker on Hyper-V

                
tags: Docker
 Windowsには8以降でHyper-Vが導入されている。アプリ開発でWindowsOSのエミュレータが動くときはこのHyper-Vにお世話になる。そういうわけで欠かせない機能になっているが、このHyper-VをOnにするとCPU仮想化機能の都合で他の仮想化ソフトが使えなくなる。VirtualBoxとか。VirtualBoxが使えなくなるとBoot2Dockerが起動しなくなる。そんなわけでBoot2DockerをHyper-Vで動かすことにする。

参考
http://www.henning.ms/2015/05/11/running-docker-on-hyper-v/
http://blog.thestateofme.com/2014/02/18/boot2docker-on-hyper-v/

 やることはわりと単純。Boot2DockerはISOが提供されているのでそれを入手し、それをHyper-Vで動かす。Boot2Dockerの永続ストレージを用意する。ホストOSがネットワークでシェアしているディレクトリをVirtualBox上で動かしたBoot2Dockerと同様にマウントして、ホストで用意したファイルをBoot2Docker内で使えるようにする。


・Boot2DockerのISOの入手
 下記から。
https://github.com/boot2docker/boot2docker/releases

・Hyper-VでBoot2Dockerの立ち上げ
 落としたISOをHyper-Vで立ち上げる。新しいVirtual Machineを作成し、DVDドライブにISOイメージを登録。とりあえず立ち上げを確認したいのでハードディスクはまだ付けておかなくてもいい。もちろんネットワークはLAN内ファイルシェアやもろもろのダウンロードができるようにつないでおく。External設定で。
 準備ができたらその仮想マシンを起動し、Boot2Dockerが入力を受け付ける画面にまで進むことを確認する。気が済んだら仮想ハードディスクを取り付けるので落とす。

・ストレージの用意
 Boot2Dockerに仮想ハードディスクを取り付ける。Boot2Docker仮想マシンのSettingsを開いて、IDE Controller0のところにHDDを追加する。新規の仮想ハードディスクを取り付ける。
 仮想ハードディスクを取り付けたらBoot2Docker仮想マシンを立ち上げる。そしてまずフォーマットを下記のようにかける。

sudo fdisk /dev/sda
n
e
ターミナルに従ってデフォルトとされてる値を入力
同様にデフォルト値を入力
n
l
同様にデフォルト値を入力
同様にデフォルト値を入力
w
sudo mkfs.ext4 -L boot2docker-data /dev/sda5

 パーティションの1から4でどれにするか聞かれたら1を選ぶ。
 上記のコマンドが済んだら準備ができたので再起動。

・ホストマシンのシェアディレクトリをBoot2Dockerにマウント
 せっかくだからホストマシンのPowerShellからSSH接続をまず試し、接続が成功したら続いてマウントをする。Boot2Dockerが立ち上がるとき、あるいは起動後にifconfigでIPアドレスを調べる。そしてそこにuser:docker pass:tcuserでPowerShellからログインする。PowerShellで下記を入力。
SSH docker@[Boot2Docker IP]
 パスワードを入れればBoot2Dockerに入れる。このままVirtualBoxのBoot2Dockerと同様に/c/Usersにホストのユーザーディレクトリをマウントする。
 まずディレクトリの作成。
sudo mkdir -p /c/Users
 続いてマウント。
sudo mount //[host's ip]/Users /c/Users -o username=[host user],password=[password]
 マウントコマンドにはパスワードまでつける。LinuxMintで同様のマウントをパスワード抜きでやったら、コマンド入力後にパスワードを聞き返された。しかしBoot2Dockerではパスワード抜きでは即刻access deniedではじかれた。
 VirtualBoxのBoot2Dockerと同様に/c/Users以下にディレクトリがマウントされていることを確認する。


 ついでに以前Boot2Dockerのために作成していた設定ファイルをそのまま使い、コンテナ上で立ち上げたWebアプリにホストマシンからアクセスする。成功すればHello from sv.という文字列がブラウザに表示される。
http://elicon.blog57.fc2.com/blog-entry-465.html
 SSH接続してあるPowerShellからこれまでの追加で以下を入力した。用意済みのシェルスクリプトを実行するコマンドである。
cd /Users/john/docker/b3
sh hello.sh
 接続成功。
1508071502470.jpg



 Hyper-Vの使用によってVirtualBoxが立ち上げられなくなるので、Boot2DockerをHyper-Vで使うことを試みた。Boot2Dockerを立ち上げて永続ストレージを用意できてしまえば、あとは立ち上げ時にホストのネットワークシェアディレクトリをマウントするだけでVirtualBoxのBoot2Dockerと同様に使えた。同様ということでこれまでのBoot2Dockerで使っていた設定ファイルそのままでコンテナを動かせている。これならVirtualBoxなしでもうまくいけそうである。
 参考にした記事では仮想ハードディスクを作成した後、それをベースとしてコピーを作って再び取り付けて使用している。それで新しいBoot2Docker仮想マシンの作成時にフォーマットの手間などが省けるということらしい。ぼくはBoot2Docker仮想マシンは一台で十分だったし、もしのちのちそれを作り直すことになってもその手間が5分(もしかしたら3分程度かも)で済むものだったのでベースのみで使用している。


 さらにVirtualBoxのBoot2Dockerに近づけるには・・・
 Hyper-V管理ツールではなくPowerShellからゲストを立ち上げるには下記。
Start-VM -Name "boot2docker"

 いちいち実行するたびにマウントコマンドを実行するのは面倒。マウントコマンドを起動時に実行されるシェルスクリプトに書いておく。
http://stackoverflow.com/questions/26639968/boot2docker-startup-script-to-mount-local-shared-folder-with-host
 Boot2Dockerでは/var/lib/boot2docker/bootlocal.shが起動時に実行されるので、ここにマウントコマンドを書いておけば立ち上げるたびに自分で書く必要がなくなる。

Cassandra: CQLを学ぶ

                
 前回、datastax社がオープンソースにしているcassandra-driverを使って軽くCassandraに触れてみた。cassandra-driverからデータの検索やらデータ追加などの処理をするには、ドライバに特別なメソッドなどが備えられているわけでなく、executeステートメントを使ってほぼCQL文まんまのもので命令を出していった。CassandraのデータをPythonからいじるのに必要なのはまずCQLを理解すること、というのがわかった。
 というわけで今回はCQLの基礎的なところをさらっていく。

 まずは具体的なデータ作成の前の準備ということでキースペースの作成、キースペースのセットまで。Pythonでcassandra-driverを使ってやることを想定しておく。
 キースペースは下にテーブルが入るものなので、それほど複雑でないものなら一つのプロジェクトにつき一つのキースペースを割り当てればいいんじゃないだろうか。
session.exexute("CREATE KEYSPACE fooSpace")
session.exexute("USE fooSpace")


 次にテーブルを作る。テーブル作成時にはどんなセットを持つデータを格納するかを宣言しておく。昔はこのキースペース直下のデータのまとまりの単位にTABLEでなく、COLUMNFAMILY(カラムファミリー)という言葉を使っていたようだが、これを書いている時点で公式のCQLドキュメントではTABLEという言葉になっている。
session.execute(
"""CREATE TABLE men (id int PRIMARY KEY,
fname text,
lname text,
age int,
sports set<text>)
"""
)

menというテーブルを用意した。とりあえず一人の男のデータとして適当に割り当てたid、姓、名、年齢、あとセットとしてsportsというデータを定義している。Cassandraのデータとして文字列や数値を複数並べて入れられる三種類のコレクションも使えるようになっている。コレクションはPythonで言うところのキーバリューが対応した辞書型と同様のmap、リスト型と同様のlist、ユニークな要素で常にソートされるsetの三種類がある。今回はsportsに経験したスポーツの名前を入れるとして、値の重複は必要ないのでsetを選んだ。

 テーブル定義の次はテーブルにデータを突っ込む。この辺は適当に適当な名前で適当な人を仮定してやっていく。基本は"INSERT INTO tablename (key1, key2...) VALUES (value1, value2...)"
session.execute(
"""
INSERT INTO men (fname, lname, id, age, sports)
VALUES (%s, %s, %s, %s, %s)
""",
("John", "O'Reilly", 1600, 30, {"soccer", "golf", "tennis", "karate"})
)

session.execute(
"""
INSERT INTO men (fname, lname, id, age, sports)
VALUES (%s, %s, %s, %s, %s)
""",
("John", "Smith", 1601, 25, {"soccer", "golf"})
)

session.execute(
"""
INSERT INTO men (fname, lname, id, age, sports)
VALUES (%s, %s, %s, %s, %s)
""",
("John", "Suzuki", 1602, 30, {"soccer"})
)

session.execute(
"""
INSERT INTO men (fname, lname, id, age, sports)
VALUES (%s, %s, %s, %s, %s)
""",
("John", "Kawasaki", 1603, 29, {"golf"})
)

session.execute(
"""
INSERT INTO men (fname, lname, id, age, sports)
VALUES (%s, %s, %s, %s, %s)
""",
("John", "Honda", 1604, 30, {"tennis"})
)


 データ検索。"SELECT fname, lname FROM men"
SELECTの後ろに欲しい値のキーをカンマ","区切りで。全部欲しければ"*"ワイルドカード。あとはどのテーブルからデータを引っ張ってくるかをFROMのあとに。
men = session.execute("SELECT * FROM men")
for man in men:
print man.id, man.fname, man.lname

WHEREを使う。けどそのまえにプライマリキー以外を条件にかけたい場合、そのインデックスを作っておくこと。
http://cassandra.apache.org/doc/cql3/CQL.html#createIndexStmt
session.execute("CREATE INDEX on men (fname)")
session.execute("CREATE INDEX on men (fname)")
session.execute("CREATE INDEX on men (lname)")


men = session.execute("SELECT * FROM men WHERE fname='John'")
for man in men:
print man.id, man.fname, man.lname

プレースホルダを使う。
session.execute("SELECT * FROM men WHERE lname=%s", ("O'Reilly",))

条件を増やす。
session.execute("SELECT * FROM men WHERE fname='John' AND age>30 ALLOW FILTERING")

下記は不正なCQLでエラーとなる。WHERE節を使うならその中に一つは"="がなければならないのがCQLとのこと。
session.execute("SELECT * FROM men WHERE age>30")

じゃあ"fname='*'"のようにやって、ワイルドカードで全行にひっかかるようにしてやればと思うけど、そういうワイルドカードはない。じゃあ全行にダミーでブール値Trueを入れるカラムを作って"dummy=True"とか条件に追加すればってstackoverflowで言ってるのがあるけど、それは悪手だと批判もされている。でもそれをやる良い手がCassandraにはないだろとも。Cassandraはここら辺がちょっとだけ難しいか。
CQL SELECT Query on non key column

*********************************
 ここからはCassandra2.1以降の話。これを書いている時点ではベータ版で2.1.0がリリースされているので、そのベータ版Cassandraを使う。
 上で三種類のコレクションを紹介した。これにインデックスを作ってクエリで条件をかけられるのが2.1以降の機能だ(参考)。
session.execute("CREATE INDEX ON men (sports)")
rows = session.execute("SELECT * FROM men WHERE sports CONTAINS 'tennis'")

このコレクションのなにが素晴らしいかっていうと、中間テーブルを省けるようになったりすること。多対多が中間テーブルなしに作れるようになる。
 たとえばブログ記事がいくつかのタグを持っていたとして、一つの記事を読んで同じタグの記事を探したい場合、そのタグで中間テーブルにクエリをかけて、クエリに引っかかったデータから同じタグの記事への参照を洗い出す。コレクションを持っていれば、中間テーブルにでなく記事をカラムとして持つデータのテーブルに直接クエリをかけられる。一つテーブルを省けるというのはうれしいところ。

InstallShield LE: error : -5008: Intel64 or AMD64 must be specified in the template of the Summary Stream

                
Windowsアプリケーションのインストーラを、InstallShield LEで作っている。昨晩、ふとこれまでビルドできていたセットアッププロジェクトがエラーを吐くようになったので、解決策をさぐった。エラーメッセージは以下。
「error : -5008: Intel64 or AMD64 must be specified in the template of the Summary Stream」

エラーの原因になっていたのは、アプリケーションのファイルとして加えていたIronPython.Modules.dll。これをプロジェクトから外してみると、ビルドは成功する。だけどこのファイルはアプリケーションには必須。このファイルをプロジェクトに入れたままビルドを成功させたい。

ビルド時のVisualStudioからのメッセージを読むと、IronPython.Modules.dllがVC++のランタイム依存だと書かれている。これは気にかかる。IronPythonは基本的に.NET Framework上で動作するように作られている。わざわざ.NETから外れてVC++でモジュールを実装するとは考えづらい。この依存を切ってみる。

ソリューションエクスプローラから2番のSpecify Application Data→Filesとたどり、中央のウィンドウに出てきたIronPython.Modules.dllを右クリック、Dependencies from scan at build...を選ぶ。VC++のランタイムにチェックが入っているので外し、プロジェクトのビルドを試みる。成功。これで生成されたインストーラを使ってインストールしたアプリも難なく動作した。



"multipart/from-data"を使ってファイルデータを複数送る(HTML5, XHTML, HTML4)

                
tags:

<input type="file" id="files" name="files[]" multiple />

inputタグにmultipleを付けておくと、ファイルを複数選択できるようになっている。これはHTML5に限ったことではないようで、XHTMLやHTML4のドキュメントでも機能が宣言されていた。このinputタグを適切なformタグでパックしてやれば、複数ファイルをポストすることができる。
<form action="/add" method="post" enctype="multipart/form-data">

W3C HTML5


これでクライアント側はいい。次はサーバー側。今回の環境はGoogleAppEngine(Python2.5)。webappリクエストハンドラを使う。

クライアント側でinputのnameを"files[]"にした。だからself.request.POST.getall('files[]')とすれば複数のオブジェクトとして返すことができる。
参考資料:WebOb_Document
def post(self):
""""""
title = self.request.get('title')
location = self.request.get('location')
tookdate = self.request.get('tookdate')
for file_data in self.request.POST.getall('files[]'):
entry = Entry()
entry.filedata = file_data.value
entry.put()
プロフィール

h

Author:h

最新記事
リンク
作ったものなど
月別アーカイブ
カテゴリ
タグリスト

検索フォーム
Amazon