[JAWS-UG CLI] Lambda #25 StepFunctions用関数 (FailFunction)

前提条件
========


Lambdaへの権限
--------------

Lambdaに対してフル権限があること。


AWS CLI
-------

以下のバージョンで動作確認済

- AWS CLI 1.10.60

```bash:コマンド:
aws --version
```

結果(例):

      aws-cli/1.11.34 Python/2.7.10 Darwin/15.6.0 botocore/1.4.91

バージョンが古い場合は最新版に更新しましょう。

```bash:コマンド:
sudo -H pip install -U awscli
```



IAM Role
--------

'lambdaBasicExecution'ロールが存在すること。


0. 準備
=======

まず変数の確認をします。

```bash:変数の確認:
cat << ETX

        AWS_DEFAULT_PROFILE: (0.1) ${AWS_DEFAULT_PROFILE}
        AWS_DEFAULT_REGION:  (0.2) ${AWS_DEFAULT_REGION}
        IAM_ROLE_ARN:        (0.3) ${IAM_ROLE_ARN}

ETX
```

結果(例):

      AWS_DEFAULT_PROFILE: (0.1) lambdaFull-prjz-mbp13
      AWS_DEFAULT_REGION:  (0.2) ap-northeast-1
      IAM_ROLE_ARN:        (0.3) arn:aws:iam::XXXXXXXXXXXX:role/lambdaBasicExecution

変数が入っていない、適切でない場合は、それぞれの手順番号について作業を
行います。


0.1. プロファイルの指定
-----------------------

プロファイルの一覧を確認します。

```bash:コマンド:
cat ~/.aws/credentials \
       | grep '\[' \
       | sed 's/\[//g' | sed 's/\]//g'
```

結果(例):

      iamFull-prjz-mbpr13
      lambdaFull-prjz-mbp13

```bash:変数の設定:
export AWS_DEFAULT_PROFILE='lambdaFull-prjz-mbp13'
```


0.2. リージョンの指定
---------------------

```bash:変数の設定:
export AWS_DEFAULT_REGION='ap-northeast-1'
```


0.3. IAMロールの指定
--------------------

```bash:変数の設定:
IAM_ROLE_NAME='lambdaBasicExecution'
```

```bash:コマンド:
aws iam get-role \
         --role-name ${IAM_ROLE_NAME}
```

結果(例):

      {
          "Role": {
            "AssumeRolePolicyDocument": {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Action": "sts:AssumeRole",
                        "Principal": {
                            "Service": "lambda.amazonaws.com"
                        },
                        "Effect": "Allow",
                        "Sid": ""
                    }
                ]
            },
            "RoleId": "AROAXXXXXXXXXXXXXXXXX",
            "CreateDate": "2017-03-19T01:23:45Z",
            "RoleName": "lambdaBasicExecution",
            "Path": "/",
            "Arn": "arn:aws:iam::XXXXXXXXXXXX:role/lambdaBasicExecution"
          }
      }

```bash:コマンド:
IAM_ROLE_ARN=$( \
        aws iam get-role \
          --role-name ${IAM_ROLE_NAME} \
          --query 'Role.Arn' \
          --output text \
) \
        && echo ${IAM_ROLE_ARN}
```

結果(例):

      arn:aws:iam::XXXXXXXXXXXX:role/lambdaBasicExecution


1. 事前作業
===========


1.1. Lambda関数名の決定
-----------------------

```bash:変数の設定:
LAMBDA_FUNC_NAME='FailFunction'
```

同名のLambda関数の不存在確認

```bash:コマンド:
aws lambda get-function \
        --function-name ${LAMBDA_FUNC_NAME}
```

結果(例):

      A client error (ResourceNotFoundException) occurred when calling the GetFunction operation: Function not found: arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:FailFunction


1.2. Lambda関数
---------------

```bash:変数の設定:
FILE_LAMBDA_FUNC='FailFunction.js'
```

```bash:コマンド:
cat << EOF > ${FILE_LAMBDA_FUNC}
exports.handler = function(event, context, callback) {
   function AccountAlreadyExistsError(message) {
       this.name = "AccountAlreadyExistsError";
       this.message = message;
   }
   AccountAlreadyExistsError.prototype = new Error();

   const error = new AccountAlreadyExistsError("Account is in use!");
   callback(error);
};
EOF
```

      cat ${FILE_LAMBDA_FUNC}

結果(例):

      exports.handler = function(event, context, callback) {
         function AccountAlreadyExistsError(message) {
             this.name = "AccountAlreadyExistsError";
             this.message = message;
         }
         AccountAlreadyExistsError.prototype = new Error();

         const error = new AccountAlreadyExistsError("Account is in use!");
         callback(error);
      };

```bash:コマンド:
zip ${LAMBDA_FUNC_NAME}.zip ${FILE_LAMBDA_FUNC}
```

結果:

      adding: FailFunction.js (deflated 43%)


2. Lambda関数の作成
===================

```bash:変数の設定:
LAMBDA_FUNC_DESC='Always generate an error.'
LAMBDA_RUNTIME='nodejs4.3'
LAMBDA_HANDLER="${LAMBDA_FUNC_NAME}.handler"
FILE_LAMBDA_ZIP="${LAMBDA_FUNC_NAME}.zip"
```

```bash:変数の確認:
cat << ETX

        LAMBDA_FUNC_NAME:  ${LAMBDA_FUNC_NAME}
        LAMBDA_FUNC_DESC: "${LAMBDA_FUNC_DESC}"
        LAMBDA_RUNTIME:    ${LAMBDA_RUNTIME}
        FILE_LAMBDA_ZIP    ${FILE_LAMBDA_ZIP}
        IAM_ROLE_ARN:      ${IAM_ROLE_ARN}
        LAMBDA_HANDLER:    ${LAMBDA_HANDLER}

ETX
```

```bash:コマンド:
aws lambda create-function \
        --function-name ${LAMBDA_FUNC_NAME} \
        --description "${LAMBDA_FUNC_DESC}" \
        --zip-file fileb://${FILE_LAMBDA_ZIP} \
        --runtime ${LAMBDA_RUNTIME} \
        --role ${IAM_ROLE_ARN} \
        --handler ${LAMBDA_HANDLER}
```

結果(例):

      {
        "CodeSha256": "uW+ZzaP1iDzaUfhFUyed0CdaOcSxbcsFd7yJXjHbWX8=",
        "FunctionName": "FailFunction",
        "CodeSize": 353,
        "MemorySize": 128,
        "FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:FailFunction",
        "Version": "$LATEST",
        "Role": "arn:aws:iam::XXXXXXXXXXXX:role/lambdaBasicExecution",
        "Timeout": 3,
        "LastModified": "2017-03-19T01:23:45.678+0000",
        "Handler": "FailFunction.handler",
        "Runtime": "nodejs4.3",
        "Description": "Always generate an error."
      }

```bash:コマンド:
aws lambda get-function \
        --function-name ${LAMBDA_FUNC_NAME}
```

結果(例):

      {
        "Code": {
          "RepositoryType": "S3",
          "Location": "https://awslambda-ap-ne-1-tasks.s3-ap-northeast-1.amazonaws.com/snapshots/XXXXXXXXXXXX/FailFunction-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx?x-amz-security-token=AQxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&AWSAccessKeyId=ASIAXXXXXXXXXXXXXXXX&Expires=xxxxxxxxxx&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      },
      "Configuration": {
          "Version": "$LATEST",
          "CodeSha256": "uW+ZzaP1iDzaUfhFUyed0CdaOcSxbcsFd7yJXjHbWX8=",
          "FunctionName": "FailFunction",
          "MemorySize": 128,
          "CodeSize": 353,
          "FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:FailFunction",
          "Handler": "FailFunction.handler",
          "Role": "arn:aws:iam::XXXXXXXXXXXX:role/lambdaBasicExecution",
          "Timeout": 3,
          "LastModified": "2017-03-19T01:23:45.678+0000",
          "Runtime": "nodejs4.3",
          "Description": "Always generate an error."
        }
      }

```bash:コマンド:
aws lambda get-function-configuration \
        --function-name ${LAMBDA_FUNC_NAME}
```

結果(例):

      {
        "CodeSha256": "uW+ZzaP1iDzaUfhFUyed0CdaOcSxbcsFd7yJXjHbWX8=",
        "FunctionName": "FailFunction",
        "CodeSize": 353,
        "MemorySize": 128,
        "FunctionArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:FailFunction",
        "Version": "$LATEST",
        "Role": "arn:aws:iam::XXXXXXXXXXXX:role/lambdaBasicExecution",
        "Timeout": 3,
        "LastModified": "2017-03-19T01:23:45.678+0000",
        "Handler": "FailFunction.handler",
        "Runtime": "nodejs4.3",
        "Description": "Always generate an error."
      }


3. Lambda関数の動作確認
=======================


3.1. サンプルデータの作成
-------------------------

```bash:変数の設定:
FILE_INPUT="${LAMBDA_FUNC_NAME}-data.json" \
          && echo ${FILE_INPUT}
```

サンプルデータ:

      cat << EOF > ${FILE_INPUT}
      {
        "key3": "value3",
        "key2": "value2",
        "key1": "value1"
      }
      EOF

      cat ${FILE_INPUT}

JSONファイルを作成したら、フォーマットが壊れてないか必ず確認します。

```bash:コマンド:
jsonlint -q ${FILE_INPUT}
```

エラーが出力されなければOKです。


3.2. lambda関数の手動実行
-------------------------

```bash:変数の設定:
FILE_OUTPUT_LAMBDA="${LAMBDA_FUNC_NAME}-out.txt"
FILE_LOG_LAMBDA="${LAMBDA_FUNC_NAME}-$(date +%Y%m%d%H%M%S).log"
```

```bash:変数の確認:
cat << ETX

        LAMBDA_FUNC_NAME:   ${LAMBDA_FUNC_NAME}
        FILE_INPUT:         ${FILE_INPUT}
        FILE_OUTPUT_LAMBDA: ${FILE_OUTPUT_LAMBDA}
        FILE_LOG_LAMBDA:    ${FILE_LOG_LAMBDA}

ETX
```

```bash:コマンド:
aws lambda invoke \
        --function-name ${LAMBDA_FUNC_NAME} \
        --log-type Tail \
        --payload file://${FILE_INPUT} \
        ${FILE_OUTPUT_LAMBDA} \
        > ${FILE_LOG_LAMBDA}
```

```bash:コマンド:
cat ${FILE_LOG_LAMBDA} \
        | jp.py 'StatusCode'
```

結果(例):

      200


3.3. lambda関数の実行結果の確認
-------------------------------

```bash:コマンド:
cat ${FILE_OUTPUT_LAMBDA}
```

結果:

      {"errorMessage":"Account is in use!","errorType":"AccountAlreadyExistsError","stackTrace":["exports.handler (/var/task/FailFunction.js:6:42)"]}


3.4. lambda関数のログの確認
---------------------------

```bash:コマンド:
cat ${FILE_LOG_LAMBDA} \
        | jp.py 'LogResult' \
        | sed 's/\"//g' \
        | base64 --decode
```

結果(例):

      START RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Version: $LATEST
      2017-03-19T01:23:45.678Z     xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx    {"errorMessage":"Account is in use!","errorType":"AccountAlreadyExistsError","stackTrace":["exports.handler (/var/task/FailFunction.js:6:42)"]}
      REPORT RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx      Duration: 41.14 ms      Billed Duration: 100 ms         Memory Size: 128 MB        Max Memory Used: 10 MB


完了
====