3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

XonshAdvent Calendar 2017

Day 5

(fd)pexpect+xonshで(シリアル)コンソール自動化

Last updated at Posted at 2017-12-04

pexpectとは

https://pexpect.readthedocs.io/en/stable/
対話式のコマンドを自動化するために使われる、expectというコマンドのPython版です。
expectは昔からある有名なコマンドぽいですが、tclという言語を使わなければならず大変とてもつらいので、python実装をできれば使いたい。そんなとこです。

pexpectの問題 

しかしここで問題になるのがpythonなこと。
そもそもすべてのコマンドが対話なわけでなく、基本的には普通にコマンドを並べて、たまにpexpectしたい場合、そこだけpythonの別ファイルにしなければならず、別ファイルになって見通しが悪くなったり、引数を渡してあげたりしなきゃいけません。

pexpect+xonsh

xonshだと下みたいにかけます。便利。
(適当な例なのでchpasswdは投げつけないでください…)
ということでpexpect使う場合はxonsh使うと便利と言う話でした。
ちなみにpexpectの部分だけコンソール上に表示されないのは気持ち悪いので、logfile=os.fdopen(sys.stdout.fileno(), 'wb')で端末上に出るようにしています。
subprocessはプログレスバーみたいなものが来ると表示が崩れたりして微妙という私見です。

setup.xsh
import pexpect
import os, sys

username = "test"
passwd   = "hoge"

sudo useradd @(username)
p = pexpect.spawn("sudo passwd "+username, logfile=os.fdopen(sys.stdout.fileno(), 'wb'))
p.expect("password:")
p.send(passwd+"\n")
p.expect("password:")
p.send(passwd+"\n")
mkdir @(username)
# chown...

シリアルコンソールの自動化をする

多分こっから先は、タイトルの機能を切望してる人意外は読まなくていいと思います。

上記の話は正直、そもそも対話を自動化したい時とかあまり無いし、だいたいオプションでなんとかなる。みたいなとこあると思います。長時間ターミナルで対話してるとしても、それ全部シェルスクリプトで自動化できるからみたいなことあると思います。

しかし、ブートローダやRTOSなどでスクリプトというものがない場合や、そもそもネットワークが物理的に使えない場合、ネットワークドライバがまだ安定してない場合、シリアルコンソールを自動化したいことが多々あるんです。そういう話です。

fdpexpect

先ほどのpexpectに、コマンドのspawnではなくてファイルデバイスを操作するfdpexpectというものがあります。
例えば

  1. /dev/ttyUSB0にボーレート38400で接続
  2. ローダーのオートブートを止めて適当な設定
  3. 成功したらブート
  4. Linux立ち上がったらsshで接続
    を書くとこんな感じになります。
boot.xsh
import serial
from pexpect import fdpexpect

# 1.
ser = serial.Serial('/dev/ttyUSB0', 38400)
terminal = fdpexpect.fdspawn(ser, logfile=os.fdopen(sys.stdout.fileno(), 'wb'), timeout=5)

# 2.
terminal.expect("AutoBoot...")
terminal.send("\n")
terminal.expect("loader#")
terminal.send("some boot loader command")
# 3.
res = terminal.expect(["loader#", "Error"])
if res:
    error_handle()
else:
    terminal.send("boot command")

# 4.
terminal.expect("root#")
ssh user@address

fdpexpect+xonshでできること

上の例はそのままsshしてるだけ(でも便利)ですが、

  • カーネルがエラー吐いたのをトリガにgrepしてエラーメッセージのコードをvimで立ち上げる
  • 対向をホストPCにしたネットワークドライバのテスト自動化
  • 起動オプションとftpサーバで見えるカーネルを同期取りながらいろいろなブート試す

とかそんな感じのことできたりします。

…以上です。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?