概要 †AWS SDK for Go を触ってみる。 目次 †
Go Lambda のハンドラ †基本形 †有効な関数ハンドラは以下のページに記載されている通り。 例) package main import ( "github.com/aws/aws-lambda-go/lambda" ) func hello() (string, error) { return "Hello World!", nil } func main() { lambda.Start(hello) } Lambdaプロキシ統合を使用する場合 †API Gateway用のLambdaで Lambdaプロキシ統合を使用する場合、 https://github.com/aws/aws-lambda-go/blob/master/events/apigw.go 上記URLを見る限り、各パラメータはそれぞれ以下の通り取得できると思われる。
sample.go package main import ( "fmt" "github.com/aws/aws-lambda-go/events" "github.com/aws/aws-lambda-go/lambda" ) func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { return events.APIGatewayProxyResponse{ Body: fmt.Sprintf("Hello %s!", request.QueryStringParameters["name"]), StatusCode: 200, }, nil } func main() { lambda.Start(handler) } SAM CLI によるローカルでの動作確認 †ハンドラをビルドしておく †GOOS=linux GOARCH=amd64 go build -o sample sample.go template.yml の作成 †AWSTemplateFormatVersion: 2010-09-09 Transform: AWS::Serverless-2016-10-31 Resources: SampleFunction: Type: AWS::Serverless::Function Properties: Handler: sample Runtime: go1.x Tracing: Active Events: GetEvent: Type: Api Properties: Path: / Method: get SAM CLI で Lambda をinvoke †sample_request.json { "path": "/", "httpMethod": "GET", "queryStringParameters": { "name": "Taro" } } イベントJSONの内容を入力として invoke sam local invoke "SampleFunction" -e sample_request.json 標準入力からリクエストデータを渡す場合は -e に "-" を指定する。(JSONを作りたくない場合) echo '{"path": "/", "httpMethod": "GET", "queryStringParameters": {"name": "Taro"}}' | sam local invoke -e "-" "SampleFunction" SAM CLI で API を起動 †ローカルでAPI Gatewayを起動 sam local start-api --template template.yml 動作確認 curl http://127.0.0.1:3000/?name=Taro Hello Taro! ビルド †GOPATHを通しておく export GOPATH=/usr/local/Cellar/go/1.13.5 必要なライブラリをgo getしておく go get github.com/aws/aws-lambda-go/lambda ビルド GOOS=linux GOARCH=amd64 go build -o main main.go パッケージングとデプロイ †TODO: aws cloudformation package と deploy を使用する場合はzip圧縮等も自動でやってくれる?(未確認)
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-go-how-to-create-deployment-package.html 実装メモ †JSONデータを返却する †package main import ( "fmt" "encoding/json" "github.com/aws/aws-lambda-go/events" "github.com/aws/aws-lambda-go/lambda" ) type response struct { Name string `json:"name"` Message string `json:message` } func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { res := &response{ Name: request.QueryStringParameters["name"], Message: fmt.Sprintf("Hello %s!", request.QueryStringParameters["name"]), } body, err := json.Marshal(res) fmt.Printf("%+v", string(body)) if err != nil { return events.APIGatewayProxyResponse{}, err } return events.APIGatewayProxyResponse{ Headers: map[string]string{ "Content-Type": "application/json", }, Body: string(body), StatusCode: 200, }, nil } func main() { lambda.Start(handler) } S3へのアクセス †https://docs.aws.amazon.com/sdk-for-go/api/service/s3/ package main import ( "fmt" "encoding/json" "strings" "github.com/aws/aws-lambda-go/events" "github.com/aws/aws-lambda-go/lambda" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/s3" "github.com/aws/aws-sdk-go/aws" ) type response struct { Objects []string `json:objects` } var svc *s3.S3 var mybucket = "bucket.example" /** * 初期処理 */ func init() { svc = s3.New(session.New()) } /** * Lambdaハンドラ */ func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { // バケットにオブジェクトを追加 putInput := &s3.PutObjectInput{ Body: aws.ReadSeekCloser(strings.NewReader("test1 text!")), Bucket: aws.String(mybucket), Key: aws.String("test1.txt"), } putResult, putErr := svc.PutObject(putInput) if putErr != nil { fmt.Printf("Put Error!\n") fmt.Printf("%+v\n", putErr) } else { fmt.Printf("Put Success!\n") fmt.Printf("%+v\n", putResult) } // バケット内のオブジェクトを取得 getInput := &s3.GetObjectInput{ Bucket: aws.String(mybucket), Key: aws.String("test1.txt"), } getResult, getErr := svc.GetObject(getInput) if getErr != nil { fmt.Printf("Get Error!\n") fmt.Printf("%+v\n", getErr) } else { fmt.Printf("Get Success!\n") fmt.Printf("%+v\n", getResult) } // バケット内のオブジェクト一覧を取得 listInput := &s3.ListObjectsV2Input{Bucket: aws.String(mybucket)} result, _ := svc.ListObjectsV2(listInput) myObjects := result.Contents objects := []string{} for i := 0; i < len(myObjects); i++ { objects = append(objects, *myObjects[i].Key) } // レスポンスデータの設定 body, err := json.Marshal(&response{Objects: objects}) if err != nil { return events.APIGatewayProxyResponse{}, err } else { return events.APIGatewayProxyResponse{ Headers: map[string]string{ "Content-Type": "application/json", }, Body: string(body), StatusCode: 200, }, nil } } func main() { lambda.Start(handler) } DynamoDBへのアクセス †テーブル名:SampleTable、パーティションキー: pkey、ソートキー: skey とした場合の、登録(PutItem)、検索(GetItem、Query)の例。 参考: https://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/ package main import ( "fmt" "encoding/json" "github.com/aws/aws-lambda-go/events" "github.com/aws/aws-lambda-go/lambda" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/dynamodb" "github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute" "github.com/aws/aws-sdk-go/aws" ) type response struct { Items []Record `json:items` } type Record struct { Pkey string `json:pkey` Skey string `json:skey` Value string `json:value` } var svc *dynamodb.DynamoDB var mytable = "SampleTable" /** * 初期処理 */ func init() { svc = dynamodb.New(session.New()) } /** * Lambdaハンドラ */ func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { //------------------------------- // PutItem //------------------------------- putInput := &dynamodb.PutItemInput{ Item: map[string]*dynamodb.AttributeValue{ "pkey": {S: aws.String("test1")}, "skey": {S: aws.String("101")}, "value": {S: aws.String("sample data!")}, }, ReturnConsumedCapacity: aws.String("TOTAL"), TableName: aws.String(mytable), } putResult, putErr := svc.PutItem(putInput) if putErr != nil { fmt.Printf("Put Error!\n") fmt.Printf("%+v\n", putErr) } else { fmt.Printf("Put Success!\n") fmt.Printf("%+v\n", putResult) } //------------------------------- // GetItem //------------------------------- getInput := &dynamodb.GetItemInput{ Key: map[string]*dynamodb.AttributeValue{ "pkey": {S: aws.String("test1")}, "skey": {S: aws.String("101")}, }, TableName: aws.String(mytable), } getResult, getErr := svc.GetItem(getInput) if getErr != nil { fmt.Printf("Get Error!\n") fmt.Printf("%+v\n", getErr) } else { fmt.Printf("Get Success!\n") fmt.Printf("%+v\n", getResult) } //------------------------------- // Query //------------------------------- items := []Record{} queryInput := &dynamodb.QueryInput{ ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{ ":key": {S: aws.String("test1")}, }, KeyConditionExpression: aws.String("pkey = :key"), TableName: aws.String(mytable), } queryResult, queryErr := svc.Query(queryInput) if queryErr != nil { fmt.Printf("Query Error!\n") fmt.Printf("%+v\n", queryErr) } else { fmt.Printf("Query Success!\n") fmt.Printf("%+v\n", queryResult) // 取得結果の構造体への変換は dynamodbattribute を使用して行う事ができる // https://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/dynamodbattribute/ err := dynamodbattribute.UnmarshalListOfMaps(queryResult.Items, &items) if err != nil { panic(fmt.Sprintf("failed to unmarshal Dynamodb Scan Items, %v", err)) } } //------------------------------- // レスポンスデータの設定 //------------------------------- body, err := json.Marshal(&response{Items: items}) if err != nil { return events.APIGatewayProxyResponse{}, err } else { return events.APIGatewayProxyResponse{ Headers: map[string]string{ "Content-Type": "application/json", }, Body: string(body), StatusCode: 200, }, nil } } func main() { lambda.Start(handler) } Credentialの取得 †任意の Credential を指定する場合は credentials.NewChainCredentials などが利用できる。 ec2metrics.go package main import ( "fmt" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awsutil" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/cloudwatch" ) func main() { region := "ap-northeast-1" accessKeyId := "XXXXXXXXXXXXXXXXXXXXXX" secretAccessKey := "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" value, err := getAllMetrics(region, accessKeyId, secretAccessKey) fmt.Printf("%+v", value) if err != nil{ fmt.Printf("Error!") } } /** * メトリクスの一覧を取得する. */ func getAllMetrics(region string, accessKeyId string, secretAccessKey string) (cloudwatch.ListMetricsOutput, error) { namespace := "AWS/EC2" //metric := "CPUUtilization" creds, err := GetCredentials(accessKeyId, secretAccessKey) if err != nil { return cloudwatch.ListMetricsOutput{}, err } cfg := &aws.Config{ Region: aws.String(region), Credentials: creds, } sess, err := session.NewSession(cfg) if err != nil { return cloudwatch.ListMetricsOutput{}, err } svc := cloudwatch.New(sess, cfg) params := &cloudwatch.ListMetricsInput{ Namespace: aws.String(namespace), //MetricName: aws.String(metric), } var resp cloudwatch.ListMetricsOutput err = svc.ListMetricsPages(params, func(page *cloudwatch.ListMetricsOutput, lastPage bool) bool { metrics, _ := awsutil.ValuesAtPath(page, "Metrics") for _, metric := range metrics { resp.Metrics = append(resp.Metrics, metric.(*cloudwatch.Metric)) } return !lastPage }) if err != nil { return resp, err } return resp, err } /** * クレデンシャル取得. */ func GetCredentials(accessKeyId string, secretAccessKey string) (*credentials.Credentials, error) { creds := credentials.NewChainCredentials( []credentials.Provider{ &credentials.StaticProvider{Value: credentials.Value{ AccessKeyID: accessKeyId, SecretAccessKey: secretAccessKey, }}, //&credentials.EnvProvider{}, // 環境変数から取得? }) return creds, nil } |