Module: Domctl

Defined in:
lib/domctl.rb,
lib/domctl/config.rb,
lib/domctl/commands.rb,
lib/domctl/commands/help.rb,
lib/domctl/commands/mem_info.rb,
lib/domctl/commands/dom0_info.rb,
lib/domctl/commands/domu_info.rb,
lib/domctl/commands/farm_info.rb,
lib/domctl/commands/show_vifs.rb,
lib/domctl/commands/locate_domu.rb,
lib/domctl/commands/list_running.rb,
lib/domctl/commands/oldest_domus.rb,
lib/domctl/commands/recent_domus.rb,
lib/domctl/commands/cluster_nodes.rb,
lib/domctl/commands/cpu_utilisation.rb

Defined Under Namespace

Classes: Config

Constant Summary collapse

VERSION =
"0.3.20090415155328"
DestroyDomuCommand =
Proc.new do
end
CreateDomuCommand =
Proc.new do
end
HelpCommand =

help ##############

Proc.new do
  cmd = DOMCTL_COMMANDS[:help][:args][0]
  if not cmd.nil? and not DOMCTL_COMMANDS[cmd.to_sym].nil?
    puts DOMCTL_COMMANDS[cmd.to_sym][:help]
  else
puts """
domctl #{Domctl::VERSION}

Usage: #{File.basename(__FILE__)} command [arguments...]

Available commands:

help                          print this help or the help associated
                              to a command
list_running                  list all running domUs in the specified dom0
locate_domu                   find the dom0 hosting the specified domU
show_vifs                     list the VIFs from a given domU
domu_info                     print DomU info
dom0_info                     print Dom0 info
recent_domus                  print the last 10 domus created
oldest_domus                  print the first 10 domus created
mem_info                      print the memory available in a host
farm_info                     print statistics from all the Hosts 
cpu_utilisation               CPU utilisation from all the Hosts 
cluster_nodes                 print the cluster nodes defined in #{Domctl::Config.config_file} 

Type domctl help <command> to get specific command help.

"""
  end
end
MemInfoHelp =

mem_info ##############

<<-HERE

Usage: domctl mem_info [dom0_name]

dom0_name is optional. If dom0_name is supplied, it only prints the memory info from the given host.

EXAMPLES

1. domctl mem_info xen0

"Print the memory info from xen0"

2. domctl mem_info

"Print the memory info from all the hosts defined in domctl config file"
HERE
MemInfoCommand =
Proc.new do
  node = DOMCTL_COMMANDS[:mem_info][:args][0]
  threads = []
  buffer = ""
  if node.nil?
    print 'Working'
    Domctl::Config.each_host do |h|
      print '.'
      threads << Thread.new do
        mfree = Pangea::Util.humanize_bytes(h.metrics.memory_free)
        mtotal = Pangea::Util.humanize_bytes(h.metrics.memory_total)
        buffer << "#{h.label.ljust(30)} #{(mfree + ' free').ljust(15)} #{mtotal} available\n"
      end
    end
    threads.each { |t| t.join }
    puts
    puts buffer
  else
    Domctl::Config.exit_if_not_defined(node)
    settings = Domctl::Config.cluster_nodes[node]
    begin
      h = Pangea::Host.connect(settings['url'], settings['username'], settings['password'])
      mfree = Pangea::Util.humanize_bytes(h.metrics.memory_free)
      mtotal = Pangea::Util.humanize_bytes(h.metrics.memory_total)
      print "#{h.label}".ljust(30)
      print "#{mfree} free".ljust(15)
      puts "#{mtotal} available"
    rescue Exception
      puts "Error connecting to host #{node}. Skipping."
    end
  end
end
Dom0InfoHelp =

dom0_info

<<-HERE

domctl dom0_info <dom0_name>

Print some info from the given dom0

EXAMPLES

1. domctl dom0_info xen0

"Print info from the xen0 host"

HERE
Dom0InfoCommand =
Proc.new do
  def print_dom0_info(h)
    puts "Label:             #{h.label}"
    puts "Memory Free:       #{Pangea::Util.humanize_bytes(h.metrics.memory_free)}"
    puts "Resident VMs:      #{h.resident_vms.size}"
    puts "Scheduler Policy:  #{h.sched_policy}"
    puts "CPUs:              #{h.cpus.size}"
    puts "Xen Version:       #{h.software_version['Xen']}"
    puts "Arch:              #{h.software_version['machine']}"
    puts "Kernel Version:    #{h.software_version['release']}"
    print "CPUs:              "
    h.cpus.each do |c|
      print "%.2f  " % (c.utilisation * 100)
    end
    puts
  end
  dom0 = DOMCTL_COMMANDS[:dom0_info][:args][0]
  if dom0.nil?
    $stderr.puts DOMCTL_COMMANDS[:dom0_info][:help]
    exit 1
  end
  Domctl::Config.exit_if_not_defined(dom0)
  dom0.strip.chomp!
  settings = Domctl::Config.cluster_nodes[dom0] 
  begin
    h = Pangea::Host.connect(settings['url'], settings['username'], settings['password'])
    print_dom0_info(h)
  rescue Exception
    puts "Error connecting to host #{dom0}. Skipping."
  end
end
DomuInfoHelp =

domu_info

<<-HERE

domctl domu_info <domu_name>

Print some info from the given domU. domu_name can be the full name
or the partial name from a running domU.

EXAMPLES

1. domctl domu_info vm-test

"Print info from vm-test"

2. domctl domu_info xen0:vm-test

"Print info from vm-test, but match only domUs resident in xen0 host"

HERE
DomuInfoCommand =
Proc.new do
  def print_vm_status(h, vm_label)
    h.resident_vms.each do |vm|
      if vm.label =~ /^.*#{vm_label}.*$/
        puts
        header = "[#{vm.label}]"
        puts header
        puts "-" * header.size
        puts "Dom ID:            #{vm.domid}"
        puts "Max Mem:           #{Pangea::Util::humanize_bytes(vm.dyn_max_mem)}"
        puts "Min Mem:           #{Pangea::Util::humanize_bytes(vm.dyn_min_mem)}"
        puts "Power State:       #{vm.power_state}"
        puts "Resident On:       #{vm.resident_on.label}"
        puts "Actions:"
        puts "  after crash:       #{vm.actions_after_crash}"
        puts "  after reboot:      #{vm.actions_after_reboot}"
        puts "  after shutdown:    #{vm.actions_after_shutdown}"
      end
    end
  end
  args = DOMCTL_COMMANDS[:domu_info][:args][0]
  if args.nil?
    $stderr.puts DOMCTL_COMMANDS[:domu_info][:help]
    exit 1
  end
  args.strip.chomp!
  # dom0:domU notation
  if args =~ /^.*:.*$/
    host, domu = args.split(':')
    settings = Domctl::Config.cluster_nodes[host]
    h = Pangea::Host.connect(settings['url'], settings['username'], settings['password'])
    print_vm_status(h, domu)
  else
    domu = args
    puts "Searching..."
    Domctl::Config.each_host do |h|
      print_vm_status(h, domu)
    end
  end
end
FarmInfoHelp =

farm_info ##############

<<-HELP

domctl farm_info

Print info from all the hosts defined in the config file:
- Memory Free
- Total Memory
- Number of CPUs
- Resident Virtual Machines (domUs)
- Number of CPUs/Cores
- CPUs/Cores utilisation

HELP
FarmInfoCommand =
Proc.new do
  buffer = ""
  print "Gathering Info"
  farm_total_mem = 0
  farm_free_mem = 0
  farm_resident_vms = 0
  farm_cpus = 0
  farm_hosts = 0
  threads = []
  Domctl::Config.each_host do |h|
    print '.'
    threads << Thread.new(buffer) do |bf|
      farm_hosts += 1
      buff = ''
      buff << "\n\n[#{h.label}]\n"
      buff << "-------\n"
      metrics = h.metrics
      mfree = Pangea::Util.humanize_bytes(metrics.memory_free)
      farm_free_mem += metrics.memory_free.to_i
      mtotal = Pangea::Util.humanize_bytes(metrics.memory_total)
      farm_total_mem += metrics.memory_total.to_i
      vms = h.resident_vms.size - 1
      farm_resident_vms += vms
      buff += "Resident VMs: #{vms}\n"
      buff += "Mem Free: #{mfree}  Mem Total: #{mtotal}\n"
      cpus = h.cpus.sort { |a,b| a.number <=> b.number }
      buff += "CPUs (#{cpus.size}): "
      cpus.each do |c|
        farm_cpus += 1
        buff += "%.2f  " % (c.utilisation * 100)
      end
      bf << buff
    end
  end
  threads.each { |t| t.join }
  buffer += "\n\n"
  puts buffer
  puts
  puts 'Global Info:'
  puts '-----------------------------------------------'
  puts "Farm Hosts:                #{farm_hosts}"
  puts "Farm Total Memory:         #{Pangea::Util.humanize_bytes(farm_total_mem)}"
  puts "Farm Free Memory:          #{Pangea::Util.humanize_bytes(farm_free_mem)}"
  puts "Farm Resident VMs:         #{farm_resident_vms}"
  puts "Farm CPUs:                 #{farm_cpus}"
  puts '-----------------------------------------------'
end
ShowVifsHelp =

show_vifs ##############

<<-HERE

domctl show_vifs <[dom0_name:]domU_name>

Print the virtual interfaces from the given domU

EXAMPLES

1. domctl show_vifs vm-test

"Print the VIFs found in vm-test (if vm-test exists)"

1. domctl show_vifs xen0:vm-test

"Print the VIFs found in vm-test, but look for vm-test in xen0 host only."
HERE
ShowVifsCommand =
Proc.new do
  def print_vifs(h, vm_label)
    buffer = ''
    h.resident_vms.each do |vm|
      if vm.label =~ /^.*#{vm_label}.*$/
        header = "\n[#{vm.label}]\n"
        buffer << header
        buffer << ("-" * header.size)
        vm.vifs.each do |vif|
          buffer << "\nDevice:      #{vif.device} **\n"
          buffer << "MAC Address: #{vif.mac}\n"
          metrics = vif.metrics
          buffer << "KBits/s IN:  %.3f\n" % metrics.io_read_kbs
          buffer << "KBits/s OUT: %.3f\n" % metrics.io_write_kbs
        end
      end
    end
    buffer
  end
  domu_name = DOMCTL_COMMANDS[:show_vifs][:args][0]
  if domu_name.nil?
    $stderr.puts DOMCTL_COMMANDS[:show_vifs][:help]
    exit 1
  end
  if domu_name =~ /^.*:.*$/
    host, domu = domu_name.split(':')
    Domctl::Config.exit_if_not_defined(host)
    settings = Domctl::Config.cluster_nodes[host]
    h = Pangea::Host.connect(settings['url'], settings['username'], settings['password'])
    puts print_vifs(h, domu)
  else
    threads = []
    print "Searching"
    buffer = ''
    Domctl::Config.each_host do |h|
      print '.'
      threads << Thread.new do
        buffer << print_vifs(h, domu_name)
      end
    end
    threads.each { |t| t.join }
    puts ' done.'
    puts buffer if not buffer.empty?
  end
end
LocateDomuHelp =

locate_domu ##############

<<-HERE

domctl locate_domu <domU name>

Find the domUs matching <domU name>

EXAMPLES

domctl locate_domu test-vm

"Locates a DomU named test-vm."

HERE
LocateDomuCommand =
Proc.new do
  domus = []
  threads = []
  arg = DOMCTL_COMMANDS[:locate_domu][:args][0]
  if arg.nil?
    $stderr.puts DOMCTL_COMMANDS[:locate_domu][:help]
    exit 1
  end
  print "Searching"
  Domctl::Config.each_host do |h|
    print '.'
    threads << Thread.new do 
      h.resident_vms.each do |vm|
        if vm.label =~ /^.*#{arg}.*$/
          domus << "#{h.label}: #{vm.label}" 
        end
      end
    end
  end
  threads.each { |t| t.join }
  puts
  puts "DomU matching '#{arg}' not found." if domus.empty?
  domus.each { |d| puts d }
end
ListRunningHelp =

list_running ##############

<<-HERE

Usage: domctl list_running <dom0_name|all>

Lists the running domUs in a given host (in every defined host if 'all' parameter is used instead of the dom0 name)

EXAMPLES

1. domctl list_running xen0

"List all the domUs running in xen0"

2. domctl list_running all

"List all the domUs in every host defined in #{Domctl::Config.config_file}"

HERE
ListRunningCommand =
Proc.new do
  def print_running(h)
    buffer = "\n"
    header = 'label'.ljust(30) + 'memory'.ljust(15) + 'power state'.ljust(15) + 'cpus'
    buffer << "[#{h.label}]".rjust(header.size) + "\n"
    buffer << header + "\n"
    buffer << ("-" * header.size) + "\n"
    h.resident_vms.each do |vm|
        label = vm.label
        next if vm.is_control_domain?
        buffer << "#{label}".ljust(30) 
        metrics = vm.metrics
        m = Pangea::Util.humanize_bytes(metrics.memory_actual)
        buffer << m.ljust(15) 
        buffer << vm.power_state.to_s.ljust(15) 
        buffer << metrics.vcpus_number + "\n"
    end
    buffer
  end
  node = DOMCTL_COMMANDS[:list_running][:args][0]
  if node.nil?
    $stderr.puts DOMCTL_COMMANDS[:list_running][:help]
    exit 1
  end
  threads = []
  buffer = ''
  if node == 'all'
    print "Working"
    Domctl::Config.each_host do |h|
      print '.'
      threads << Thread.new do
        buffer << print_running(h)
      end
    end
  else
    Domctl::Config.exit_if_not_defined(node)
    settings = Domctl::Config.cluster_nodes[node]
    begin
      puts 'Working...'
      h = Pangea::Host.connect(settings['url'], settings['username'], settings['password'])
      threads << Thread.new do
        buffer << print_running(h)
      end
    rescue Exception => e
      puts e.message
      puts "Error connecting to host #{node}. Skipping."
    end
  end
  threads.each { |t| t.join }
  puts buffer
end
OldestDomusHelp =
<<-HELP

Usage: domctl oldest_domus

Print the oldest domUs (the first 10 created).

HELP
OldestDomusCommand =
Proc.new do
  oldest = []
  threads = []
  print 'Working '
  Domctl::Config.each_host do |h|
    print '.'
    threads << Thread.new do
      h.resident_vms.each do |vm|
        oldest << [vm.label, vm.metrics.start_time] if vm.label != 'Domain-0'
      end
    end
  end
  threads.each { |t| t.join }
  puts ' done.'
  oldest.sort { |a,b| a[1] <=> b[1] }[0..9].each do |label, date|
    puts "#{label}".ljust(30) + date.to_s
  end
end
RecentDomusHelp =
<<-HELP

domctl recent_domus

Print the most recent domUs created (the last 10 created).

HELP
RecentDomusCommand =
Proc.new do
  recent = []
  t = []
  print 'Working '
  Domctl::Config.each_host do |h|
    t << Thread.new do
      print '.'
      h.resident_vms.each do |vm|
        recent << [vm.label, vm.metrics.start_time] if vm.label != 'Domain-0'
      end
    end
  end
  t.each { |thread| thread.join }
  puts ' done.'
  recent.sort { |a,b| a[1] <=> b[1] }[-10..-1].reverse.each do |label, date|
    puts "#{label}".ljust(30) + date.to_s
  end
end
ClusterNodesHelp =

cluster_nodes ##############

<<-EOF

Usage: domctl cluster_nodes

Show the Xen hosts (dom0) defined in #{Domctl::Config.config_file}

EOF
ClusterNodesCommand =
Proc.new do
  Domctl::Config.cluster_nodes.keys.sort.each do |n|
    puts n
  end
end
CpuUtilisationCommand =
Proc.new do
  puts "Gathering info..."
  table = {}
  Domctl::Config.each_host do |h|
    table[h.label] = h.cpus.sort { |a,b| a.number <=> b.number }
  end
  cols = 0
  rows = []
  rc = 0
  table = table.sort { |a,b| a[0] <=> b[0] }
  table.each do |l,cpus|
    cols = cpus.size if cpus.size > cols
    r = Term::ANSIColor.bold("[#{l}]") + "\n"
    cpus.each do |c|
      r += ("%.2f" % (c.utilisation * 100)).ljust(8)
    end
    rows << r
  end
  header = ''
  0.upto(cols - 1) do |i| 
    header += "CPU#{i}".ljust(8)
  end
  puts header
  puts "-" * header.size
  rows.each do |r|
    puts r
  end
end