読者です 読者をやめる 読者になる 読者になる

Amazon 互換 API を超簡単に作れる sinatra エクステンションを作った

一見釣りエントリっぽいタイトルのようでごく一部の人にしか刺さらない感が満載ですが、タイトル通りの sinatra エクステンションを作成して公開しました。

gem install sinatra-ace でインストールできます。(ace というのは Amazon Compatible Environments の略で、Transcend Computing | Amazon Compatible Environment で使われていたのをそのまま使っている感じです。)

下記のようなコードを書いて ruby app.rb するだけで、

require 'sinatra'
require 'sinatra/ace'

action 'DescribeDreams' do
  response_xml do |xml|
    xml.Dreams do
     %w(NiceDream Nightmare DayDream).each {|member| xml.member member }
    end
  end
end

dispatch!

下記のような AWS っぽいたいへんな感じの XML を返却できます。

$ curl "http://localhost:4567/?Action=DescribeDreams"
<?xml version="1.0" encoding="UTF-8"?>
<DescribeDreamsResponse>
  <DescribeDreamsResult>
    <Dreams>
      <member>NiceDream</member>
      <member>Nightmare</member>
      <member>DayDream</member>
    </Dreams>
  </DescribeDreamsResult>
  <ResponseMetadata>
    <RequestId>3f5a54f4-2781-4903-98e4-8977cdc184ef</RequestId>
  </ResponseMetadata>
</DescribeDreamsResponse>

Version パラメーターによる挙動の切り分けも簡単に行えます。

require 'sinatra'
require 'sinatra/ace'

version '2014-06-18' do
  action 'GetMessage' do
    response_xml do |xml|
      xml.Message 'old version'
    end
  end
end

version '2014-07-12' do
  action 'GetMessage' do
    response_xml do |xml|
      xml.Message 'new version'
    end
  end
end

dispatch!
$ curl "http://localhost:4567/?Action=GetMessage&Version=2014-06-18"
<?xml version="1.0" encoding="UTF-8"?>
<GetMessageResponse>
  <GetMessageResult>
    <Message>old version</Message>
  </GetMessageResult>
  <ResponseMetadata>
    <RequestId>d98216a5-19bc-476c-99ab-ea377c284a9b</RequestId>
  </ResponseMetadata>
</GetMessageResponse>
$ curl "http://localhost:4567/?Action=GetMessage&Version=2014-07-12"
<?xml version="1.0" encoding="UTF-8"?>
<GetMessageResponse>
  <GetMessageResult>
    <Message>new version</Message>
  </GetMessageResult>
  <ResponseMetadata>
    <RequestId>0c7085ba-f4d5-4d1f-928b-0971e85e57ee</RequestId>
  </ResponseMetadata>
</GetMessageResponse>

Amazon SQS のようにリクエストパスの概念があるシステムも記述することができるのですが、この機能については q3/lib/q3.rb#L60 あたりを見ると使い方が分かると思います。

自分で作りたいもので必要がでてきたら、認証機能とか最近の AmazonJSON っぽい API にも対応していきたいと思います。
たまには REST ではなく Amazon 互換っぽいインタフェースでオレオレ API を作ってみると、荘厳な感じになっておもしろいんじゃないかと思います。

250 行ぐらいの Amazon SQS 互換 API を作ってエンドポイントを公開した

redis の勉強も兼ねて、redis + sinatra250 行ぐらいの Amazon SQS 互換 API を作ってみた。本当は 100 行ぐらいで作りたかったんだけど、色々機能を足していたら 250 行ぐらいになってしまった。

250 行なのでバリデーションをあまりしていなくて、異常系はあまり動かないけど、正常系はだいたい動くと思う。

Wiki みたいに誰でも手紙を送ったり受け取ったりできるメッセージキューシステムがあるとおもしろいだろうなと思っていてたので、認証が要らず誰でもキューを作成したり、キューに対してメッセージを送信・受信したりできるようにしてある。

heroku + redis to go に公開しているので、

http://q3-global.herokuapp.com/?Action=CreateQueue&QueueName=tily.hatenablog.com

とかやるとキューを作れるし、

http://q3-global.herokuapp.com/*/tily.hatenablog.com?Action=SendMessage&MessageBody=hello

とかやるとキューに対してメッセージを送信できるし、

http://q3-global.herokuapp.com/*/tily.hatenablog.com?Action=ReceiveMessage

とかやるとメッセージを受信できる。

基本機能の統合テストを書いたので、割とちゃんと動くと思う。メッセージを遅延させるやつ (DelaySeconds) とか、VisibilityTimeout も普通に使える。

Amazon SQS と互換しているので、Amazon SQS 互換のクライアントからなら自由にメッセージを送受信できるはず。

q3-global は何の役に立つかよく分からないので、これから使い方を考える。ローカルに redis さえ立ち上がっていれば、gem install q3 して q3 コマンドを打つだけで気軽に API を立ち上げることができるので、よかったら使ってみてください。

AWS Simple Icons のセキュリティグループの赤黒の囲みを CSS で再現してみた

非常に地味な話なんですが、AWS Simple Icons ではセキュリティグループを赤と黒のボーダーによる枠線で囲むことになっており、シンプルでかっこいいので HTML+CSS で実現できないかなーと思って色々試していたらそれっぽいものができたので書いておきます。こんな感じのやつ。

security group

ソースは上記リンクのページに載っています。CSS に詳しくないので他のスタイルシートと組み合わせるとうまく描画されないとか色々あるかも。昔から CSS 苦手なので勉強したいと思った。

ニフティクラウドの情報取得系 API を RESTful なインタフェースで利用できるようにする Sinatra アプリ

ニフティクラウドの APIAWS 互換なのですが、レスポンスの形式が独特で少々扱いづらいので、REST っぽいインタフェースから情報取得できるようにしてみました。

/computing/instances でサーバー一覧がとれたりするので、Backbone.js の Collection から使ったりすると便利なんじゃないかと思います。

ひまなときにニフクラ RDB/MQ/ESS/DNS/Automation にも対応したい。

追記 (2014/06/27)

現在のバージョンで v0.0.3 で RDB/MQ/DNS に対応しています。

(きこえる) CIDR アドレス計算ツール

(きこえる) CIDR アドレス計算ツール by tily

ソース: tily/cidrcalc

仕事で必要になったとき、(今さら)CIDRアドレス計算ツール by yamagata21 にお世話になっていたんだけど、IPをそのままコピペできない点とかがやや不便だったので、勉強がてらに自分がほしい感じの CIDR アドレス計算ツールを作った。下記が工夫した点です。

  • オクテット毎の入力ではなく IP アドレスをそのままペーストできる
  • クライアントサイドだけで完結しているのでサーバーサイドに IP アドレスを送らなくていい
  • ボタンをおさなくても正しい IP アドレスを入力すれば結果が反映される
  • パーマリンクをはれる
  • 8 進数・16 進数・整数の表示は必要になることが少ないので思い切って削った

あと、どうせなら何か機能を追加しようと思い、2 進数にした IP アドレスを 32 分音符に見立てて、音として聴ける機能を追加してみた。Web Audio API を使っているのでそれなりにちゃんと聴こえるのではないかと思います。10. ではじまる IP アドレス、192.168. ではじまる IP アドレス、172. ではじまるIP アドレスぐらいは聴き分けられそうでおもしろい。

ボタン一発で @nifty ID を切り替える Google Chrome 拡張 Nifty Id Switcher

インストール:Chrome Web Store - nifty id switcher
ソース:tily/nifty-id-switcher

http://i.gyazo.com/5d65486bcb1a10b5f67f0382a6f8423b.png
http://i.gyazo.com/b1187b69dd3b2415f124ff8536b05e25.png


ものすごくニッチな感じの Google Chrome 拡張を作りました。
ニフティクラウドで複数のアカウントを使い分けている人とかにおすすめです。
本当に基本的な機能しか実装しておらず、デザインも適当なのでプルリクをお願いします。

  • 個人の製作物でありニフティ株式会社とは一切関係ありません
  • パスワードを含む @nifty ID アカウント情報を Google Chrome のローカルストレージへ保存します、自己責任でご利用ください

追記:ログアウトのロジックが足りないのとか、もろもろ不具合に気づいたので近日中に直します。

Chef のレシピから serverspec のテストを自動生成する chef-serverspec-handler という gem を作ってみた

『Chef のレシピは「こうあるべき」を記述するものだから、レシピからテストが自動生成できるべきだよな』とずっと思っていたんだけど、最近触りはじめた serverspec がシンプルで簡単に自動生成できそうなのでやってみた。

使い方は上記リンクに書いてある通りなのですが、たとえば Chef のレシピにこう書いてあるやつを、

template '/var/tmp/template.txt' do
  source 'template.txt.erb'
  mode 0777
  owner 'root'
  group 'root'
  variables(:val1 => 'val1', :val2 => 'val2', :val3 => 'val3')
  action :create
end

このような serverspec のテストに自動変換してくれます。

context file('/var/tmp/template.txt') do
  it {
    should be_file
    should be_mode 777
    should be_owned_by 'root'
    should contain 'val1'
    should contain 'val2'
    should contain 'val3'
  }
end

(もっと詳しくは 入力例出力例 を参照。)

この形がよいのかどうかはよく分からないけど Chef の Handler として実装してあり、--why-run オプションと組み合わせて使うことを想定しています。

コンセプトコードみたいなものなので、ちゃんと動かないところがたくさんあるかも。というか試しに Opscode コミュニティの wordpress クックブック + ニフティクラウドの CentOS 6.3 64bit Plain サーバーで試したら、自動生成された 77 テスト中 4 つのテストが失敗した。

Failures:                                                                                                                                                                  [18/829]

  1) apache2::default Package "apache2" 
     Failure/Error: it { should be_installed }
       rpm -q apache2
       パッケージ apache2 はインストールされていません。
       expected Package "apache2" to be installed
     # ./spec/localhost/apache2/default_spec.rb:5:in `block (3 levels) in <top (required)>'

  2) apache2::mod_php5 Package "php package" 
     Failure/Error: it { should be_installed }
       rpm -q php\ package
       パッケージ php package はインストールされていません。
       expected Package "php package" to be installed
     # ./spec/localhost/apache2/mod_php5_spec.rb:9:in `block (3 levels) in <top (required)>'

  3) mysql::server File "/etc/my.cnf" 
     Failure/Error: should contain 'false'
       grep -q -- false /etc/my.cnf
       expected File "/etc/my.cnf" to contain "false"
     # ./spec/localhost/mysql/server_spec.rb:73:in `block (3 levels) in <top (required)>'

  4) wordpress::default File "/etc/httpd/sites-available/wordpress.conf" 
     Failure/Error: should contain '{:template=>"wordpress.conf.erb", :enable=>true, :docroot=>"/var/www/wordpress", :server_name=>"localhost", :server_aliases=>["localhost"], :na
me=>"wordpress"}'
       grep -q -- \{:template\=\>\"wordpress.conf.erb\",\ :enable\=\>true,\ :docroot\=\>\"/var/www/wordpress\",\ :server_name\=\>\"localhost\",\ :server_aliases\=\>\[\"localhost\"
\],\ :name\=\>\"wordpress\"\} /etc/httpd/sites-available/wordpress.conf
       expected File "/etc/httpd/sites-available/wordpress.conf" to contain "{:template=>\"wordpress.conf.erb\", :enable=>true, :docroot=>\"/var/www/wordpress\", :server_name=>\"l
ocalhost\", :server_aliases=>[\"localhost\"], :name=>\"wordpress\"}"
     # ./spec/localhost/wordpress/default_spec.rb:44:in `block (3 levels) in <top (required)>'

1,2 は CentOS なのに Debian/Ubuntu のパッケージをインストールしようとしているのでレシピが悪いように思うのですが、
3,4 は chef-serverspec-handler が template リソースの variables で指定されたハッシュの値を単純に should contain しているのがダメで、そもそも variables は単純な値の埋め込み以外にも true/false を渡してテンプレートの内容を切り分けるような用途にも使うので、テンプレートの内容を論理的に解析する必要があり、対応するのがむずかしそうに思った。

というようにマダマダな感じなのですが、既存のレシピ資産にテストを書く足がかりにはなると思うので、よかったらお試しください。