わたねこコーリング

野良プログラマ発、日々のアウトプット

【AWS EC2】bash プロンプトにインスタンス名を表示する

インフラ屋の皆様、年末年始に向けたサーバ増強はお済でしょうか。そんな貴兄に EC2 関連の小ネタです。

スケールアウトなんかを目的としてクローン・サーバー・パターンを実施するとき、同じ AMI から立てたインスタンスだと bash のプロンプトもぜんぶ同じになっちゃうのですが、やっぱりこれはインスタンス毎に変えておきたい。でないと思わぬ操作ミスをしちゃいそうですもんね。

さて、どうするか。まず、起動したインスタンスで自分のメタデータ(インスタンスIDとか)を取得するには、こうすれば良いみたい。

Amazon EC2インスタンスの自身のMetadataを簡単に取得する

ふむふむ、

wget -q -O - http://169.254.169.254/latest/meta-data/instance-id

とすれば良いのですな(チョー簡単で嬉しいけどなんで生の IP なんだろ?)。

インスタンス名が判ればあとは AWS CLIインスタンスに付けた名前(タグの Name の値)を取得出来ますね。こんな感じ?

aws ec2 describe-instances --instance-ids <インスタンスID> --query "Reservations[*].Instances[*].[Tags]" --output table

これで問題は解決。perl で 上記出力からインスタンス名だけ抜き取って PS1 にセットすればよしっと。

export PS1="["$(/usr/bin/aws ec2 describe-instances --instance-ids $(/usr/bin/wget -q -O - http://169.254.169.254/latest/meta-data/instance-id) --query "Reservations[*].Instances[*].[Tags]" --output table | /usr/bin/perl -n -e 'print $1 if / Name \|\s*([^\s]+)/')" \W]\$ "

これを .bash_profile でも追記して完了! ムキになってワンライナーにしちゃいましたが、可読性が悪くていやんという場合は、

INSTANCE_ID=`/usr/bin/wget -q -O - http://169.254.169.254/latest/meta-data/instance-id`
MYNAME=`/usr/bin/aws ec2 describe-instances --instance-ids $INSTANCE_ID --query "Reservations[*].Instances[*].[Tags]" --output table | /usr/bin/perl -n -e 'print $1 if / Name \|\s*([^\s]+)/'`
export PS1="["$MYNAME" \W]\$ "

でも良いと思います。さあ、紅白歌合戦でも除夜の鐘でもどんと来い!(うそ、なるべく来ないで)。

「ブッシュマン・ワールド・ウクレレ・ヴィデオ・コンテスト」のこと

先日の記事に書いたように当方、「Beat Ukulele」というウクレレによるポップスカバー動画のキュレーションサービス(のようなもの)を運営していますが、そのネタを YouTube で漁っている時にタイトルや説明に「Bushman Ukulele Video Contest」というフレーズが入っているものに多々出会いまして。こりゃいったい何だろうということで、調べてみました。

ブッシュマン・ワールド・ウクレレ・ヴィデオ・コンテストとは?

どうやらこれ、インディアナポリス市にある Bushman Ukuleles というウクレレ屋さんが始めたウクレレ動画のコンテストのようです。ウェブサイトはこちらになりますが、オンラインショップを営みながらオリジナルブランドのウクレレも数本リリースしている模様。コンテストは2007年から始まっており、3度の休止はありましたが今年(2014年)も無事行われたようです。毎回100を超えるエントリーがあり、なかなか盛況なようです。

このウクレレ屋さん、ほんの10年程前まではハーモニカ専門店だったとかで、ここにあるウクレレショップに進出したいきさつが面白いのでチョウ訳してみます。

それは2003年の5月…(遠い目) ハーモニカショップを営んでいた僕らの元にホーナー社のラニカイ・ウクレレを取り寄せできないかいう引き合いが入った。「ホーナーはハーモニカ製造会社なのでウクレレは作ってませんよ?」とドヤ顔でアドバイスした僕らに、そのお客さんは「んなことあるかい! LU21 ってモデルを現に作っとるわい!」と逆切れ。ホーナーに確認してみたら、うっわー、本当だった! そこでお客さんと弦楽器好きな僕の父と、そしてお店の在庫用に3本のウクレレを取り寄せて、自分達のウェブページでも注文できるようにしておいたんだ。そうしたら驚いたことにそれが大当たりしちゃって、60件以上の注文が! それ以来僕らもウクレレに入れ込むようになっちゃったのね。そんなこんなで、その年のロードアイランド州でのウクレレ・エキスポに僕らもブースを出したんだけど、そこに80歳のおばあちゃんがやって来て、ちっちゃなソプラノ・ウクレレビートルズの「ハピネス・イズ・ア・ウォーム・ガン」をプレイしたんだYo! それを聴いて確信したのさ。「世界中でウクレレほどクールで、魅惑的なサウンドで、楽しい楽器は無い!」ってね。

何やらリーマン・ショック以前の絶好調だったアメリカの情景が垣間見えるようですがw、とにかく彼等のウクレレにかける熱い想いが伝わってきますな。

過去の優勝作品

ではこれまでの優勝動画を年代順に追って紹介しましょう。

【2007年】 「サヴァイヴァー (デスティニーズ・チャイルド)」


Survivor Destinys Child on Ukulele - YouTube
ご存知、R&B ガールズグループ「デスチャ」のヒット曲。チャキチャキ娘のジュリア・ニュネスちゃん、かわいい♡

【2008年】 「キラメキ☆ンー・バップ (ハンソン)」


Bushman World Video Ukulele Contest - MMMbop ...
世界中で大ヒットした兄弟ロック・バンド、ハンソンのデビュー作。小中学生くらいの少女達がはにかみながら… と思ってたら堂々としてて上手いのなんのw

【2010年】 「オールド・バザー・イン・カイロ (クリントン・フォード&ジョージ・チゾーム)」


Felukuleles &#39;Old Bazaar in Cairo&#39; - YouTube
カイロで働く4人組の作品で、個人的には一番突き刺さりますた。原曲はクリントン・フォード&ジョージ・チゾームという英国人ミュージシャンによる'60年代のものらしいです。

【2011年】 「ホェアー・ザ・サイドウォーク・エンズ (オリジナル)」


Shel Silverstein - Where the Sidewalk Ends ...
シェル・シルヴァスタインという作家による詩に、自作の曲を付けたものらしいです。組曲風になっていて、力量の凄さが伺えますな。

【2014年】 「アイ・ワント・ア・ブッシュマンウクレレ (オリジナル)」


I Want A Bushman Ukulele by Uke-A-Lady ...
ユーク・ア・レディという自らのユニットの自作曲。こいつら、おねだりしてるよ… 本当に身もフタもないったらwwww

上記優勝作品の他にも多くのエントリー作がここのリンクを辿って見られますので、どうぞ。

さて、来年は?

という訳で、来年の2015年は例年通りコンテストが開催されるのか? ウェブサイトには今のところ言及は見当たりませんが、注視していきたいと思います。日本人によるエントリーがあるかは確認していないのですが、ウデに覚えのある方は是非。そういえば、日本でも某最大手ウクレレブランドさんが隔年でウクレレ・コンテストを開催されていますが、こんな感じの動画コンテストもイイんじゃないですかね? 費用もそれ程かからないと思いますしw

file input を使わないでスマートな画像アップロードを実現する

今日は、ウェブプログラマの皆さんにはお馴染みの「画像アップロード」について。いまどきはウェブアプリでも画像登録機能なんてのが開発要件として普通にある訳ですが、これが結構古くて新しい問題というか厄介な代物です。勿論、file input (type 属性が file の input タグ)でちょちょいのちょいと実装するのはカンタンなんですが、それだと決して U/I 的には使い勝手がよくない訳ですよね。具体的には、

  • 画像ファイル選択の際にドラッグ & ドロップできない。
  • アップロードする前に画像のプレビューができない。
  • AJAX でのアップロードができない。

という所が今どき何とかならんかなぁと。HTML5 もやっと勧告が出たことだし、ここはひとつ気合入れて使い勝手のよい画像アップロード手法を考えてみるかぁ! と本気出してみましたw 説明は後にして、デモをご覧頂ければと(↓)。

https://labo.mariyudu.net/img4form/

アップロードするには、「No Image」となっているデフォルト画像の上に、適当なローカルファイル画像をドラッグ&ドロップしてアップロードボタンをクリックするだけです。画像が AJAX 経由でサーバにアップロードされ、そのリンクが表示されます。

仕掛けは大筋で以下のような感じ。

  1. D&D の際に FileReader インターフェースを使って hidden input の value 属性に画像のバイナリデータ(data:image/jpeg;base64,xxxx の形式)をセットする。
  2. アップロードボタンクリックで、上記 hidden input の内容をサーバに POST する。
  3. サーバ側では値の文字列をパースして、base64 デコードしてファイルに保存する。

とまぁ、仕組みはシンプルなもんです。画像上にボタンを配置する等、U/I として画像アップロードのイージーオペレーションを突き詰めてみたところを評価して頂ければと。まだ作ってみたばかりで汎用的に使えるか自信が無いのでデモに留めますが、業務等で揉んでみてモノになりそうだったら github デビューでもさせようかなー。

【AppleScript】TimeMachine バックアップ終了を待ってアンマウント・スリープさせる

Yosemite、リリースされましたねー。けど、仕事マシンなのでアップデートはしばらくガマンの Mariyudu@実は3ヶ月前にマーヴェリクスにアプデしたばっか です。

さて、マカならバックアップは TimeMachine で決まりでしょうが、自分的にはバックアップドライブを繋ぎっぱなしにして自動バックアップという使い方はせずに、一日の仕事の終わりにバックアップドライブの電源を入れて1回だけバックアップ、という使い方をしてます。理由は、

  • 仕事中にバックアップが始まると、そのディスクアクセスで作業のパフォーマンスが落ちてしまうのがイヤ。
  • 数時間単位での世代バックアップがそれ程必要ない(プログラマなので重要作成物の履歴管理はバージョン管理システムでやってるし)。
  • 何か作業している最中のバックアップは、ファイルの状態が中途半ばのままスナップショットとられるようで精神衛生上良くない。

てな感じです。で、仕事が終わるとバックアップさせておいてフロメシテレビみたいな感じなのですが、さてマク落として寝ようと言う時にタイミング悪く再度バックアップがかかっていたりするのが一寸困りもの。この不便を解消する為に、バックアップ終了を待ってバックアップドライブを取り出してからスリープさせる、という処理を AppleScript で書いてみました。電気代も節約できるしな!

main()

on main()
	-- 設定値
	set watchCycle to 15 -- バックアップ状態監視サイクル[秒]
	set watchDuration to 3600 -- バックアップ状態監視時間[秒]
	
	-- バックアップディスクのボリュームを調べる
	set perlScript to quoted form of "print $1 if /Mount Point   : (.+)$/"
	set distMountPoint to do shell script "/usr/bin/tmutil destinationinfo | /usr/bin/perl -ne " & perlScript
	if distMountPoint = "" then
		beep
		display dialog "バックアップボリュームが見つかりません。処理を終了します。" buttons {"OK"}
		return
	end if
	
	-- バックアップの終了を待つ
	display notification "バックアップ状態を監視します…"
	set limitTime to (current date) + watchDuration
	repeat
		set currentphase to do shell script "/usr/bin/tmutil currentphase"
		if currentphase = "BackupNotRunning" then exit repeat
		if limitTime < (current date) then
			display notification "監視時間が" & watchDuration & "秒を超えたので処理を終了します。"
			return
		end if
		delay watchCycle
	end repeat
	
	-- バックアップボリュームを取り出し
	display notification "バックアップが終了したようなので、ディスクを取り出してスリープします。"
	do shell script "diskutil eject \"" & distMountPoint & "\""
	tell application "Finder" to sleep
end main

使い方はカンタン。バックアップが始まったらこのスクリプトで生成したアプリを起動して、そっとその場を立ち去るだけですw あと、アンマウントおよびスリープの際には通知センターにメッセージを残すようにしてます。

短いスクリプトなので、処理の流れはコメントでだいたい判るかと。キモはバックアップのボリュームやステータス等の情報を取得するのに、tmutil というコマンドを使ってることくらいです(出力を整形するのに perl も組み合わせてますが)。

AppleScript は普段ほとんど書かないので、こんな書き方で良いのか自信ないですが、ご参考までに。

ポップスのウクレレカバー動画を毎日紹介するよ! 「Beat Ukulele」、はじめました

先日またひとつ齢を数えて秋風が身にしみる筈が今日はなんでか暑いでんなー、な Mariyudu@野良プログラマです。みなさん No Music No Life してまっか。

という訳で先日、また性懲りもなくサービスをひとつ始めました。YouTube の、ポップス(主に洋楽)ナンバーをウクレレでカバーしている動画のレコメンデーション・サービスです。題してBeat Ukulele。(↓)

f:id:mariyudu:20140930181728p:plain

きっかけは、「初めてのWebサービスを3日でつくってみた(Node.jsで)」というブログ記事を読んだこと。何を作るかより先に「3日でローンチ可能なサービスづくりをしてみる」というミッションを立てるのも面白いなー、と思った訳です。じゃぁ俺も動画紹介にすっか? おーそうだ、日頃面白いウクレレ動画なぞ見つけるとツイッターとかでダラダラ流してるけど、それをサービス化しちゃうか。原曲の情報も動画付きで付記してあげて… あ、収録アルバムも紹介すればアリフィエイトになるじゃん! とここまで考えた時点でワイヤーフレームを書き始めてましたw

自分はカナーリ年季の入った洋楽リスナーで「こんな良い曲があるんだけど、みんなに紹介したいなぁ」的な欲求は常に隠し持っているし、また、ウクレレというカジュアルな楽器でカバーを披露し合ったりしたいよねぇ(自分でもちょっとは弾くし)、という気持ちもあって、要は自分のライフスタイルをそのままサービスにしちゃったような感じですかな。

f:id:mariyudu:20140930185425p:plain

サービス構築は、前述のブログの方とは違って普通のレンタルサーバで普通に LAMP をゴリゴリ書いた感じなので、技術的なことには触れません。下記のプロダクト・サービスにお世話になったことを付記しておきます。

さて、コンテンツがスカスカなのは情けないので、まずは100本程たまるまで1日5本ペースでアップしていきますよ、と。

付記) 結局、サービス構築は3日に収まらず、5日弱程かかってしまいました… orz

※ BeatUkulele は 2021年12月にクローズしました。

お手軽ガントチャート「Quick Gantt」にタブ区切り編集機能を追加しますた

先般「『タスクリストをガントチャートに一発変換!』な Quick Gantt、作りました」で公開した Quick Gantt ですが、タスク一覧をタブ区切りテキストで編集できるように機能追加しました。いちおうインラインでセル毎に編集は出来てたんですが、やっぱりテキストエディタスプレッドシートからコピペしたいことが多いので。

タスク一覧上の「TSV で編集」ボタンをクリックするとダイアログが表示されて、その中のテキストボックスで編集したりコピペできます(↓)。
f:id:mariyudu:20140821122813p:plain

MySQL データベースからテーブル定義書を生成する

ネクタイ締めて SE らしきものをやってた頃はコードよりドキュメントのほうを山のように書いてたもんですが、限りなくプータローに近いフリーの身になってからはそんな苦行も今は昔… と言いつつ、タマに「DB の仕様書下さい」「ダンプした DDL でいいっすよね」「…え?」「え?」てなこともあります。

てな訳で、既存の MySQL データベースをソースに、よくあるテーブル定義書を生成するのが今日のお題。車輪の再発明を避けるべくグーグル先生に相談してみたら SQL::Translator という、様々な DBMSSQL をこれまた様々なフォーマットに変換する、正にうってつけの CPAN モジュールがあったので、これを使ってみます。全体的には

  1. mysqldump でテーブル定義を SQL 出力
  2. SQL::Translator を使って SQL から XML に変換
  3. XSLTXML をテーブル仕様書 HTML に変換

という手順をとります。

まずは DB からテーブル構造をダンプ。

$ mysqldump -u hoge -pXXXXXX --no-data sample_db > sample.ddl.sql

ダンプした SQL はこんなん(↓)だとします。テーブルや列には論理名となるコメントが付けてあることを前提にしてます。

--
-- データベース: `sample_db`
--

-- --------------------------------------------------------

--
-- テーブルの構造 `persons`
--

CREATE TABLE IF NOT EXISTS `persons` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'レコードID',
  `name` varchar(50) NOT NULL COMMENT '氏名',
  `address` varchar(100) NOT NULL COMMENT '住所',
  `phone` varchar(20) NOT NULL COMMENT '電話番号',
  `email` varchar(50) NOT NULL COMMENT 'Eメール',
  `created` datetime NOT NULL COMMENT '登録日時',
  `modified` datetime NOT NULL COMMENT '最終更新日時',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='住所録' AUTO_INCREMENT=1 ;

で、SQL::Translator を使って SQLXML に変換する簡単なスクリプト sql2xml.pl (↓)を作って、これを実行。

#!/usr/bin/perl
use strict;
use SQL::Translator;

my @data = <STDIN>;
my $t = SQL::Translator->new(
	from           => 'MySQL',
	to             => 'XML-SQLFairy',
	data           => join("\n", @data),
	show_warnings  => 1,
);
print $t->translate;
$ perl sql2xml.pl < sample.ddl.sql > sample.ddl.xml

はい、SQL がこんな XML に変換されますた。

<?xml version="1.0" encoding="UTF-8"?>
<!-- 
Created by SQL::Translator::Producer::XML::SQLFairy
Created on Fri Jul 18 19:29:19 2014
 -->

<schema name="" database="" xmlns="http://sqlfairy.sourceforge.net/sqlfairy.xml">
  <extra />
  <tables>
    <table name="persons" order="1">
      <extra />
      <fields>
        <field name="id" data_type="int" size="10" is_nullable="0" is_auto_increment="1" is_primary_key="1" is_foreign_key="0" order="1">
          <extra unsigned="1" />
          <comments>レコードID</comments>
        </field>
        <field name="name" data_type="varchar" size="50" is_nullable="0" is_auto_increment="0" is_primary_key="0" is_foreign_key="0" order="2">
          <extra />
          <comments>氏名</comments>
        </field>
        <field name="address" data_type="varchar" size="100" is_nullable="0" is_auto_increment="0" is_primary_key="0" is_foreign_key="0" order="3">
          <extra />
          <comments>住所</comments>
        </field>
        <field name="phone" data_type="varchar" size="20" is_nullable="0" is_auto_increment="0" is_primary_key="0" is_foreign_key="0" order="4">
          <extra />
          <comments>電話番号</comments>
        </field>
        <field name="email" data_type="varchar" size="50" is_nullable="0" is_auto_increment="0" is_primary_key="0" is_foreign_key="0" order="5">
          <extra />
          <comments>Eメール</comments>
        </field>
        <field name="created" data_type="datetime" size="0" is_nullable="0" is_auto_increment="0" is_primary_key="0" is_foreign_key="0" order="6">
          <extra />
          <comments>登録日時</comments>
        </field>
        <field name="modified" data_type="datetime" size="0" is_nullable="0" is_auto_increment="0" is_primary_key="0" is_foreign_key="0" order="7">
          <extra />
          <comments>最終更新日時</comments>
        </field>
      </fields>
      <indices></indices>
      <constraints>
        <constraint name="" type="PRIMARY KEY" fields="id" reference_table="" reference_fields="" on_delete="" on_update="" match_type="" expression="" options="" deferrable="1">
          <extra />
        </constraint>
      </constraints>
      <comments>
        <comment>住所録</comment>
      </comments>
    </table>
  </tables>
  <views></views>
  <triggers></triggers>
  <procedures></procedures>
</schema>

あとはこの XML をお好みにドキュメント変換するだけ。ここでは HTML に XSLT 変換します。XSL (2html.xsl)はこんな感じ(↓)。

<?xml version="1.0" encoding="utf8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:s="http://sqlfairy.sourceforge.net/sqlfairy.xml">
	<xsl:output method="html" encoding="utf8" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"/>

	<xsl:template match="/s:schema">
		<html lang="ja">
			<head>
				<meta charset="utf-8"/>
				<title>データベース テーブル定義</title>
				<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"/>
				<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"/>
				<style>
					table.htable {
						margin: 3em auto 1em auto !important;
					}
					table.htable th {
						border-left: 10px solid #e5e5e5 !important;
					}
					footer {
						border-top: 1px solid #e5e5e5;
						padding: 0.5em;
					}
				</style>
			</head>

			<body>
				<div class="container">
					<h1 class="page-header">データベース テーブル定義</h1>
					<xsl:apply-templates select="s:tables"/>
				</div>
				<footer class="text-center">
					mariyudu.net
				</footer>
			</body>
		</html>
	</xsl:template>

	<xsl:template match="s:table">
		<table class="table table-bordered htable">
			<tbody>
				<tr class="active">
					<th>テーブル名</th>
					<td><xsl:value-of select="s:comments"/></td>
				</tr>
				<tr class="active">
					<th>スキーマ</th>
					<td><xsl:value-of select="@name"/></td>
				</tr>
			</tbody>
		</table>
		<table class="table table-condensed">
			<thead>
				<tr>
					<th class="text-right">#</th>
					<th>論理名</th>
					<th>物理名</th>
					<th></th>
					<th class="text-right">長さ</th>
					<th>主キー</th>
				</tr>
			</thead>
			<tbody>
				<xsl:apply-templates select="s:fields"/>
			</tbody>
		</table>
	</xsl:template>

	<xsl:template match="s:field">
		<tr>
			<td class="text-right"><xsl:value-of select="@order"/></td>
			<td><xsl:value-of select="s:comments"/></td>
			<td><xsl:value-of select="@name"/></td>
			<td><xsl:value-of select="@data_type"/></td>
			<td class="text-right"><xsl:if test="@size!=0"><xsl:value-of select="@size"/></xsl:if></td>
			<td><xsl:if test="@is_primary_key!=0"><span class="glyphicon glyphicon-ok"></span></xsl:if></td>
		</tr>
	</xsl:template>

</xsl:stylesheet>
$ xsltproc -o sample.ddl.html 2html.xsl sample.ddl.xml

お疲れさま。出来たのがこんな HTML のテーブル定義書です。
f:id:mariyudu:20140718201849p:plain

ER 図とかは MySQL Workbench が便利かも。ネクタイの頃とはツール類が段違いすぐる… まぁ、ドキュメントなんて古くて新しい悩みですが、巨人の肩に乗っかってカジュアルに片付けたいもんですな。

2015-2-1 付記 : MySQL ではもっとカンタンな方法があることが判ったので続編記事を書きました → 「続・MySQL データベースからテーブル定義書を生成する