1. BMC二次开发

1.1. 监控数据获取

所有监控数据都存储到主板的 Prometheus 数据库里,可以使用其命令工具 promtool 去获取监控数据。

监控数据是透过 node_exporter 去获取的。

网页的仪表盘定义 json 文件存放在 /var/lib/grafana/dashboards/ 里。

1.1.1. 获取所有子板的即时在线状态

$ promtool query instant http://127.0.0.1:9090 node_cluster_up
node_cluster_up{instance="127.0.0.1:9100", job="node", nodename="main", state="android", subnode="sub1-01"} => 1 @[1608772515.659]
node_cluster_up{instance="127.0.0.1:9100", job="node", nodename="main", state="android", subnode="sub1-02"} => 1 @[1608772515.659]
node_cluster_up{instance="127.0.0.1:9100", job="node", nodename="main", state="android", subnode="sub1-03"} => 1 @[1608772515.659]
node_cluster_up{instance="127.0.0.1:9100", job="node", nodename="main", state="android", subnode="sub1-04"} => 1 @[1608772515.659]
...
  • subnode: 子板编号

  • state:子板状态

    • android:子板运行的操作系统为 Android。

    • linux:子板运行操作系统为 Linux。

    • netrecovery:子板处于辅助升级系统 netrecovery 状态。

    • offline:子板离线,无法通过 USB 连接检测到。

    • online:子板能通过 USB 连接检测到,但无法解析进一步的状态。

    • loader:子板处于 Loader 状态。

    • fastboot: 子板处于 Fastboot 状态。

    • adb:子板被识别为 adb 设备,但暂未识别到其操作系统。

    • adb_offline: 子板被识别为处于 offline 状态的 adb 设备,无法进行正常 adb 操作。

    • android_recovery: 子板进入了 Android 的 recovery 系统。

  • metric:

    • 1.0: 子板处于 android 或 linux 状态。

    • 0.0: 子板处于 offline 状态。

    • 0.5: 子板处于上述状态之外。

1.1.2. 获取主机温度

1.1.2.1. A. 获取主板温度(仅R2)

通过读取底板上的热敏电阻来获取其温度(单位:摄氏度):

$ promtool query instant http://127.0.0.1:9090 'node_hwmon_temp_celsius{chip=~"platform_ntc.*"}'
node_hwmon_temp_celsius{chip="platform_ntc", instance="127.0.0.1:60101", job="node", nodename="sub1-01", sensor="temp1"} => 34.779 @[1608773513.849]
node_hwmon_temp_celsius{chip="platform_ntc", instance="127.0.0.1:60102", job="node", nodename="sub1-02", sensor="temp1"} => 42.81 @[1608773513.849]
node_hwmon_temp_celsius{chip="platform_ntc", instance="127.0.0.1:60103", job="node", nodename="sub1-03", sensor="temp1"} => 43.305 @[1608773513.849]
...

1.1.2.2. B. 获取主机内环境温度(仅R2)

通过读取主机内的 ds18b20 温度传感器的数据来获取主机内的环境温度(单位:摄氏度):

$ promtool query instant http://127.0.0.1:9090 'node_cluster_env_temp_celsius'

1.1.3. 获取风扇的转速(仅R2)

单位:RPM (转/分钟)

$ promtool query instant http://127.0.0.1:9090 node_cluster_fan_speed
node_cluster_fan_speed{fan="fan1", instance="127.0.0.1:9100", job="node", nodename="main"} => 7812 @[1607501007.839]
node_cluster_fan_speed{fan="fan2", instance="127.0.0.1:9100", job="node", nodename="main"} => 7936 @[1607501007.839]
...
  • R2v2 有 10 块能监控转速的风扇。

1.1.4. 获取接入硬盘状态

获取硬盘设备名称和型号:

$ promtool query instant http://127.0.0.1:9090 node_cluster_disk_up
node_cluster_disk_up{device="sda", instance="127.0.0.1:9100", job="node", model="ST1000DM010-2EP1", nodename="main"} => 1 @[1609228221.442]

获取硬盘总容量(单位:字节):

$ promtool query instant http://127.0.0.1:9090 node_cluster_disk_bytes_total
node_cluster_disk_bytes_total{device="sda", instance="127.0.0.1:9100", job="node", nodename="main"} => 1000204886016 @[1609228289.651]

获取硬盘已使用空间(单位:字节):

$ promtool query instant http://127.0.0.1:9090 node_cluster_disk_bytes__used
node_cluster_disk_bytes_used{device="sda", instance="127.0.0.1:9100", job="node", nodename="main"} => 121475072 @[1609228366.843]

1.1.5. 获取所有设备的 IP 地址

$ promtool query instant http://127.0.0.1:9090 node_network_ipaddr
node_network_ipaddr{device="eth0", instance="127.0.0.1:60101", ipaddr="168.168.101.198", job="node", nodename="sub1-01"} => 1 @[1609396443.993]
node_network_ipaddr{device="eth0", instance="127.0.0.1:60102", ipaddr="168.168.100.180", job="node", nodename="sub1-02"} => 1 @[1609396443.993]
node_network_ipaddr{device="eth0", instance="127.0.0.1:60103", ipaddr="168.168.101.145", job="node", nodename="sub1-03"} => 1 @[1609396443.993]
...
  • device: 网络接口名称,各个子板仅有一个以太网接口 eth0, 主板有多个。每个网络接口对应一个 IP 地址。

  • ipaddr:IP 地址,如果尚没有取得 IP 地址,则为 “0.0.0.0”。

  • nodename:子板 sub 编号,或主板 main。

1.2. 硬件控制

1.2.1. 重置子板电源

  • 功能: 重置子板电源

  • 描述: 通过操控子板的 RESET 脚来重置子板电源,达到强制重启子板的目的。如果子板没有 RESET 脚,则通过关闭、打开电源来实现。

  • 调用:

    • 命令行可运行: /usr/bin/bmc <子板SUB编号> reset

    • Web API:GET http://localhost:7070/api/reset/<子板SUB编号>

1.2.2. 重启子板操作系统

  • 功能: 重启子板操作系统

  • 描述: 首先通过 adb reboot 命令来重启系统,如果 10 秒内没有反应,则通过复位电源的方式强行重启子板。

  • 调用:

    • 命令行可运行: /usr/bin/bmc <子板SUB编号> reboot

    • Web API:GET http://localhost:7070/api/reboot/<子板SUB编号>

1.2.3. 打开子板电源(仅R2)

  • 功能:打开子板电源

  • 描述:通过操控子板的 POWER 脚来打开子板电源。集群服务器开机默认打开所有子板电源。

  • 调用:

    • 命令行可运行: /usr/bin/bmc <子板SUB编号> poweron

    • Web API:GET http://localhost:7070/api/poweron/<子板SUB编号>

1.2.4. 关闭子板电源(仅R2)

  • 功能:关闭子板电源

  • 描述:通过操控子板的 POWER 脚来关闭子板电源。

  • 调用:

    • 命令行可运行: /usr/bin/bmc <子板SUB编号> poweroff

    • Web API:GET http://localhost:7070/api/poweroff/<子板SUB编号>

1.3. 固件升级

使用脚本添加固件升级任务:

sudo netrecovery-master queue <固件文件绝对路径> <子板SUB编号> [<子板SUB编号> ...]

例如:

sudo netrecovery-master queue /home/firefly/Firmware/xxx.img sub1-01 sub1-02

查看固件升级进度:

$ promtool query instant http://127.0.0.1:9090 node_cluster_firmware_upgrade_stat
node_cluster_firmware_upgrade_stat{firmware="SR-C11G-3399JD4_Android10_HDMI_201202.img", instance="127.0.0.1:9100", job="node", node="sub02", nodename="main", state="done"} => 100 @[1608795873.055]
node_cluster_firmware_upgrade_stat{firmware="SR-C11G-3399JD4_Android10_HDMI_201202.img", instance="127.0.0.1:9100", job="node", node="sub03", nodename="main", state="done"} => 100 @[1608795873.055]
  1. node: 升级固件的子板编号。

  2. state: preparing: 正在准备;flashing: 正在烧写;done: 已完成;error:出错。

  3. metric: 烧写进度百分比,例如 100 表示已全部完成(100%)。

注意:有可能出现同一块子板有两种不同的 state,这时如果存在 state=”flashing” 则表示子板尚在烧写中,因此更稳妥的办法是,先查 flashing 进度,如果有则在升级中,如果没有则再查是完成还是出错:

$ promtool query instant http://127.0.0.1:9090 'node_cluster_firmware_upgrade_stat{node="sub02",state="flashing"}'
$ promtool query instant http://127.0.0.1:9090 'node_cluster_firmware_upgrade_stat{node="sub02",state=~"done|error"}'
node_cluster_firmware_upgrade_stat{firmware="SR-C11G-3399JD4_Android10_HDMI_201202.img", instance="127.0.0.1:9100", job="node", node="sub02", nodename="main", state="done"} => 100 @[1608796078.37]

1.4. 子板上传下载文件,运行命令

以下命令使用 bmc_adb,此脚本是对 adb 命令的包装,使用户可以方便地使用子板编号去操作对应子板,而不用理会实际的子板 adb 序列号。当然,adb 命令也可以使用。

1.4.1. 从主板上传文件到子板

在主板上运行:

$ bmc_adb -s sub01 push home.json /data/local/tmp

1.4.2. 从子板下载文件到主板

在主板上运行:

$ bmc_adb -s sub01 pull home.json /data/local/tmp

1.4.3. 在子板运行特定命令

在主板上运行:

$ bmc_adb -s sub01 shell ifconfig

1.5. bmc 命令行工具

bmc 命令行工具必须在主板(即结点名称为 main 的设备)的 Shell 终端窗口下运行,当然,远程通过 ssh 连接到主板也可使用。

获取命令帮助:

$ bmc --help
Usage:

  bmc list [--offline] [<pattern>]
    List all the active nodes usable with adb, optionally matched by pattern

  bmc serials
    List all the active nodes with coresponding adb serial.

  bmc <node> {reset|poweron|poweroff}
    Invoke reset, poweron or power off on <node>

  bmc <node> state
    Show node state

  bmc <node> shell [<command>...]
    Invoke shell with command.

  bmc forall <command> %{node}

1.5.1. 显示 adb 设备列表

列出所有在线(adb 成功连接)设备:

$ bmc list
sub03
sub04
sub05
sub06
sub07
sub08
sub09
sub10

列出所有 adb 状态为 offline 的设备:

$ bmc list --offline

1.5.2. 列出子板编号和 adb 序列号的对应关系

$ bmc serials
sub02 B09CCSUB02 usb:2-1.2.3
sub03 A8232SUB03 usb:2-1.2.4
sub06 4DE1ESUB06 usb:2-1.2.7
sub07 505C3SUB07 usb:2-1.1.2
sub08 FFBCCSUB08 usb:2-1.4
sub09 710AFSUB09 usb:2-1.1.1

1.5.3. 重置子板的电源

$ bmc sub03 reset
  okay

1.5.4. 打开、关闭子板电源(仅R2)

关闭子板电源:

$ bmc sub1-01 poweroff
   okay

打开子板电源:

$ bmc sub1-01 poweron
   okay

1.5.5. 查看子板状态

查看子板的明细状态:

# 单个子板
$ bmc sub1-01 state
android

# 所有子板
$ bmc state
main: linux
sub1-01: android
sub1-02: android
...

# 所有状态为 offline 的子板
$ bmc state | grep offline
sub7-01: offline
sub7-02: offline
sub7-03: offline
...

列出 sub3-01 的 adb 状态和 ifconfig 结果:

$ bmc sub3-01
node: sub3-01
state: android
adb_state: device
ifconfig:
eth0      Link encap:Ethernet  HWaddr ae:bb:8b:e7:b4:38  Driver rk_gmac-dwmac
          inet addr:168.168.100.171  Bcast:168.168.255.255  Mask:255.255.0.0
          inet6 addr: fe80::7298:5297:6ab9:7fd0/64 Scope: Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:66181 errors:0 dropped:0 overruns:0 frame:0
          TX packets:190 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:4414382 TX bytes:22295
          Interrupt:27

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope: Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:715 errors:0 dropped:0 overruns:0 frame:0
          TX packets:715 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:885911 TX bytes:885911

1.5.6. 进入子板 shell 或在子板执行命令

进入 sub03 的 adb shell:

$ bmc sub03 shell
rk3399_firefly_sr_c11g_jd4:/ $

在 sub03 上运行命令:

$ bmc sub03 shell id
uid=2000(shell) gid=2000(shell) groups=2000(shell),1004(input),1007(log),1011(adb),1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats),3009(readproc) context=u:r:shell:s0

1.5.7. 批量执行命令

bmc 提供了可以批量执行命令的快捷方式 bmc forall,此命令从标准输入读入子板编号,替换命令行上的 %{node} 参数再执行命令。例如:

批量获取子板 adb 状态,%{node} 会被替换为实际的设备结点:

$ echo sub03 sub04 | bmc forall adb -s %{node} get-state
>>> adb -s sub03 get-state
device
>>> adb -s sub04 get-state
device

为了简化操作,bmc forallreset, poweronpoweroff 命令提供了快捷支持。

批量重置子板电源:

$ echo sub03 sub04 | bmc forall reset
>>> bmc sub03 reset
    okay
>>> bmc sub04 reset
    okay

# 等价于
$ echo sub03 sub04 | bmc forall bmc %{node} reset

另外,bmc forall 也对 shell 命令还提供了简化。

例如,批量获取子板 Android 序列号:

$ echo sub03 sub04 | bmc forall shell getprop ro.serialno
>>> bmc sub03 shell getprop ro.serialno
A82328MDDT
>>> bmc sub04 shell getprop ro.serialno
2E8178MDDT

# 等价于
$ echo sub03 sub04 | bmc forall bmc %{node} shell getprop ro.serialno

1.5.8. 查询监控数据

promtoolPrometheus 提供的命令行工具,可用于查询数据库等功能。

bmc querypromtool 的快捷查询方式,不加参数默认返回 node_cluster_up 的值:

$ bmc query
node_cluster_up{instance="127.0.0.1:9100", job="node", nodename="main", state="android", subnode="sub1-01"} => 1 @[1609227870.112]
...

也可以直接指定需要查询的参数,参数请参阅 node_exporter 文档和 BMC 的 API 说明。

以下是插入硬盘后查询其状态:

$ bmc query node_cluster_disk_up
node_cluster_disk_up{device="sda", instance="127.0.0.1:9100", job="node", model="ST1000DM010-2EP1", nodename="main"} => 1 @[1609228042.393]

1.5.9. 写入序列号,以太网 MAC 地址等(v1.3 新增)

命令格式:

bmc {main|sub??} vendor <type> [<data>]
  • <type>:

    • sn: 对应 VENDOR_SN_ID,用来修改 Android 系统的 ro.serialno 属性。

    • lan: 对应 VENDOR_LAN_MAC_ID, eth0 网卡的 MAC 地址,设置后重启生效。

    • 更多类型请在主控板运行:/usr/share/bmc/vendor_storage_linux -h

  • <data>: 该参数可选,若提供则写入,否则是读取。

例如,要对 sub8-09 写入 MAC 地址 ae:0e:fb:84:0f:c2:

# 写入
$ bmc sub8-09 vendor lan ae0efb840fc2

# 读取
$ bmc sub8-09 vendor lan

该命令实际是对 /usr/share/bmc/vendor_storage_linux (Linux 系统) 和 /usr/share/bmc/vendor_storage_android (Android 系统) 的包装,更高级的用法可以直接调用原始命令。

1.5.10. 列出主子板的软硬件版本号(v1.3 新增)

列出主板和所有子板的软硬件版本号:

$ bmc versions
main    linux   OS:Ubuntu18.04.4        HW:v1.0
sub1-01 android OS:CLUSTER-SERVER-R2_20210118   HW:v1.0
sub1-02 android OS:CLUSTER-SERVER-R2_20210118   HW:v1.0
sub1-03 android OS:CLUSTER-SERVER-R2_20210118   HW:v1.0
...