更新时间:2024-10-25 GMT+08:00
分享

创建自定义策略函数

了解函数接口定义

函数服务对函数有明确的接口定义。

以java语言为例,接口定义为:作用域 返回参数 函数名(函数参数,Context参数)

  • 作用域:提供给FunctionGraph调用的用户函数必须定义为public。
  • 返回参数:用户定义,FunctionGraph负责转换为字符串,作为HTTP Response返回。对于返回参数对象类型,HTTP Response该类型的JSON字符串。
  • 函数名:用户定义函数名称。
  • 用户定义参数:当前函数只支持一个用户参数。对于复杂参数,建议定义为对象类型,以JSON字符串提供数据。FunctionGraph调用函数时,解析JSON为对象。
  • Context参数:runtime提供函数执行上下文,其接口定义在SDK接口说明。

创建Java函数时,函数入口参数需要提供函数完整的名字空间,参数格式为:包名.类名.函数名。

设备发放在此基础上,要求函数代码满足如下条件:

编写自定义函数

  1. 创建函数工程,编写函数。

    首先建立一个普通的Java项目,添加FunctionGraph函数JavaSDK为工程依赖,可下载设备发放提供函数Demo,参照Demo创建工程编写函数。

    FunctionGraph函数JavaSDK提供了Event事件接口、Context接口和日志记录接口。其中Runtime-x.x.x.jar包含了函数执行上下文,其他Jar包为附带的第三方库,可按需添加。

    Java函数开发指南参见函数工作流 FunctionGraph > 开发指南 > 如何开发函数 > Java函数开发指南

    参照如下代码编写函数,实现必要逻辑。

    package com.huawei.demo;
     
    import com.huawei.demo.common.logger.DefaultLogger;
    import com.huawei.demo.model.AccessPointPara;
    import com.huawei.demo.model.FunctionGraphPara;
    import com.huawei.demo.model.TdpFuncResult;
    import com.huawei.services.runtime.Context;
     
    import java.util.Optional;
     
    /**
     * 实现该类。
     * WARNING:{@link #apiHandle(FunctionGraphPara, Context)} 该方法必须在子类中定义,否则函数无法触发该函数接口!!!
     * <pre>
     * {@code
     *     @Override
     *     public TdpFuncResult apiHandle(FunctionGraphPara para, Context context) {
     *         return super.apiHandle(para, context);
     *     }
     * }
     * </pre>
     */
    public abstract class TdpFunction {
        protected static final DefaultLogger LOGGER = new DefaultLogger(TdpFunction.class);
     
        /**
         * 函数定义
         */
        public TdpFuncResult apiHandle(FunctionGraphPara para, Context context) {
            // 获取日志
            DefaultLogger.init(Optional.ofNullable(context)
                .map(Context::getLogger)
                .orElse(null));
     
            // 校验入参
            TdpFuncResult result = checkPara(para, context);
            if (result != null) {
                return result;
            }
     
            // 确定接入点
            AccessPointPara accessPointPara = determineAccessPoint(para);
     
            // 发放设备
            result = provisionDevice(para, accessPointPara);
     
            LOGGER.info("result:{}", result);
            return result;
        }
     
        /**
         * 校验入参
         */
        protected abstract TdpFuncResult checkPara(FunctionGraphPara para, Context context);
     
        /**
         * 从备选的接入点中选择合适的接入点
         */
        protected abstract AccessPointPara determineAccessPoint(FunctionGraphPara para);
     
        /**
         * 调用设备发放的发放接口发放设备
         */
        protected abstract TdpFuncResult provisionDevice(FunctionGraphPara para, AccessPointPara accessPointPara);
    }

  2. 打包函数,上传代码。

    函数打包规范参见函数工作流 FunctionGraph > 开发指南 > 概述 > 函数工程打包规范

    如函数工程未使用到第三方库,则可将工程打成一个Jar包上传。如使用到第三方库,则需将工程Jar包和第三方Jar包打包成一个Zip包。

    本文使用到了多个第三方库,因此,如下图所示,将工程Jar包和第三方Jar包打包成一个Zip包。

    进入函数工作流服务控制台,创建函数并上传包含工程Jar包和第三方Jar包的Zip包。

    为避免调试过程中函数因内存不足或超时导致调用失败,视实际使用情况调整内存大小和超时时间。

  3. 配置测试事件,调试函数。

    创建测试事件,填写满足设备发放约束的函数参数的JSON格式。

    单击“保存并测试”,查看函数运行结果,确认函数逻辑的正确性。

    日志显示,已调用了发放设备接口,函数主要逻辑正确。至此,您已完成自定义策略函数的编写,可进行后续步骤。

后续操作

完成自定义策略函数的编写后,创建关联该函数的自定义策略实例以及设备或注册组,通过设备南向操作触发函数,将设备发放到指定目的接入点(设备接入实例)。

后续操作包括:

最佳实践:

  • 结合函数服务通过自定义策略发放证书认证的设备。

设备发放对返回参数的约束

表1 TdpFuncResult

名称

说明

类型

statusCode

String

函数执行状态码,用于标识函数执行过程是否出现异常,遵循HTTP状态码含义。

body

String

字符串,但格式为JSON,结构为TdpFuncBody。

表2 TdpFuncBody

名称

说明

类型

status

String

设备发放业务功能标识,allow表示发放成功,deny表示发放失败,设备发放使用此标识判断函数内业务功能执行成功与否。

context

TdpFuncBodyContext

扩展字段,用于承载函数执行结果。

表3 TdpFuncBodyContext

名称

说明

类型

allocationResult

String

发放结果,存放发放接口返回的响应结构体。

errorCode

String

错误码,如发放失败,则此值需不为空。

errorMsg

String

错误描述,如发放失败,则此值需不为空。

发放设备成功的返回参数样例

{
  "statusCode": 200,
  "body": "{\"status\":\"allow\",\"context\":{\"allocationResult\":\"dps返回的下发结果\"}}"
}

发放设备失败的返回参数样例

{
  "statusCode": 200,
  "body": "{\"status\":\"deny\",\"context\":{\"errorCode\":\"错误码\",\"errorMsg\":\"错误描述\"}}"
}

设备发放对函数参数的约束

表4 FunctionGraphPara

名称

类型

说明

iamToken

String

委托Token,便于用户调用发放接口。

deviceId

String

设备ID。

deviceName

String

设备名称。

accessPoints

List<AccessPointPara>

备选接入点列表。

authInfo

AuthInfoPara

设备认证信息。

表5 AccessPointPara

名称

类型

说明

regionId

String

备选接入点的区域ID。

accessPointId

String

备选接入点的接入点ID。

authorizingDomainId

String

备选接入点的接入点授权租户,仅在授权场景下使用。

表6 AuthInfoPara

名称

类型

说明

authType

String

认证类型。可选 SECRET 和 CERTIFICATES。

secret

String

设备密钥信息,当认证类型为 SECRET 时携带。

certInfo

CertInfoPara

证书信息,当认证类型为 CERTIFICATES 时携带。

表7 CertInfoPara

名称

类型

说明

caCert

CaCertPara

设备CA证书信息。

deviceCert

List<DeviceCertPara>

设备证书信息。

表8 CaCertPara

名称

类型

说明

subjectCnName

String

证书使用者CN NAME。

caCertName

String

证书名。

fingerprint

String

证书指纹。

表9 DeviceCertPara

名称

类型

说明

subjectCnName

String

证书使用者CN NAME。

issuerCnName

String

证书颁发者CN NAME。

sha1Fingerprint

String

证书指纹(使用SHA-1算法计算)。

sha256Fingerprint

String

证书指纹(使用SHA-256算法计算)。

证书认证设备触发函数策略的函数参数样例

{
  "iamToken": "MIIT3gYJKoZIhvcNAQcCoIIT...",
  "deviceId": "testDeviceId",
  "deviceName": "testDeviceName",
  "accessPoints": [
    {
      "regionId": "cn-north-4",
      "accessPointId": "cn-north-4",
      "authorizingDomainId": null
    },
    {
      "regionId": "cn-north-4",
      "accessPointId": "86a45e59-3003-24b8-4e81-df0a9a694639",
      "authorizingDomainId": "84fd2c95ddf03b840f18100a000d45c2"
    }
  ],
  "authInfo": {
    "authType": "CERTIFICATES",
    "certInfo": {
      "caCert": {
        "subjectCnName": "serverCommonName20200922204814",
        "caCertName": "ca20200922204814",
        "fingerprint": "dc0f1016f495157344ac5f1296335cff725ef22f"
      },
      "deviceCert": [
        {
          "subjectCnName": "deviceCommonName20200922204814",
          "issuerCnName": "serverCommonName20200922204814",
          "sha1Fingerprint": "b2217bd882968b0bc15b1c2b132ba8a598f11879",
          "sha256Fingerprint": "734326bb5f3065d8e90d95ce1910b831d3856a1318770768bf9b03923d641ddd"
        }
      ]
    }
  }
}

密钥认证设备触发函数策略的函数参数样例

{
  "iamToken": "MIIT3gYJKoZIhvcNAQcCoIIT...",
  "deviceId": "testDeviceId",
  "deviceName": "testDeviceName",
  "accessPoints": [
    {
      "regionId": "cn-north-4",
      "accessPointId": "cn-north-4",
      "authorizingDomainId": null
    },
    {
      "regionId": "cn-north-4",
      "accessPointId": "86a45e59-3003-24b8-4e81-df0a9a694639",
      "authorizingDomainId": "84fd2c95ddf03b840f18100a000d45c2"
    }
  ],
  "authInfo": {
    "authType": "SECRET",
    "secret": "29ccf3ff01247d731fef"
  }
}

相关文档