AwsPowerShellLambda?

2019-09-26

やりたいこと

AWS Lambda .NET Core (PowerShell)をつかって、S3にアップロードされたファイルを処理する関数を作りたい。
でもどういうInputでどういうライブラリ/コードを書けばいいかイメージが湧いていないので、サンプルコードを書く。

想定環境/前準備

.NET Core SDKやAWSPowerShell.NetCoreのインストール等は済んでいる想定。

テンプレートS3Eventをベースとしたスクリプトを作成する。

#sh(ruby){{

New-AwsPowerShellLambda -Template S3Event -Directory ./Sample -ScriptName ./S3FileManipulationSample

}}

パッケージングのために

AWSPowerShell.NetCoreが必要。

#sh(ruby){{

Install-Module -Name AWSPowerShell.NetCore -Scope CurrentUser;

}} 参考:https://conortolan.com/PowerShell-Lambda/

また、zip化するので"zip"コマンドがなければインストールしておく。

#sh(bash){{

sudo yum install zip

}}

生成されたコードなど

自動生成されたコード

#sh(ruby){{
#Requires -Modules @{ModuleName='AWSPowerShell.NetCore';ModuleVersion='3.3.590.0'}


foreach ($record in $LambdaInput.Records) {
$bucket = $record.s3.bucket.name
$key = $record.s3.object.key

Write-Host "Processing event for: bucket = $bucket, key = $key"

# TODO: Add logic to handle S3 event record, for example
$obj = Get-S3Object -Bucket $bucket -Key $key
Write-Host "Object $key is $($obj.Size) bytes"
}

}}

S3イベントのInputObject

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-s3.html

#sh(javascript){{

{
"Records":[
{
"eventVersion":"2.0",
"eventSource":"aws:s3",
"awsRegion":"us-west-2",
"eventTime":"1970-01-01T00:00:00.000Z",
"eventName":"ObjectCreated:Put",
"userIdentity":{
"principalId":"AIDAJDPLRKLG7UEXAMPLE"
},
"requestParameters":{
"sourceIPAddress":"127.0.0.1"
},
"responseElements":{
"x-amz-request-id":"C3D13FE58DE4C810",
"x-amz-id-2":"FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD"
},
"s3":{
"s3SchemaVersion":"1.0",
"configurationId":"testConfigRule",
"bucket":{
"name":"sourcebucket",
"ownerIdentity":{
"principalId":"A3NL1KOZZKExample"
},
"arn":"arn:aws:s3:::sourcebucket"
},
"object":{
"key":"HappyFace.jpg",
"size":1024,
"eTag":"d41d8cd98f00b204e9800998ecf8427e",
"versionId":"096fKKXTRTtl3on89fVO.nfljtsv6qko"
}
}
}
]
}

}}

これはJavaScriptなので、おそらくPowerShellから見ると相応のPSCustomObjectに見えるはず。

これらの情報から「新規にファイルがアップロードされた」イベントと適切に処理するためには

  • "$LambdaInput.Records | ? { $_.eventName -eq 'eventName' }" でフィルタ
  • "$LambdaInput.Records | % { $_.s3.bucket.name }" からバケット名を取得
  • "$LambdaInput.Records | % { $_.s3.object.key }" からバケット内のファイルパスを取得
  • "$LambdaInput.Records | % { $_.s3.object.size }" からバケット内のファイルのサイズを取得
  • バケット名およびパスを元に"Get-S3Object"等で処理

すればよさそう。
https://docs.aws.amazon.com/ja_jp/powershell/latest/reference/index.html

S3FSでファイルをコピーした場合、0バイト(空)ファイル作成→Nバイト(完全)ファイル作成の2回ファイル作成イベントが発生するため
S3トリガでフィルタ出来ないこのイベントをsizeを元に内部で分岐させることが必要。

ファイルの中身を扱うには

Get-S3ObjectはあくまでAmazon.S3.Model.S3Objectオブジェクトであり、中身のデータは持っていない。
https://docs.aws.amazon.com/sdkfornet/v3/apidocs/index.html?page=S3/TS3S3Object.html&tocid=Amazon_S3_Model_S3Object

中身を見るには、Read-S3Objectを使う必要があるが、Read-S3Objectは説明にも書いてある通りローカルファイルシステムにダウンロードし、System.IO.FileInfoオブジェクトを返す。
AWS Lambdaでは一時的でもファイルシステムを使っていいのか不明...だが、PowerShellからはこのAPIしか提供されていないのでRead-S3Objectを使うしかない。

#sh(ruby){{

foreach ($record in $LambdaInput.Records) {
$bucket = $record.s3.bucket.name;
$key = $record.s3.object.key;
$size = $record.s3.object.size;

if($size -eq 0) {
continue;
}

$obj = Get-S3Object -BucketName $bucket -Key $key;
$filenameTemp = Join-Path -Path ([IO.Path]::GetTempPath()) -ChildPath ([IO.Path]::GetRandomFileName());
$file = Read-S3Object -BucketName $bucket -S3Object $obj -File $filenameTemp;

$stream = $file.OpenRead();

# Write your process with $stream here

$stream.Close();
}

}}

パッケージング

#sh(ruby){{

# 通常はVerboseなしでOK
$pack = New-AWSPowerShellLambdaPackage -ScriptPath /path/to/main-script.ps1 -OutputPackage ./path/to/package.zip

# エラーが出て失敗したら、-Verboseつけて詳細を探る
$pack = New-AWSPowerShellLambdaPackage -ScriptPath /path/to/main-script.ps1 -OutputPackage ./path/to/package.zip -Verbose


$pack.LambdaHandler;

}}


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-10-06 (日) 02:17:10