AWS LambdaからKintoneアプリケーションのレコードを更新してみる

AWS LambdaからKintoneのアプリケーションレコードを更新してみたのでその備忘録。

前提

  1. AWS Lambda Pythonを使います。
  2. LambdaはVPC内には配置しません。
  3. Kitoneのアプリケーションにはデフォルトで用意されている「備品在庫管理」を利用します。

Kintone側の設定

スクリーンショット 2017-05-28 17.05.06.png

手動で登録したこのレコード(ボールペン)をAWS Lambdaから変更したいと思います。

基本的にはこちらのサイトを参考にさせてもらいました。とてもわかりやすかったです。バージョンの違いなのか若干書き方が異なるところがあったりしましたが、なんとかなりました。

http://www.yamamanx.com/kintone-python-query-check/

Lambdaの実装

以下のような実装になります。一応メソッドによって処理を変更できるような作りにはしてはみましたが、実運用で使うならきちんと設計したほうが良いですね。

def kintone_operator(event, context):
    KINTONE_URL = "https://{kintone_domain}/k/v1/record.json"
    url = KINTONE_URL.format(
        kintone_domain=os.environ['KINTONE_DOMAIN'],
        kintone_app=os.environ['KINTONE_APP']
    )
    headers_key = os.environ['KINTONE_HEADERS_KEY']
    api_key = os.environ['KINTONE_API_KEY']
    basic_headers_key = os.environ['KINTONE_BASIC_HEADERS_KEY']
    basic_headers_value =os.environ['KINTONE_BASIC_HEADERS_VALUE']

    headers = {headers_key: api_key}
    headers["Content-Type"] = "application/json"
    if basic_headers_value != '':
        headers[basic_headers_key] = basic_headers_value

    if event['api'] == 'PUT':
        result = put_record(headers, url, event['data'])
    else:
        result = 'NO KEY'

    return result

def put_record(headers, url, data):
    response_record = requests.put(url, json=data, headers=headers)
    record_data = json.loads(response_record.text)

    return record_data

全て大文字の変数は環境変数としてLambdaで定義しました。API Keyなどを公開しなくて済むので非常に楽です。

実行時には以下のようなデータを送付しました。

{
  "api": "PUT",
  "data": {
      "app": 498,
      "id": 1,
      "record": {
          "文字列__1行_": {
              "value": "シャープペンシル"
          }
      }
  }
}

で、実行してみたところ、無事更新されたようです。

スクリーンショット 2017-06-06 19.45.48.png

まとめ

いろいろなサイトをベースにさせてもらい、更新機能を作ってみました。うまくAPI Gatewayやら他の機能やらと連携できれば、KintoneとAWSでどんどんとできることが増えてきますね。

続きを読む

AWS LambdaでDynamoDBから取得した値に任意の集計をかける

前回書いた記事「AWS LambdaでDynamoDBから取得した値の最新レコードを取得する」を、以下の集計にも対応させてみました。

  • 最新値 (latest)
  • 最大値 (max)
  • 最小値 (min)
  • 平均値 (avg)
  • 合計値 (sum)
  • 件数 (count)

前提&仕様

以下を前提&仕様として作成しました。

  1. DynamoDBのハッシュキーにID(文字列)、レンジキーに時刻(文字列)を指定しているものとする。
  2. データは時系列に格納されているものとする。
  3. 指定したカラムの集計を取るようにする。
  4. 集計の時間を指定できるようにする。
  5. 集計の種類は指定可能とする。
  6. ID、集計期間、集計対象のカラム、集計の種類はそれぞれJSONのインプットで指定可能とする。

結果

こちらに登録してあります。

https://github.com/kojiisd/lambda-dynamodb-aggregator

サンプルデータ

以下のデータをDynamoDBに入れました。これについて色々と操作をしようと思います。

スクリーンショット 2017-05-03 11.49.57.png

使い方

インプットデータの準備

以下のインプットデータが必要になります。

カラム名 内容
label_id DynamoDBで指定しているハッシュキー名
label_range DynamoDBで指定しているレンジキー名
id 集計したいIDの値
aggregator 集計種別。種別は最初に書いた6種類に対応
time_from 集計対象期間(開始)
time_to 集計対象期間(終了)
params [個別]集計時必要になるパラメータ

インプットデータの準備(個別部)

上述の「params」に該当する部分は以下の様なパラメータの準備が必要になります。

集計種別 必要な値
最新値(latest) range: レンジキー名(共通部で指定していますが、一応他に体裁を合わせました)
最大値(max) score: 集計対象のカラム名
最小値(min) score: 集計対象のカラム名
平均値(avg) score: 集計対象のカラム名
合計値(sum) score: 集計対象のカラム名
件数(count) score: 集計対象のカラム名

こんな感じで指定すれば実行可能になります。

とりあえず実行してみる

とりあえず動かしてみたい人は以下の様な感じで実行すれば結果が見れます。今回はSERVERLESS FRAMEWORK上で動かしています。

「sensor1」に対して指定した時間の中での:

最新値(latest)
$ sls invoke local -f run -d '{"label_id": "id", "label_range": "timestamp", "id": "sensor1", "aggregator": "latest", "time_from": "2017-04-30T22:00:00.000", "time_to": "2017-04-30T22:05:00.000", "params": {"range": "timestamp"}}'
"{"timestamp": "2017-04-30T22:05:00.000", "score": 0.0, "id": "sensor1"}"
最大値(max)
$ sls invoke local -f run -d '{"label_id": "id", "label_range": "timestamp", "id": "sensor1", "aggregator": "max", "time_from": "2017-04-30T22:00:00.000", "time_to": "2017-04-30T22:05:00.000", "params": {"score": "score"}}'
"{"timestamp": "2017-04-30T22:04:00.000", "score": 1.0, "id": "sensor1"}"

(同じ値がヒットした場合は新しい方のデータを取得する様にしています。)

最小値(min)
$ sls invoke local -f run -d '{"label_id": "id", "label_range": "timestamp", "id": "sensor1", "aggregator": "min", "time_from": "2017-04-30T22:00:00.000", "time_to": "2017-04-30T22:05:00.000", "params": {"score": "score"}}'
"{"timestamp": "2017-04-30T22:05:00.000", "score": 0.0, "id": "sensor1"}"
平均値(avg)
$ sls invoke local -f run -d '{"label_id": "id", "label_range": "timestamp", "id": "sensor1", "aggregator": "avg", "time_from": "2017-04-30T22:00:00.000", "time_to": "2017-04-30T22:05:00.000", "params": {"score": "score"}}'
"0.3333333333333333"
合計値(sum)
$ sls invoke local -f run -d '{"label_id": "id", "label_range": "timestamp", "id": "sensor1", "aggregator": "sum", "time_from": "2017-04-30T22:00:00.000", "time_to": "2017-04-30T22:05:00.000", "params": {"score": "score"}}'
"2.0"
件数(count)
$ sls invoke local -f run -d '{"label_id": "id", "label_range": "timestamp", "id": "sensor1", "aggregator": "count", "time_from": "2017-04-30T22:00:00.000", "time_to": "2017-04-30T22:05:00.000", "params": {"score": "score"}}'
"6"

仕組み

最新値

以前の記事と同様、指定したレンジキーの最大値を取るようにしただけです。

max(data, key=(lambda x:x[params['range']]))

最大値 / 最小値

max関数とmin関数が使えるようにこんな実装にしています。

max_aggregator.py
max(data, key=(lambda x:x[params['score']]))
min_aggregator.py
min(data, key=lambda x: x[params['score']])

平均値

後述の合計値と件数を使っての計算になります。

sum(map(lambda x: x['score'], data)) / len(map(lambda x: x['score'], data))

合計値

sum関数使ってサクッと計算したかったのでこんな感じです。

sum(map(lambda x: x['score'], data))

件数

対象カラムの長さをとっただけです。

len(map(lambda x: x['score'], data))

AWS Lambdaでも動くのか?

現状のserverless.ymlには権限周りの設定が足りなかったようなのですが、とりあえずデプロイ後に手動で権限を正しくセットしたらうまくいきました。

とりあえずデプロイは何も問題なく完了。

$ sls deploy 
Serverless: Packaging service...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (10.19 KB)...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
...............
Serverless: Stack update finished...
Service Information
service: lambda-dynamodb-aggregator
stage: dev
region: us-east-1
api keys:
  None
endpoints:
  None
functions:
  run: lambda-dynamodb-aggregator-dev-run

スクリーンショット 2017-05-03 12.20.13.png

動きはしました。(件数を取得しています)

スクリーンショット 2017-05-03 12.38.32.png

続きを読む

AWS LambdaでDynamoDBから取得した値の最新レコードを取得する

DynamoDBに値が入っている前提で、

  • とある時間の
  • あるIDにおける
  • 集計値

を取ろうする際の実装。(AWS Lambda Python 2.7を使っています)

前提

以下の前提とします。

  1. DynamoDBのハッシュキーにID(文字列)、レンジキーに時刻(文字列)を指定
  2. データは時系列に格納されているものとする。
  3. 指定したカラムの集計を取るようにする。
  4. とりあえず指定したIDで全件取得(時間による絞り込みはしない)

こんな感じのデータを想定。

id score timestamp
sensor1 0 2017-04-30T22:00:00.000
sensor1 0 2017-04-30T22:00:01.000
sensor1 1 2017-04-30T22:00:02.000
sensor1 0 2017-04-30T22:00:03.000
sensor2 1 2017-04-30T22:00:04.000

このうちsensor1の最新値を取るための実装をしてみます。結果としてscore:0が取得できるロジックを期待します。

実装

実行環境にはSERVERLESS FRAMEWORKを利用しました。こんな感じの実装でできました。

import boto3
import json
import decimal
from boto3.dynamodb.conditions import Key

dynamodb = boto3.resource('dynamodb')
table    = dynamodb.Table('test')

def run(event, context):

    res = table.query(
            KeyConditionExpression=Key('id').eq("sensor1")
        )

    return_response = max(res["Items"], key=(lambda x:x["timestamp"]))

    return json.dumps(return_response, default=decimal_default)

def decimal_default(obj):
    if isinstance(obj, decimal.Decimal):
        return float(obj)
    raise TypeError

まずは最新値を求めるというところで手抜き感満載の実装ですが、Aggregate部分を別クラスにしてしまって少しインテリジェンスに選択できるようにすれば、一気に用途が広がる気がします。

実行結果は以下の通りです。無事取得できてますね。

$ sls invoke local -f run
"{"timestamp": "2017-04-30T22:03:00.000", "score": 0.0, "id": "sensor1"}"

続きを読む

AWS X-RayでLambda→Athenaのアクセスを可視化してみた

以前こんなものを作りましたが、これをAWS X-Rayで可視化してみたら、何がわかるのか、実験してみました。

Amazon AthenaをAWS Lambdaから操作できるようにしてみた

AWS X-Ray デーモンの実行

AWS X-Ray SDK は、AWS X-Ray に Trace データを直接送信しないらしいので、送付用のEC2インスタンスを作成します。ユーザデータとして以下を登録してインスタンスを生成するだけなので、簡単です。

#!/bin/bash
curl https://s3.dualstack.us-east-1.amazonaws.com/aws-xray-assets.us-east-1/xray-daemon/aws-xray-daemon-2.x.rpm -o /home/ec2-user/xray.rpm
yum install -y /home/ec2-user/xray.rpm

システムログにxrayのインストールログが出力されていたのでOKでしょう。

Examining /home/ec2-user/xray.rpm: xray-2.0.0-1.x86_64
Marking /home/ec2-user/xray.rpm to be installed
Resolving Dependencies
--> Running transaction check
---> Package xray.x86_64 0:2.0.0-1 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

================================================================================
 Package         Arch              Version               Repository        Size
================================================================================
Installing:
 xray            x86_64            2.0.0-1               /xray            6.6 M

Transaction Summary
================================================================================
Install  1 Package

Total size: 6.6 M
Installed size: 6.6 M
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : xray-2.0.0-1.x86_64                                          1/1 
xray start/running, process 2576
  Verifying  : xray-2.0.0-1.x86_64                                          1/1 

Installed:
  xray.x86_64 0:2.0.0-1                                                         

Complete!

Lambdaアプリ側の準備

今回Javaアプリケーションを動かすわけですが、LambdaアプリケーションをX-Rayで監視したい場合は、Lambdaアプリケーションの「設定」タブの中で以下のチェックボックスをONにするだけで良いようです。

スクリーンショット 2017-04-23 22.21.44.png

参考:http://docs.aws.amazon.com/ja_jp/xray/latest/devguide/xray-services.html

またX-Rayを操作するための権限をIAMで設定する必要もあります。今回は試験的な運用だったため「AWSXrayFullAccess」をつけてしまいましたが、実際の運用に合わせてこの辺りは慎重に選びたいですね。

アプリを起動して可視化してみる

ここまでできれば、普通にLambdaアプリを動かしてみてX-Rayでどのように見えるのか確認ができます。今回Lambdaアプリケーションには以下のJSONをインプットとして与えるようにしました。以前の記事でサンプルとしてAthenaのテーブルからデータを取得するようにした際の入力値です。

{
  "region": "us-east-1",
  "s3Path": "s3://ishida-athena-staging-dir/",
  "sql": "SELECT elbname, requestip,  requestport, backendip, backendport, requestprocessingtime, backendprocessingtime, timestamp FROM sampledb.elb_logs order by timestamp desc limit 10",
  "columnListStr": "elbname, requestip,  requestport, backendip, backendport, requestprocessingtime, backendprocessingtime,  timestamp"
}

実行後1分ほど待つと、以下のような表示がX-Rayで確認できました。無事可視化ができたようです。

スクリーンショット 2017-04-23 22.56.40.png

X-Rayの中身を確認してみる

表示されたService Mapの右側のオブジェクトをクリックすると以下のような表示がされました。
スクリーンショット 2017-04-23 22.56.51.png

それぞれの処理にどの程度時間がかかってレスポンスとして何を返しているのかが一覧でわかります。
表示されているIDをクリックすると、そのTraceの詳細が確認できました。

スクリーンショット 2017-04-23 22.56.58.png

これをみる限り、Lambdaアプリの初期化に230ms程度、実際のAthena接続部分に約3秒程度かかっている、という風にみればいいんですかね。この処理全体としては4.6秒かかっているので、実際にAthenaにアクセスするため以外に1.5秒ほどは時間が取られている、と理解すればいいんでしょうか。この辺はもっと勉強が必要だ(^^;

ちなみにエラーが出ている場合は、その例外の中身も確認することができるようです。

まとめ

それぞれの処理がどの程度時間にかかっていて、さらに呼び出し関係までこれほど簡単にセットアップしつつ可視化ができるのは強力ですね。これからMicroservicesなどで分散して処理をさせることが当たり前になることを考えると、必須の技術と言えると思います。Springで言えばZipkinとSleuthをAWS上で実現しているような感じですね。

続きを読む

AtlassianのLocalStackを使ってみてなんとなく理解するまでのお話

Atlassianが「LocalStack」なんてとても便利そうなものを出していたけど、なかなか使い方を解説しているページが見つからなかったので、とりあえず使いながらなんとなく中身を理解するまでのお話。

https://github.com/atlassian/localstack
スクリーンショット 2017-04-23 17.53.59.png

起動

いくつかGithubで利用方法が紹介されていますが、今回はdockerでの利用をしてみます。

$ docker run -it -p 4567-4578:4567-4578 -p 8080:8080 atlassianlabs/localstack
2017-04-23 08:50:15,876 INFO supervisord started with pid 1
2017-04-23 08:50:16,879 INFO spawned: 'dashboard' with pid 7
2017-04-23 08:50:16,885 INFO spawned: 'infra' with pid 8
(. .venv/bin/activate; bin/localstack web --port=8080)
. .venv/bin/activate; exec localstack/mock/infra.py
Starting local dev environment. CTRL-C to quit.
 * Running on http://0.0.0.0:8080/ (Press CTRL+C to quit)
 * Restarting with stat
Starting local Elasticsearch (port 4571)...
Starting mock ES service (port 4578)...
Starting mock S3 server (port 4572)...
Starting mock SNS server (port 4575)...
Starting mock SQS server (port 4576)...
Starting mock API Gateway (port 4567)...
Starting mock DynamoDB (port 4569)...
Starting mock DynamoDB Streams (port 4570)...
Starting mock Firehose (port 4573)...
Starting mock Lambda (port 4574)...
Starting mock Kinesis (port 4568)...
Starting mock Redshift server (port 4577)...
 * Debugger is active!
2017-04-23 08:50:18,537 INFO success: dashboard entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2017-04-23 08:50:18,538 INFO success: infra entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
 * Debugger PIN: 844-652-544
Ready.

とりあえず起動はしたみたい。で、http://localhost:8080/にアクセスしてみたけど、こんな感じで何も表示されず。

スクリーンショット 2017-04-23 17.59.04.png

使ってみてわかりましたが、要は本当に各種サービスが以下のアドレスで利用できるようにしてくれたもののようです。

全部試すのもアレなので、とりあえず馴染み深いDynamoDBとS3を使ってみる。

DynamoDBのテーブル作成

全然関係ないですが、http://localhost:4569/にアクセスすると以下のレスポンスをもらえます。デフォルトはus-east-1で動いている想定のようで。(Githubページにも書いてあった。バインドすればいくつか設定を変更できるようですね。)

healthy: dynamodb.us-east-1.amazonaws.com 

では早速テーブルをCLIから作ってみます。一応作成前にlist-tablesをしてみますが、もちろん何も登録されていません。

$ aws --endpoint-url=http://localhost:4569 dynamodb list-tables
{
    "TableNames": []
}

こちらを参考にさせていただいて、create-tableコマンドを発行します。

$ aws --endpoint-url=http://localhost:4569 dynamodb create-table --table-name test --attribute-definitions AttributeName=testId,AttributeType=S --key-schema AttributeName=testId,KeyType=HASH --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1
{
    "TableDescription": {
        "TableArn": "arn:aws:dynamodb:us-east-1:000000000000:table/test", 
        "AttributeDefinitions": [
            {
                "AttributeName": "testId", 
                "AttributeType": "S"
            }
        ], 
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0, 
            "WriteCapacityUnits": 1, 
            "ReadCapacityUnits": 1
        }, 
        "TableSizeBytes": 0, 
        "TableName": "test", 
        "TableStatus": "CREATING", 
        "KeySchema": [
            {
                "KeyType": "HASH", 
                "AttributeName": "testId"
            }
        ], 
        "ItemCount": 0, 
        "CreationDateTime": 1492937089.534
    }
}

なんか作られたっぽいですね。もう一度list-tablesをしてみます。

$ aws --endpoint-url=http://localhost:4569 dynamodb list-tables
{
    "TableNames": [
        "test"
    ]
}

出来上がってますね。なるほど、本当にAWS上でやる操作をEndpointURLを変更するだけで操作できてしまうようです。これは思っていたよりも便利かも。

S3のバケットを作成してみる

S3のバケットも作成できるのか試してみます。まずバケットのリストを見てみますが、当然何もありません。

$ aws --endpoint-url=http://localhost:4572 s3 ls
(何も表示されず)

では作成してみます。

$ aws --endpoint-url=http://localhost:4572 s3 mb s3://kojiisd-test/
make_bucket: s3://kojiisd-test/
$ aws --endpoint-url=http://localhost:4572 s3 ls
2006-02-04 01:45:09 kojiisd-test

まじか、これは便利。ただdockerでサービス起動したら停止時に中身が消えてしまうから、できれば作成したものが残るような起動方法の方が色々試そうとしたら適していそうですね。
(作成時間がはちゃめちゃですが、とりあえずそこまで問題にはならないかな)

ちなみにDynamoDBのテーブルとS3のバケットを作成してから気づきましたが、http://localhost:8080/にアクセスしたら、作成したものが表示されていました。なるほど、そのためのDashBoardだったのか。素敵。

スクリーンショット 2017-04-23 18.20.02.png

まとめ

どれくらいどこまで何ができるのかは気になりますが、一般的なことであればだいたいローカルでできるような気がします。しかもEndpointURLを変更するだけで良さそうなので、これはかなり便利かも。今度作成したアプリを全てLocalStackで動かしてみるとかやってみようかな。

とりあえず、もっとこれは知られるべきと、思いました。

続きを読む

DynamoDB Local Viewerに機能追加(スキーマ情報取得、ソート・フィルタ、データ削除)

以前作成したDynamoDBのLocal Viewerですが、現状の機能だと色々と不足してきたため更新をかけました。以前の記事はこちら。

DynamoDB Local用のViewerをSpring Bootベースで作ってみた

当時はScanメソッドでとりあえずデータを取ってましたが、今回は以下に対応させました。

  • テーブルの詳細情報確認
  • 指定したテーブルの中身の削除(制限あり)
  • 指定したテーブルの削除
  • テーブルデータのソートと絞り込み

結果はこちらに登録してあります。

https://github.com/kojiisd/dynamodb-local-view

テーブルの詳細情報確認

テーブル名をクリックした際にスキーマ情報を取得できるようにしました。

スクリーンショット 2017-04-21 7.10.54.png

こんな感じのダイアログを出すようにしています。

スクリーンショット 2017-04-21 7.11.21.png

指定したテーブルの中身の削除(制限あり)

個人的には一番欲しかった機能です。ローカルでDynamoDBを使った動作確認をしている際に、いちいちテーブルをドロップしてから作り直すのをスクリプトを組んで実施するのが面倒でした。なので「Clear」をクリックすれば中身をからにしてくれる機能を作りました。

スクリーンショット 2017-04-21 7.12.01.png

以下は削除後のスキーマ情報です。tableSizeBytesやitemCountが0になっているのがわかります。
ただいくつか制限があり、以下の実装のようにいくつかテーブル情報を引き継いでいません。この辺りうまい方法を知っている人がいればぜひ知りたいです。

CreateTableRequest createRequest = new CreateTableRequest().withTableName(tableName)
        .withAttributeDefinitions(describeResult.getTable().getAttributeDefinitions())
        .withKeySchema(describeResult.getTable().getKeySchema())
        .withProvisionedThroughput(new ProvisionedThroughput()
                .withReadCapacityUnits(describeResult.getTable().getProvisionedThroughput().getReadCapacityUnits())
                .withWriteCapacityUnits(describeResult.getTable().getProvisionedThroughput().getWriteCapacityUnits()));

スクリーンショット 2017-04-21 7.11.49.png

どんな仕組みにしたかはこちらに書きました。

Local DynamoDBのテーブルデータを削除したいときの実装(テーブル削除→作成)

指定したテーブルの削除

スクリーンショット 2017-04-21 7.13.16.png

スクリーンショット 2017-04-21 7.13.40.png

テーブルデータのソートと絞り込み

Scanのページには、各ヘッダで並び替えができるように、また検索結果にフィルタをかけられるように簡易のフィルタ機能をつけました。

スクリーンショット 2017-04-21 9.06.23.png

まとめ

そろそろQuery機能もつけて、実際のAWS ConsoleでのDynamoDBのユーザビリティを再現したいと思います。

続きを読む

Local DynamoDBのテーブルデータを削除したいときの実装(テーブル削除→作成)

Local DynamoDBのテーブルを残したまま中身を削除したくなったので、その時のメモ。Amazon DynamoDBを使っていれば、コンソールから消せますが、ローカルのDynamoDBを使っていると、なかなか面倒ですよね。

前提1:DynamoDBには複数データ削除用のメソッドはない

テーブルの削除(deleteTable)、データを1件削除(deleteItem)はありますが、テーブル定義を残しつつデータのみを削除するメソッドは用意されていません。(DynamoDBの特性を考えればわからんでもないですが)

前提2:Scanした結果のItemはdeleteItemメソッドでは使えない

ではとりあえずScanした結果を使ってItemを取り出して1個ずつ消そうかとこんなコードを組んでみますが

for (Map<String, AttributeValue> item : scanResult.getItems()) {
  DeleteItemRequest request = new DeleteItemRequest().withTableName(tableName).withKey(item);
  this.dynamoDB.deleteItem(request);
}

エラーが出力され、削除できません。deleteItemメソッドが受け付けるItemの内容は、getItemで取得したデータとマッチするようです。

com.amazonaws.services.dynamodbv2.model.AmazonDynamoDBException: The number of conditions on the keys is invalid (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1586) ~[aws-java-sdk-core-1.11.75.jar:na]
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1254) ~[aws-java-sdk-core-1.11.75.jar:na]
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1035) ~[aws-java-sdk-core-1.11.75.jar:na]

一度テーブルを削除して同じ名前で複製。

結局はこの方法をとりました。Queryで1件1件取得しては削除して、、、とも考えたのですが、こちらの方が楽かな、、、と。

で、以下がコードになります。まだ削除後のテーブルを復旧しきれていないものもあるので、これから足りない分は補足します。

DescribeTableRequest describeRequest = new DescribeTableRequest().withTableName(tableName);
DescribeTableResult describeResult = this.dynamoDB.describeTable(describeRequest);
CreateTableRequest createRequest = new CreateTableRequest().withTableName(tableName)
        .withAttributeDefinitions(describeResult.getTable().getAttributeDefinitions())
        .withKeySchema(describeResult.getTable().getKeySchema())
        .withProvisionedThroughput(new ProvisionedThroughput()
                .withReadCapacityUnits(describeResult.getTable().getProvisionedThroughput().getReadCapacityUnits())
                .withWriteCapacityUnits(describeResult.getTable().getProvisionedThroughput().getWriteCapacityUnits()));

DynamoDB db = new DynamoDB(this.dynamoDB);
Table table = db.getTable(tableName);
table.delete();
table.waitForDelete();

table = db.createTable(createRequest);
table.waitForActive();

ちなみにこれだとグローバルセカンダリインデクスやローカルセカンダリインデクスに対応していないなど、いくつも問題がありますが、一般的なテーブルの用途としてはなんとか使えるかな、とは思います。

スクリーンショット 2017-04-17 8.45.17.png

まとめ

何かいい方法があればぜひ教えてください。

続きを読む

JAWS DAYS 2017 ブログ/記事まとめ #jawsdays #jawsug

JAWS DAYS 2017のブログや記事が続々上がってきてますね。社内フィードバック用にまとめていましたが、せっかくなので公開。敬称略で、順不同(見つけた順)に載せてます。

スライドのまとめはこちらに載せています。

JAWS DAYS 2017スライドまとめ #jawsdays #jawsug

登壇者が書いたブログ/記事

坂本知子:Rogue One Rekognition Story
Road to JAWS DAYS LT – JAWS DAYS 2017 LTへの道 – #jawsdays

大谷イビサ:自分と組織を「クラウド対応」にするための実践的な方法を考える
JAWS DAYS 2017のどこがすごかったのか? かみさんに説明してみた

岡本秀高:WordPress goes more Cloud ! – Infrastructure as Code & ServerlessでWordPressをより便利&快適に運用する
JAWS Days 2017でEC2 Systems ManagerとかについてのLTしてきました

星直史:CloudSearchのコスト削減術
PIXTAにおけるCloudSearchのコスト削減

森永大志:AWS SECURITY DEATH m/ ~セキュ鮫様からのお告げ~ by Security-JAWS
【イベントレポート】JAWS DAYS 2017にてSecurity-JAWSメンバーとして登壇してきました。 #jawsug #jawsdays #secjaws

大喜多利哉:AWS SECURITY DEATH m/ ~セキュ鮫様からのお告げ~ by Security-JAWS/IAM 権限をこえて
JAWS DAYS 2017で登壇しました

伊藤秀樹:AWS初心者いらっしゃい
JAWS DAYS 2017の思い出

運営スタッフが書いたブログ/記事

JAWS DAYS 2017 公式サイトの話

JAWS DAYS 2017 に行ってきました。

JAWS DAYS 2017にスタッフとして参加して得たこと

JAWS DAYS 2017へのご参加ありがとうございました!

参加者が書いたブログ/記事

【イベントレポート】JAWS-UG meets Windows 〜 Windows開発者及びインフラエンジニアのためのDev&Ops On AWS 〜 #jawsug #jawsdays

【イベントレポート】知らない間に使われていませんか?AWSの利用監査対策 #jawsug #jawsdays

【イベントレポート】ひとりでも怖くない!コミュニティの広げ方 #jawsug #jawsdays

「JAWS DAYS 2017」に行ってきました!

JAWS UG 2017 に行ってきた #jawsdays [AWS]

#jawsdays JAWS DAYS 2017に参加しました

JAWS DAYS 2017に参加してきた #jawsdays

JAWS DAYS 2017に行ってきた

#jawsdays 「JAWS DAYS 2017」に行ってきた #jawsug

[まとめ]JAWS-DAYS2017行ってきた

20170311-JAWS-DAYS.md

その他

「社内のいいおじさんを探せ」、AWSユーザーの武闘派CIOが直言

続きを読む

JAWS DAYS 2017スライドまとめ #jawsdays #jawsug

JAWS DAYS 2017に参加してきました。見たいセッションが並行していたりしたので、復習がてら、できるだけ公開されているセッションをまとめます。

  • ランチセッションとLTは(とりあえず)除いています。
  • 一つのタイトルで複数発表があったものは、発表者にスライドへのリンクをつけています。
  • 編集リクエスト大歓迎です。

Aトラック Bトラック Cトラック Dトラック Eトラック Fトラック Gトラック Hトラック
新訳 とあるアーキテクトのクラウドデザインパターン目録 by JAWS-UGアーキテクチャ専門支部
山崎奈緒美 / 金平晃尚 / 神希嘉
赤ドクロ Presents 『AWSで開発するならこれやっときゃいいよ的な話』(仮)
西谷圭介
自分と組織を「クラウド対応」にするための実践的な方法を考える
大谷イビサ/小野和俊/斎藤昌義
JAWS-UG meets Windows ~Windows開発者およびインフラエンジニアのためのDev&Ops on AWS~
渡邉源太 / 福井厚
エンタープライズ企業におけるAWS公式採用への挑戦〜レガシーを微笑みにかえて〜
大橋 衛
[2コマ連続 1/2]
Raspberry Pi + SORACOM Harvestで可視化
辻 一郎
[3コマ連続 1/3]
Raspberry PI で自作 Echo を作ろう!
伊東知治 / 市川 純 / 堀田 直孝
不安で夜眠れないAWSアカウント管理者に送る処方箋という名のハンズオン
角山恵介
本当の敵は社内にいる!? ~攻める情シスが吠える座談会~
石井大河 / 大橋衛 / 久保田有紀 / 松本紘直
AWS SECURITY DEATH \m/ ~セキュ鮫様からのお告げ~ by Security-JAWS
大喜多利哉 / 吉江瞬/ 森永大志
ひとりでも怖くない!コミュニティの広げ方
小深田あゆみ
—–
サーバーレスでシステムを開発する時に大切な事
比企宏之
[AWS UG Taiwan] Greetings from AWS User Group Taiwan
Cliff Chao-kuan Lu (呂昭寬)
AWSで温暖化シミュレーション!
池上香苗
—–
mizuderuからnekoderuへ
山ノ内祥訓
[2コマ連続 2/2]
Raspberry Pi + SORACOM Harvestで可視化
辻 一郎
[3コマ連続 2/3]
Raspberry PI で自作 Echo を作ろう!
伊東知治 / 市川 純 / 堀田 直孝
Docker on Elastic Beanstalk 〜明日から本番で使えるかも〜
子安 輝
コミュニティで拓く、パラレルキャリアへの道
小島英揮
この世界のあちこちのわたしへ 〜 Woman in tech 〜
山﨑奈緒美 / 小椋敦子 / 高田美紀 / 河合真知子
EXCEL構成管理からの脱却と次世代MSPとDevOps 2.0 by OpsJAWS
伊藤覚宏 / 会澤康二
[AWS UG Singapore] Chat bots with Amazon Lex
Alex Smith(アレックス スミス) / Jo-Anne Tan
kintoneとAWSのよい関係
金春利幸
—–
[JAWS-UG New heroes]
夏目祐樹 / 高橋哲也 / 加藤貴宏 / 渡邊翼
[2コマ連続 1/2]
[ワークショップ] IoTとセキュリティ
辻一郎 / 中村明彦 / 松井基勝 / 藤原吉規
[3コマ連続 3/3]
Raspberry PI で自作 Echo を作ろう!
伊東知治 / 市川 純 / 堀田 直孝
EC2の管理で学ぶ、AWS Lambda入門
廣山豊
6年前のその時、クラウドで何ができたのか 〜JAWSとタイガーチーム〜
大石良
サーバレスの今と未来
吉田真吾
金融クラウド&FINTECH最前線。~AWSで金融からイノベーション! 2017
渥美俊英
知らない間に使われていませんか? ~AWSの利用監査対策~
多田友昭
DevOpsとか言う前にAWSエンジニアが知るべきアプリケーションのこと
照井将士
[2コマ連続 2/2]
[ワークショップ] IoTとセキュリティ
辻一郎 / 中村明彦 / 松井基勝 / 藤原吉規
—–
[3コマ連続 1/3]
Raspberry Pi + Athena + QuickSightで可視化
山下光洋 / 浅賀功次
Alexa Skills Kit で遊ぼう【基礎編】 1回目
市川純 / 伊東知治 / 森大樹 / Mr.T 流しのAlexaおじさん / 堀田 直孝
AWS初心者いらっしゃい
伊藤秀樹
武闘派CIO3人が、ホンネで語るITの現実
友岡賢二 / 喜多羅滋夫 / 長谷川秀樹
おとなのたしなみ、おコンテナ by JAWS-UGコンテナ支部
原康紘
IAM 権限をこえて
大喜多利哉 / 大竹 孝昌 / 好光 泰章
[AWS Korea User Group]
ソウルリージョンを通じたマルチリージョンアーキテクチャの高可用性を構成する

Channy Yun
—–
[AWS Korea User Group]
Raspberry Piを利用した顔の表情分析と感情を認識するシステム構築

Hyunmin Kim
子ども向けプログラミング道場を運営してみたお話し〜CoderDojo長岡京と、時々、EC2〜
永田明
—–
SORACOM UGで発表されたLTやブログを紹介しちゃうよ!!
松下享平
[3コマ連続 2/3]
Raspberry Pi + Athena + QuickSightで可視化
山下光洋 / 浅賀功次
Alexa Skills Kit で遊ぼう【応用編】
市川純 / 伊東知治 / 森大樹 / Mr.T 流しのAlexaおじさん / 堀田 直孝
Amazon Kinesis Analyticsを触ってみよう
高田雅人
AWSデータベースアップデート 2017
星野豊
東日本大震災を経験した私達が後世に残す物資支援の仕組み「必要な人に必要な支援を必要な分だけ」
矢崎 淳一
—–
熊本震災時におけるクラウド活用について
渡邉一弘 / 富山孝治
The AWS Japan Mafia トークセッション 2017
吉田真吾 / 上原誠 / 佐々木きはる / 今井雄太
APIを叩くだけでない、Deep Learning on AWS で自分だけの学習モデルを作ろう! by JAWS-UG AI支部
長尾太介 / 中丸 良
社内でAWS育成講座を運営したよもやま話
石田真彩
—–
サーバーレスが切り拓く、Eightのリアルタイム大規模データ分析
藤井洋太郎
[3コマ連続 3/3]
Raspberry Pi + Athena + QuickSightで可視化
山下光洋 / 浅賀功次
Alexa Skills Kit で遊ぼう【基礎編】 2回目
市川純 / 伊東知治 / 森大樹 / Mr.T 流しのAlexaおじさん / 堀田 直孝
※1回目と同じ内容です
AWSで始めるサーバレスな RESTful API システム
加藤雅之

続きを読む

AWS Lambda Javaをローカルで実行できる環境をSpring Bootベースで作ってみた

AWS Lambda Javaでアプリケーションを作成した際に、まずはローカルでデバッグしようとするとJUnitを書くことが普通かと思います。が、AWS Lambdaのテストのようなことをローカルでも簡単にできるようにしたい、で、デバッグをできるようにしたいと思い、今回ローカルでAWS Lambda Javaを実行できる環境を作ってみました。

ネット環境は悪いけど、ちょっと作ったAWS Lambda Javaの確認をしたい、という時にも使えるかと思います。

結果

現状だとhandleRequestメソッドの第一引数はString型とMap<String, Object>型に対応しています。とりあえずこれだけあればダイジョーブなはず。

https://github.com/kojiisd/aws-lambda-rest

使い方

大まかな流れは以下になります。

  1. AWS Lambda Java(実行対象)のJarファイル作成
  2. AWSLambdaRestへの適用
  3. 実際に実行

AWS Lambda Java(実行対象)のJarファイル作成

サンプルとしてこんな感じのAWS Lambda Javaを組んでみます。

AWSLambdaExample.java
public class AwsLambdaExample  implements RequestHandler<String, Object> {

    public String handleRequest(String input, Context context) {
        context.getLogger().log("Input: " + input);

        return "Input result: " + input;
    }
}

pom.xmlにはこんな感じでjar-with-dependenciesを作れるように設定しておきます。

pom.xml
<dependencies>
    <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>aws-lambda-java-core</artifactId>
        <version>1.1.0</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </plugin>
    </plugins>
</build>

AWSLambdaRestへの適用

作成したJarファイルをAWSLambdaRestに適用します。例ではextlibフォルダ配下にJarファイルを配置して、pom.xmlとapplication.ymlを編集します。

まずpom.xmlには以下を記述します。

pom.xml
<dependency>
    <groupId>jp.gr.java_conf.kojiisd</groupId>
    <artifactId>aws-lambda-example</artifactId>
    <version>1.0-SNAPSHOT</version>
    <scope>system</scope>
    <systemPath>${basedir}/extlib/aws-lambda-example-1.0-SNAPSHOT.jar</systemPath>
</dependency>

application.ymlには実行させたいhandleRequestが所属するクラスを指定します。

application.yml
lambda-rest:
  target: jp.gr.java_conf.kojiisd.AwsLambdaExample

実際に実行

上記まで実施できたら、実行してみます。Jarファイルを作成し、以下のコマンドを実行してください。

$ java -cp target/aws-lambda-local-rest-0.0.1-SNAPSHOT.jar jp.gr.java_conf.kojiisd.AwsLambdaLocalRestApplication

結果の確認

起動したら、実際に値を送付してみます。RestClientを利用して、以下のJSONコードを送付します。

"test"

通りましたね。

スクリーンショット 2017-03-04 8.37.33.png

ちなみに今回のサンプルでは、ログに入力値を出力する処理が書かれていますが、下記のような手抜きな実装のため、ログに出力する処理はコンソールに出力されます。

スクリーンショット 2017-03-04 8.38.02.png

            @Override
            public LambdaLogger getLogger() {
                return new LambdaLogger() {
                    @Override
                    public void log(String s) {
                        System.out.println(s);
                    }
                };
            }

もちろん今回利用したJarファイルは、そのままAWS Lambda Javaでも実行可能です。

まとめ

今回ローカルでAWS Lambda Javaのシミュレートができる環境を作ってみました。まだ実行対象のメソッド特定を動的にできないなど改善点はありますが、ひとまずこれでやりたいことはできるようになりました。もちろんプルリク、大歓迎です。

続きを読む