AWS Lambda (Node.js)の環境変数をTerraformから設定する

# はじめに
先月（2016/11/18）に [AWS Lambda が 環境変数をサポート](https://aws.amazon.com/jp/about-aws/whats-new/2016/11/aws-lambda-supports-environment-variables/ "https://aws.amazon.com/jp/about-aws/whats-new/2016/11/aws-lambda-supports-environment-variables/") しました。
それに合わせて、[Terraform](https://www.terraform.io/ "https://www.terraform.io/") も [バージョン0.7.12で対応](https://github.com/hashicorp/terraform/blob/v0.7.13/CHANGELOG.md#0712-november-22-2016 "terraform/CHANGELOG.md") しました。

この記事では、TerraformからAWS Lambdaの環境変数を設定する方法を紹介します。
なお、Terraform のバージョンは2016/12/11時点での最新 `0.7.13` を使っています。

```bash:Terraformのバージョン
$ terraform.exe -v
Terraform v0.7.13
```

# 環境変数のうれしさ
環境変数を使うと、関数(zip)内のパラメータの変更が容易になります。

今までだったらパラメータを使う時、例えば以下のような方法が取っていたかとおもいます。

* 関数内に直書き
* 関数名に入れてパース
* DBに持たせる

しかし、関数内に直書きしていると、関数の何かのパラメータが変わるたびにzipファイルを作り直してアップロードしなくてはなりませんでした。
関数名に入れてパースは事故の元になりそうです。
DBに持たせるのは手軽さに欠けます。

今回のLambdaによる環境変数のサポートで、手軽かつスマートにパラメータを使用・変更できるようになりました。
※ ただし、環境変数のサイズには上限（[4 KB](http://docs.aws.amazon.com/lambda/latest/dg/env_variables.html#env_limits "Environment Variables - AWS Lambda #env_limits")）があります。


# 環境変数の使い方
## 設定方法（Terraform側）
`environment` 引数の中に 属性名を `variables`、値をMap形式で書きます。

```js:aws_lambda_function.tf
	environment {
		variables = {
			key1 = "aaaabbbb"
			key2 = "aaaa\nbbbb"
			key3 = "${var.value3}"
			key4 = "${var.value4}"
			key6 = "${var.value6}"
		}
	}
```
※ 下にaws_lambda_functionリソース全体も書いてあります。

## 取得方法（Node.js側）
`process.env` 変数から取得

```js:Node.js
const value1 = process.env.key1;
const value2 = process.env.key2;
const keyName = "key3"
const value3 = process.env[keyName];
```

# サンプル
https://github.com/tksugimoto/terraform_aws-lambda-environment-variables-sample

## Terraform
```js:variables.tf
variable "value3" {
	default = "aaaa\nbbbb"
}
variable "value4" {
	default = "aaaa\\nbbbb"
}
variable "value6" {
	default = "日本語もOK"
}
```

```js:lambda-function.tf
resource "aws_lambda_function" "env_test" {
	function_name = "${var.prefix}"
	role = "${aws_iam_role.iam_for_lambda.arn}"
	runtime = "nodejs4.3"
	handler = "index.handler"
	filename = "index.zip"
	source_code_hash = "${base64sha256(file("index.zip"))}"
	environment {
		variables = {
			key1 = "aaaabbbb"
			key2 = "aaaa\nbbbb"
			key3 = "${var.value3}"
			key4 = "${var.value4}"
			key6 = "${var.value6}"
		}
	}
}
```

## Node.js
```js:index.js
exports.handler = () => {
	console.log("Fired!");

	const value1 = process.env.key1;
	console.log(`key1: ${value1}`);

	const value2 = process.env.key2;
	console.log(`key2: ${value2}`);

	const keyName = "key3"
	const value3 = process.env[keyName];
	console.log(`key3: ${value3}`);

	console.log(`key4: ${process.env.key4}`);
	console.log(`key5: ${process.env.key5}`);
	console.log(`typeof key5: ${typeof process.env.key5}`);
	console.log(`key6: ${process.env.key6}`);
};
```

# 備考

## 改行は `\n` ではなく `\\n` 推奨

### 理由1) マネジメントコンソール上で変数の値内の改行を確認できない
![マネジメントコンソールの環境変数表示画像](https://qiita-image-store.s3.amazonaws.com/0/92375/4c0c2d31-4a23-f3e1-be02-ca9053bc1790.png "マネジメントコンソールの環境変数表示")
※ key名でソートしてくれないみたいです

* `key2`, `key3` に `\n` をいれてあるが改行が見えない
    * `key4` には `\\n` (`value4`)を渡したので、表示が `\n` になっています
* 下の出力結果では改行されているので内部では改行が存在するようです

    ```text:key1-4の出力結果
    2016-12-11T06:02:02.678Z	55e4239f-bf67-11e6-956c-4d9dde297bec	key1: aaaabbbb
    2016-12-11T06:02:02.678Z	55e4239f-bf67-11e6-956c-4d9dde297bec	key2: aaaa
    bbbb
    2016-12-11T06:02:02.678Z	55e4239f-bf67-11e6-956c-4d9dde297bec	key3: aaaa
    bbbb
    2016-12-11T06:02:02.678Z	55e4239f-bf67-11e6-956c-4d9dde297bec	key4: aaaa
    bbbb
    ```

### 理由2) マネジメントコンソール上から編集すると、改行がなくなる
例) `key2`, `key3`, `key4` に `cccc` をマネジメントコンソール上から追加した場合
マネジメントコンソール上で改行が表示されていなかった `key2`, `key3` の改行が消えました

```text:key1-4の出力結果（マネジメントコンソールで編集後）
2016-12-11T06:14:46.537Z	1d359235-bf69-11e6-bdcc-73d201f9fb5d	key1: aaaabbbb
2016-12-11T06:14:46.537Z	1d359235-bf69-11e6-bdcc-73d201f9fb5d	key2: aaaabbbbcccc
2016-12-11T06:14:46.537Z	1d359235-bf69-11e6-bdcc-73d201f9fb5d	key3: aaaabbbbcccc
2016-12-11T06:14:46.537Z	1d359235-bf69-11e6-bdcc-73d201f9fb5d	key4: aaaa
bbbbcccc
```


## 日本語も使用可
```text:key6の出力結果
2016-12-11T06:02:02.678Z	55e4239f-bf67-11e6-956c-4d9dde297bec	key6: 日本語もOK
```


## カンマ `,` が使えない
Terraform関係なく、AWS Lambdaの環境変数の仕様です。
`terraform apply` すると以下のエラーメッセージが出ます。

```text:エラーメッセージ
ValidationException: 1 validation error detected: Value at 'environment.variables' failed to satisfy constraint: Map value must satisfy constraint: [Member must satisfy regular expression pattern: [^,]*]
```

※ `terraform plan` ではエラーになりません。

## 指定していないkeyの環境変数を取得すると `undefined` になる
Terraform関係なく、AWS Lambda (Node.js) の環境変数の仕様です。

```text:key5の出力結果
2016-12-11T06:02:02.678Z	55e4239f-bf67-11e6-956c-4d9dde297bec	key5: undefined
2016-12-11T06:02:02.678Z	55e4239f-bf67-11e6-956c-4d9dde297bec	typeof key5: undefined
```
※ String型の `undefined` （文字列）ではなく **undefined**型です。

```js
process.env.key5.replace("unde", "----")
```
のようにmethodをつなげるとエラーになります。

```text:エラーメッセージ
TypeError: Cannot read property 'replace' of undefined
```


----
# あとがき
* Terraformのcodeのシンタックスハイライトって何を指定すると良いんでしょう？  
    `text` だと読みづらいので `js` (JavaScript) を指定してみましたが、一部おかしくなります。。
* [Amazon Web Services Advent Calendar 2016 - Qiita](http://qiita.com/advent-calendar/2016/aws "http://qiita.com/advent-calendar/2016/aws") がガラ空きだったので入れておきました。