目的
前回記事でcfn-response モジュールを使用したが、
インライン実装にしか対応しておらず不便なためLayerとして実装する
ファイル構成
lambda-layer/
├─ layers/
│ └─ cfn-response-layer/
│ └─ nodejs/
│ ├─ node_modules/ # [npm i cfn-response] で生成
│ ├─ cfn-response/
│ │ ├─ package.json # [npm init] で生成
│ │ └─ index.js # Layerとして提供する機能
│ │
│ ├─ package.json
│ └─ package-lock.json # [npm i cfn-response] で生成
│
└─ template.yaml # SAMテンプレート
※nodejs
フォルダは名前変更不可
※index.js
ファイルは名前変更不可ではないが、別名とした場合はnpm init
した際にファイル名の指定が必要
SAMテンプレート
CfnResponse:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: !Sub ${RootStackName}_cfn-response
ContentUri: layers/cfn-response-layer
CompatibleRuntimes:
- nodejs12.x
RetentionPolicy: Delete
Layerとして提供する機能はnodejs
フォルダに入れることが決められているので、
ContentUri
には、その1個手前までのパスを指定
cfn-response モジュール実装
index.js
index.js
にcfn-response モジュールの機能を実装する
githubで公開されているcfn-response モジュールのコードを基本コピペする
SUCCESS
, FAILED
の定義値と、send関数を提供する
const https = require('https');
const url = require('url');
module.exports = {
SUCCESS: 'SUCCESS',
FAILED: 'FAILED',
send(
event,
context,
responseStatus,
responseData,
physicalResourceId,
noEcho,
) {
return new Promise((resolve, reject) => {
const responseBody = JSON.stringify({
Status: responseStatus,
Reason: `See the details in CloudWatch Log Stream: ${context.logStreamName}`,
PhysicalResourceId: physicalResourceId || context.logStreamName,
StackId: event.StackId,
RequestId: event.RequestId,
LogicalResourceId: event.LogicalResourceId,
NoEcho: noEcho || false,
Data: responseData,
});
console.log('Response body:\n', responseBody);
const parsedUrl = url.parse(event.ResponseURL);
const options = {
hostname: parsedUrl.hostname,
port: 443,
path: parsedUrl.path,
method: 'PUT',
headers: {
'content-type': '',
'content-length': responseBody.length,
},
};
const request = https.request(options, response => {
console.log(`Status code: ${response.statusCode}`);
console.log(`Status message: ${response.statusMessage}`);
resolve(context.done());
});
request.on('error', error => {
console.log(`send(..) failed executing https.request(..): ${error}`);
reject(context.done(error));
});
request.write(responseBody);
request.end();
});
},
};
nodejs/cfn-response/package.json
nodejs/cfn-response/
以下でnpm init
を実行する
全てデフォルト値で回答すると以下のようなpackage.json
が生成される
{
"name": "cfn-response",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
nodejs/package.json
package.json
は内容{}
のみで作成
npm install <パッケージ名>
を実行すると追記される
node_modules
およびpackage-lock.json
nodejs
フォルダ以下でnpm i cfn-response
を実行すると生成される
index.js
内でhttps
、url
パッケージを使用しているが、これらはnodejsの標準モジュールのためインストールは不要
Layerの使用
SAMテンプレート
ApplyNotificationFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub ${RootStackName}-ApplyNotificationFunction
CodeUri: handlers
Role: !GetAtt 'ApplyNotificationFunctionRole.Arn'
Layers:
- !Ref CfnResponse # 先ほどSAMテンプレートで定義したLayerを参照
コード
const cfnResponse = require('cfn-response');
exports.handler = async (event, context) => {
try {
if (event.RequestType !== 'Create') {
await cfnResponse.send(event, context, cfnResponse.SUCCESS);
return;
}
...