[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

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 に、bucketNamesample_events と手入力することで、特定のバケットに制限
  • Actions : Function の 名前を指定

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