创建自定义策略函数
了解函数接口定义
函数服务对函数有明确的接口定义。
以java语言为例,接口定义为:作用域 返回参数 函数名(函数参数,Context参数)。
- 作用域:提供给FunctionGraph调用的用户函数必须定义为public。
- 返回参数:用户定义,FunctionGraph负责转换为字符串,作为HTTP Response返回。对于返回参数对象类型,HTTP Response该类型的JSON字符串。
- 函数名:用户定义函数名称。
- 用户定义参数:当前函数只支持一个用户参数。对于复杂参数,建议定义为对象类型,以JSON字符串提供数据。FunctionGraph调用函数时,解析JSON为对象。
- Context参数:runtime提供函数执行上下文,其接口定义在SDK接口说明。
创建Java函数时,函数入口参数需要提供函数完整的名字空间,参数格式为:包名.类名.函数名。
设备发放在此基础上,要求函数代码满足如下条件:
- 返回参数:需满足设备发放对返回参数的约束;
- 函数参数:需满足设备发放对函数参数的约束;
- 函数接口实现:从函数参数中的备选接入点中选择一个接入点,调用发放设备接口,根据接口响应拼接参数返回。
编写自定义函数
- 创建函数工程,编写函数。
首先建立一个普通的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); }
- 打包函数,上传代码。
函数打包规范参见函数工作流 FunctionGraph > 开发指南 > 概述 > 函数工程打包规范。
如函数工程未使用到第三方库,则可将工程打成一个Jar包上传。如使用到第三方库,则需将工程Jar包和第三方Jar包打包成一个Zip包。
本文使用到了多个第三方库,因此,如下图所示,将工程Jar包和第三方Jar包打包成一个Zip包。
进入函数工作流服务控制台,创建函数并上传包含工程Jar包和第三方Jar包的Zip包。
为避免调试过程中函数因内存不足或超时导致调用失败,视实际使用情况调整内存大小和超时时间。
- 配置测试事件,调试函数。
创建测试事件,填写满足设备发放约束的函数参数的JSON格式。
单击“保存并测试”,查看函数运行结果,确认函数逻辑的正确性。
日志显示,已调用了发放设备接口,函数主要逻辑正确。至此,您已完成自定义策略函数的编写,可进行后续步骤。
后续操作
完成自定义策略函数的编写后,创建关联该函数的自定义策略实例以及设备或注册组,通过设备南向操作触发函数,将设备发放到指定目的接入点(设备接入实例)。
后续操作包括:
最佳实践:
- 结合函数服务通过自定义策略发放证书认证的设备。
设备发放对返回参数的约束
名称 |
说明 |
类型 |
---|---|---|
statusCode |
String |
函数执行状态码,用于标识函数执行过程是否出现异常,遵循HTTP状态码含义。 |
body |
String |
字符串,但格式为JSON,结构为TdpFuncBody。 |
名称 |
说明 |
类型 |
---|---|---|
status |
String |
设备发放业务功能标识,allow表示发放成功,deny表示发放失败,设备发放使用此标识判断函数内业务功能执行成功与否。 |
context |
TdpFuncBodyContext |
扩展字段,用于承载函数执行结果。 |
名称 |
说明 |
类型 |
---|---|---|
allocationResult |
String |
发放结果,存放发放接口返回的响应结构体。 |
errorCode |
String |
错误码,如发放失败,则此值需不为空。 |
errorMsg |
String |
错误描述,如发放失败,则此值需不为空。 |
发放设备成功的返回参数样例
{ "statusCode": 200, "body": "{\"status\":\"allow\",\"context\":{\"allocationResult\":\"dps返回的下发结果\"}}" }
发放设备失败的返回参数样例
{ "statusCode": 200, "body": "{\"status\":\"deny\",\"context\":{\"errorCode\":\"错误码\",\"errorMsg\":\"错误描述\"}}" }
设备发放对函数参数的约束
名称 |
类型 |
说明 |
---|---|---|
iamToken |
String |
委托Token,便于用户调用发放接口。 |
deviceId |
String |
设备ID。 |
deviceName |
String |
设备名称。 |
accessPoints |
List<AccessPointPara> |
备选接入点列表。 |
authInfo |
AuthInfoPara |
设备认证信息。 |
名称 |
类型 |
说明 |
---|---|---|
regionId |
String |
备选接入点的区域ID。 |
accessPointId |
String |
备选接入点的接入点ID。 |
authorizingDomainId |
String |
备选接入点的接入点授权租户,仅在授权场景下使用。 |
名称 |
类型 |
说明 |
---|---|---|
authType |
String |
认证类型。可选 SECRET 和 CERTIFICATES。 |
secret |
String |
设备密钥信息,当认证类型为 SECRET 时携带。 |
certInfo |
CertInfoPara |
证书信息,当认证类型为 CERTIFICATES 时携带。 |
名称 |
类型 |
说明 |
---|---|---|
caCert |
CaCertPara |
设备CA证书信息。 |
deviceCert |
List<DeviceCertPara> |
设备证书信息。 |
名称 |
类型 |
说明 |
---|---|---|
subjectCnName |
String |
证书使用者CN NAME。 |
caCertName |
String |
证书名。 |
fingerprint |
String |
证书指纹。 |
名称 |
类型 |
说明 |
---|---|---|
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" } }