通过前面13篇文章,我们已经完全准备好了PXE的装机环境, 按PXE系列文章(9)- 优化 PXE 装机流程系统架构,我们需要实现带外管理的Driver以及带内执行逻辑的Agent.

  • Driver 负责带外功能的实现,功能包括 开机关机重启PXE启动Disk启动Ping ILO Host等等功能、主要是基于 ipmitool 命令来实现, 也提供了可插拔的机制来实现其他带外管理的能力,比如 iDRAC、Redfish、SNMP等,目前我们使用 ipmitool 能满足使用需求, 所以从实现上来讲仅实现 ipmitool 的支持就足够了。

对于系统技术选型,前面也分析过,方案如下

  • API --- Java
  • Scheduler --- Java
  • Driver --- Python
  • Agent --- Python

对于API/Scheduler,我们使用Java是因为Java在作为Http Server以及流程调度这块足够健壮和严谨, 当然其他语言也一样可以实现,比如PHP/Python/NodeJS,但相对来说Java在HTTP相关部分有成熟、易于使用和便于维护的优势, 同时良好的多线程机制以及异步处理框架方便我们来抽象业务逻辑,以便构建成熟稳定可靠的集群。这话不绝对,其他任何语言都可以实现,可能这部分有个人的感性因素,可以多多沟通讨论,PHP/Python也一样可以实现易读易维护的系统。

对于Driver/Agent, 更多是和系统层面交互,以便完成系统API调用、Shell 命令执行等逻辑,我比较偏向于这块用Python来实现,有足够多优秀的系统操作Lib库。如果要让我们使用Java来操作这些逻辑,我估计大多数人都要崩溃,成本太高,而且性能不好, 哪怕你用JNI实现,研发实现的成本将大大的增加。

除了API是使用HTTP API对外提供服务,其他组建之间都将使用MQ来完成具体任务的下发和反馈。

本节我们优先实现Driver组建,相对来说Driver是比较轻量,接收Scheduler下发的带外管理指令,执行对应指令逻辑并反馈是否执行成功。

设计的Driver内部结构图如下:

Driver 结构图

  • Driver Context 负责管理服务环境,包括消息总线的管理,任务的执行流程控制。
  • 消息总线, 因为我们使用rabbitmq来作为消息队列服务,在选型时,我们详细调研了下,使用官方推荐pika库来处理消息的接收和发布。
  • 生命周期指令集,主要适用于控制物理机的生命周期,开机/关机/重启/PXE启动等等。

具体实现的代码可以详细参见我们发布到github的仓库 suzaku-driver

需要调试的话, 需要准备一个能访问的RabbitMQ的服务,suzaku-driver 的配置信息在 (https://github.com/veryplay/suzaku-parent/blob/master/suzaku-driver/suzaku_driver/cfg/config-dev.yml)路径下,将MQ的信息更改为自己的调试环境的RabbitMQ的信息

然后就可以在根目录下执行 make develop 来构建测试环境,建议使用 virtualenv 来构建python环境, 而影响全局库, virtualenvpython 研发还是很重要的,打算写一篇介绍 virtualenv 的文章。

Makefile中包含对应平台的包的依赖,目前考虑的主要是Ubuntu和CentOS,使用 make centosmake ubuntu 安装对应依赖。

源码目录调试,执行 python cmd/server.py

如果执行过 make install 则直接运行 suzaku-driver 命令就好了, 默认启用的是 dev 环境。

如果启动后显示下面这些内容, 说明 suzaku-driver 已经正常工作了,可以发送MQ消息来验证下driver的工作机制。

python suzaku_driver/cmd/server.py 
=============================================================================================

    --..,_                     _,.--.
       `'.'.                .'`__ o  `;__. 
          '.'.            .'.'`  '---'`  `  SUZAKU Driver Service
            '.`'--....--'`.'
              `'--....--'`

=============================================================================================

2019-07-11 09:09:23,071 server.py[line:29] INFO {'version': 1, 'root': {'level': 'INFO', 'handlers': ['console', 'info_file_handler']}, 'formatters': {'simple': {'format': '%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s'}}, 'disable_existing_loggers': False, 'handlers': {'console': {'formatter': 'simple', 'class': 'logging.StreamHandler', 'stream': 'ext://sys.stdout', 'level': 'DEBUG'}, 'info_file_handler': {'formatter': 'simple', 'backupCount': 100, 'level': 'INFO', 'encoding': 'utf8', 'class': 'logging.handlers.RotatingFileHandler', 'maxBytes': 104857600, 'filename': '/root/logs/suzaku-driver.log'}}}
2019-07-11 09:09:23,101 loader.py[line:31] INFO load config from /root/suzaku-parent/suzaku-driver/suzaku_driver/cfg/config-dev.yml
2019-07-11 09:09:23,101 server.py[line:33] INFO {'heart': {'period': 10}, 'mq': {'username': 'admin', 'vhost': '/suzaku', 'host': '192.168.56.10', 'password': 'admin', 'exchange': 'SUZAKU_SCHEDULER', 'receive_routing_key': 'dev', 'port': 5672}, 'env': 'dev'}
2019-07-11 09:09:23,101 engine.py[line:42] INFO use heart period : 10
2019-07-11 09:09:23,102 lifecycle.py[line:33] INFO Engine is starting
2019-07-11 09:09:23,102 lifecycle.py[line:33] INFO Broker is starting
2019-07-11 09:09:23,102 rabbitmq.py[line:112] INFO Connecting to <ConnectionParameters host=192.168.56.10 port=5672 virtual_host=/suzaku ssl=False>
2019-07-11 09:09:23,103 rabbitmq.py[line:112] INFO Connecting to <ConnectionParameters host=192.168.56.10 port=5672 virtual_host=/suzaku ssl=False>
2019-07-11 09:09:23,103 lifecycle.py[line:36] INFO Broker is started
2019-07-11 09:09:23,104 base_connection.py[line:237] INFO Pika version 0.13.1 connecting to 192.168.56.10:5672
2019-07-11 09:09:23,104 base_connection.py[line:237] INFO Pika version 0.13.1 connecting to 192.168.56.10:5672
2019-07-11 09:09:23,104 engine.py[line:129] INFO trigger a heart period 10.
2019-07-11 09:09:23,105 lifecycle.py[line:36] INFO Engine is started
2019-07-11 09:09:23,109 blocking_connection.py[line:1201] INFO Created channel=1
2019-07-11 09:09:23,111 blocking_connection.py[line:1201] INFO Created channel=1
2019-07-11 09:09:23,111 rabbitmq.py[line:125] INFO Declaring exchange : SUZAKU_SCHEDULER
2019-07-11 09:09:23,112 rabbitmq.py[line:125] INFO Declaring exchange : SUZAKU_SCHEDULER
2019-07-11 09:09:23,112 rabbitmq.py[line:139] INFO Declaring queue SUZAKU_SCHEDULER
2019-07-11 09:09:23,113 rabbitmq.py[line:139] INFO Declaring queue dev
2019-07-11 09:09:23,113 rabbitmq.py[line:155] INFO Binding SUZAKU_SCHEDULER to SUZAKU_SCHEDULER with SUZAKU_SCHEDULER
2019-07-11 09:09:23,114 rabbitmq.py[line:155] INFO Binding SUZAKU_SCHEDULER to dev with dev
2019-07-11 09:09:23,115 rabbitmq.py[line:268] INFO initial tx connect completely.
2019-07-11 09:09:23,116 rabbitmq.py[line:238] INFO begin to subscribe message
2019-07-11 09:09:23,215 rabbitmq.py[line:291] INFO deliver message to SUZAKU_SCHEDULER SUZAKU_SCHEDULER {"action": "Heart", "status": "OK", "sn": "dev"}

访问 http://192.168.56.10:15672 的 RabbitMQ 服务,因为 suzaku-driver 工作环境在 dev, 调度下发指令的队列名也即使用 dev 作为driver的监听消息的队列, 如图所是:

RabbitMQ Web UI

https://github.com/veryplay/suzaku-parent/blob/master/suzaku-driver/command.md 文件中, 有所有支持的指令的模板文档, 那其中的 PingHost 指令来说,PingHost 是用于验证 ilo ip的可达性,以验证带外管理网络可正常访问。

我们 ping 我们的PXE Server的IP, 看看执行结果,整理指令内容如下:

{

"sn" : "0",
"action" : "PingHost",
"ip" : "192.168.56.10"

}

sn在Driver操作部分是可选参数,不过尽量正确填写,以便跟踪对具体资源的操作行为记录。

将指令在 dev 队列 Publish message 部分输入上述内容:

RabbitMQ Publish message

看到 `suzaku-driver的日志如下:

2019-07-11 09:28:19,772 rabbitmq.py[line:191] INFO Received message # 1 from None: {
    "sn" : "0",
    "action" : "PingHost",
    "ip" : "192.168.56.10"
}
2019-07-11 09:28:19,772 rabbitmq.py[line:201] INFO Acknowledging message 1
2019-07-11 09:28:19,845 executor.py[line:144] INFO ready to run ping -c 3 192.168.56.10
2019-07-11 09:28:21,919 executor.py[line:172] INFO execute `ping -c 3 192.168.56.10` completely, exit code : 0, stdout : 
PING 192.168.56.10 (192.168.56.10) 56(84) bytes of data.
64 bytes from 192.168.56.10: icmp_seq=1 ttl=64 time=0.154 ms
64 bytes from 192.168.56.10: icmp_seq=2 ttl=64 time=0.139 ms
64 bytes from 192.168.56.10: icmp_seq=3 ttl=64 time=0.163 ms

--- 192.168.56.10 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 62ms
rtt min/avg/max/mdev = 0.139/0.152/0.163/0.009 ms

2019-07-11 09:28:21,919 ping.py[line:35] INFO ping 192.168.56.10 successfully
2019-07-11 09:28:21,919 common.py[line:72] INFO run PingHost success.
2019-07-11 09:28:22,015 rabbitmq.py[line:291] INFO deliver message to SUZAKU_SCHEDULER SUZAKU_SCHEDULER {"action": "PingHost", "status": "OK", "message": "run PingHost success.", "sn": "0", "ip": "192.168.56.10"}

显示 suzaku-driver 成功收到我们的 PingHost 指令,执行过程是发送数次 ping 指令,成功执行之后,给Scheduler反馈

{"action": "PingHost", "status": "OK", "message": "run PingHost success.", "sn": "0", "ip": "192.168.56.10"}

目前 Driver lifecycle 抽象还未实现,后续逐步完善这块的抽象,以便可以接入其他带外管理工具,比如 iDRACredfish等。

如果还有任何问题欢迎通过 github 或者 电子邮箱: mailto:linuxcoming@qq.com 沟通交流.

【腾讯云】境外1核2G服务器低至2折,半价续费券限量免费领取!
https://cloud.tencent.com/act/cps/redirect?redirect=1068&cps_key=e4b50f6c64a4480367f8a8d16fd07c5a&from=console

标签: pxe, driver, ipmi, ipmitool, 指令, power on, power off

添加新评论