銀の弾丸

プログラミングに関して、いろいろ書き残していければと思っております。

DynamoDB:条件式のプレースホルダを自動生成してみましょう

コンソールから AWSを操作するコマンドセットを提供するNodeモジュール(npm)のご紹介。 DynamoDBのクエリやスキャンでプレースホルダーを自動生成するAPIも提供してます。

f:id:takamints:20160604133023p:plain

DynamoDBから条件付きでQueryやScanを行う場合、条件式等の中で使われている単語がDynamoDBのキーワード(予約語)と一致する場合、その単語をプレースホルダーに変換して、別途指定しなければなりません。

プレースホルダーは2種類あります。属性名を置き換える属性名のプレースホルダと、検索条件等で指定する値を置き換える値のプレースホルダで、それぞれ別の対応が必要です。DynamoDBのキーワードの数はかなり多く、全部覚えていられないし、一般的な単語がたくさん含まれてるので厄介なんです。

てなことで、怒りに任せて、条件式をテーブルの属性名や値をそのまま使って記述してDynamoDBからクエリできるnode.jsのコマンド群をnpmとして公開しているのでご紹介。DynamoDB関係以外のコマンドセットも含まれています(Lambda, API Gateway, IoT, IAM等)。 コンソールからデータの有無や内容を、軽く確認する時に、ちょっと便利。

最新バージョン(v0.8.6以降)では、DynamoDBをSQLで扱うためのステートメントクラスも使えるようになりました。 これについては、以下の記事で説明してます。

takamints.hatenablog.jp

npmは以下↓からどうぞ。

www.npmjs.com



DynamoDBのプレースホルダを気にせず使える3つのコマンド

  1. aws-dynamodb-put-item - 項目の追加と更新
  2. aws-dynamodb-query - 項目のクエリ
  3. aws-dynamodb-scan - 項目のスキャン

AWS CLIのデフォルトユーザー、デフォルトリージョンで接続します。

セットアップ

npmでグローバルにインストールしてください。

$ npm install aws-node-util --global

1. aws-dynamodb-putItem - 項目追加・更新

テーブルに項目を追加、または更新します。item-expressionで指定したキーがすでにあるなら上書きされ、なければ追加されます。

aws-dynamodb-put-item [options] <tableName> <item-expression>

パラメータ

  • tableName - 操作対象のテーブル名

  • item-expression - 追加・更新する項目を属性名=属性値,属性名=属性値という形式で記述します。

項目には、少なくともテーブルの全てのキー属性が含まれていなくてはなりません。キーの値によって項目が追加されるか更新されるかが決まるからです。これはDynamoDBの仕様です。

属性名と属性値のプレースホルダーは自動的に生成されるので、気にする必要はありません。

実行例

$ aws-dynamodb-put-item stars "mainStar = 'SUN',
    role='planet', orbitOrder=3,
    name='EARTH', mass=5.97, diameter=12756, density=5514,
    gravity=9.8, escapeVelocity=11.2, rotation=23.9";
OK.

$ aws-dynamodb-put-item stars "mainStar = 'EARTH',
    role='satellite', orbitOrder=1,
    name='MOON', mass=0.0073, diameter=3475, density=3340,
    gravity=1.6, escapeVelocity=2.4, rotation=655.7";
OK.

$

値の型

属性値は、文字列、数値、ブーリアンの3つの型に対応しています。 文字列は引用符でくくられている必要があり、ブーリアンtruefalseのどちらかです。

MAP型のデータを表現するには

MAP型のデータは、属性名をドットで区切ってpath.to.the.subitemという形式で記述します。これによって、指定されたキーの名前を持つMAP型のデータを自動生成します。

2. aws-dynamodb-query - 項目のクエリ

キーを指定してテーブルから項目を抽出します。

aws-dynamodb-query [options] <tableName> <keyConditionExpression>

オプション

オプション 長いオプション 説明
-p --projection-expression=ARG 表示する属性名をカンマ区切りで指定
-f --filter-expression=ARG 検索後のフィルター条件式
-c --max-items=ARG 表示する件数(既定値は20)
-s --sort-item=ARG 表示時に並び替える項目名を指定
-d --desc 降順の並び替えを指定

パラメータ

  • tableName - 操作対象のテーブル名
  • keyConditionExpression - 抽出するキーの条件式を与えます。

実行例

$ aws-dynamodb-query stars 'mainStar="SUN"'\
    --projection-expression 'name,orbitOrder,mass,diameter,
        gravity,density,rotation'\
    --sort-item orbitOrder
Count: 9
ROWNUM mass      rotation name    gravity orbitOrder density diameter
     1    0.33     1407.6 MERCURY     3.7          1    5427     4879
     2    4.87    -5832.0 VENUS       8.9          2    5243    12104
     3    5.97       23.9 MARS        9.8          3    5514    12756
     4    0.642      24.6 MARS        3.7          4    3933     6792
     5 1898.0         9.9 JUPITER    23.1          5    1326   142984
     6  568.0        10.7 SATURN      9.0          6     687   120536
     7   86.8       -17.2 URANUS      8.7          7    1271    51118
     8  102.0        16.1 NEPTUNE    11.0          8    1638    49528
     9    0.0146   -153.3 PLUTO       0.7          9    2095     2370
ScannedCount: 9

$

上記表形式でのコンソール出力は、以下の記事でご紹介している npm list-itを利用しています。

takamints.hatenablog.jp

3. aws-dynamodb-scan - 項目のスキャン

テーブルをScanします。キーの条件式は指定できませんが、その他の使い方はQueryとほぼ同じです。

aws-dynamodb-scan [options] <tableName>

オプション

オプション 長いオプション 説明
-p --projection-expression=ARG 表示する属性名をカンマ区切りで指定
-f --filter-expression=ARG 検索後のフィルター条件式
-c --max-items=ARG 表示する件数(既定値は20)
-s --sort-item=ARG 表示時に並び替える項目名を指定
-d --desc 降順の並び替えを指定

パラメータ

  • tableName - 操作対象のテーブル名

実行例

$ aws-dynamodb-scan stars \
    --projection-expression 'name,orbitOrder,mass,diameter,
        gravity,density,rotation'\
    --filter-expression 'role="planet"'\
    --sort-item orbitOrder --desc
Count: 10
ROWNUM mass      rotation name    gravity orbitOrder density diameter
     1    0.0146   -153.3 PLUTO       0.7          9    2095     2370
     2  102.0        16.1 NEPTUNE    11.0          8    1638    49528
     3   86.8       -17.2 URANUS      8.7          7    1271    51118
     4  568.0        10.7 SATURN      9.0          6     687   120536
     5 1898.0         9.9 JUPITER    23.1          5    1326   142984
     6    0.642      24.6 MARS        3.7          4    3933     6792
     7    5.97       23.9 MARS        9.8          3    5514    12756
     8    4.87    -5832.0 VENUS       8.9          2    5243    12104
     9    0.33     1407.6 MERCURY     3.7          1    5427     4879
ScannedCount: 10

$

共通オプション

以下は各コマンド共通のオプションです。

オプション 長いオプション 説明
-j --output-json AWSのレスポンスを複数行のJSONとして表示
-J --output-json-oneline AWSのレスポンスを1行のJSONとして表示
-h --help ヘルプを表示。

※ ヘルプは、オプションの説明しか表示しません。

参考

オプション --projection-expression--filter-expression--key-condition-expressionと、パラメータkeyConditionExpressionの表記内容や使用可能な演算子については、Query - Amazon DynamoDB、または、Scan - Amazon DynamoDBを参考にしてください。 ただし、プレースホルダ―については、自動的に変換しますので気にしなくて結構です。

制限事項

  • 使用可能な型は、文字列(S)、数字(N)、真偽値(BOOL)、マップ(M)だけです。 リスト(L)はできれば対応したいと思っています。

  • 表示時のカラムの順序は指定できません。一見、projectionExpressionで指定した順番でデータを取得すればよいように思えるのですが、AWSから得られるデータの並びが、この順になっているわけではないからです。とはいえ、なんとか順序を指定できるようにしたいとは思っています。

リポジトリ

その他

同モジュールでは、他にも雑多なコマンドがたくさん含まれていますが、ドキュメントだけでなく動作確認等、まったく追いついていません。

不具合、御要望、改善案などございましたらGitHubのissueでご指摘ください。もちろん他の方法でも構いません。

また、個人的な取り組みとして最近ドキュメントは全て英文でチャレンジしていますので、妙な表現、文法間違い、Typoなど、山ほどあるかと思います。 こちらについても、おかしなところがあれば、ご指摘くださいヨロシクお願いいたします。

AWSへの接続について

※ 以下、~はホームディレクトリを表します。Windowsなら、C:\Users\<ユーザー名>などに読み替えてください。

aws-sdkでは、AWSへの接続のため、以下のAWS CLIで作成される認証情報を使用しているようです。 しかし、同じくAWS CLIが生成するデフォルトリージョンは利用してくれないため、このコマンド独自に読み込んでいます。

認証情報 ~/.aws/credential

[default]
aws_access_key_id = <アクセスキー>
aws_secret_access_key = <シークレットアクセスキー>

コンフィグ ~/.aws/configure

[default]
output = json
region = ap-northeast-1

DynamoDBのプレースホルダーについての基本

DynamoDBのテーブル操作の「式」の中で、プレースホルダ―を使用しなければならないケースがある。プレースホルダ―は以下2種類。

  1. 「属性名のプレースホルダ―」 - 式の中の属性名を置き換える。式の中には予約済みキーワードを表記できないので、属性名が予約済みキーワードとかぶった場合に使用。
  2. 「属性値のプレースホルダ―」 - 式の中の値を置き換えるためのもの。式の中には値を直接表記できないから、全ての値を置き換える必要がある。

予約済みのキーワードが多く、また一般的な単語も多く含まれている。 属性名に関して、予約済みキーワードがどうかにかかわらず全部置き換えても構わない。

npm「list-it」― コンソールへ列を揃えてデータを表示

コンソールへの表形式でのデータ表示を支援するNode.jsのモジュール(npm)「list-it」のご紹介。

2次元配列的なデータの列幅を揃えてキレイに表示。

文字列は左寄せ、数値は右寄せ。同じ列内の数値の小数点の位置も揃えます。

npmは、便利なツールが揃っていて、気楽にコードが書けるのがヨロシイですね。

f:id:takamints:20160501161451p:plain



駆け足でご説明するざっくりした使い方

  1. require("list-it")する。
  2. buffer()メソッドで空のバッファを作成。
  3. d()メソッドで、現在の行へ列(セル)データを追加。複数指定も可。
  4. nl()メソッドで現在行への列の追加を終了し次の行へ。
  5. 追加できるデータの型は文字列か数値。配列は行の追加になる(行追加時はnl()不要)
  6. 複数の配列を与えると複数の行が出来上がります。2次元配列でも可。
  7. toString()で文字列化してconsole.log()

機能の概要

表形式のデータを放り込んでコンソールへそのまま表示できる文字列を生成します。列ごとに数値の小数点位置を揃えられます。なんとなく便利でしょ?

  • autoAlign(自動整列)モードON(デフォルト)で、数値は小数点位置を揃えて右寄せ、文字列は普通に左寄せ。
  • 文字列の色や表示スタイルにANSIエスケープシーケンスが使用できます。カーソル移動とかは無理ですけどね。エスケープシーケンスのリセットは自動では行わないので、追加文字列の最後にリセットシーケンスを入れておいてください。

サンプルコードと出力例

japanese-foods.js

const ListIt = require("list-it");//①
const buf = new ListIt();      //②
console.log(
    buf
        .d("1").d("Sushi")      //③
            .d("vinegared rice combined raw seafood")
            .d("Healthy").nl()  //④
        .d("2").d("Yakiniku")
            .d("Grilled meat on Japanese")
            .d("Juicy").nl()
        .d("3").d("Ramen")
            .d("Japanese noodle soup dish")
            .d("I like it").nl()
        .d("4").d("Tempura")
            .d("Deep fried seafood or vegetables")
            .d("Delicious").nl()
        .d("5").d("Sashimi")
            .d("Very fresh sliced fish")
            .d("Try it now, It's good").nl()
        .toString());

出力: 文字列は左寄せです

$ node sample/japanese-food.js
1 Sushi    vinegared rice combined raw seafood Healthy
2 Yakiniku Grilled meat on Japanese            Juicy
3 Ramen    Japanese noodle soup dish           I like it
4 Tempura  Deep fried seafood or vegetables    Delicious
5 Sashimi  Very fresh sliced fish              Try it now, It's good

autoAlign

autoAlignオプションをtrueにすれば(デフォルトでtrueです)、データの型を考慮してセルの整形を行います。

planets.js

const ListIt = require("list-it");
const buf = new ListIt({ "autoAlign" : true });
var PLANETS = [
    ["NAME", "Mass(10^24kg)", "Dia(km)", "Dens(kg/m3)",
                        "Grav(m/s2)", "EscV(km/s)", "Rot(hours)" ],
    ["MERCURY", 0.33,   4879,   5427,   3.7,    4.3,    1407.6  ],
    ["VENUS",   4.87,   12104,  5243,   8.9,    10.4,   -5832.5 ],
    ["EARTH",   5.97,   12756,  5514,   9.8,    11.2,   23.9    ],
    ["MOON",    0.0073, 3475,   3340,   1.6,    2.4,    655.7   ],
    ["MARS",    0.642,  6792,   3933,   3.7,    5.0,    24.6    ],
    ["JUPITER", 1898,   142984, 1326,   23.1,   59.5,   9.9     ],
    ["SATURN",  568,    120536, 687,    9.0,    35.5,   10.7    ],
    ["URANUS",  86.8,   51118,  1271,   8.7,    21.3,   -17.2   ],
    ["NEPTUNE", 102,    49528,  1638,   11.0,   23.5,   16.1    ],
    ["PLUTO",   0.0146, 2370,   2095,   0.7,    1.3,    -153.3  ]
];
console.log( buf.d( PLANETS ).toString() ); //⑤、⑥

出力: 数値は小数点の位置を揃えて右寄せ

$ node sample/planets.js
NAME    Mass(10^24kg) Dia(km) Dens(kg/m3) Grav(m/s2) EscV(km/s) Rot(hours)
MERCURY        0.33      4879        5427        3.7        4.3     1407.6
VENUS          4.87     12104        5243        8.9       10.4    -5832.5
EARTH          5.97     12756        5514        9.8       11.2       23.9
MOON           0.0073    3475        3340        1.6        2.4      655.7
MARS           0.642     6792        3933        3.7        5.0       24.6
JUPITER     1898.0     142984        1326       23.1       59.5        9.9
SATURN       568.0     120536         687        9.0       35.5       10.7
URANUS        86.8      51118        1271        8.7       21.3      -17.2
NEPTUNE      102.0      49528        1638       11.0       23.5       16.1
PLUTO          0.0146    2370        2095        0.7        1.3     -153.3

日本語(ワイド文字)

japanese-foods-jp.js

const ListIt = require("list-it");
const buf = new ListIt();
console.log(
    buf
        .d("1").d("寿司")
            .d("酢とご飯とシーフード")
            .d("健康的だ").nl()
        .d("2").d("焼肉")
            .d("日本のグリルされたお肉")
            .d("ジューシー").nl()
        .d("3").d("ラーメン")
            .d("日本のスープに入った麺")
            .d("大好き").nl()
        .d("4").d("天ぷら")
            .d("シーフードや野菜に衣をつけて揚げたもの")
            .d("おいしー").nl()
        .d("5").d("刺身")
            .d("大変フレッシュな魚のスライス")
            .d("食べてみて!あご落ちるぜ").nl()
        .toString());

出力: HTMLでは何故か微妙にズレるけどコンソールではズレてません。

$ node sample/japanese-food-jp.js
1 寿司     酢とご飯とシーフード                   健康的だ
2 焼肉     日本のグリルされたお肉                 ジューシー
3 ラーメン 日本のスープに入った麺                 大好き
4 天ぷら   シーフードや野菜に衣をつけて揚げたもの おいしー
5 刺身     大変フレッシュな魚のスライス           食べてみて!あご落ちるぜ

未実装機能(将来追加する可能性はあり…ます…)

  • 文字列の折り返しができるようになればいいな。列幅指定してとか、コンソールの幅を判別して、自動的に列を折り返すとかできると超クール。
  • 見出し行とか見出しセルの概念を、我、欲す。行、列、セル単位でスタイル指定したい。
  • 表を転置(トランスポーズ:行列入れ替え)したいときがたまにある。
  • 演算機能があってもよいかなとか。あ、行列演算できてもよいか?いや、それはやりすぎか。

リポジトリ

メソッドの詳細などは、以下のリポジトリにあります。どう考えてもおかしな結果が得られたって時は、バンバンIssue入れてください。

GitHub

github.com

npm

www.npmjs.com

その他

これ、結構需要がある気がしていますが、プロジェクト単位でガチガチに力技で作ったりしがちですよね。 また、こういったモジュールは既にあるのかもしれませんが、軽く検索して見つけられなかったので作りました。

npmにはまる以前に作っていた別ソフトがベースになっています。 当時必要だと感じていた機能以上に、あれもこれもとドンドン実装したくなるから面白いもんですね。

npm 「hash-arg」 ― コマンドラインパラメータに名前でアクセス

コマンドラインで指定されたパラメータに名前でアクセスする為の、シンプルなNode.jsのモジュール hash-argをnpmで公開したので御紹介します。

npm便利ですね。若干敷居が高い気がしていましたが、まずはいろんなモジュールを検索して使うところから始めるといいですね。

f:id:takamints:20160403163627p:plain

'hash-arg'コマンドラインパラメータに名前でアクセスするためのシンプルなnpmモジュールです。

www.npmjs.com

ソースはGitHibに置いています。

github.com


JavaScript 第6版
JavaScript 第6版
posted with amazlet at 16.04.03
David Flanagan
オライリージャパン
売り上げランキング: 16,569

はじめに

このモジュールは、コマンドラインオプションの処理をするものではありません

単純に、コマンドライン引数、または配列の各要素に、前から順に名前を付けてハッシュ(JavaScriptのobject)を返すモジュールです。 追加の機能として、各パラメータの型指定と、省略時の既定値の指定ができますが、基本的には単純なものです。

Node.jsのコマンドラインパラメータは、process.argv[2] 以降に文字列として格納されています([0][1]"node"と、スクリプト名)から、本モジュールにパラメータの定義(名前、型、既定値)だけを与えた場合は、process.argv[2]以降の要素を処理対象とします。 別の配列を与えた場合は、すべての要素を処理します。

オプションが含まれる場合

コマンドライン引数に'-'で始まるようなオプションを含ませたい場合は、先にnode-getoptのようなオプションのパーサーで処理しておいて、そのモジュールが(おそらく)提供している、「オプションではない引数の配列」を、当モジュールで処理させます。

少しだけ気楽になるモジュールです(多分)

オプションではない引数が配列に入っている場合、その要素数をチェックして、必要なパラメータが足りていなかったりすると、エラーにしたり、省略時の既定値を設定したりしますよね。これって、少し邪魔くさい。

本来ザクザク書きたいのはそういうところじゃないはずです。 どの位置に何が指定されていたのか?という情報は、その後、使わない情報ですし。

あと、最初のパラメータなのにprocess.argv[2]とか書いちゃうあの妙な違和感(笑)もどうにかできます。

使い方:単純に'process.argv'を使用する場合

唯一のメソッドgetの第一引数にパラメータ名の定義を与えて呼び出せば、process-argvから値を取り出し、オブジェクトの指定されたキーに値を格納して返します。 (第二引数は省略可能なパラメータの配列です)

simple.js

args = require("hash-arg").get(
        "inputFilePath outputFilePath");
 
console.log(JSON.stringify(args, null, "  "));

実行例:

$ node test/simple.js input.json output.json
{
  "inputFilePath": "input.json",
  "outputFilePath": "output.json"
}

使い方:node-getoptのようなコマンドラインパーサーと共に使用

省略可能な第二引数に、たとえば、node-getoptモジュールの argv プロパティを与えればOK。

with-node-argv.js

getopt = require("node-getopt").create([
    ['s', '', 'short option'],
    ['l', 'long', 'long option'],
    ['S', 'short-with-arg=ARG', 'option with argument']
]).parseSystem();
 
args = require("hash-arg").get([
        "inputFilePath",
        {
            "name":"outputFilePath",
            "default": "out.json"
        }
        ], getopt.argv);
 
console.log(JSON.stringify(args, null, "  "));

実行例:

$ node test/with-node-getopt.js -S DUMMY input.json -sl output.json
{
  "inputFilePath": "input.json",
  "outputFilePath": "output.json"
}

GET メソッド

呼び出し形式

HashArg.get(<argument-def> [, <argv-source-array>]);

argument-def

パラメータの定義を行う。

単一の文字列、または、文字列配列、または、パラメータ定義オブジェクトの配列を指定できる。

1) 文字列の場合

パラメータのキー名称をスペースで区切った文字列

例)

"inputFilePath outputFilePath"

2) Array of string

各要素がパラメーター名である文字列の配列。

例)

["inputFilePath", "outputFilePath"]

3) Array of definition object

このフォーマットでは、省略時のデフォルト値を指定できます。

デフォルト値が指定されていない場合は、nullが使用されます。

[
    {"name":"inputFilePath"},
    {
        "name"      : "outputFilePath",
        "default"   : "out.json"
    }
]

argv-source-array (省略可能)

コマンドラインパラメータを保持する文字列配列。

省略時はprocess.argvが使われます。

※ 注意:v0.0.2以前では、getの第二引数に、process.argvを与えると誤動作します。

定義より多くパラメータが指定されたら

v0.0.3以上では、パラメータ定義の数よりもコマンドラインで指定されたパラメーターが多い場合、未定義のパラメータが、返されるオブジェクトの空文字のキーに配列として保存されます(v0.0.2以前ではそれらは失われていました)。

args = require("hash-arg").get("inputFilePath outputFilePath");
console.log(JSON.stringify(args, null, "  "));

実行例:

$ node test/with-node-getopt.js input.json output.json foo bar
{
  "inputFilePath": "input.json",
  "outputFilePath": "output.json",
  "": ["foo", "bar"]
}

ライセンス

MIT

その他

単に利用するだけなら、npm install hash-argでOKですよ。


Node.jsで正常終了するとき process.exit(0) を呼んではいけない

f:id:takamints:20160402113544p:plain

Node.jsで正常終了するとき、 process.exit(0) を明示的に呼び出すべきではないってことを書いています。



関連記事:

takamints.hatenablog.jp

勢い余って呼んじゃった

Node.jsでコマンドラインのツールを書くとき、特に他の人に使ってもらうようなものだと特に、エラー処理をキチンと書くように努めています。

エラーメッセージを分かりやすく表示して、process.exit(-1) で、OSに対して異常終了を示すわけですが、勢い余って正常終了時に、ついつい process.exit(0) と書いてしまったのです。

その結果、「正常終了しているけれど、処理が正しくできてない」というよくわからない状況に困惑しました。

以下のようなコードです。

var fs = require("fs");
if(process.argv.length < 2) {
    console.error("エラー:ファイル名なし");
    process.exit(1);
}
fs.readFile(process.argv, "utf-8", function(err, data) {
    //
    //ファイルを読み込んであれこれする
    //
});
process.exit(0); //ここで正常終了ですよ

process.exitは「非同期処理を待ってくれない」

もうお気づきでしょうね最後の行です。

これだと readFileのコールバックが呼ばれる前に、プロセスが正常終了しちゃいます。

「nodeのプロセスは、全てのコールバックが終わってから終了する」けど、明示的にprocess.exitを呼び出したら、その時点で終了してしまいます。

これ当たり前。そうでなきゃ困るんだけど、意識していなかった。

呼び出さないほうがよい

ということで早速結論

Nodeのスクリプトで正常に処理を終了するときは、process.exitを呼び出さないほうが良い。

呼び出さなければ全部の処理を確実に実行してから、自動的に終了コード=0で終了してくれますが、 呼び出していると「これ、本当に全部の処理が行われてから正常終了しているの?」と疑うことが出来てしまいます。 コードレビューで指摘されると正統性を示すのが結構大変になりそうですし。

よく「呼び出す必要が無い」と説明されているのですが、もうチョット強めのニュアンスの方が良いのではないかと思います。 「呼び出さないほうがよい」ぐらいのほうが適当かと。

おまけ:0以外の終了コードで正常終了する方法

じゃあ0以外の終了コードで正常終了を表したい場合は、どうすればいいの?って思いますよね。

以下のようにすると良いですよ。

process.on("exit", function() {
    process.exit(1);
});

確認してみる。

$ node -e "process.on('exit', function(){process.exit(255);});"

$ echo $?
255

$

OKですね。


Nodeクックブック
Nodeクックブック
posted with amazlet at 16.04.02
David Mark Clements
オライリージャパン
売り上げランキング: 277,422

AWS Lambdaの関数アップロードをお手軽に

Lambda関数を、ローカルPCからアップロードするコマンドをご紹介。ダウンロードも出来ますよっと。

Lambda関数はAWSのWEBコンソールで編集できますが、数が増えるとやってらんない。そして外部モジュールを使う場合はWEBでは無理ですし。

でき得るならばローカルで、編集したのをアップロードしたいのだけど、その都度ZIPしてアップしてとか、それはそれで手間がかかってイライラします…

f:id:takamints:20160309213632p:plain
photo credit: 150120-N-ZZ999-002 via photopin (license)

てなことで、怒りに任せて(笑)取り急ぎ、勢いで3つばかり作ってしまいました。

その後、いろいろ更新してnpmとして公開してます。 最新版では、SQLライクな構文でDynamoDBを操作できるようになりました。 これについては以下の記事で説明してます。

takamints.hatenablog.jp


目次

  1. コマンド
    1. aws-lambda-get - Lambda関数をダウンロード
    2. aws-lambda-upload - Lambda関数を更新(上書き)
    3. aws-lambda-create - Lambda関数を新規作成
  2. 機能説明
    1. ローカルのLambda関数のディレクトリ構造
    2. アップロード前に特定の処理を実行する
  3. セットアップ
    1. 実行環境と必要なツール等
    2. インストール方法
    3. リポジトリ


aws-node-utilDynamoDB関連記事はこちらです:

takamints.hatenablog.jp


1. コマンド

1-1. aws-lambda-get - Lambda関数をダウンロード

AWSのLambda関数をダウンロードします。

$ aws-lambda-get <function-name>

パラメータ

  • function-name - Lambda関数名。

ちゃんとダウンロードできたら、カレントディレクトリに関数名のディレクトリが作られ、全てのファイルが展開されます。

安心してください、上書きしませんよ

既に同名のサブディレクトリがカレントディレクトリ直下にある場合はダウンロードしません。 ディレクトリの名前を変更して再実行してください。

1-2. aws-lambda-upload - Lambda関数を更新(上書き)

AWSのLambda関数をローカルファイルで更新します。

カレントディレクトリ直下の関数名のディレクトリをZIPファイルにまとめてAWSへアップロードして上書きます。

$ aws-lambda-upload <function-name>

パラメータ

  • function-name - Lambda関数名。カレントディレクトリ直下に同名のサブディレクトリが必要です。それをZIPしてアップします。

1-3. aws-lambda-create - Lambda関数を新規作成

ローカルのLambda関数をAWSへアップロードし、新規作成します。

カレントディレクトリ直下の関数名のディレクトリをZIPファイルにまとめてAWSへアップロードします。

$ aws-lambda-create <function-name> <role-arn>

パラメータ

  • function-name - Lambda関数名です。カレントディレクトリ直下に同名のサブディレクトリが必要です。それをZIPしてアップします。
  • role-arn - Lamdaに付けられるRoleのarnを指定してください。RoleはAWS IAMで作成出来ます。

Node.js限定です

新規作成に関しては、言語はnode.jsだけで、ハンドラーは index.handlerに固定されています。

生成だけなら別途awsコマンドでやってもたいした手間ではありません。その後、uploadすれば大丈夫なんじゃないかな?(試してないのでスミマセン)

2. 機能説明

2-1. ローカルのLambda関数のディレクトリ構造

AWSからダウンロードするとカレントディレクトリ直下に関数名のサブディレクトリが作成されます。 このディレクトリは、そのままアップロードできる状態になっています。

たとえば、以下のようにHelloLambdaという関数をダウンロードすると、 カレントディレクトリ直下にディレクトHelloLambdaが作成され、全ファイルが展開されます。

$ aws-lambda-get HelloLambda

以下は、HelloLambdaがモジュールを使用している場合の例です。

./HelloLambda/
    index.js
    node_modules/
      node-uuid/
        ....

2-2. アップロード前に特定の処理を実行する

アップロードする前に、Lambda関数が利用しているモジュールを更新したり、エディタのテンポラリファイルを削除したくなると思います。

各関数のディレクトリ直下に、.onupload.sh というファイルがあれば、アップロード前(正確にはZIPで固める前)に、これをシェルスクリプトとして実行します。

このファイル自体はAWSへはアップロードされません。

#node-uuidをインストール
if [ ! -d node_modules ]; then
    npm install node-uuid
else
    npm update node-uuid
fi
#VIMのバックアップファイルを消す
rm *~ .*~ 

3. セットアップ

3-1. 実行環境と必要なツール等

利用するには、以下のものが必要です。

  • AWSのアカウント - これがないと始まらない。今なら登録から1年間は基本的に無料。
  • AWSCLI - AWSコマンドラインインターフェースです。AWSからダウンロードしてインストールし、AWSアカウントで接続できるようにしておいてください。各コマンドから利用しています。
  • Bash - コマンドがシェルスクリプトなので必要です。
  • Node.js - JSONの処理等に利用しています。将来的には全部Nodeでやりたいです。
  • Zip/Unzipコマンド - Lambda関数のアップロード、ダウンロードで必要になります。(Bashで最初から利用できるのかも?)

3-2. インストール方法

npmにpublishしたので、インストールは npm install -g aws-node-utilでOKです。

インストールスクリプトINSTALL.sh

$ sh INSTALL.sh

実行すると、各スクリプト~/binへコピーし、node_modules以下のファイルを ~/node_modules へコピーしています。

かなりいい加減なインストールスクリプトで申し訳ないです。当方MinGW使ってるのでこれで済んでいます。

可能ならば、Forkして適切に修正してください。そしてプルリク下さい。よろしくお願いいたします。

3-3. リポジトリ

ソースは全て以下のGitHubに置いています。 ご自由に利用なさってください(MIT license)。 他にも雑多なスクリプトが入っていますが、それはそれでまたおいおい。

github.com