[Oracle Cloud] Events のパラメータを、Oracle Functions 側で取得

# はじめに

Oracle Cloud Infrastructure(以下OCI)では、サーバレスサービス群でコアの部分である FaaS サービスの Oracle Function がリリースされました。
また、OCI 上のリソースでの各種イベントをトリガーにして、様々なサービスを呼び出す Events サービスも一緒にリリースされています。



Events のトリガーは、現時点で 2種類のサービスに対応しています。

- Object Storage
- Autonomous DB



また、Events のアクションは、現時点で3種類のサービスに対応しています。

- Functions
- Streaming
- Notifications



今回は、Object Storage 上で Object の作成・更新・削除をイベントをトリガーにして、Oracle Functions を呼び出したときにどのようなパラメータを取得できるか確認をします。



# Functions の作成

まず、Functions を動かす準備が出来ていない場合は、以下の Doucment や Quick Start Guide を参考にして、事前準備をします。
Preparing for Oracle Functions
https://docs.cloud.oracle.com/iaas/Content/Functions/Concepts/functionsprerequisites.htm

Quick Start Guide
https://www.oracle.com/webfolder/technetwork/tutorials/infographics/oci_faas_gettingstarted_quickview/functions_quickview_top/functions_quickview/index.html

Functions を動かす準備が出来たあと、Events の入力を受け取りJSON として output するためのコードをプログラミングします。

GitHub にアップロードしているものと同一です
https://github.com/Sugi275/oci-go-fdk-events-sample/blob/master/func.go

```go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"time"
	_ "os"

	fdk "github.com/fnproject/fdk-go"
)

func main() {
	fdk.Handle(fdk.HandlerFunc(myHandler))

	// ------- local development ---------
	// reader := os.Stdin
	// writer := os.Stdout
	// myHandler(context.TODO(), reader, writer)
}

//EventsInput test
type EventsInput struct {
	CloudEventsVersion string      `json:"cloudEventsVersion"`
	EventID            string      `json:"eventID"`
	EventType          string      `json:"eventType"`
	Source             string      `json:"source"`
	EventTypeVersion   string      `json:"eventTypeVersion"`
	EventTime          time.Time   `json:"eventTime"`
	SchemaURL          interface{} `json:"schemaURL"`
	ContentType        string      `json:"contentType"`
	Extensions         struct {
		CompartmentID string `json:"compartmentId"`
	} `json:"extensions"`
	Data struct {
		CompartmentID      string `json:"compartmentId"`
		CompartmentName    string `json:"compartmentName"`
		ResourceName       string `json:"resourceName"`
		ResourceID         string `json:"resourceId"`
		AvailabilityDomain string `json:"availabilityDomain"`
		FreeFormTags       struct {
			Department string `json:"Department"`
		} `json:"freeFormTags"`
		DefinedTags struct {
			Operations struct {
				CostCenter string `json:"CostCenter"`
			} `json:"Operations"`
		} `json:"definedTags"`
		AdditionalDetails struct {
			Namespace        string `json:"namespace"`
			PublicAccessType string `json:"publicAccessType"`
			ETag             string `json:"eTag"`
		} `json:"additionalDetails"`
	} `json:"data"`
}

func myHandler(ctx context.Context, in io.Reader, out io.Writer) {
	input := &EventsInput{}
	json.NewDecoder(in).Decode(input)

	outputJSON, _ := json.Marshal(&input)
	fmt.Println(string(outputJSON))
	out.Write([]byte("text message wo kaku"))
}
```



1個目のポイントは、14行目の次の箇所です。この指定により、myHandler が Oracle Functions の関数として呼び出されます

```
	fdk.Handle(fdk.HandlerFunc(myHandler))
```



myHandler の定義を見ていきます。引数の2つ目の `in io.Reader` に、Events から入力されたパラメータ群が格納されています。
`in` を EventsInput structとして定義した JSONを作成して、出力します。
Oracle Functions のなかで `fmt.Println` を行うと、Functions の logging 先に出力されます。
現時点でlogging は、Object Storage と syslog の二種類がありますが、syglog を選択して Papertrail などを利用すると楽で良いでしょう。

```
func myHandler(ctx context.Context, in io.Reader, out io.Writer) {
	input := &EventsInput{}
	json.NewDecoder(in).Decode(input)

	outputJSON, _ := json.Marshal(&input)
	fmt.Println(string(outputJSON))
	out.Write([]byte("text message wo kaku"))
}
```



上記作成後、deploy を行います。以下はdeployのコマンド例です。環境にあわせて適宜変更してください。

```
fn --verbose deploy --app susugiya
```



なお、function の名前は `events-sample` としています

```
> cat func.yaml 
schema_version: 20180708
name: events-sample
version: 0.0.7
runtime: go
entrypoint: ./func
```



# Object Storage の Bucket を作成

Events の対象とするための Object Storage Bucket を作成します。
OCIのメニューから、Object Storage を開き、Create Bucket を選択します。

以下のパラメータを入力し、Create を行います。

- name : sample_events



# Events の設定

Events サービスの設定を行い、Object Storage のイベントをトリガーにして、Oracle Functions を呼び出します。
OCIのメニューから、Application Integration > Events Serviceを選択します。
Create Rule を押します。

以下のパラメータを入力して、Create Rule を押します。

- DISPLAY NAME : events_test
- DESCRIPTION : events_test
- Events Matching : 下の画像を参考にして設定する
  - EVENT TYPE に Object の Create, Delete, Update の3種類を入力
  - Attribute に、`bucketName` を `sample_events` と手入力することで、特定のバケットに制限
- Actions : Function の 名前を指定

![1566736873799.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/454c5bb6-572d-dbd8-3a82-097c277eb79f.png)



# Bucket にファイルをアップロード

作成した Bucket `sample_events` にファイルをアップロードすると、Events がトリガーして、Function が起動します。
Function に設定した logging の先を確認すると、Events から入力されたパラメータを確認することが出来ます。


## Create Object 

- `"eventType": "com.oraclecloud.objectstorage.createobject"` となっています

- `"resourceName": "3eventsample.txt",` となっており、Bucket にアップロードしたファイル名が含まれています

- パラメータに、Bucket 名やOCIDが含まれていない。Function側でBucket名が必要な場合は環境変数設定などで工夫が必要そう

```
{
	"cloudEventsVersion": "0.1",
	"eventID": "51827a0e-7d03-4d6a-b274-fb51e2b0b764",
	"eventType": "com.oraclecloud.objectstorage.createobject", <======== Event の Type
	"source": "objectstorage",
	"eventTypeVersion": "1.0",
	"eventTime": "2019-08-25T09:51:55Z",
	"schemaURL": null,
	"contentType": "application/json",
	"extensions": {
		"compartmentId": "ocid1.compartment.oc1..secret"
	},
	"data": {
		"compartmentId": "ocid1.compartment.oc1..secret",
		"compartmentName": "susugiya",
		"resourceName": "3eventsample.txt",               <======== Object の名前
		"resourceId": "",
		"availabilityDomain": "",
		"freeFormTags": {
			"Department": ""
		},
		"definedTags": {
			"Operations": {
				"CostCenter": ""
			}
		},
		"additionalDetails": {
			"namespace": "tenancyname",
			"publicAccessType": "",
			"eTag": "498e8542-2e9b-4684-87e2-f75ab90354b9"
		}
	}
}
```



## Update Object

`"eventType": "com.oraclecloud.objectstorage.updateobject"` となっています。

```
{
    "cloudEventsVersion": "0.1",
    "eventID": "494ec7c7-9b72-4fed-b81f-f857b5be3616",
    "eventType": "com.oraclecloud.objectstorage.updateobject",
    "source": "objectstorage",
    "eventTypeVersion": "1.0",
    "eventTime": "2019-08-25T11:21:06Z",
    "schemaURL": null,
    "contentType": "application/json",
    "extensions": {
        "compartmentId": "ocid1.compartment.oc1..secret"
    },
    "data": {
        "compartmentId": "ocid1.compartment.oc1..secret",
        "compartmentName": "susugiya",
        "resourceName": "eventsample.txt",
        "resourceId": "",
        "availabilityDomain": "",
        "freeFormTags": {
            "Department": ""
        },
        "definedTags": {
            "Operations": {
                "CostCenter": ""
            }
        },
        "additionalDetails": {
            "namespace": "tenancyname",
            "publicAccessType": "",
            "eTag": "6439bd89-fdc2-4e1b-90af-12643456bfee"
        }
    }
}
```



## Delete Object

`"eventType": "com.oraclecloud.objectstorage.deleteobject"` となっています。

```
{
    "cloudEventsVersion": "0.1",
    "eventID": "355b29aa-883c-42ea-9fea-28cdb153a4d0",
    "eventType": "com.oraclecloud.objectstorage.deleteobject",
    "source": "objectstorage",
    "eventTypeVersion": "1.0",
    "eventTime": "2019-08-25T11:24:59Z",
    "schemaURL": null,
    "contentType": "application/json",
    "extensions": {
        "compartmentId": "ocid1.compartment.oc1..secret"
    },
    "data": {
        "compartmentId": "ocid1.compartment.oc1..secret",
        "compartmentName": "susugiya",
        "resourceName": "4eventsample.txt",
        "resourceId": "",
        "availabilityDomain": "",
        "freeFormTags": {
            "Department": ""
        },
        "definedTags": {
            "Operations": {
                "CostCenter": ""
            }
        },
        "additionalDetails": {
            "namespace": "tenancyname",
            "publicAccessType": "",
            "eTag": ""
        }
    }
}
```





# 参考URL

Contents of an Event Message
https://docs.cloud.oracle.com/iaas/Content/Events/Reference/eventenvelopereference.htm