vSphere APIを使えば、ESXiだけじゃなくて、VMごとのCPU、メモリなんかのステータスも取得てきます。 取得した値をZabbixに食わせて、Zabbixで監視してみます。 VMwareのサイトにPerlのSDKがありますが、書き方が分かりにくかったので、 今回はRubyのRbVmomiを使ってみます。
まずはインストール
1
|
|
使い方
1
|
|
これでステータスが取れます。簡単です。
取得する値は、
VMware vSphere API Reference Documentation
とか https://(vCenter)/mob
を参照します。
Zabbixへの取込み方は、 ESXi 4.0 Hardware and Software Monitoring VMWare を参考にして、
- 取得した値をローカルにテキストで保存する
- それをZabbix AgentのUserParameterで取得する
というやり方にしてみます。
上記のサイトでは1つのファイルにしていますが、VMごとに取得したいので、
ついでに、ESXi、データストアのステータスも取得したいと思います。
VM、ESXi、データストアそれぞれをZabbixに監視ホストとして登録しようと思うので、それぞれ別ファイルにしてみます。
RbVmomiスクリプト
で、スクリプトはこんな感じになりました。
#!/usr/bin/ruby | |
require 'rubygems' | |
require 'zbxapi' | |
require 'logger' | |
require 'rbvmomi' | |
require 'fileutils' | |
ESX_GROUP = "VM ESXi" | |
DS_GROUP = "VM Datastore" | |
VM_GROUP = "VM VirtualMachine" | |
ESX_TEMPLATE = "Template-vSphere-ESXi" | |
DS_TEMPLATE = "Template-vSphere-Datastore" | |
VM_TEMPLATE = "Template-vSphere-VM" | |
FILEPATH = "/tmp/vsphere" | |
class Zbx < ZabbixAPI | |
def initialize() | |
@user = "Admin" | |
@pass = "zabbix" | |
begin | |
@zbxapi = ZabbixAPI.new($zbxUrl).login(@user, @pass) | |
rescue => exc | |
p exc | |
$log.error(exc) | |
exit | |
end | |
end | |
def send_zbx(zbxCmd, zbxHash) | |
begin | |
@zbxapi.raw_api(zbxCmd, zbxHash) | |
rescue => exc | |
p exc | |
$log.error(exc) | |
exit | |
end | |
end | |
def search_zbxGroup(groupName) | |
zbxHash = { | |
:name => groupName | |
} | |
send_zbx("hostgroup.exists", zbxHash) | |
end | |
def create_zbxGroup(groupName) | |
zbxHash = { | |
:name => groupName | |
} | |
send_zbx("hostgroup.create", zbxHash) | |
end | |
def get_zbxGroupId(groupName) | |
if search_zbxGroup(groupName) | |
zbxHash = { | |
:name => groupName | |
} | |
send_zbx("hostgroup.getobjects", zbxHash)[0]['groupid'] | |
else | |
create_zbxGroup(groupName)['groupids'][0] | |
end | |
end | |
def search_zbxTemplate(templateName) | |
zbxHash = { | |
:name => templateName | |
} | |
send_zbx("template.exists", zbxHash) | |
end | |
def get_zbxTemplateId(templateName) | |
unless search_zbxTemplate(templateName) | |
errmsg = "#{templateName} is not exist." | |
$log.error(errmsg) | |
abort(errmsg) | |
end | |
@zbxapi.raw_api("template.getobjects", { | |
:name => templateName | |
})[0]['templateid'] | |
end | |
def search_zbxHost(hostName) | |
zbxHash = { | |
:host => hostName | |
} | |
send_zbx("host.exists", zbxHash) | |
end | |
def create_zbxHost(hosts, groupName, templateName) | |
@groupId = get_zbxGroupId(groupName) | |
@templateId = get_zbxTemplateId(templateName) | |
hosts.each {|host| | |
zbxHash = { | |
:host => host, | |
:interfaces => [{ | |
:type => 1, | |
:main => 1, | |
:useip => 1, | |
:ip => "127.0.0.1", | |
:dns => "", | |
:port => "10050" | |
}], | |
:groups => [{ | |
:groupid => @groupId | |
}], | |
:templates => [{ | |
:templateid => @templateId | |
}] | |
} unless search_zbxHost(host) | |
send_zbx("host.create", zbxHash) | |
} | |
end | |
def get_zbxHostId(hostName) | |
zbxHash = { | |
:host => hostName | |
} | |
send_zbx("host.getobjects", zbxHash)[0]['hostid'] | |
end | |
def delete_zbxHost(hostName) | |
zbxHash = { | |
:hostid => get_zbxHostId(hostName) | |
} if search_zbxHost(hostName) | |
send_zbx("host.delete", zbxHash) if zbxHash | |
end | |
end | |
class VSphere < RbVmomi::VIM | |
def initialize(host, user, pass) | |
@host = host | |
@user = user | |
@password = pass | |
begin | |
@vim = RbVmomi::VIM.connect :host => @host, :user => @user, :password => @password, :insecure => true | |
rescue => exc | |
p exc | |
$log.error(exc) | |
exit | |
end | |
begin | |
@dc = @vim.serviceInstance.find_datacenter | |
rescue => exc | |
p exc | |
$log.error(exc) | |
exit | |
end | |
end | |
def get_host_status(type) | |
new_list = Array.new | |
case type | |
when "host" | |
@dc.hostFolder.childEntity[0].host.grep(RbVmomi::VIM::HostSystem).each do |stat| | |
newname = stat.name.gsub(/:/,"-") | |
stat_fileName = "h_#{newname}" | |
new_list << newname unless File.exist?($filePath + stat_fileName) | |
statData = { | |
"host-Hostname" => stat.name, | |
"host-Product" => stat.summary.config.product.fullName, | |
"host-HardwareMode" => stat.summary.hardware.model, | |
"host-CPUModel" => stat.summary.hardware.cpuModel, | |
"host-CPUMHz" => stat.summary.hardware.cpuMhz, | |
"host-CPUCore" => stat.summary.hardware.numCpuCores, | |
"host-CPUUsage" => stat.summary.quickStats.overallCpuUsage, | |
"host-TotalMemorySize" => stat.summary.hardware.memorySize/1024/1024, | |
"host-MemoryUsage" => stat.summary.quickStats.overallMemoryUsage, | |
"host-PowerState" => stat.summary.runtime.powerState, | |
"host-MaintenanceMode" => stat.summary.runtime.inMaintenanceMode, | |
"host-Uptime" => stat.summary.quickStats.uptime | |
} | |
writefile(stat_fileName, statData) | |
end | |
if new_list.length > 0 | |
unless defined?(@zbxapi) | |
@zbxapi = Zbx.new | |
end | |
@zbxapi.create_zbxHost(new_list, ESX_GROUP, ESX_TEMPLATE) | |
end | |
when "ds" | |
@dc.datastore.grep(RbVmomi::VIM::Datastore).each do |stat| | |
newname = stat.name.gsub(/:/,"-") | |
stat_fileName = "d_#{newname}" | |
new_list << newname unless File.exist?($filePath + stat_fileName) | |
vm_list =[] | |
stat.vm.grep(RbVmomi::VIM::VirtualMachine).each {|v| vm_list << v.name } | |
statData = { | |
"ds-Name" => stat.name, | |
"ds-Capacity" => stat.summary.capacity, | |
"ds-FreeSpace" => stat.summary.freeSpace, | |
"ds-VM" => vm_list.join(', ') | |
} | |
writefile(stat_fileName, statData) | |
end | |
if new_list.length > 0 | |
unless defined?(@zbxapi) | |
@zbxapi = Zbx.new | |
end | |
@zbxapi.create_zbxHost(new_list, DS_GROUP, DS_TEMPLATE) | |
end | |
when "vm" | |
@dc.vmFolder.childEntity.grep(RbVmomi::VIM::VirtualMachine).each do |stat| | |
newname = stat.name.gsub(/:/,"-") | |
stat_fileName = "v_#{newname}" | |
new_list << newname unless File.exist?($filePath + stat_fileName) | |
statData = { | |
"vm-Name" => stat.name, | |
"vm-ESXi" => stat.runtime.host.name, | |
"vm-powerState" => stat.summary.runtime.powerState, | |
"vm-guestFullName" => stat.summary.guest.guestFullName, | |
"vm-HostName" => stat.summary.guest.hostName, | |
"vm-IPAddress" => stat.summary.guest.ipAddress, | |
"vm-VMwareTools" => stat.summary.guest.toolsStatus, | |
"vm-maxCpuUsage" => stat.summary.runtime.maxCpuUsage, | |
"vm-numCpu" => stat.summary.config.numCpu, | |
"vm-overallCpuUsage" => stat.summary.quickStats.overallCpuUsage, | |
"vm-memorySizeMB" => stat.summary.config.memorySizeMB, | |
"vm-hostMemoryUsage" => stat.summary.quickStats.hostMemoryUsage, | |
"vm-guestMemoryUsage" => stat.summary.quickStats.guestMemoryUsage, | |
"vm-UncommittedStorage" => stat.summary.storage.uncommitted, | |
"vm-UsedStorage" => stat.summary.storage.committed, | |
"vm-UnsharedStorage" => stat.summary.storage.unshared, | |
"vm-Uptime" => stat.summary.quickStats.uptimeSeconds | |
} | |
writefile(stat_fileName, statData) | |
end | |
if new_list.length > 0 | |
unless defined?(@zbxapi) | |
@zbxapi = Zbx.new | |
end | |
@zbxapi.create_zbxHost(new_list, VM_GROUP, VM_TEMPLATE) | |
end | |
end | |
end | |
end | |
def print_usage | |
puts "usage: rbvmomi_zabbix.rb (vCenter Host) (vCenter Username) (vCenter Password) (Zabbix URL)" | |
exit | |
end | |
def writefile(fileName, data) | |
begin | |
statsFile = open($filePath + fileName, "w") | |
rescue => exc | |
p exc | |
$log.error(exc) | |
exit | |
end | |
data.each_pair {|key, value| statsFile.puts "#{key}:#{value}"} | |
statsFile.close | |
end | |
def stats_file_age_check(time) | |
# 1日以上更新がないホストはZabbixから削除 | |
Dir::glob($filePath + "*").each do |f| | |
if Time.now - File.stat(f).mtime >= time | |
/\A[vhd]_(.*)\z/ =~ File.basename(f) | |
unless defined?(zbxapi) | |
@zbxapi = Zbx.new | |
end | |
@zbxapi.delete_zbxHost($1) | |
File.delete(f) | |
end | |
end | |
end | |
def stats_file_check(zbx_host, fileName) | |
create_zbxHost(hosts, groupName, templateName) unless File.exist?(fileName) | |
end | |
print_usage if ARGV.size != 4 | |
vcHost = ARGV[0] | |
vcUser = ARGV[1] | |
vcPass = ARGV[2] | |
$zbxUrl = ARGV[3] | |
$filePath = FILEPATH + "/stats/" | |
FileUtils.mkdir_p($filePath) unless File.exists?($filePath) | |
logPath = FILEPATH + "/logs/" | |
FileUtils.mkdir_p(logPath) unless File.exists?(logPath) | |
$log = Logger.new(logPath + 'test.log', 'weekly') | |
stats_file_age_check(3600 * 24) | |
ds = VSphere.new(vcHost, vcUser, vcPass) | |
ds.get_host_status("host") | |
ds.get_host_status("ds") | |
ds.get_host_status("vm") | |
puts 0 |
/tmp/vsphere にファイルを保存するのdで、zabbixの実行ユーザに書き込み権を与えておきます。
chown zabbix:zabbix /var/vsphere
引数にvCenter(or ESXi)のIPアドレス、ユーザ名、パスワードを指定して実行します。
su -u zabbix rbvmomi-zabbix.rb 192.168.1.1 root password
成功すれば、/tmp/vspere以下にESXi、データストア、VMごとのファイルができます。
Zabbix設定
次はZabbix側です。
まず、APIからのデータ取得は結構時間がかかるので、サーバ側、エージェント側両方のタイムアウトを30秒にして、再起動しておきます。
- /etc/zabbix/zabbix_server.conf
1
|
|
- /etc/zabbix/zabbix_agentd.conf
1
|
|
テンプレートをインポートします。
Zabbix UserParameterの設定
下記のファイルを/etc/zabbix/zabbix_agentd.d/以下に保存します。
vCenterの登録
Zabbixにホストとして、vCenterを登録します。
ホスト - ホスト名:適当 - エージェントのIPアドレス:127.0.0.1 - ポート:10050 テンプレート - インポートしたvCenter用テンプレート マクロ - {$HOST} : IPアドレス - {$USERNAME} : ユーザ名 - {$PASSWORD} : パスワード
これで、スクリプトが設定した間隔で実行されます。
ESXi、データストア、VMの登録
ホスト - ホスト:各登録名 - IPアドレス:127.0.0.1 - ポート:10050 テンプレート - インポートしたESXi、データストア、VM用テンプレート
名前に「:」が含まれていると、登録できないので、「-」に変換して登録してください。