tl;dr
LXD の REST API クライアントを作っているのでメモ。
メモ
使い方
- インストール
$ git clone https://github.com/inokappa/oreno_lxdapi.git $ cd oreno_lxdapi $ bundle install
以下、pry
を使って説明。
- 初期化
$ bundle exec pry [1] pry(main)> require 'oreno_lxdapi' => true [2] pry(main)> c = OrenoLxdapi::Client.new("oreno-ubuntu-image", "test-container") => #<OrenoLxdapi::Client:0x007f1ad0f5e348 @container_name="test-container", @image_name="oreno-ubuntu-image", @uri="unix:///var/lib/lxd/unix.socket">
- コンテナ作成
[3] pry(main)> c.create_container => "{\"type\":\"async\",\"status\":\"OK\",\"status_code\":100,\"metadata\":{\"id\":\"1a9e85e6-ce3a-4f60-9e80-6b5977184043\",\"class\":\"task\",\"created_at\":\"2015-12-30T10:06:42.084161349+09:00\",\"updated_at\":\"2015-12-30T10:06:42.084161349+09:00\",\"status\":\"Running\",\"status_code\":103,\"resources\":{\"containers\":[\"/1.0/containers/test-container\"]},\"metadata\":null,\"may_cancel\":false,\"err\":\"\"},\"operation\":\"/1.0/operations/1a9e85e6-ce3a-4f60-9e80-6b5977184043\"}\n
- コンテナ起動
[4] pry(main)> c.run_container still starting... still starting... still starting... => "{\"type\":\"async\",\"status\":\"OK\",\"status_code\":100,\"metadata\":{\"id\":\"3cae9859-159f-4cc5-b444-d99e01767480\",\"class\":\"task\",\"created_at\":\"2015-12-30T10:06:47.970125199+09:00\",\"updated_at\":\"2015-12-30T10:06:47.970125199+09:00\",\"status\":\"Running\",\"status_code\":103,\"resources\":{\"containers\":[\"/1.0/containers/test-container\"]},\"metadata\":null,\"may_cancel\":false,\"err\":\"\"},\"operation\":\"/1.0/operations/3cae9859-159f-4cc5-b444-d99e01767480\"}\n"
- コンテナ一覧
[5] pry(main)> c.list_containers => "{\"type\":\"sync\",\"status\":\"Success\",\"status_code\":200,\"metadata\":[\"/1.0/containers/oreno-container\",\"/1.0/containers/oreno-ubuntu\",\"/1.0/containers/oreno-ubuntu01\",\"/1.0/containers/test-container\"],\"operation\":\"\"}\n"
- コマンド実行
[6] pry(main)> c.run_lxc_exec("pwd") /root => true
- コンテナ停止
[7] pry(main)> c.stop_container => "{\"type\":\"async\",\"status\":\"OK\",\"status_code\":100,\"metadata\":{\"id\":\"8052b60d-32dd-4e0c-988b-469eab82b3a4\",\"class\":\"task\",\"created_at\":\"2015-12-30T10:07:23.500527489+09:00\",\"updated_at\":\"2015-12-30T10:07:23.500527489+09:00\",\"status\":\"Running\",\"status_code\":103,\"resources\":{\"containers\":[\"/1.0/containers/test-container\"]},\"metadata\":null,\"may_cancel\":false,\"err\":\"\"},\"operation\":\"/1.0/operations/8052b60d-32dd-4e0c-988b-469eab82b3a4\"}\n"
何が出来ていないのか
- コマンド実行
コンテナ内でコマンドを実行する場合には /1.0/containers/
見よう見まねで以下のように実装してみるが...
#!/usr/bin/env ruby require 'net_http_unix' require 'json' require 'websocket-client-simple' class LxdApi def initialize(image_name, container_name) @uri = "unix:///var/lib/lxd/unix.socket" @image_name = image_name @container_name = container_name end def client NetX::HTTPUnix.new(@uri) end def create_exec(command) commands = command.split(" ") req = Net::HTTP::Post.new("/1.0/containers/#{@container_name}/exec") req["Content-Type"] = "application/json" payload = { "command" => commands, "environment" => { "HOME" => "/root", "TERM" => "screen", "USER" => "root", }, "wait-for-websocket" => true, "interactive" => true, } req.body = payload.to_json resp = client.request(req) json = JSON.parse(resp.body) operation_id = "" secret = "" if json['metadata'] operation_id = json['metadata']['id'] unless json['metadata']['metadata'] == nil secret = json['metadata']['metadata']['fds']['0'] return operation_id, secret else return operation_id end end end def run_command(http_endpoint, id, secret) url = "#{http_endpoint}/1.0/operations/#{id}/websocket?secret=#{secret}" ws = WebSocket::Client::Simple.connect url ws.on :message do |msg| puts ">> #{msg.data}" end ws.on :open do puts "-- websocket open (#{ws.url})" end loop do ws.send STDIN.gets.strip end end end c = LxdApi.new("oreno-ubuntu-image", "oreno-container") metadata = c.create_exec("pwd") c.run_command("https://127.0.0.1:8443", metadata[0], metadata[1])
実行すると...以下のように実行結果は取得出来る。
-- websocket open (https://127.0.0.1:8443/1.0/operations/27308a13-079d-4aed-9412-cf1f71c63a6d/websocket?secret=56c5ab8397e9072276996fc7184c414ce8b765ac47ec5abdda1b2996aa4dabcb) >> /root >>
しかし、通常のコマンドの実行結果のようにコマンドが終了した時点でプロンプトに戻る(戻す)方法が解らなかった。
ということで...コマンドの実行だけは以下のように直接 lxc exec
コマンドを直接実行することにした。
def run_lxc_exec(command) lxc_exec = "lxc exec #{@container_name} -- " run_command = lxc_exec + command status = system(run_command) return status end
残念...引き続きの課題にしたい。
以上
test-kitchen のドライバ作ってみたい
次はこのオレオレライブラリを使って test-kitchen のドライバを作ってみたいけど。
注意
LXD の REST API は絶賛開発中とのことですので、ここに書いてある内容は本記事を書いた時点の内容となりますのでご注意くださいませ。