2017年11月7日火曜日

rbvmomi で GuestProcessManager を使って VM 内のプロセスを操作してみる

概要

GuestProcessManager は VM のプロセスを制御することができる vSphere API です
VM に SSH ログインすることなくコマンドなどを実行することができます
今回は Ruby + rbvmomi を使ってプロセスの制御を行ってみました

環境

  • Ubuntu 16.04.3
  • Ruby 2.3.1p112
  • gem 2.5.1
  • rbvmomi 1.11.3

ライブラリインストール

  • bundle init
  • vim Gemfile
gem "rbvmomi"
  • bundle install --path vendor

プロセスの一覧を表示する

  • vim list_processes.rb
require 'rbvmomi'

vim = RbVmomi::VIM.connect(
  host: '192.168.100.1',
  user: 'vcenter-user',
  password: 'vcenter-pass',
  insecure: 'true'
)

dc = vim.serviceInstance.find_datacenter('datacenter') || fail('datacenter not found')
vm = dc.find_vm('directory/path/to/vm') || fail('VM not found')

auth = RbVmomi::VIM::NamePasswordAuthentication(
  interactiveSession: false,
  username: "root",
  password: "password"
)

processes = vim.serviceContent.guestOperationsManager.processManager.ListProcessesInGuest(
  vm: vm,
  auth: auth,
  pids: []
)

processes.each { |process|
  puts "name => #{process.props[:name]}, pid => #{process.props[:pid]}, owner => #{process.props[:owner]}, cmdLine => #{process.props[:cmdLine]}, startTime => #{process.props[:startTime]}"
}

ListProcessesInGuest を使います
引数には VM の情報と VM の認証情報を付与します
第 3 引数に pid の配列を指定することができ、指定のプロセス情報だけ取得することもできます
結果は RbVmomi::VIM::GuestProcessInfo の配列が返ってくるので each で回してプロパティにアクセスしています

VM の情報を取得するのに find_datacenter -> find_vm という流れを使っています
データセンターを取得したあとそのデータセンター配下にある VM を検索するのですが、フォルダで階層化されている場合はパス形式で指定する必要があるので注意してください

VM 情報取得 -> VM 認証情報作成の流れはこのあとの処理でも共通処理として登場します

環境変数の一覧を表示する

  • vim read_environment.rb
require 'rbvmomi'

vim = RbVmomi::VIM.connect(
  host: '192.168.100.1',
  user: 'vcenter-user',
  password: 'vcenter-pass',
  insecure: 'true'
)

dc = vim.serviceInstance.find_datacenter('datacenter') || fail('datacenter not found')
vm = dc.find_vm('directory/path/to/vm') || fail('VM not found')

auth = RbVmomi::VIM::NamePasswordAuthentication(
  interactiveSession: false,
  username: "root",
  password: "password"
)

env = vim.serviceContent.guestOperationsManager.processManager.ReadEnvironmentVariableInGuest(
  vm: vm,
  auth: auth,
  names: []
)

puts env

ReadEnvironmentVariableInGuest を使います
流れは先程のプロセスを取得するスクリプトとほぼ同じです
結果が String の配列で返ってくる部分が違います
第 3 引数に環境変数名を配列で指定すれば指定した環境変数のみ取得することも可能です

プロセスを起動する

  • vim start_program.rb
require 'rbvmomi'

vim = RbVmomi::VIM.connect(
  host: '192.168.100.1',
  user: 'vcenter-user',
  password: 'vcenter-pass',
  insecure: 'true'
)

dc = vim.serviceInstance.find_datacenter('datacenter') || fail('datacenter not found')
vm = dc.find_vm('directory/path/to/vm') || fail('VM not found')

auth = RbVmomi::VIM::NamePasswordAuthentication(
  interactiveSession: false,
  username: "root",
  password: "password"
)

spec = RbVmomi::VIM::GuestProgramSpec(
  programPath: "/bin/hostname",
  arguments: ""
)

pid = vim.serviceContent.guestOperationsManager.processManager.StartProgramInGuest(
  vm: vm,
  auth: auth,
  spec: spec
)

puts pid

StartProgramInGuest を使います
第 3 引数に実行するコマンド情報を指定する必要があります
コマンド情報は GuestProgramSpec から生成します
コマンド情報はフルパスで指定しましょう、PATH が通っているコマンドでもフルパスで指定しないと見つかりません

返り値は実行したコマンドのプロセス ID が返却されます
ここが少し残念なのですが実行したコマンドの標準出力などを取得することができません
なので結果がほしい場合はどこかのファイルのリダイレクトしてあとからそのファイルを取得するなどの工夫が必要になります

プロセスを停止する

  • vim terminate_process.rb
require 'rbvmomi'

vim = RbVmomi::VIM.connect(
  host: '192.168.100.1',
  user: 'vcenter-user',
  password: 'vcenter-pass',
  insecure: 'true'
)

dc = vim.serviceInstance.find_datacenter('datacenter') || fail('datacenter not found')
vm = dc.find_vm('directory/path/to/vm') || fail('VM not found')

auth = RbVmomi::VIM::NamePasswordAuthentication(
  interactiveSession: false,
  username: "root",
  password: "password"
)

pid = 3004
vim.serviceContent.guestOperationsManager.processManager.TerminateProcessInGuest(
  vm: vm,
  auth: auth,
  pid: pid
)

TerminateProcessInGuest を使います
第 3 引数には停止するプロセス ID を指定します
これも少し残念なのですが、返り値は void です
成功したかどうかの判断ができないので、もし判断したい場合はこのあとで ListProcessesInGuest などを呼び出してプロセスがなくなっているか確認するなどの工夫が必要になります

最後に

GuestProcessManager を使って vmware-tools 経由で VM 内のプロセスの制御をしてみました
VM に SSH する必要がないのが嬉しい点かなと思います
簡単なプロセス制御であれば GuestProcessManager で代用できるかなと思います
また実行条件としては vmware-tools が起動している必要があります

今回認証は VM のユーザ、パスワード認証を使いました
そもそもパスワード認証を設定していない場合もあるのでその場合は SSPIAuthentication や TicketedSessionAuthentication を使うのですがどうやらこれらだと OperationNotSupportedByGuest になってしまいアクセスできません
やり方が悪いのかもわからないのですが、ネット上でも同じように SSPI or Ticket 認証で GuestProcessManager を制御しようとしているようなのですが解決できてそうな情報は見つかりませんでした
(もし判明したら教えてほしいくらいです)

あと rbvmomi の場合ドットつなぎでオブジェクトを辿り API をコールします
次に何をつなぐかわからなくなるケースが多くなると思うのでその場合は vCenter の mob を見ながらやると次に何のメソッドがコールできるかわかると思います
本当はそ rbvmomi のコードを見ながらやりたいのですが、API の殆どが vmodl.db というバイナリファイルで定義されているため内容が確認するのが大変です

参考サイト

0 件のコメント:

コメントを投稿