OctoMation应用开发手册 - flagify-com/OctoMation GitHub Wiki

🚀️ OctoMation 应用开发文档🚀️

开发概述

OctoMation 为用户与第三方设备、平台等协作提供了一个运行环境, 应用开发者只需要按照规范开发并且上传于第三方对接的App即可完成对第三方工具、设备、平台的调用。

应用的开发可以使用Python3(推荐Python3.10+)进行开发。

OctoMation 的 应用 和 HoneyGuide SOAR的 应用 是互通的。

点击查看快速生成应用

名词解释

  1. App:与第三方设备、平台等对接的应用,并且在OctoMation 中可执行。
  2. Action: 应用的动作,在App中某个具体功能的实现, 一个App中可以存在1-N个动作。
  3. 资源: 对应于App中的绑定设备、平台中的资产(资源), 资源可以是账号、密码、链接、甚至可以是文件。

应用运行机制

应用执行逻辑

OctoMation剧本调度引擎会根据剧本逻辑,向执行引擎发送指令,启动某个指定的Python应用APP,同时向该应用传递执行参数和设备资源信息,从完成动作执行,并获取执行结果。

image

应用输出逻辑

应用APP根据入参和设备信息,调用目标设备资源,执行动作,并获取结果。默认结果为JSON格式,可以根据需要参照模板定义,进行输出渲染。

应用开发指引

目录结构

以下是一个标准的OctoMation Python 应用的工程目录结构:

|-- shakespeare-app-helloworld
    |-- config.json
    |-- helloworld.py
    |-- resources
    |   |-- fif.png
    |   |-- readme.md
    |-- shakespeare-action-template
    |   |-- show.art

这是OctoMation标准的目录结构, 为了简化应用的创建, 我们也提供了应用生成器

目录结构各文件夹和文件解释

名称 属性 是否必须 说明
shakespeare-app-helloworld 根目录 应用根文件夹为应用包的名称, 发布时将该文件夹打包为zip文件后即可上传到OctoMation中, 应用名可以自定义, 但不能与已有的应用同名。
config.json 配置文件 应用配置说明文件, 文件名不可更改, 必须存在。
helloworld.py 代码文件 应用的实现代码文件, 文件名可自定义, 但必须在 config.json 中的jar字段中配置。
resources 目录 此目录中存放应用的 帮助文档应用icon图标
resources - newapp.png 图片文件 应用的icon文件, 可以是PNG、JPG、ICON格式。
resources - readme.md 说明文件 应用的使用说明文件, Markdown格式。
shakespeare-action-template 目录 应用渲染模板目录, 所有应用返回结果渲染文件都保存在此目录中。
shakespeare-action-template - show.art 渲染文件 渲染模板文件, 创建时名字可以自定义,以config.json中的配置为主,如不配置模板, 系统直接展示应用动作的json返回值。

配置文件(config.json)

下面,将用一个helloworld来详细了解config.json文件

{
    // 应用名称: 要求英文格式
    "name": "helloworld",
    // 应用说明: 必填, 详细说明这个应用是干嘛的
    "description": "一个helloworld应用",
    // 应用版本
    "app_version": "1.0.0",
    // 最小的系统版本,这里填写 1.0 即可
    "min_shakespeare_version": "1.0",
    // 应用提供者: 可以是公司或者名字
    "app_supplier": "wuzhi",
    // 项目名称
    "product_name": "helloworld",
    // 应用 logo, 在resources目录下面的logo文件, 等应用上传后会显示在系统内
    "logo": "resources/fif.png",
    // 应用的readme,应用详细的帮助文档
    "read_me": "resources/readme.md",
    //运行主程序, 应用的实现代码文件
    "jar": "helloworld.py",
    // 运行环境, 这里就固定为PYTHON
    "logic_language": "PYTHON",
    // 语言版本,这里固定为3
    "logic_language_version": "3",
    // 是否测试, 这里固定为false
    "has_test": false,
    // 测试的动作, 这里填空即可
    "test_action": "",
    // 应用使用到的资源, 字段必须存在,但如果没有资源的话,可以使用{}
    // 代码中中以assets[$参数名]的方式实现配置获取。如 APP使用mysql,需要配置mysql地址,则参数名为 mysql_host,项目中使用assets["mysql_host"]获取。
    "configuration": {
        // 字段名可以自定义,这里定义了一个 `host` 资源
        // 当定义好资源名后,则需要定义如下字段
        "host": {
            // 资源是否必填, true 为 必填, flask 为非必填
            "required": true,
            // 在前端页面的排序,0为最前面
            "order": 0,
            // 资源的数据类型:
            // string 字符串
            // integer 整形
            // password 密码类型,存储的数据会在数据库中进行加密
            // long 长整形
            // date 时间类型
            // double 浮点型
            // boolean 布尔型
            // outside_file 上传文件
            // json json类型
            // jsonarray jsonarray类型
            "data_type": "string",
            // 此资源的详细说明
            "description": "helloworld 演示资源"
        }
    },
    // 应用的动作,是个list[json], 应用最少有一个动作
    "actions": [
        {
            // 动作名称,不能使用中文
            "action": "helloworld",
            // 动作详细说明
            "description": "helloworld 演示动作",
            // 动作在代码中的 `函数名` 
            "class_name": "helloworld",
            // 动作的渲染文件, 如果不渲染,可以为 ""
            "result_display_tmpt": "shakespeare-action-template/show.art",
            // 渲染方式,使用 js 即可
            "result_display_tmpt_type": "js",
            // 是否安全模式, 当系统以安全模式运行时,所有的write动作将不会真正执行
            "safe_mode": false,
            // 定义该动作是否是测试动作,如果是true,则在资源配置时可以调用测试,并且系统会定时调用该方法检查资源是否可用。如果不可用,返回结果必须按照以下格式返回:code!=200 or sumarry存在且其中的statusCode存在且!=200
            "is_test": false,
            // 动作类型
            // query 查询
            // write 写入
            // notify 通知
            "classify": "query",
            // 入参, 如果没有入参则填写 {}
            "parameters": {},
            // 出参,是个list[json],每个动作最少一个出参
            "output": [
                {
                    // 参数路径必须以 action_result
                    // 后面的每一层则为返回json 中的 key
                    // 如果key中的value是个 list,可以用 * 进行返回
                    // 具体参考 `out_list` 这个动作的 output
                    "data_path": "action_result.data",
                    // 动作返回的类型
                    // string 字符串
                    // integer 整形
                    // password 密码类型,存储的数据会在数据库中进行加密
                    // long 长整形
                    // date 时间类型
                    // double 浮点型
                    // boolean 布尔型
                    // outside_file 上传文件
                    // json json类型
                    // jsonarray jsonarray类型
                    "data_type": "string",
                    // 动作的详细说明
                    "description": "返回值演示"
                }
            ]
        },
        {
            "action": "out_list",
            "description": "out list 演示",
            "class_name": "query_file",
            // 这里将不进行渲染
            "result_display_tmpt": "",
            "result_display_tmpt_type": "js",
            "safe_mode": false,
            "is_test": false,
            "classify": "query",
            "parameters": {
                 // 字段名可以自定义,这里定义了一个 `file_name` 入参
                 // 当定义好参数名后,则需要定义如下字段
                "file_name": {
                    // 参数是否必填, true 为 必填, flask 为非必填
                    "required": true,
                    // 在前端页面的排序,0为最前面
                    "order": 0,
                    // 动作参数的类型
                    // string 字符串
                    // integer 整形
                    // password 密码类型,存储的数据会在数据库中进行加密
                    // long 长整形
                    // date 时间类型
                    // double 浮点型
                    // boolean 布尔型
                    // outside_file 上传文件
                    // json json类型
                    // jsonarray jsonarray类型
                    "data_type": "string",
                    "description": "要查询的文件名字"
                }
            },
            "output": [
                {
                    // 这里的 * 代表一个自循环
                    // 在运行这个动作后,返回的数据将是一个循环,在剧本中使用这个返回结果后会一条一条的运行
                    "data_path": "action_result.data.*",
                    "data_type": "string",
                    "description": "一个测试 list"
                },
                {
                    "data_path": "action_result.data.*.hellowrold",
                    "data_type": "string",
                    "description": "一个测试 list"
                }
            ]
        }
    ]
}

TIPS:返回结果为JSON数组时如何设计输出参数的data_path

{
	"code":200,
	"data":{
		"result":[
			{
			"ip":"1.2.3.4",
			"type":"ipv4"
			},
			{
			"ip":"1.2.3.5",
			"type":"ipv4"
			}
		]
	}
}

ip的data_path可以设计为:action_result.data.result.*.ip
为什么这样设计路径:在设计剧本时,如果后续的节点选择ip作为参数,result中有多个对象,执行剧本时系统会自动取得result中所有的ip自动循环执行。

代码文件

示例代码: helloworld.py

# -*- coding: utf-8 -*-

# 如果需要引入依赖,import xxxx 即可, 但在使用时,此依赖必须在python环境中存在

# helloworld 函数名称, 在config.json 中 actions - class_name 的值,必须一致
# params、assets、context_info 为函数必要的参数,
# params 入参 在config.json 中 actions - parameters 的值,是个字典,同python的字典相同操作方式
# assets 资源 在config.json 中 configuration 的值,是个字典,同python的字典相同操作方式
# context_info 上下文
#   context_info["activieId"]   执行链事件ID 字符串
#   context_info["appName"]     执行链应用名称 字符串   
#   context_info["actionName"]  执行链动作名称 字符串         
#   context_info["eventId"]     执行链事件ID 字符串   
#   context_info["logMode"]     执行链 日志模型 布尔值
#   context_info["executor"]    执行链 执行人 字符串
#   context_info["executeTime"] 执行链 执行时间 整型
def helloworld(params, assets, context_info):
    """helloworld 演示动作"""

    # helloworld 演示资源
    host = assets["host"]

    # 返回值
    # 返回值中 code、msg是必须的, code 非 200的情况下, 应用运行会报错
    json_ret = {"code": 200, "msg": "","data": ""}

    '''添加函数实现
    
    '''
    json_ret['data'] = "这是一个测试"

    return json_ret 

def out_list(params, assets, context_info):
    """out list 演示"""

    # helloworld 演示资源
    host = assets["host"]
    # 要查询的文件名字
    file_name = params["file_name"]

    # 返回值
    # 这里的返回值将返回一个list,因为在config.json中我们定义了这个动作返回取的是*
    json_ret = {"code": 200, "msg": "","data": [{"hellowrold": ""}]}

    '''添加函数实现
    
    '''
    json_ret['data'] = [{"hellowrold": "h1"}, {"hellowrold": "h2"}]

    return json_ret

渲染模板

渲染模板是一个 art-template [参考文档](介绍 - art-template (aui.github.io))

helloworld.art作为示例,详细的语句可以参考 art-template

<div class="ant-table ant-table-default ant-table-bordered">
   <div class="ant-table-content">
       <div class="ant-table-body">
           <table>
               <thead class="ant-table-thead">
                   <tr>
                       <th>
                           <span class="ant-table-header-column">
                               <div>
                                   <span class="ant-table-column-title">value</span>
                                   <span class="ant-table-column-sorter"></span>
                               </div>
                           </span>
                       </th>
                   </tr>
               </thead>
               <tbody class="ant-table-tbody">
               <!-- action_results 则是这个动作的所有返回结果 -->
               {{each action_results action_result}}
               <!-- action_result.data 则是对于这个动作的返回结果,在congfig.json的 actions - action - output 中 对应的字段-->
               {{if action_result.data}}
                   <tr class="ant-table-row">
                       <td>{{action_result.data}}</td>
                   </tr>
               {{/if}}
               {{/each}}
               </tbody>
           </table>
       </div>
   </div>
</div>

应用打包、上传和测试

打包

直接将工程目录打包成zip包,确保解压后的结构跟工程目录结构一致。

上传

登录到 OctoMation, 点击应用管理 - 上传应用(右上角)- 选择刚打包后的zip包。

如果上传成功,则会显示 上传成功 的字样

image

image

测试

如果应用存在资源, 则需要点击应用 - 切换到资源 - 新建 , 对资源进行配置, 配置完成后点击保存即可。

image image image

进入到作战室 - 执行动作 - 选择上传的应用 - 选择要执行的动作 - 配置好参数(如果存在)- 点击立即执行。

image image image image image

应用生成器

为了方便开发人员快速开发应用,我们在 OctoMation 中内置了一个 应用生成器, 可以用来快速生成应用, 详细使用手册: 应用开发辅助工具

应用生成器使用视频

dev.mp4

别忘了单元测试

合格的应用APP还包括单元测试代码🧪🧪🧪

⚠️ **GitHub.com Fallback** ⚠️