Hyper-V 上の Debian VM の vNIC の IP アドレスを管理 OS 側から取得できるように LIS を有効にする
表題通り。 Hyper-V 上の Debian 8.7.1 で Linux 統合サービス (Linux Integration Services; LIS) を有効にした方法のメモ。
私が試したのは、Windows 10 Pro (Insider Preview Build 14986) の Hyper-V 上の VM に Debian 8.7.1 Jessie をインストールする Packer のビルドを実行しようとした、というもの。
前提
- Hyper-V の管理 OS 側から、VM の仮想ネットワークアダプタ (vNIC) の IP アドレスを取得できるようになっている。
- Hyper-V マネージャの GUI で確認できる。
- PowerShell の Hyper-V モジュールのコマンドを使う場合は、
Get-VM
コマンドで返ってくるMicrosoft.HyperV.PowerShell.VirtualMachine
オブジェクトのNetworkAdapters
プロパティで確認できる。- PowerShell で
Get-VM | %{$_.NetworkAdapters}
と入力。 - Packer のソースコード上でも hyperv.go の中で使われている。
- PowerShell で
直面した状況
Packer でビルドして Hyper-V VM に Debian 8.7.1 Jessie をインストールしようとしたところ、Packer がゲストマシンに SSH 接続しようとしてずっと待ち続けるという状況になった。 (下記表示のまま進まない。)
==> hyperv-iso: Waiting for SSH to become available...
Packer のログ ($env:PACKER_LOG=1
でログ出力されるようにした) を確認したところ、以下のようなメッセージが表示されていた。
2017/02/18 19:48:48 packer.exe: 2017/02/18 19:48:48 [DEBUG] Error getting SSH address: No ip address.
すなわち、管理 OS 側から仮想ネットワークアダプタの IP アドレスを取得できなかったぽい。
管理 OS 側から仮想ネットワークアダプタの IP アドレスを取得できなかった原因
「Error getting SSH address: No ip address.」 の原因を探したところ、以下の issue が引っかかった。 ここでゲスト OS 側が管理 OS に IP アドレスを伝える必要があるということを知った。
で、Linux ゲストの場合は、Linux 統合サービスが必要とのこと。
Debian 8.7.1 Jessie で LIS を有効にする
Debian 8 系では、LIS がディストリビューションに含まれている。
有効にするための手順がどこに書かれているのかわからなかったので困ったのだけれど、やってみたところ Debian 8.7.1 では、APT の hyperv-daemons パッケージをインストールして再起動するだけで LIS が有効になるっぽかった。 (実際に試して、管理 OS 側から IP アドレスを取得できることを確認した。)
apt-get install hyperv-daemons
今回の場合、Packer でビルドするために Preseed を使っていたので、preseed.cfg のパッケージ選択に hyperv-daemons を含めるようにした。
d-i pkgsel/include string openssh-server build-essential hyperv-daemons # これは一例です。 hyperv-daemons パッケージ以外のパッケージは必ずしも必要ではありません。
参考
- Debian Jessie Hyper-V : Debian 8 で LIS を有効にする方法。 KVP、VSS、FCOPY 統合のために hyperv-daemons と 4.2 カーネルが必要とのこと。 KVP やら VSS やら FCOPY まで追いかけられていないが、参考にした。
- Install Hyper-V (LIS) On Debian 8 : Debian 8 で LIS を有効にする方法。 こちらも参考にはしたが、ここに書かれている方法を全て実行する必要はなさそうだった。
読んだ : RESTful Web Services with Dropwizard / Alexandros Dallas 著
Dropwizard に関わる仕事をしているので読んでみました。
RESTful Web Services with Dropwizard
- 作者: Alexandros Dallas
- 出版社/メーカー: Packt Publishing
- 発売日: 2014/02/19
- メディア: Kindle版
- この商品を含むブログを見る
Dropwizard について
Dropwizard は Java の web アプリケーションフレームワークです。 基本的には既存ライブラリの組み合わせで web アプリケーションを構築するというもので、Dropwizard 固有の仕組みはさほど多くありません。 (例えば Web リクエストを受け取るのは Jersey で、DB アクセスには Hibernate か jDBI が使われる。)
特に Java EE 系の知識を持っている人であれば、とっつきやすい感じです。
本書について
本書は、Dropwizard を使って web アプリケーションを構築するための方法を説明するものです。 プロジェクトの準備や、HTTP リクエストを受けるエンドポイントの記述、DB アクセス、ユーザー認証、HTML を返す View テンプレートについてなど、基本的な要素について、サンプルコードを交えながら仕組みが解説されます。
Java EE などについてある程度わかっている人が読むと Dropwizard の公式ドキュメントを読むのと大差ないと思いますが、初心者の人が読むと結構わかりやすいんじゃないかなと思います。 (ある程度わかってる人にとっても、Dropwizard についてざっと知ることができて良いかもしれませんが、そういう使い方だとちょっと値段は高めに感じる気がします。)
本書での学び
参考のリンクとしては現時点での最新バージョンのドキュメントへのリンクです。 閲覧時の最新バージョンのドキュメントは各自探してください。
- Dropwizard では、maven-shade プラグイン を使って、単体で web アプリケーションとして実行可能な JAR ファイル (uber-jar) を作る。
- Hibernate Validator によるアプリケーション設定のバリデーションが可能。
- jDBI で DB から取得した結果をオブジェクトにマップする方法として、
@MapResultAsBean
アノテーションを使うという方法もある。- 参考 : MapResultAsBean (jDBI 2.48.2 API)
- とはいえ公式的なドキュメントは何もなく、ドキュメント化されていない挙動に依存することになるので不安。 (JDBI の機能の多くがドキュメント化されてないのでまあこれに限った話ではないのだけど。)
- HTTP リクエストパラメータのバリデーション周り。
- JAX-RS のリソースメソッドのパラメータのバリデーションを明示的に実行することも可能。 (
@Valid
アノテーションでのバリデーション実行しか知らなかった。) - 複数フィールドにまたがるバリデーション。
- 参考 : Dropwizard Validation | Dropwizard
- JAX-RS のリソースメソッドのパラメータのバリデーションを明示的に実行することも可能。 (
- Dropwizard には HTTP クライアント用モジュールも含まれている。
- 認証周り。
- Basic 認証用のクラスが用意されている。
- オプションの認証も可能。 (認証されたユーザーの場合はそのユーザー専用のコンテンツを表示し、さもなければ一般ユーザー向けのコンテンツを表示する、みたいな。)
CachingAuthenticator
によるキャッシング。- 参考 : Dropwizard Authentication | Dropwizard
- Fixtures for Easy Software Testing (FEST) というプロジェクトがある。 TestNG や JUnit と一緒に使える。 ソフトウェアテストを書きやすくするライブラリ。
感想
Dropwizard をそこそこ使ってて公式ドキュメントも (全部ではないけど) 読んでいたので、本書での学びはあんまりなかったです。 とはいえ上に書いたように新たに知れたこともいくつかあったので読んでよかったです。 (そんなに時間もかけずにざっと読めましたし。)
とはいえ紙の本だと 30 ドル以上するので、ちょっと高い感じはしますね。
読んだ : Kotlin スタートブック ― 新しい Android プログラミング / 長澤 太郎 著
Kotlin エバンジェリスト (JetBrains 黙認) であり、日本 Kotlin ユーザグループ代表であるたろーさん (長澤 太郎) によって書かれた書籍 『Kotlin スタートブック ― 新しい Android プログラミング』 (赤べこ本) を読みました!!
Kotlinスタートブック -新しいAndroidプログラミング
- 作者: 長澤太郎
- 出版社/メーカー: リックテレコム
- 発売日: 2016/07/13
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
本書を読む前から、公式のリファレンスやチュートリアルなどの気になる箇所を見てはいて Kotlin についてはなんとなく理解はしていたのですが、ところどころ知識が欠けている部分もあったので、本書によってそういった知識の欠落を埋めることができました。
どんな本か?
内容については著者のたろーさんが紹介されています。
導入としてまず 1 部があり、2 部で Kotlin の文法や機能の詳細が解説されます。 3 部にて、Android アプリ開発で Kotlin をどのように活用できるかが説明されます。 対象読者は 「Java および Android 開発経験者」 と書かれていますが、2 部までなら Android アプリ開発については知らなくても問題なく読み進められます。 「Android アプリ開発で Kotlin を使うために読む本」 というわけではなく、「Kotlin を使い始めるときに読む本」 かつ 「Android 開発に Kotlin を活用するためにどうすればいいかが書かれている本」 という感じです。
全体としては易し目の説明でスクリーンショットも多用されているのでプログラム開発の初心者でも読みやすい本だと思います。 一方で、説明する内容についてきちんと節が分かれていて飛ばし気味に読むこともやりやすいので、ソフトウェア開発についてある程度経験がある人が Kotlin の導入のために読むというのにも適しています。
感想
Kotlin を Java の代わりとして使い始めるのは結構簡単で、いくつかある Java との違い (各種文法の違いや 「==
演算子は同一性検査ではない」 みたいな違い) をおさえさえすれば導入できます。 逆に導入するのが簡単なせいで、「ちゃんと Kotlin 特有の機能や文法を学ぶ」 機会を設けず、必要に応じて公式リファレンスを参照している、という人も多いのではないでしょうか。 私もまさにそんな感じだったので、今回本書を読んで Kotlin 特有の機能、文法を学べたのは非常に良かったです。
内容的には深く突っ込んでいくという感じではないので、本書を読みつつ気になったところは公式リファレンスを参照する、みたいに読み進めていくといい気がします。 公式リファレンスとは違った視点での説明されている項目もあったりするので、両方参照することで理解が深まったりもすると思います。 公式リファレンスには書かれていない 『!!
演算子の代わりに requireNotNull
メソッドを使うと良い』 というような記述があるのも本書の良いところですね。
まさに 「これから Kotlin を使っていこうと思っている人のための Kotlin 入門本」 として、以下のような人にオススメできる書籍でした。
- Kotlin を使ってみてるけどまだ Kotlin 全体についてちゃんとは学んでいない。
- まだ Kotlin を使ってみてないけどこれから使ってみようかと思っている。
第 3 部の内容 (Kotlin で Android アプリ開発) について、ほとんど知っているものだったので自分にとってはあまり意味はなかったのですが、Kotlin を使った Android アプリ開発がどんな感じか全然知らない人にとってはそれらも役立つと思います。
読書メモ
自分にとって気になった箇所と、それに関連する公式リファレンスへのリンク。
require
メソッド で満たすべき条件を記述できる。 (P31)- string template と raw string 50
List
型の値がイミューダブルとはかぎらない。List
型のサブクラスにImmutableList
があるので、ImmutableList
オブジェクトがList
型として渡される可能性がある。 (P54)List
以外のコレクションクラスも同様。
Range
のin
演算子で、値が範囲に含まれているかどうか調べられる。 (P55)- イテレータに何らかのインターフェイスを実装する必要はない。 規定のメソッドさえオペレータとして定義されていれば良い。 (P63)
- 可変長引数は
vararg
修飾子で宣言。 配列を渡すときには spread 演算子 (*
; アスタリスク) で展開。 (P73) - 末尾再起呼び出し最適化に
tailrec
修飾子。 (P76) - ローカル関数、関数定義の中に関数を定義できる。 (P77)
- インライン関数の引数としてインライン関数外で呼ばれうるラムダを受け取る場合は
noinline
修飾子を付ける。 (P94)- 修飾子を何もつけないと、インライン関数の実行コンテキストでの実行しかできない。 インライン関数の引数のラムダもインライン展開されるため。
- スタックトレースの内容に影響を受けるような関数も
noinline
にすることを検討すると良いとのこと。 - 参考 : Inline Functions - Kotlin Programming Language
- インライン関数の引数として別の実行コンテキストでインライン化されて実行されるラムダを受け取る場合は
crossinline
修飾子を付ける。 (P94)- これにより、非ローカルリターンが使えないことを呼び出し側に伝える。
- 参考 : Inline Functions - Kotlin Programming Language
- インライン展開されるラムダ式では非ローカルリターンが使える。 (P95)
- ラムダ式から脱出する場合はラベルへのリターン。 (P96)
- Kotlin にはラムダ式以外に無名関数もある。 ラムダと違い
return
で無名関数から脱出する。 (P97) - ラムダ式と無名関数をあわせて関数リテラルという。 (P97)
- 公開範囲は public と internal (同一モジュール内) と private と protected (Java とは違って同一パッケージからは見えない)。 (P138)
- 使用場所変位指定による型投影。 使用側で
in
またはout
修飾子を指定する。 (P163) - クラス宣言における型パラメータが共変の場合は
out
修飾子を、反変の場合はin
修飾子で宣言。 宣言場所変位指定。 (P165) - 型引数について何もわからない場合でもそのジェネリック型を使いたい場合にはスター投影。 (P167)
- インライン関数の型パラメータを具象型パラメータ (reified type parameter) にすることで実行時にその型を扱えるようになる。 (P168)
!!
演算子の代わりにrequireNotNull
メソッドを使うことで意図をメッセージで表現できる。 (P180)- 安全キャスト
as?
を使うと、キャストできないときはnull
になる。 (P183) - 参照の等価性と構造の等価性。 (P190)
- 言葉遣いが 「同一性」 と 「等価性 (同値性)」 じゃないんだなー、という部分がちょっと驚き。
- 参考 : Equality - Kotlin Programming Language
infix
キーワードのついた 1 引数のメソッドを中置表記で呼び出せる。 (P192)- 範囲を作る
..
も中置表記。 - 参考 : Functions - Kotlin Programming Language
- 範囲を作る
- 分解宣言 (destructuring declaration) には
operator
つきのcomponentN
メソッドが必要。 (P194)- データクラスは componentN も自動生成してくれる。 (P197)
- 参考 : Destructuring Declarations - Kotlin Programming Language
- 内部クラスには
inner
修飾子を付ける。 (P199) try
は式。 (P211)- レシーバ付き関数リテラルの型
A.(B)->C
は(A, B)->C
のサブタイプ。 (P214)
Dropwizard + JDBI で SQL オブジェクトの返り値に Optional を使うときには SingleValueResult アノテーションが必要
Dropwizard で SQL ライブラリ JDBI を使うときのおはなし。
OptionalContainerFactory
dropwizard-jdbi ライブラリは OptionalContainerFactory
クラスを提供してくれていて、JDBI の SQL オブジェクトで返り値に Java 8 で導入された Optional
指定することができます。
ちなみに普通に dropwizard-jdbi の DBIFactory#build
メソッドを使うと自動的に OptionalContainerFactory
を DBI
に登録してくれるので、自分で登録する必要はありません。 (Dropwizard 1.0.5 で確認。)
SingleValueResult
アノテーションが必要 (単に Optional
を指定するだけでは動かない)
SQL オブジェクトのクラス定義で返り値に Optional
を指定すればそれだけで動くのかと思いきや、実はそんなことはありません。 Optional
を返すメソッドに SingleValueResult
アノテーションを付ける必要があります。
import info.vividcode.app.web.example.dropwizard.domain.Person; import org.skife.jdbi.v2.sqlobject.SqlQuery; import org.skife.jdbi.v2.sqlobject.customizers.SingleValueResult; import java.util.Optional; public interface PersonDao { @SqlQuery("SELECT * FROM person LIMIT 1") @SingleValueResult(Person.class) Optional<Person> findOne(); }
ここら辺のドキュメントがないので、ソースコードを読んで確認しました。
- 返り値に応じた
ResultReturnThing
を生成する箇所 : jdbi/ResultReturnThing.java at 3fe1480fcc3c42be94d355f8c7335bd784dbbc13 · jdbi/jdbi · GitHub SingleValueResult
アノテーションがあるかどうかを検査している箇所 : jdbi/ResultReturnThing.java at 3fe1480fcc3c42be94d355f8c7335bd784dbbc13 · jdbi/jdbi · GitHub
Optional
を使う場合に限らず、Iterable
じゃなくてコンテナを使いたい場合は SingleValueResult
アノテーションを付ける必要がありそうですね。
関連ページ
MySQL Connector/J 5.1 系では useLegacyDatetimeCode=false にしよう
JDBC で MySQL に接続するときに使用する MySQL Connector/J (mysql:mysql-connector-java) の話。 サーバー・クライアントのタイムゾーン設定が違っている場合にどう対応するのがいいか。
結論
- MySQL Connector/J 6 (まだ開発版だけど) 以降は自動でやってくれるので気にする必要はない。
- MySQL Connector/J 5.1 では URL に
useLegacyDatetimeCode=false
を入れて、時刻周りの新しい処理が動くようにしろ。- 新しい処理では、タイムゾーンの変換を一貫性をもってやってくれるようになる。
- 『Use code for DATE/TIME/DATETIME/TIMESTAMP handling in result sets and statements that consistently handles time zone conversions from client to server and back again』
- 参考 : 5.1 Driver/Datasource Class Names, URL Syntax and Configuration Properties for Connector/J
- 5.1 系ではデフォルトでは互換のために新しい処理は動かないようになっているので、明示的に新しい処理を使うように URL で指定する必要がある。
- バージョン 5.1.6 で導入された機能なので、それより古いものでは使えない。
問題
そもそもどういう問題に遭遇したのか。
- Java のアプリケーションサーバーのタイムゾーンが JST。
- MySQL サーバーのタイムゾーンが UTC。
- Java アプリケーションから MySQL サーバーには MySQL Connector/J 5.1 系で接続。
- タイムゾーン周りのオプションは何も指定せず。
- SQL 文の
NOW()
関数やDEFAULT CURRENT_TIMESTAMP
で設定された時刻を Java アプリケーション側で取得すると、現在時刻から 9 時間前の時刻が返ってきた。 - → MySQL Connector/J がサーバー・クライアント間のタイムゾーン差を扱ってくれてない。
MySQL Connector/J とタイムゾーン
- もともとは
useTimezone
プロパティやserverTimezone
プロパティを使って対応する必要があった。 - MySQL Connector/J 5.1.6 で時刻周りの処理が書き直されて、
useLegacyDatetimeCode=false
することでタイムゾーン変換などを自動で扱ってくれるようになった。 - MySQL Connector/J 6 では
useLegacyDatetimeCode
プロパティを含め、古いタイムゾーン周りのプロパティは全部削除される。
おわり
タイムゾーンはライブラリ側がちゃんと面倒見てくれるだろう、と思って気にしなかったら、環境を変えて Java アプリケーションと MySQL サーバーのタイムゾーン設定がずれたときにいきなり想定しない動作になったりするので気を付けましょう。