188 lines
6 KiB
Ruby
188 lines
6 KiB
Ruby
require 'pmap'
|
|
|
|
class PVE::Cli
|
|
|
|
def cli_base
|
|
cli.cmd :list, "List CT/VM-IDs", aliases: ['ls'], &lambda {|target=nil|
|
|
connect
|
|
nodes = Proxmox::Node.all
|
|
nodes.
|
|
flat_map {|n| [ n.method(:lxc), n.method(:qemu) ] }.
|
|
flat_pmap {|m| m.call.map {|c| c.vmid.to_i } }.
|
|
sort.
|
|
each {|c| puts c }
|
|
}
|
|
|
|
cli.cmd( :status, "Lists Nodes/VMs/CTs with status", &lambda {|target=nil, sort: 'n', node: nil|
|
|
connect
|
|
node &&= /\A#{node}\z/
|
|
to = TablizedOutput.new %w[Status HA ID Name Host Uptime CPU/% Mem/MiB Mem/% Disk/MiB Disk/%]
|
|
push =
|
|
if target
|
|
target = /\A#{target}\z/
|
|
lambda {|n| to.virt n if n === target }
|
|
else
|
|
lambda {|n| to.virt n }
|
|
end
|
|
nodes = Proxmox::Node.all
|
|
nodes.
|
|
select {|n| not node or n === node }.
|
|
flat_map {|n| [ n.method(:lxc), n.method(:qemu) ] }.
|
|
each {|m| m.call.each &push }
|
|
to.print order: sort.each_char.map {|c| (2*c.ord[5]-1) * (' sainhucmd'.index( c.downcase)) }
|
|
}).
|
|
opt( :sort, '-s', '--sort=COLUMNS', "Sort by COLUMNs eg hn for host and name ([s]tatus, h[a], [i]d, [n]ame (default), [h]ost, [u]ptime, [c]pu, [m]em, [d]isk)").
|
|
opt( :node, '-n', '--node=NODE', "List only hosted by this NODE")
|
|
|
|
def prepare_show_config cnf
|
|
r = {}
|
|
cnf.each do |k,v|
|
|
case k
|
|
when :network
|
|
v.each do |net|
|
|
s =
|
|
net.
|
|
reject {|k, v| :card == k }.
|
|
sort_by {|k, v| :name == k ? :AAAAAAAAA : k }.
|
|
map {|k, v| case v when true then [k,1] when false then [k,0] else [k,v] end }.
|
|
map {|k, v| "#{k}=#{v}" }
|
|
r[net[:card].to_sym] = s.join(",")
|
|
end
|
|
when :sshkeys
|
|
r[k] = CGI.unescape(v).gsub( /^/, " "*14).gsub /\A {14}|\n\z/, ''
|
|
else
|
|
case v
|
|
when true then v = 1
|
|
when false then v = 0
|
|
end
|
|
r[k] = v.to_s.gsub( /$^/, " "*14).gsub /\n\z/, ''
|
|
end
|
|
end
|
|
r
|
|
end
|
|
|
|
def show_config cnf, old = nil
|
|
cnf = prepare_show_config cnf
|
|
if old
|
|
old = prepare_show_config old
|
|
(cnf.keys+old.keys).uniq.sort.each do |k|
|
|
v, o = cnf[k], old[k]
|
|
if v == o
|
|
puts "#{k}:#{' ' * (12-k.length)} #{v}"
|
|
else
|
|
puts "\e[31m#{k}:#{' ' * (12-k.length)} #{o}\e[0m" unless o.nil?
|
|
puts "\e[32m#{k}:#{' ' * (12-k.length)} #{v}\e[0m" unless v.nil?
|
|
end
|
|
end
|
|
else
|
|
cnf.sort_by{|k,v|k}.each do |k,v|
|
|
puts "#{k}:#{' ' * (12-k.length)} #{v}"
|
|
end
|
|
end
|
|
end
|
|
|
|
cli.sub :config, "CT/VM Configuration", min: 2, aliases: %w[cnf] do |ccli|
|
|
ccli.cmd 'help', '', aliases: [nil, '-h', '--help'], &lambda {|*args| help ccli, *args }
|
|
|
|
ccli.cmd :show, "Show Config of CT/VM", &lambda {|name_or_id|
|
|
connect
|
|
th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id)
|
|
show_config th.config
|
|
}
|
|
|
|
ccli.cmd :set, "Set Configs for CT/VM", &lambda {|name_or_id, *args|
|
|
if %w[-h --help].include? name_or_id
|
|
STDERR.puts "Usage: set -h|--help # Show help"
|
|
STDERR.puts " set ct|vm --CNF1=VAL1 --CNF2=VAL2 ... # Set config-value. Empty value clears field."
|
|
exit 1
|
|
end
|
|
opts = {}
|
|
until args.empty?
|
|
case arg = args.shift
|
|
when /\A--(\w+)=(.*)\z/
|
|
opts[$1.to_sym] = $2
|
|
when /\A--(\w+)\z/
|
|
opts[$1.to_sym] = args.shift
|
|
else
|
|
raise UsageError, "Expection option to set. What do you mean with: #{arg}"
|
|
end
|
|
end
|
|
opts.each do |k, v|
|
|
opts[k] =
|
|
case v = opts[k]
|
|
when '' then nil
|
|
else v
|
|
end
|
|
end
|
|
%i[migrate_downtime].each do |k|
|
|
next unless opts.has_key? k
|
|
opts[k] =
|
|
case v = opts[k]
|
|
when nil, '', 'nil' then nil
|
|
else v.to_f
|
|
end
|
|
end
|
|
%i[memory background_delay balloon cores cpulimit cpuunits migrate_speed shares smp sockets vcpus swap tty].each do |k|
|
|
next unless opts.has_key? k
|
|
opts[k] =
|
|
case v = opts[k]
|
|
when nil, '', 'nil' then nil
|
|
else v.to_i
|
|
end
|
|
end
|
|
%i[unprivileged debug onboot protection template].each do |k|
|
|
next unless opts.has_key? k
|
|
opts[k] =
|
|
case v = opts[k]
|
|
when *%w[1 T TRUE t true True Y YES y yes Yes] then true
|
|
when *%w[0 F FALSE f false False N NO n no No] then false
|
|
when '', 'nil', nil then nil
|
|
else raise UsageError, "Boolean expected, given: #{v.inspect}"
|
|
end
|
|
end
|
|
connect
|
|
th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id)
|
|
old = th.config
|
|
opts[:digest] ||= old[:digest]
|
|
th.cnfset opts
|
|
show_config th.config, old
|
|
}
|
|
end
|
|
|
|
cli.cmd :enter, "Enter Console of CT/Node", &lambda {|name_or_id|
|
|
connect
|
|
th = Proxmox::LXC.find( name_or_id) || Proxmox::Node.find_by_name( name_or_id)
|
|
raise UsageError, "Container or Node not found: #{name_or_id}" unless th
|
|
STDERR.puts "! #{$?.exitstatus}" unless th.enter
|
|
}
|
|
|
|
cli.cmd :run, "Starts CT/VM", aliases: %w[start star], &lambda {|name_or_id|
|
|
connect
|
|
th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id)
|
|
raise UsageError, "Container or Node not found: #{name_or_id}" unless th
|
|
start th
|
|
}
|
|
|
|
#cli.cmd :reboot, "Reboot CT/VM (not implemented, yet)", min: 6, &lambda {|name_or_id|
|
|
# connect
|
|
# th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id)
|
|
# raise UsageError, "Container or Node not found: #{name_or_id}" unless th
|
|
# reboot th
|
|
#}
|
|
|
|
cli.cmd :stop, "Stops CT/VM", min: 4, &lambda {|name_or_id|
|
|
connect
|
|
th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id)
|
|
raise UsageError, "Container or Node not found: #{name_or_id}" unless th
|
|
stop th
|
|
}
|
|
|
|
cli.cmd 'help', '', aliases: ['-h', '--help'], &lambda {|*args| help cli, *args }
|
|
|
|
cli.cmd 'cli', 'Opens interactive console', min: 3, aliases: [nil], &lambda {
|
|
@interactive = true
|
|
cli.interactive( File.basename($0,'.rb')).run
|
|
}
|
|
end
|
|
end
|