注:

使用通知事件调用 Oracle Cloud Infrastructure 定制功能并将更新的消息发布到 Lark 协作工具

简介

Oracle Cloud Infrastructure (OCI) 客户通过订阅的 OCI 通知主题接收通知,包括实例事件、预警、控制台公告等事件。这些订阅的主题还支持 OCI 功能作为通知目标,允许客户在通知事件期间调用定制功能并将更新的通知详细信息发送到支持 API 调用的通信渠道。在本教程中,我们将介绍如何将这些更新的通知转发到具有消息传递 API 的企业协作平台 Lark

使用定制 OCI 函数,您可以检索各种数据并执行操作,下面是几个示例:

本教程将全面介绍如何触发定制 OCI 函数以响应实例的电源事件(例如 STOP)。用户可以灵活地定制此功能并根据订阅的 OCI 通知主题触发此功能。有关 OCI 功能的更多信息,请参见 OCI Functions Overview

目标

OCI 功能允许您编写可根据 OCI 通知、OCI 公告订阅的通知主题、计算实例事件等调用定制代码。在本教程中,我们创建了一个以 Python 代码编写的定制函数,该函数根据通知事件调用,并使用代码中的 webhook URL 将更新的消息发布到 Lark 协作工具。这样,您可以选择包括和更新最终用户可以使用的必需附加信息。

先决条件

听众

本教程面向 Cloud Service 提供商管理员和专业人员。

体系结构

以下是解决方案的示例用例拓扑和高级体系结构。

OCI Azure 互连跨区域连接体系结构

如果要创建定制 OCI 函数并基于通知事件调用该函数,可以引用此体系结构。您可以按照本教程中概述的一系列任务来设置和验证此体系结构。

任务 1:创建动态组

动态组允许您将 OCI 计算实例分组为“主要”角色(类似于用户组)。

注:您需要具有管理员权限才能创建动态组。

  1. 登录到 OCI 控制台租户账户。

  2. 从服务菜单中选择身份和安全性,然后从身份部分中选择动态组

  3. 单击创建动态组

  4. 输入一个有意义的名称说明

  5. 规则 1 部分中,添加以下行:

    ALL {resource.type = 'fnfunc', resource.compartment.id = 'ocid1.compartment.oc1', instance.compartment.id = 'ocid1.compartment.XXXXX'}

    注:

    • 将区间 ID 替换为所需的区间 ID。
    • 还可以在动态组中包含特定的函数资源 OCID。
  6. 单击创建,应成功创建动态组,如下图所示。

    已创建动态组

任务 2:创建动态组 OCI IAM 策略

通过 Oracle Cloud Infrastructure Identity and Access Management (OCI IAM),您可以控制谁可以访问云资源。为了使此体系结构正常工作,我们需要授予对计算、网络和其他一些服务的功能即服务 faas 的访问权限。

  1. 从服务菜单中选择身份和安全性,然后从身份部分中选择策略

  2. 单击创建策略

  3. 输入适当的名称说明,并确保选择正确的区间(在本例中,我们将使用区间名称 oc-demo)。

  4. 策略构建器部分中,确保启用显示手动编辑器选项并粘贴以下行:

    Allow dynamic-group <dynamic_group_name> to read instances in compartment <compartment_name_path>

    Allow dynamic-group <dynamic_group_name> to read vnics in compartment <compartment_name_path>

    Allow dynamic-group <dynamic_group_name> to read vnic-attachments in compartment <compartment_name_path>

    注:dynamic_group_name 名称和 compartment_name_path 替换为所需的值。

  5. 单击创建,应在根/区间级别成功创建策略,如下图中所示。

    已创建 IAM 策略

任务 3:创建存储库以存储定制函数映像

通过容器注册表,您可以在 Oracle 管理的注册表中存储、共享和管理容器映像(例如 Docker 映像)。

  1. 在控制台中,打开服务菜单并单击开发人员服务。在容器下,单击容器注册表

  2. 单击创建资料档案库

  3. 创建资料档案库对话框中,指定所选的区间资料档案库名称,并将其保留为专用

  4. 单击创建资料档案库,并且应在指定的区间中成功创建容器注册表,如下图中所示。

    已创建容器注册表资料档案库

任务 4:创建包含子网的虚拟云网络来存储函数应用程序

虚拟云网络 (virtual cloud network,VCN) 是您在 OCI 中定义的网络。它包括子网、路由表和网关。

:如果您已经具有 VCN,则之前创建的子网可以跳过此任务并继续执行任务 5

  1. 单击 OCI Web 控制台左上角附近的服务菜单。

  2. 网络下,选择虚拟云网络

  3. 在“虚拟云网络”页上,单击启动 VCN 向导

  4. 选择使用 Internet 连接创建 VCN ,然后单击启动 VCN 向导

  5. 完成 VCN 配置,然后单击下一步

  6. 单击创建,应成功创建具有子网的虚拟云网络,如下图所示。

    已创建具有子网的虚拟网络

任务 5:创建用于存储函数的应用程序

  1. 打开服务菜单,然后单击开发人员服务。在函数下,单击应用程序

  2. 单击创建应用程序

  3. 创建应用程序窗口中,选择应用程序的名称(例如,function-app),选择您在任务 4 中创建的 VCN,然后选择公共子网。

  4. 单击创建,应成功创建函数应用程序,如下图所示。

    创建的函数应用程序

任务 6:部署函数来存储函数

此步骤将使用可从本教程的“先决条件”部分下载的 zip 档案。

  1. 导航到 OCI 云控制台,然后单击开发人员工具Cloud Shell

    启动 Cloud Shell

  2. 单击启动云 Shell 按钮后,将在页面末尾显示一个新的小 shell 窗口。在该窗口的右上角,单击齿轮菜单并选择上载

    加载 ZIP 文件

  3. 上载本教程的“先决条件”部分中提供的 zip 文件并导航到复制的目录。

  4. 您将看到 func.py 文件,如下所示,我们已创建该文件以确保您可以读取通知 JSON 并添加其他字段(如 IP 地址详细信息),并使用更新的消息向标记 Webhook URL 发送消息。

    • parse_message :函数读取通知 JSON 并更新消息
    • get_ip_address :使用计算、网络客户机库来读取其他详细信息的功能,例如基于实例的资源 OCID 的 IP 地址。
    • make_post :使用 Webhook URL 将帖子发布到 Lark 通道的功能。

    注:

    • 我们正在使用 OCI python sdk,但您可以使用 go/java sdks 根据其他受支持的语言进行定制。
    • 您必须更新 Webhook URL(Lark 或其他协作工具,例如 Slack)。
    • 您可以根据自己的要求定制此功能。我们已使用某些通知 JSON 有效负载读取值,但您也可以使用控制台公告 JSON 或其他事件 JSON。
    ###
    This is a sample code,
    End user can modify as needed
    ###
    import io
    import oci
    import json
    import logging
    import requests
    
    """
    Read Notification Message
    Add IP address of Resource.
    """
    def parse_message(body):
        notification = ""
        ocid = ""
        type = body["source"]
        description = body["eventType"]
        compartment_id = body["data"]["compartmentId"]
        compartment_name = body["data"]["compartmentName"]
        affected_resources = ""
    
        if len(body["data"]) > 0:
            signer = oci.auth.signers.get_resource_principals_signer()
            affected_resources = "Affected Resources: "
            ocid = body["data"]["resourceId"]
            notification_reason = body["data"]["additionalDetails"]["instanceActionType"]
            affected_resources += "\nResource OCID: " + ocid
            resource_ip_address = get_ip_address(signer, ocid)
            affected_resources += "\nResource Private IP Address: " + resource_ip_address
    
        notification = type + " " + "\n\n" + compartment_name + " - " + compartment_id + "\n\n" + description + "\n\n" + affected_resources + "\n\n" + notification_reason
        logging.getLogger().debug(notification)
    
        make_post(notification)
    
    """
    Get Resource IP address
    based of resource OCID.
    """
    def get_ip_address(signer, resource_id):
        compute_client = oci.core.ComputeClient(config={}, signer=signer)
        network_client = oci.core.VirtualNetworkClient(config={}, signer=signer)
        instance_details = compute_client.get_instance(instance_id=resource_id).data
        vnic_response = compute_client.list_vnic_attachments(compartment_id=instance_details.compartment_id, instance_id=resource_id)
        vnics = vnic_response.data
    
        for vnic in vnics:
            vnic_details = network_client.get_vnic(vnic_id=vnic.vnic_id).data
            private_ip = vnic_details.private_ip
            return private_ip
    
    """
    Post a Message to Lark.
    You can also use OCI Vault/Secret to store Lark credentials and access them here.
    """
    def make_post(post_text):
        url = "https://open.larksuite.com/open-apis/bot/v2/hook/XXXX"
        headers = {
            "Content-Type": "application/json"
        }
        req_body = {
            "msg_type": "text",
            "content": {
                "text": post_text
            }
        }
        payload = json.dumps(req_body)
        try:
            post_response=requests.post(url=url, data=payload, headers=headers)
        except Exception as e:
            logging.getLogger().error(e)
            return
    
        response_dict = json.loads(post_response.text)
        code = response_dict.get("StatusCode", -1)
    
        if code != 0:
            logging.getLogger().error("error sending post text, code: " + str(code))
        return
    
    def to_bool(a):
        return True if a == "True" else False
    
    """This is the function entry point.
    ctx will contain function variables defined in OCI console,
    data contains the payload
    """
    def handler(ctx, data: io.BytesIO = None):
        try:
            cfg = dict(ctx.Config())
            for a in cfg:
                cfg[a]=to_bool(cfg[a])
    
        except Exception as e:
            print('ERROR: Missing configuration keys', e, flush=True)
            logging.getLogger().debug(cfg)
            return 'error parsing config keys: ' + str(ex)
    
        try:
            raw_body = data.getvalue()
            body = json.loads(raw_body)
            logging.getLogger().info(body)
            parse_message(body)
        except (Exception, ValueError) as ex:
            logging.getLogger().error('error parsing json payload: ' + str(ex))
            return 'error parsing json payload: ' + str(ex)
    
  5. 使用 fn deploy 命令部署函数以在云 shell 中构建函数 docker 映像和关联的依赖项。您可以将映像推送到指定的 Docker 注册表,并将函数部署到之前创建的应用程序中的 OCI 函数。

    fn -v deploy --app <app-name>
    

    例如:

    fn -v deploy --app function-app
    

    注:您可以查看 func.yaml 文件,请参阅函数 docker 映像所需的详细信息。

  6. 部署后,应成功创建您的函数,如下图所示。

    创建的函数

任务 7:将功能订阅到主题

  1. 打开服务菜单,然后单击开发人员服务。在应用程序集成下,单击通知。确保位于正确的区间中。

  2. 单击创建主题

  3. 设置合适的名称,然后单击创建

  4. 创建主题后,从主题列表中选择该主题。

  5. 主题窗口中,从左侧的资源下选择订阅,然后单击创建订阅

  6. 创建订阅侧面窗口中,选择要函数的协议,选择区间、应用程序以及在任务 6 中创建的函数。

  7. 单击创建,您的函数应成功订阅主题,如下图中所示。

    已创建通知订阅

任务 8:创建实例和通知事件规则

要验证此步骤中的函数,我们将在任务 7 中为 instance-stopped 等事件创建实例和关联的创建通知主题。

  1. 在控制台中,导航到计算实例以创建计算实例。

  2. 单击创建实例图标并提供所需的详细信息:

    • 实例名
    • 实例的区间
    • 选择所需的 AD
    • 选择网络 VCN 和公共子网
    • 复制 - 粘贴您的公共 SSH 密钥
    • 单击“创建”。
  3. 等待实例显示 running ,然后使用以下命令登录到实例。

    ssh opc@<public ip> -i <private key>
    
  4. 定位至计算实例实例详细信息通知窗口以创建通知事件。

  5. 单击创建通知,然后选择 QuickStart 模板,例如将实例状态更改为已停止

  6. 输入事件规则名称,然后从任务 7 中选择创建的主题,然后单击创建通知。应成功创建订阅主题的通知事件规则,如下图中所示。

    已创建事件规则

任务 9:验证通知事件规则

在此步骤中,您将停止将触发关联通知主题的实例。还可以包括您的电子邮件地址以查看通知有效负载。

  1. 导航到创建的实例,然后单击停止

  2. 实例停止后,您应通过订阅的通知主题收到电子邮件,并触发功能。

  3. 确认您已收到一封电子邮件,如下图所示。

    OCI 通知主题电子邮件

  4. 转到用于包括 Webhook URL 的 Lark 通道。

    较深的通知发布

    注:如果您从收到的电子邮件中仔细注意到此更新消息,根据自定义功能,我们使用 OCI sdk 包括了实例的 IP 地址。

  5. [可选] 您还可以根据控制台公告详细信息将此通知主题与更新功能详细信息关联。您可以关注这些文档,以了解更多信息

    注:必须修改定制函数代码,以确保读取正确的 JSON 有效负载并相应地进行修改。您可以使用从服务团队收到的公告示例 JSON 有效负载。

    OCI 公告通知订阅

后续步骤

此教程向最终用户展示如何使用定制函数读取通知 JSON 有效负载,以及如何使用 OCI SDK 库更新该有效负载,并将消息发布到标记等常用协作工具。您可以展开此功能以添加其他详细信息,例如资源标记、网络详细信息等。

确认

更多学习资源

探索 docs.oracle.com/learn 上的其他实验室,或者访问 Oracle Learning YouTube 频道上的更多免费学习内容。此外,请访问 education.oracle.com/learning-explorer 成为 Oracle Learning Explorer。

有关产品文档,请访问 Oracle 帮助中心