(1)はこちら 、( 2)はこちら から。
データベースのマイグレーション
狭義のInfrastructure as Codeには含まれないかもしれませんが、オペレーションのコード化という意味では、データベースのマイグレーションの実施も立派なオペレーションです。そのために役立つモジュールは、CPANにもいくつか公開されています。本節では、DBIx::Schema::DSLとSQL::Translator::Diffを利用した、データベースのマイグレーション方法について解説します。
なお、データベースのマイグレーションを実現するモジュールとしては、ほかにもGitDDLやGitDDL::Migratorなどが存在します。データベースのマイグレーションについて考えるときは、これらのモジュールも参考にするとよいでしょう。
スキーマをPerlのDSLで表現する──DBIx::Schema::DSL
DBIx::Schema::DSLは、データベースのスキーマをPerlのDSL(Domain Specific Language 、ドメイン特化言語)で記述できるモジュールです。このモジュールは、DSLで定義したデータベースのスキーマをMySQLやSQLiteなどの各種RDBMS(Relational Database Management System )のDDL(Data Definition Language )に変換できるだけでなく、SQL::Translatorのオブジェクトに変換できます。これを次項で紹介するSQL::Translator::Diffと組み合わせると、DBIx::Schema::DSLで定義したスキーマと、現在のRDBMSのスキーマの差分の取得などを簡単に実装できます。
リスト6 は、DBIx::Schema::DSLを利用したデータベースのスキーマの例です。book
というテーブルと、このテーブルに含まれるid
とname
というカラムを定義しています。id
カラムはプライマリキーでかつオートインクリメントが、name
カラムはNOT NULL制約が、それぞれ指定されています。
リスト6 DBIx::Schema::DSLを利用したスキーマ定義
package My::Schema;
use DBIx::Schema::DSL;
create_table 'book' => columns {
integer 'id', primary_key, auto_increment;
varchar 'name', not_null;
};
1;
DBIx::Schema::DSLを利用して定義したスキーマからDDLを取得する場合、次のようなスクリプトを実装するとよいでしょう。
use My::Schema;
print My::Schema->output;
このスクリプトを実行すると、次のようなDDLを取得できます(コメント部分以外を抜粋しています) 。
SET foreign_key_checks=0;
CREATE TABLE `book` (
`id` INTEGER NOT NULL auto_increment,
`name` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8;
SET foreign_key_checks=1;
なお、このDDLはリスト6でRDBMSの指定をしていないので、DBIx::Schema::DSLのデフォルトであるMySQL向けのDDLが生成されます。ほかのRDBMSのDDLを生成したい場合、次のようにスキーマ定義時にdatabase
を利用してRDBMSを指定しなければなりません。次のコードでは、RDBMSとしてSQLiteを指定しています。
package My::Schema;
use DBIx::Schema::DSL;
database 'SQLite';
このほかDBIx::Schema::DSLでは、任意のカラムに対する制約や外部キーなど、さまざまな設定をDSLで定義できます。詳しくは、DBIx::Schema::DSLのドキュメントを参照してください。
スキーマの差分を取得する──SQL::Translator::Diff
先述したとおり、DBIx::Schema::DSLで定義したスキーマは、SQL::Translatorのオブジェクトに変換できます。そしてSQL::Translatorは、SQL::Translator::Diffを利用することで、任意の2つのSQL::Translatorオブジェクトの差分を取得できます。これを利用した、スキーマの差分の取得とマイグレーションの実行を行うスクリプトの例がリスト7 です。
リスト7 (1) は、DBIx::Schema::DSLを利用してスキーマを定義したMy::Schemaから、SQL::Trasnaltorのオブジェクトを取得するコードです。さらにSQL::Translatorは、リスト7 (2) に示すコードで任意のデータベースに接続し、そのデータベースの現在のスキーマ情報をSQL::Translatorのオブジェクトとして取得できます。
リスト7 スキーマの差分表示とマイグレーションのスクリプト例
use DBI;
use SQL::Translator;
use SQL::Translator::Diff;
use My::Schema;
# DBIx::Schema::DSLで定義したスキーマの取得
my $target = My::Schema->translator();
# データベースからのスキーマの取得
my $dbh = DBI->connect( ... );
my $source = SQL::Translator->new(
parser => 'DBI',
parser_args => { dbh => $dbh },
)->translate();
# スキーマの差分の取得
my $diff = SQL::Translator::Diff->new({
output_db => 'MySQL',
target_schema => $target->schema(),
source_schema => $source,
})->compute_differences->produce_diff_sql;
# 差分の適用(マイグレーション)
for my $stmt (split /;/, $diff) {
next unless $stmt =~ /\S/;
$dbh->do($stmt) or die $dbh->errstr();
}
これで、2つのSQL::Translatorのオブジェクトを取得できました。次に、SQL::Translator::Diffを利用して、この2つのオブジェクトの差分を取得します。リスト7 (3) は、DBIx::Schema::DSLから取得した$target
と、SQL::Translatorを利用してRDBMSから取得した$source
という2つのSQL::Translatorのオブジェクトを利用して、データベースのスキーマの差分を取得するコードです。
SQL::Translator::Diffは、source_schema
で与えた現在の状態のスキーマが、target_schema
で与えたあるべき状態のスキーマになるために必要な変更(ALTER TABLE
やCREATE TABLE
などのクエリの実行)を差分として表示します。
そのため、得られたクエリをRDBMSに対して直接適用したり、あるいはリスト7 (4) に示すコードでPerlからクエリを実行すれば、データベースのマイグレーションを行うことができます。
とはいえ、SQL::TranslatorやSQL::Translator::Diffを利用してマイグレーションのしくみを構築するのであれば、これらのモジュールがどの程度信頼できるかを考慮しなければなりません。一例として、マイグレーションを自動的に実行するのではなく、あらかじめ実行するクエリを確認できるようなマイグレーションフローを構築するという方法もあるでしょう。
チャットツールへの通知
Infrastructure as Codeを実施するにあたり、チャットツールへの通知は重要な要素です。たとえば、ここまで紹介してきたIaaSの操作やデータベースのマイグレーションを実施する際、その進捗や成否をチャットツールに自動で通知できれば、オペレーションの様子をチャットツールを通してチーム全員に共有できます。
本節では、最近利用者が増えているチャットツールのHipChatとSlackのための通知モジュールの利用方法を紹介します。
HipChatへの通知──WebService::HipChat
リスト8 は、WebService::HipChatを利用したHipChatへの通知のコードです。
リスト8 HipChatへの通知のスクリプト例
use WebService::HipChat;
# WebService::HipChatのオブジェクト生成
my $hc = WebService::HipChat->new(
auth_token => 'token',
);
# HipChatへの通知の実施
$hc->send_notification($room, {
color => 'green',
message => 'hello!',
});
まず、リスト8 (1) でWebService::HipChatのオブジェクトを生成しています。このとき、auth_token
でHipChatのAPIトークンを与える必要があります。注意点として、HipChatにはAPI v1とAPI v2という2種類のAPIがあり、それぞれ異なるトークンを取得できます。WebService::HipChatはAPI v2に対応したAPIクライアントですので、API v2のトークンを生成して与えるようにしましょう。
実際の通知の実施は、リスト8 (2) のようにsend_notification
メソッドで行います。第1引数には通知を行うHipChat上のルームのAPI IDを、第2引数にはハッシュリファレンスで通知内容を設定します。ここでは、メッセージの色を緑色で、メッセージとしてhello!
という文字列を通知しています。
Slackへの通知──WebService::Slack::WebApi
一方、Slackに通知を行うためのモジュールとしては、CPANにWebService::Slack::WebApiが公開されています。リスト9は、このモジュールを利用してSlackに通知を送るコードです。
HipChatの例と同じく、リスト9 (1) でtoken
を与えてWebService::Slack::WebApiのオブジェクトを生成し、リスト9 (2) でメッセージを送信しています。メッセージを送信する際は、メッセージの通知先となるチャンネルを指定するchannel
と、メッセージ本文のtext
が必須です。
リスト9 Slackへの通知のスクリプト例
use WebService::Slack::WebApi;
# WebService::Slack::WebApiのオブジェクト生成
my $slack = WebService::Slack::WebApi->new(
token => 'token',
);
# Slackへの通知の実施
$slack->chat->post_message(
channel => 'channel id',
text => 'hello!',
);
まとめ
今回は、PerlでInfrastructure as Codeを構築する際に役立つモジュールを紹介しました。ここで紹介したモジュール以外にも、CPANにはInfrastructure as Codeに役立つモジュールがたくさん公開されています。これらのモジュールを駆使して、ぜひPerlを使ったInfrastructure as Codeを楽しんでください。
さて、次回の執筆者は丸山晋平さんで、テーマは「Perlで作るシステム運用ツール」です。お楽しみに。