LXCの特定の1つのコンテナの起動状態をシェルスクリプトで確認したいときのお勧めの方法

イマイチな方法1: lxc listの出力をawkで加工

lxc list -h を見ると lxc list [resource] [filters] [--format table|json] [-c columns] [--fast] というコマンドラインになっていて、 -c オプションで表示するカラムを指定可能です。

例えば 以下のようにすれば cent01 コンテナの起動状態だけを表示できます。

$ lxc list -c s cent01
+---------+
|  STATE  |
+---------+
| RUNNING |
+---------+

ただ、デフォルトの --format table だとASCII文字の罫線が表示されるので、状態を抜き出すにはawkで加工する必要があります。

$ lxc list -c s cent01 | awk 'NR==4{print $2}'
RUNNING

イマイチな方法2: lxc list –format jsonの出力をjqで加工

--format json でJSON形式で出力できるのですが、この場合は -c オプションで項目を限定することは出来ませんでした。

$ lxc list --format json -c s cent01
[{"architecture":"x86_64","config":{"volatile.base_image":"a027d59858d663fb2bc12b5ba767e92196a4aee8dbb2a607db53d718b91eb5d2","volatile.eth0.hwaddr":"00:16:3e:5f:01:7e","volatile.last_state.idmap":"[{\"Isuid\":true,\"Isgid\":false,\"Hostid\":100000,\"Nsid\":0,\"Maprange\
":65536},{\"Isuid\":false,\"Isgid\":true,\"Hostid\":100000,\"Nsid\":0,\"Maprange\":65536}]"},"created_at":"2016-05-06T18:56:46+09:00","devices":{"root":{"path":"/","type":"disk"}},"ephemeral":false,"expanded_config":{"volatile.base_image":"a027d59858d663fb2bc12b5ba767e9
2196a4aee8dbb2a607db53d718b91eb5d2","volatile.eth0.hwaddr":"00:16:3e:5f:01:7e","volatile.last_state.idmap":"[{\"Isuid\":true,\"Isgid\":false,\"Hostid\":100000,\"Nsid\":0,\"Maprange\":65536},{\"Isuid\":false,\"Isgid\":true,\"Hostid\":100000,\"Nsid\":0,\"Maprange\":65536}
]"},"expanded_devices":{"eth0":{"name":"eth0","nictype":"bridged","parent":"lxdbr0","type":"nic"},"root":{"path":"/","type":"disk"}},"name":"cent01","profiles":["default"],"stateful":false,"status":"Running","status_code":103,"state":null,"snapshots":null}]

sudo apt install jqjq コマンドをインストールして、それで状態を抜き出すことは可能です。

$ lxc list --format json cent01 | jq -r '.[0].status'
Running

お勧めの方法: lxc infoの出力をawkで加工

lxc list の場合は指定した文字列は完全一致ではなくて前方一致で表示されました。上記の例のように cent01cent02 の2つのコンテナがあるときに、 lxc list -c s cent0 と実行すると以下のようになります。

$ lxc list -c s cent0
+---------+
|  STATE  |
+---------+
| RUNNING |
+---------+
| RUNNING |
+---------+

これだとどの行がどのコンテナかわからないのでコンテナ名の列も付ける必要があります。

$ lxc list -c ns cent0
+--------+---------+
|  NAME  |  STATE  |
+--------+---------+
| cent01 | RUNNING |
+--------+---------+
| cent02 | RUNNING |
+--------+---------+

この結果をawkで加工するのでも良いのですが、もっと良いのは lxc info コマンドを使うことです。

$ lxc info cent01
コンテナ名: cent01
アーキテクチャ: x86_64
作成日時: 2016/05/06 09:56 UTC
状態: Running
タイプ: persistent
プロファイル: default
Pid: 29354
IPアドレス:
  eth0: inet    10.155.92.101   vethG4XSE4
  eth0: inet6   fe80::216:3eff:fe5f:17e vethG4XSE4
  lo:   inet    127.0.0.1
  lo:   inet6   ::1
リソース:
  プロセス数: 10
  メモリ消費量:
    メモリ (現在値): 23.60MB
    メモリ (ピーク): 43.08MB
  ネットワーク使用状況:
    eth0:
      受信バイト数: 24.16kB
      送信バイト数: 8.06kB
      受信パケット: 232
      送信パケット: 88
    lo:
      受信バイト数: 0 bytes
      送信バイト数: 0 bytes
      受信パケット: 0
      送信パケット: 0

存在しないコンテナ名を指定するとエラーになります。これは標準エラー出力に出力されています。

$ lxc info hoge
エラー: not found

シェルスクリプトで加工するには英語出力のほうが良いので LANG=C 付きで実行します。

$ LANG=C lxc info cent01
Name: cent01
Architecture: x86_64
Created: 2016/05/06 09:56 UTC
Status: Running
Type: persistent
Profiles: default
Pid: 29354
Ips:
  eth0: inet    10.155.92.101   vethG4XSE4
  eth0: inet6   fe80::216:3eff:fe5f:17e vethG4XSE4
  lo:   inet    127.0.0.1
  lo:   inet6   ::1
Resources:
  Processes: 10
  Memory usage:
    Memory (current): 23.60MB
    Memory (peak): 43.08MB
  Network usage:
    eth0:
      Bytes received: 24.58kB
      Bytes sent: 8.56kB
      Packets received: 235
      Packets sent: 93
    lo:
      Bytes received: 0 bytes
      Bytes sent: 0 bytes
      Packets received: 0
      Packets sent: 0
$ LANG=C lxc info hoge
error: not found

結局以下のように実行するのがお勧めです。

$ LANG=C lxc info cent01 2> /dev/null | awk '$1=="Status:"{print $2}'
Running

存在しない場合は空文字列になります。

$ LANG=C lxc info hoge 2> /dev/null | awk '$1=="Status:"{print $2}'

判定例はこんな感じです。

$ [ x`LANG=C lxc info cent01 2> /dev/null | awk '$1=="Status:"{print $2}'` == xRunning ] && echo "container is running"
container is running
$ [ x`LANG=C lxc info hoge 2> /dev/null | awk '$1=="Status:"{print $2}'` == xRunning ] && echo "container is running"
$