use features of ruby-3.1 (lambda(&exe), **kwargs)

This commit is contained in:
Denis Knauf 2024-09-21 21:23:46 +02:00
parent 9786e145c1
commit 1c4bbbdb7d
8 changed files with 118 additions and 118 deletions

View file

@ -12,7 +12,7 @@ class PVE::Cli
using IPAddress::ToSWithNetmaskForNetworks using IPAddress::ToSWithNetmaskForNetworks
def cli_base def cli_base
cli.cmd :list, "List CT/VM-IDs", aliases: ['ls'], &lambda {|target=nil| cli.cmd :list, "List CT/VM-IDs", aliases: ['ls'] do |target=nil|
connect connect
nodes = Proxmox::Node.all nodes = Proxmox::Node.all
nodes. nodes.
@ -20,16 +20,16 @@ def cli_base
flat_pmap {|m| m.call.map {|c| c.vmid.to_i } }. flat_pmap {|m| m.call.map {|c| c.vmid.to_i } }.
sort. sort.
each {|c| puts c } each {|c| puts c }
} end
cli.cmd( :status, "Lists Nodes/VMs/CTs with status", &lambda {|target=nil, sort:, node: nil, status: nil, tags: nil| cli.cmd :status, "Lists Nodes/VMs/CTs with status" do |target=nil, sort:, node: nil, status: nil, tags: nil|
hosting_table target: target, status: status, sort: sort, tags: tags do |push| hosting_table target: target, status: status, sort: sort, tags: tags do |push|
node_opt( node). node_opt( node).
each( &push). each( &push).
flat_map {|n| [ n.method(:lxc), n.method(:qemu) ] }. flat_map {|n| [ n.method(:lxc), n.method(:qemu) ] }.
peach {|m| exc2warn( nil) { m.call.each &push } } peach {|m| exc2warn( nil) { m.call.each &push } }
end end
}). end.
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)", default: 'n'). 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)", default: 'n').
opt( :node, '-n', '--node=NODE', "List only hosted by this NODE"). opt( :node, '-n', '--node=NODE', "List only hosted by this NODE").
opt( :status, '-S', '--status=STATUS', "Filter for status (running, stopped, ...) (default: no filter)"). opt( :status, '-S', '--status=STATUS', "Filter for status (running, stopped, ...) (default: no filter)").
@ -89,9 +89,9 @@ def cli_base
end end
cli.sub :config, "CT/VM Configuration", min: 2, aliases: %w[cnf] do |ccli| 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 :help, '', aliases: [nil, '-h', '--help'] do |*args| help ccli, *args end
ccli.cmd :set, "Set Configs for CT/VM", min: 3, &lambda {|name_or_id, *args| ccli.cmd :set, "Set Configs for CT/VM", min: 3 do |name_or_id, *args|
if %w[-h --help].include? name_or_id if %w[-h --help].include? name_or_id
STDERR.puts "Usage: set -h|--help # Show help" STDERR.puts "Usage: set -h|--help # Show help"
STDERR.puts " set ct|vm --CNF1=VAL1 --CNF2=VAL2 ... # Set config-value. Empty value clears field." STDERR.puts " set ct|vm --CNF1=VAL1 --CNF2=VAL2 ... # Set config-value. Empty value clears field."
@ -157,29 +157,29 @@ def cli_base
opts[:digest] ||= old[:digest] opts[:digest] ||= old[:digest]
th.cnfset opts th.cnfset opts
show_config th.config, old show_config th.config, old
} end
ccli.cmd :show, "Show Config of CT/VM", &lambda {|name_or_id| ccli.cmd :show, "Show Config of CT/VM" do |name_or_id|
connect connect
th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id) 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 raise UsageError, "Container or Node not found: #{name_or_id}" unless th
show_config th.config show_config th.config
} end
end end
cli.cmd( :enter, "Enter Console of CT/Node", &lambda {|name_or_id| cli.cmd :enter, "Enter Console of CT/Node" do |name_or_id|
connect connect
th = Proxmox::LXC.find( name_or_id) || Proxmox::Node.find_by_name( name_or_id) 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 raise UsageError, "Container or Node not found: #{name_or_id}" unless th
STDERR.puts "! #{$?.exitstatus}" unless th.enter STDERR.puts "! #{$?.exitstatus}" unless th.enter
}). end.
completion do |*pre, arg| completion do |*pre, arg|
completion_helper *pre, arg do |f| completion_helper *pre, arg do |f|
complete_lxc( f) + complete_node( f) complete_lxc( f) + complete_node( f)
end end
end end
cli.cmd( :run, "Starts CT/VM", aliases: %w[start star], &lambda {|*names_or_ids| cli.cmd :run, "Starts CT/VM", aliases: %w[start star] do |*names_or_ids|
connect connect
raise UsageError, "Nothing to start?" if names_or_ids.empty? raise UsageError, "Nothing to start?" if names_or_ids.empty?
per_argument names_or_ids, print: "\e[34;1mRunning CT/VM\e[0m %s:\n" do |name_or_id| per_argument names_or_ids, print: "\e[34;1mRunning CT/VM\e[0m %s:\n" do |name_or_id|
@ -187,14 +187,14 @@ def cli_base
raise UsageError, "Container or Node not found: #{name_or_id}" unless th raise UsageError, "Container or Node not found: #{name_or_id}" unless th
start th start th
end end
}). end.
completion do |*pre, arg| completion do |*pre, arg|
completion_helper *pre, arg do |f| completion_helper *pre, arg do |f|
complete_lxc( f) + complete_qemu( f) complete_lxc( f) + complete_qemu( f)
end end
end end
cli.cmd( :migrate, "Migrates (halted) CTs/VMs to an other host", min: 2, &lambda {|target, *names_or_ids, fire:, timeout:, secs:| cli.cmd :migrate, "Migrates (halted) CTs/VMs to an other host", min: 2 do |target, *names_or_ids, fire:, timeout:, secs:|
connect connect
node = Proxmox::Node.find_by_name! target node = Proxmox::Node.find_by_name! target
per_argument names_or_ids, print: "\e[1;34mCT/VM(s)\e[0m %s:\n" do |name_or_id| per_argument names_or_ids, print: "\e[1;34mCT/VM(s)\e[0m %s:\n" do |name_or_id|
@ -207,41 +207,41 @@ def cli_base
task = th.migrate node task = th.migrate node
wait task, text: "Migrating", timeout: timeout unless fire wait task, text: "Migrating", timeout: timeout unless fire
end end
}).tap {|c| opts_wait c } end.tap {|c| opts_wait c }
#cli.cmd :reboot, "Reboot CT/VM (not implemented, yet)", min: 6, &lambda {|name_or_id| #cli.cmd :reboot, "Reboot CT/VM (not implemented, yet)", min: 6 do |name_or_id|
# connect # connect
# th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id) # 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 # raise UsageError, "Container or Node not found: #{name_or_id}" unless th
# reboot th # reboot th
#} #end
cli.cmd( :stop, "Stops CT/VM", min: 4, &lambda {|*names_or_ids| cli.cmd :stop, "Stops CT/VM", min: 4 do |*names_or_ids|
connect connect
per_argument names_or_ids, print: "\e[34;1mStopping CT/VM\e[0m %s:\n" do |name_or_id| per_argument names_or_ids, print: "\e[34;1mStopping CT/VM\e[0m %s:\n" do |name_or_id|
th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id) 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 raise UsageError, "Container or Node not found: #{name_or_id}" unless th
stop th stop th
end end
}). end.
completion do |*pre, arg| completion do |*pre, arg|
completion_helper *pre, arg do |f| completion_helper *pre, arg do |f|
complete_lxc( f) + complete_qemu( f) complete_lxc( f) + complete_qemu( f)
end end
end end
cli.cmd( :help, '', aliases: ['-h', '--help'], &lambda {|*args, full:| cli.cmd :help, '', aliases: ['-h', '--help'] do |*args, full:|
if full if full
cli.help_full *args, output: STDERR cli.help_full *args, output: STDERR
else else
cli.help *args, output: STDERR cli.help *args, output: STDERR
end end
}). end.
opt( :full, '-f', '--[no-]full', 'Includes all commands of all subcommands.', default: false) opt( :full, '-f', '--[no-]full', 'Includes all commands of all subcommands.', default: false)
cli.cmd :cli, 'Opens interactive console', min: 3, aliases: [nil], &lambda { cli.cmd :cli, 'Opens interactive console', min: 3, aliases: [nil] do
@interactive = true @interactive = true
cli.interactive( File.basename( $0, '.rb')).run cli.interactive( File.basename( $0, '.rb')).run
} end
end end
end end

View file

@ -1,37 +1,37 @@
class PVE::Cli class PVE::Cli
def cli_ct def cli_ct
cli.sub :ct, "Containers", aliases: %w[lx lxc] do |ct_cli| cli.sub :ct, "Containers", aliases: %w[lx lxc] do |ct_cli|
ct_cli.cmd :list, "List CT-IDs", aliases: ['ls'], &lambda {|node=nil| ct_cli.cmd :list, "List CT-IDs", aliases: ['ls'] do |node=nil|
connect connect
nodes = node ? Proxmox::Node.find_by_name( name) : Proxmox::Node.all nodes = node ? Proxmox::Node.find_by_name( name) : Proxmox::Node.all
nodes.flat_pmap do |n| nodes.flat_pmap do |n|
exc2warn( []) { n.lxc.map {|c| c.vmid.to_i } } exc2warn( []) { n.lxc.map {|c| c.vmid.to_i } }
end.sort.each {|c| puts c } end.sort.each {|c| puts c }
} end
ct_cli.cmd( :status, "Lists CTs with status", aliases: [nil], &lambda {|target=nil, sort: nil, node: nil, status: nil, tags: nil| ct_cli.cmd :status, "Lists CTs with status", aliases: [nil] do |target=nil, sort: nil, node: nil, status: nil, tags: nil|
hosting_table target: target, status: status, sort: sort, tags: tags do |push| hosting_table target: target, status: status, sort: sort, tags: tags do |push|
node_opt( node).peach {|n| exc2warn( nil) { n.lxc.each &push } } node_opt( node).peach {|n| exc2warn( nil) { n.lxc.each &push } }
end end
}). end.
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)", default: 'n'). 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)", default: 'n').
opt( :node, '-n', '--node=NODE', "List only hosted by this NODE"). opt( :node, '-n', '--node=NODE', "List only hosted by this NODE").
opt( :status, '-S', '--status=STATUS', "Filter for status (running, stopped, ...) (default: no filter)"). opt( :status, '-S', '--status=STATUS', "Filter for status (running, stopped, ...) (default: no filter)").
opt( :tags, '-t', '--tags=TAGS', "Filter by comma-seperated tags. All tags must be present for CT") opt( :tags, '-t', '--tags=TAGS', "Filter by comma-seperated tags. All tags must be present for CT")
ct_cli.cmd :enter, "Enter Console of CT", &lambda {|name_or_id| ct_cli.cmd :enter, "Enter Console of CT" do |name_or_id|
connect connect
@out.host = name_or_id @out.host = name_or_id
@out.failed "Exitstatus #{$?.exitstatus}" unless Proxmox::LXC.find!( name_or_id).enter @out.failed "Exitstatus #{$?.exitstatus}" unless Proxmox::LXC.find!( name_or_id).enter
} end
ct_cli.cmd :exec, "Executes Command in CT", min: 4, &lambda {|name_or_id, *command| ct_cli.cmd :exec, "Executes Command in CT", min: 4 do |name_or_id, *command|
connect connect
@out.host = name_or_id @out.host = name_or_id
@out.failed "Exitstatus #{$?.exitstatus}" unless Proxmox::LXC.find!( name_or_id).exec *command @out.failed "Exitstatus #{$?.exitstatus}" unless Proxmox::LXC.find!( name_or_id).exec *command
} end
ct_cli.cmd( :migrate, "Migrates halted CT(s) to an other host", min: 2, &lambda {|target, *names_or_ids, fire:, timeout:, secs:| ct_cli.cmd :migrate, "Migrates halted CT(s) to an other host", min: 2 do |target, *names_or_ids, fire:, timeout:, secs:|
connect connect
node = Proxmox::Node.find_by_name! target node = Proxmox::Node.find_by_name! target
per_argument names_or_ids, print: "Migrate CT:" do |name_or_id| per_argument names_or_ids, print: "Migrate CT:" do |name_or_id|
@ -39,39 +39,39 @@ def cli_ct
task = ct.migrate node task = ct.migrate node
wait task, text: "Migrating", timeout: timeout unless fire wait task, text: "Migrating", timeout: timeout unless fire
end end
}).tap {|c| opts_wait c } end.tap {|c| opts_wait c }
ct_cli.cmd( :volume_move, "Moves volume to an other storage/pool and marks old volume as unused.", min: 11, aliases: %i[volmv mv], &lambda {|name_or_id, volume, destination| ct_cli.cmd :volume_move, "Moves volume to an other storage/pool and marks old volume as unused.", min: 11, aliases: %i[volmv mv] do |name_or_id, volume, destination|
connect connect
ct = Proxmox::LXC.find! name_or_id ct = Proxmox::LXC.find! name_or_id
ct_volume_move ct, volume, destination ct_volume_move ct, volume, destination
}) end
ct_cli.cmd( :start, "Starts CT(s)", min: 4, &lambda {|*names_or_ids, node: nil, fire:, timeout:, secs:| ct_cli.cmd :start, "Starts CT(s)", min: 4 do |*names_or_ids, node: nil, fire:, timeout:, secs:|
connect connect
per_argument names_or_ids, print: "Start CT:" do |name_or_id| per_argument names_or_ids, print: "Start CT:" do |name_or_id|
ct = Proxmox::LXC.find! name_or_id ct = Proxmox::LXC.find! name_or_id
start ct, node: node, fire: fire, timeout: timeout, secs: secs start ct, node: node, fire: fire, timeout: timeout, secs: secs
end end
}).tap {|c| opts_wait c } end.tap {|c| opts_wait c }
ct_cli.cmd( :stop, "Stops CT(s)", min: 3, &lambda {|*names_or_ids, fire: nil, timeout:, secs:| ct_cli.cmd :stop, "Stops CT(s)", min: 3 do |*names_or_ids, fire: nil, timeout:, secs:|
connect connect
per_argument names_or_ids, print: "Start CT:" do |name_or_id| per_argument names_or_ids, print: "Start CT:" do |name_or_id|
ct = Proxmox::LXC.find! name_or_id ct = Proxmox::LXC.find! name_or_id
stop ct, fire: fire, timeout: timeout, secs: secs stop ct, fire: fire, timeout: timeout, secs: secs
end end
}).tap {|c| opts_wait c } end.tap {|c| opts_wait c }
ct_cli.cmd( :wait, "Wait till CT is in state", &lambda {|name_or_id, state, timeout: nil, secs: nil| ct_cli.cmd :wait, "Wait till CT is in state" do |name_or_id, state, timeout: nil, secs: nil|
connect connect
ct = Proxmox::LXC.find! name_or_id ct = Proxmox::LXC.find! name_or_id
wait ct, state, timeout: timeout, secs: secs wait ct, state, timeout: timeout, secs: secs
}). end.
opt( :timeout, "-tTIMEOUT", "--timeout=TIMEOUT", "Wait for max TIMEOUT seconds (default: endless)", default: nil). opt( :timeout, "-tTIMEOUT", "--timeout=TIMEOUT", "Wait for max TIMEOUT seconds (default: endless)", default: nil).
opt( :secs, "-sSECONDS", "--seconds=SECONDS", "Check every SECONDS for state (default: 0.2)", default: 0.2) opt( :secs, "-sSECONDS", "--seconds=SECONDS", "Check every SECONDS for state (default: 0.2)", default: 0.2)
ct_cli.cmd( :create, "Creates a new container", min: 2, &lambda {|template, *options| #, fire:, timeout:, secs:, start:| ct_cli.cmd :create, "Creates a new container", min: 2 do |template, *options| #, fire:, timeout:, secs:, start:|
if %w[-h --help].include? template if %w[-h --help].include? template
STDERR.puts "Usage: ct create TEMPLATE -h # Shows template-related options" STDERR.puts "Usage: ct create TEMPLATE -h # Shows template-related options"
STDERR.puts " ct create TEMPLATE [OPTIONS] # Creates a container" STDERR.puts " ct create TEMPLATE [OPTIONS] # Creates a container"
@ -115,28 +115,28 @@ EOU
end.parse! options end.parse! options
connect connect
create Proxmox::LXC, template, **ctopts create Proxmox::LXC, template, **ctopts
}) end
ct_cli.cmd( :config, 'Shows current config', aliases: %w[cnf], min: 2, &lambda {|name_or_id| ct_cli.cmd :config, 'Shows current config', aliases: %w[cnf], min: 2 do |name_or_id|
connect connect
ct = Proxmox::LXC.find! name_or_id ct = Proxmox::LXC.find! name_or_id
STDOUT.puts JSON.dump( ct.config) STDOUT.puts JSON.dump( ct.config)
}) end
ct_cli.cmd( :resize, 'Resize a disk', &lambda {|name_or_id, disk, size| ct_cli.cmd :resize, 'Resize a disk' do |name_or_id, disk, size|
connect connect
ct = Proxmox::LXC.find! name_or_id ct = Proxmox::LXC.find! name_or_id
task = ct.resize disk, size task = ct.resize disk, size
wait task, text: "Resizing #{ct.sid} #{disk} to #{size}" wait task, text: "Resizing #{ct.sid} #{disk} to #{size}"
}) end
ct_cli.cmd( :destroy, '', min: 7, &lambda {|name_or_id, fire:, secs:, timeout:, i_really_want_to_destroy:| ct_cli.cmd :destroy, '', min: 7 do |name_or_id, fire:, secs:, timeout:, i_really_want_to_destroy:|
raise UsageError, "Name/ID is not what you want to destroy" unless name_or_id == i_really_want_to_destroy raise UsageError, "Name/ID is not what you want to destroy" unless name_or_id == i_really_want_to_destroy
connect connect
ct = Proxmox::LXC.find! name_or_id ct = Proxmox::LXC.find! name_or_id
raise UsageError, "Container is not stopped" unless ct.stopped? raise UsageError, "Container is not stopped" unless ct.stopped?
destroy ct, fire: fire, timeout: timeout, secs: secs destroy ct, fire: fire, timeout: timeout, secs: secs
}).tap {|c| opts_wait c }. end.tap {|c| opts_wait c }.
opt( :i_really_want_to_destroy, "--i-really-want-to-destroy=NAMEORID", "Repeat the name/ID") opt( :i_really_want_to_destroy, "--i-really-want-to-destroy=NAMEORID", "Repeat the name/ID")
ct_cli.cmd( :help, '', aliases: ['-h', '--help']) {|*args| help ct_cli, *args } ct_cli.cmd( :help, '', aliases: ['-h', '--help']) {|*args| help ct_cli, *args }

View file

@ -10,41 +10,41 @@ end
def cli_ha def cli_ha
cli.sub :ha, "Inspect High-Availability", min: 2 do |hacli| cli.sub :ha, "Inspect High-Availability", min: 2 do |hacli|
hacli.cmd( :create, "Create HA for CT/VM", &lambda {|name_or_id, group:, comment: nil, max_relocate:, max_restart:, state:| hacli.cmd :create, "Create HA for CT/VM" do |name_or_id, group:, comment: nil, max_relocate:, max_restart:, state:|
connect connect
th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id) th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id)
raise UsageError, "Container or VirtualMachine not found: #{name_or_id}" unless th raise UsageError, "Container or VirtualMachine not found: #{name_or_id}" unless th
ha = th.ha ha = th.ha
raise UsageError, "#{th.sid} is already High-Available" if ha.active? raise UsageError, "#{th.sid} is already High-Available" if ha.active?
ha.create group: group, comment: comment, max_relocate: max_relocate, max_restart: max_restart ha.create group: group, comment: comment, max_relocate: max_relocate, max_restart: max_restart
}).tap {|cl| opts_ha cl } end.tap {|cl| opts_ha cl }
hacli.cmd :remove, "Remove CT/VM from HA", min: 5, &lambda {|name_or_id| hacli.cmd :remove, "Remove CT/VM from HA", min: 5 do |name_or_id|
connect connect
th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id) th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id)
raise UsageError, "Container or VirtualMachine not found: #{name_or_id}" unless th raise UsageError, "Container or VirtualMachine not found: #{name_or_id}" unless th
ha = th.ha ha = th.ha
raise UsageError, "#{th.sid} is not High-Available" unless ha.active? raise UsageError, "#{th.sid} is not High-Available" unless ha.active?
ha.delete ha.delete
} end
hacli.cmd( :active, "CT/VM should be high-available. Options are only for defaults, if not activated, yet.", &lambda {|name_or_id, group:, comment: nil, max_relocate:, max_restart:, state:| hacli.cmd :active, "CT/VM should be high-available. Options are only for defaults, if not activated, yet." do |name_or_id, group:, comment: nil, max_relocate:, max_restart:, state:|
connect connect
th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id) th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id)
raise UsageError, "Container or VirtualMachine not found: #{name_or_id}" unless th raise UsageError, "Container or VirtualMachine not found: #{name_or_id}" unless th
ha = th.ha ha = th.ha
ha.create group: group, comment: comment, max_relocate: max_relocate, max_restart: max_restart if ha.active? ha.create group: group, comment: comment, max_relocate: max_relocate, max_restart: max_restart if ha.active?
}).tap {|cl| opts_ha cl } end.tap {|cl| opts_ha cl }
hacli.cmd :deactive, "CT/VM should NOT be high-available.", &lambda {|name_or_id| hacli.cmd :deactive, "CT/VM should NOT be high-available." do |name_or_id|
connect connect
th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id) th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id)
raise UsageError, "Container or VirtualMachine not found: #{name_or_id}" unless th raise UsageError, "Container or VirtualMachine not found: #{name_or_id}" unless th
ha = th.ha ha = th.ha
ha.delete unless ha.active? ha.delete unless ha.active?
} end
hacli.cmd( :started, "CT/VM should be in state started. By stopping CT/VM via pct/e state will be changed in HA, too.", &lambda {|name_or_id, force: nil| hacli.cmd :started, "CT/VM should be in state started. By stopping CT/VM via pct/e state will be changed in HA, too." do |name_or_id, force: nil|
connect connect
th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id) th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id)
raise UsageError, "Container or VirtualMachine not found: #{name_or_id}" unless th raise UsageError, "Container or VirtualMachine not found: #{name_or_id}" unless th
@ -52,27 +52,27 @@ def cli_ha
ha = ha.create unless ha.active? ha = ha.create unless ha.active?
ha.disabled! if force and ha.error? ha.disabled! if force and ha.error?
ha.started! ha.started!
}).opt( :force, "-f", "--force", "If CT/VM is in error-state, first reset HA, than try to start.") end.opt( :force, "-f", "--force", "If CT/VM is in error-state, first reset HA, than try to start.")
hacli.cmd :stopped, "CT/VM should be in state stopped. By starting CT/VM via pct/e state will be changed in HA, too.", min: 3, &lambda {|name_or_id| hacli.cmd :stopped, "CT/VM should be in state stopped. By starting CT/VM via pct/e state will be changed in HA, too.", min: 3 do |name_or_id|
connect connect
th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id) th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id)
raise UsageError, "Container or VirtualMachine not found: #{name_or_id}" unless th raise UsageError, "Container or VirtualMachine not found: #{name_or_id}" unless th
ha = th.ha ha = th.ha
ha = ha.create unless ha.active? ha = ha.create unless ha.active?
ha.stopped! ha.stopped!
} end
hacli.cmd :reset, "If state of CT/VM is failed, Proxmox will not start/stop it anyway. You have to reset state (state=disabled), first", min: 3, aliases: [:rst], &lambda {|name_or_id| hacli.cmd :reset, "If state of CT/VM is failed, Proxmox will not start/stop it anyway. You have to reset state (state=disabled), first", min: 3, aliases: [:rst] do |name_or_id|
connect connect
th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id) th = Proxmox::LXC.find( name_or_id) || Proxmox::Qemu.find_by_name( name_or_id)
raise UsageError, "Container or VirtualMachine not found: #{name_or_id}" unless th raise UsageError, "Container or VirtualMachine not found: #{name_or_id}" unless th
ha = th.ha ha = th.ha
raise UsageError, "#{th.sid} is not High-Available" if ha.active? raise UsageError, "#{th.sid} is not High-Available" if ha.active?
ha.state = :disabled ha.state = :disabled
} end
hacli.cmd 'help', '', aliases: ['-h', '--help'], &lambda {|*args| help hacli, *args } hacli.cmd 'help', '', aliases: ['-h', '--help'] do |*args| help hacli, *args end
end end
end end
end end

View file

@ -1,7 +1,7 @@
class PVE::Cli class PVE::Cli
def cli_node def cli_node
cli.sub :node, "Nodes" do |nod_cli| cli.sub :node, "Nodes" do |nod_cli|
nod_cli.cmd :status, "Lists nodes with status", aliases: [nil], &lambda {|node=nil| nod_cli.cmd :status, "Lists nodes with status", aliases: [nil] do |node=nil|
connect connect
to = TablizedOutput.new %w[Status Node Uptime CPU Mem/MiB Disk/MiB] to = TablizedOutput.new %w[Status Node Uptime CPU Mem/MiB Disk/MiB]
nodes = Proxmox::Node.all nodes = Proxmox::Node.all
@ -17,7 +17,7 @@ def cli_node
] ]
end end
to.print order: [1] to.print order: [1]
} end
nod_cli.cmd :exec, "Executes command on node", min: 4 do |name, *args| nod_cli.cmd :exec, "Executes command on node", min: 4 do |name, *args|
connect connect
@ -30,14 +30,14 @@ def cli_node
end end
nod_cli.sub :task, "Inspect tasks" do |tcli| nod_cli.sub :task, "Inspect tasks" do |tcli|
tcli.cmd :list, "List done tasks", aliases: [:ls], &lambda {|node| tcli.cmd :list, "List done tasks", aliases: [:ls] do |node|
connect connect
Proxmox::Node.find_by_name!( node). Proxmox::Node.find_by_name!( node).
tasks. tasks.
map( &:upid). map( &:upid).
sort. sort.
each {|upid| puts upid } each {|upid| puts upid }
} end
end end
nod_cli.cmd( 'help', '', aliases: ['-h', '--help']) {|*args| help nod_cli, *args } nod_cli.cmd( 'help', '', aliases: ['-h', '--help']) {|*args| help nod_cli, *args }

View file

@ -1,16 +1,16 @@
class PVE::Cli class PVE::Cli
def cli_qm def cli_qm
cli.sub :qm, "Virtual Machines", aliases: %w[v vm qemu], &lambda {|qm_cli| cli.sub :qm, "Virtual Machines", aliases: %w[v vm qemu] do |qm_cli|
qm_cli.cmd :list, "List VM-IDs", aliases: ['ls'], &lambda {|node=nil| qm_cli.cmd :list, "List VM-IDs", aliases: ['ls'] do |node=nil|
connect connect
nodes = Proxmox::Node.all nodes = Proxmox::Node.all
nodes = nodes.select {|n| node == n.name } if node nodes = nodes.select {|n| node == n.name } if node
nodes.flat_pmap do |n| nodes.flat_pmap do |n|
exc2warn( []) { n.qemu.map {|c| c.vmid.to_i } } exc2warn( []) { n.qemu.map {|c| c.vmid.to_i } }
end.sort.each {|c| puts c } end.sort.each {|c| puts c }
} end
qm_cli.cmd( :migrate, "Migrates VM(s) to an other host", min: 2, &lambda {|target, *names_or_ids, fire:, timeout:, secs:|#, online:, restart:| qm_cli.cmd :migrate, "Migrates VM(s) to an other host", min: 2 do |target, *names_or_ids, fire:, timeout:, secs:|#, online:, restart:|
#if online and restart #if online and restart
# raise UsageError, "You have to decide for one migration-mode: --restart or --online." # raise UsageError, "You have to decide for one migration-mode: --restart or --online."
#end #end
@ -22,58 +22,58 @@ def cli_qm
task = qm.migrate node #, online: online task = qm.migrate node #, online: online
wait task, text: "Migrating", timeout: timeout unless fire wait task, text: "Migrating", timeout: timeout unless fire
end end
}). end.
#opt( :online, '-o', '--online', "Online-migration: Does not shutdown or interrupt running VM. Opposite of --online, Default", default: nil). #opt( :online, '-o', '--online', "Online-migration: Does not shutdown or interrupt running VM. Opposite of --online, Default", default: nil).
#opt( :restart, '-r', '--restart', "Restart-migration: Does shutdown or interrupt running VM. Opposite of --restart", default: nil). #opt( :restart, '-r', '--restart', "Restart-migration: Does shutdown or interrupt running VM. Opposite of --restart", default: nil).
tap {|c| opts_wait c } tap {|c| opts_wait c }
qm_cli.cmd( :start, "Starts VM(s)", min: 4, &lambda {|*names_or_ids, node: nil, fire:, timeout:, secs:| qm_cli.cmd :start, "Starts VM(s)", min: 4 do |*names_or_ids, node: nil, fire:, timeout:, secs:|
connect connect
per_argument names_or_ids, print: "\e[1;34mStart VM %s:\e[0m" do |name_or_id| per_argument names_or_ids, print: "\e[1;34mStart VM %s:\e[0m" do |name_or_id|
qm = Proxmox::Qemu.find! name_or_id qm = Proxmox::Qemu.find! name_or_id
start qm, node: node, fire: fire, timeout: timeout, secs: secs start qm, node: node, fire: fire, timeout: timeout, secs: secs
end end
}).tap {|c| opts_wait c } end.tap {|c| opts_wait c }
qm_cli.cmd( :stop, "Stops VM(s)", min: 3, &lambda {|*names_or_ids, fire: nil, timeout:, secs:| qm_cli.cmd :stop, "Stops VM(s)", min: 3 do |*names_or_ids, fire: nil, timeout:, secs:|
connect connect
per_argument names_or_ids, print: "\e[1;34mStart VM %s:\e[0m" do |name_or_id| per_argument names_or_ids, print: "\e[1;34mStart VM %s:\e[0m" do |name_or_id|
qm = Proxmox::Qemu.find! name_or_id qm = Proxmox::Qemu.find! name_or_id
stop qm, fire: fire, timeout: timeout, secs: secs stop qm, fire: fire, timeout: timeout, secs: secs
end end
}).tap {|c| opts_wait c } end.tap {|c| opts_wait c }
qm_cli.cmd( :wait, "Wait till VM is in state", &lambda {|name_or_id, state, timeout: nil, secs: nil| qm_cli.cmd :wait, "Wait till VM is in state" do |name_or_id, state, timeout: nil, secs: nil|
connect connect
qm = Proxmox::Qemu.find! name_or_id qm = Proxmox::Qemu.find! name_or_id
wait qm, state, timeout: timeout, secs: secs wait qm, state, timeout: timeout, secs: secs
}). end.
opt( :timeout, "-tTIMEOUT", "--timeout=TIMEOUT", "Wait for max TIMEOUT seconds (default: endless)", default: nil). opt( :timeout, "-tTIMEOUT", "--timeout=TIMEOUT", "Wait for max TIMEOUT seconds (default: endless)", default: nil).
opt( :secs, "-sSECONDS", "--seconds=SECONDS", "Check every SECONDS for state (default: 0.2)", default: 0.2) opt( :secs, "-sSECONDS", "--seconds=SECONDS", "Check every SECONDS for state (default: 0.2)", default: 0.2)
qm_cli.cmd( :status, "Lists VMs with status", aliases: [nil], &lambda {|target=nil, sort: nil, node: nil, status: nil, tags: nil| qm_cli.cmd :status, "Lists VMs with status", aliases: [nil] do |target=nil, sort: nil, node: nil, status: nil, tags: nil|
hosting_table target: target, status: status, sort: sort, tags: tags do |push| hosting_table target: target, status: status, sort: sort, tags: tags do |push|
node_opt( node).flat_pmap( &:qemu).peach &push node_opt( node).peach {|n| n.qemu.each &push }
end end
}). end.
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)", default: 'n'). 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)", default: 'n').
opt( :node, '-n', '--node=NODE', "List only hosted by this NODE"). opt( :node, '-n', '--node=NODE', "List only hosted by this NODE").
opt( :status, '-S', '--status=STATUS', "Filter for status (running, stopped, ...) (default: no filter)"). opt( :status, '-S', '--status=STATUS', "Filter for status (running, stopped, ...) (default: no filter)").
opt( :tags, '-t', '--tags=TAGS', "Filter by comma-seperated tags. All tags must be present for CT") opt( :tags, '-t', '--tags=TAGS', "Filter by comma-seperated tags. All tags must be present for CT")
qm_cli.cmd :exec, "Executes Command in VM via qemu-guest-agent", min: 4, &lambda {|name_or_id, *command| qm_cli.cmd :exec, "Executes Command in VM via qemu-guest-agent", min: 4 do |name_or_id, *command|
connect connect
STDERR.puts "! #{$?.exitstatus}" unless Proxmox::Qemu.find!( name_or_id).exec *command STDERR.puts "! #{$?.exitstatus}" unless Proxmox::Qemu.find!( name_or_id).exec *command
} end
qm_cli.cmd( :resize, 'Resize a disk', &lambda {|name_or_id, disk, size| qm_cli.cmd :resize, 'Resize a disk' do |name_or_id, disk, size|
connect connect
qm = Proxmox::Qemu.find! name_or_id qm = Proxmox::Qemu.find! name_or_id
task = qm.resize disk, size task = qm.resize disk, size
wait task, text: "Resizing #{qm.sid} #{disk} to #{size}" wait task, text: "Resizing #{qm.sid} #{disk} to #{size}"
}) end
qm_cli.cmd 'help', '', aliases: ['-h', '--help'], &lambda {|*args| help qm_cli, *args } qm_cli.cmd 'help', '', aliases: ['-h', '--help'] do |*args| help qm_cli, *args end
} end
end end
end end

View file

@ -1,19 +1,19 @@
class PVE::Cli class PVE::Cli
def cli_storage def cli_storage
cli.sub :storage, "Storages", min: 3 do |cli_sm| cli.sub :storage, "Storages", min: 3 do |cli_sm|
cli_sm.cmd :list, "List Storages", aliases: ['ls'], &lambda {|node=nil| cli_sm.cmd :list, "List Storages", aliases: ['ls'] do |node=nil|
connect connect
nodes = node ? [Proxmox::Node.find_by_name!( node)] : Proxmox::Node.all nodes = node ? [Proxmox::Node.find_by_name!( node)] : Proxmox::Node.all
nodes.flat_map do |n| nodes.flat_pmap do |n|
n.lxc.map {|c| c.vmid.to_i } n.lxc.map {|c| c.vmid.to_i }
end.sort.each {|c| puts c } end.sort.each {|c| puts c }
} end
cli_sm.cmd :status, "List Storages with status", aliases: [nil], &lambda {|node=nil| cli_sm.cmd :status, "List Storages with status", aliases: [nil] do |node=nil|
connect connect
to = TablizedOutput.new %w[A E S Storage Host Type] to = TablizedOutput.new %w[A E S Storage Host Type]
nodes = node ? [Proxmox::Node.find_by_name!( node)] : Proxmox::Node.all nodes = node ? [Proxmox::Node.find_by_name!( node)] : Proxmox::Node.all
nodes.each do |n| nodes.peach do |n|
n.storage.each do |v| n.storage.each do |v|
to.push [ to.push [
case v.active case v.active
@ -31,15 +31,15 @@ def cli_storage
end end
end end
to.print order: [4,5] to.print order: [4,5]
} end
cli_sm.sub :content, "Content of Storage", aliases: ['cnt'] do |cli_cnt| cli_sm.sub :content, "Content of Storage", aliases: ['cnt'] do |cli_cnt|
cli_cnt.cmd :list, "List Content", aliases: ['ls'], &lambda {|node=nil, storage| cli_cnt.cmd :list, "List Content", aliases: ['ls'] do |node=nil, storage|
connect connect
node = node ? Proxmox::Node.find_by_name!( node) : Proxmox::Node.all.first node = node ? Proxmox::Node.find_by_name!( node) : Proxmox::Node.all.first
storage = node.storage.select {|sm| storage == sm.storage }.first storage = node.storage.select {|sm| storage == sm.storage }.first
storage.content.each {|c| puts c.to_s } storage.content.each {|c| puts c.to_s }
} end
cli_cnt.cmd( :help, '', aliases: ['-h', '--help', nil]) {|*args| help cli_cnt, *args } cli_cnt.cmd( :help, '', aliases: ['-h', '--help', nil]) {|*args| help cli_cnt, *args }
end end
@ -49,39 +49,39 @@ def cli_storage
cli.sub :apl, "Appliances - Downloadable container images", min: 3 do |cli_apl| cli.sub :apl, "Appliances - Downloadable container images", min: 3 do |cli_apl|
cli_apl.cmd( :content, "Table of all provided appliances", aliases: [nil], &lambda {|node:, regexp:, system:, applications:| cli_apl.cmd :content, "Table of all provided appliances", aliases: [nil] do |node:, regexp:, system:, applications:|
connect connect
appliances node, regexp, system, applications appliances node, regexp, system, applications
}). end.
opt( :node, '-n=NODE', '--node', 'Ask this node for appliances (any node should list the same)', default: nil). opt( :node, '-n=NODE', '--node', 'Ask this node for appliances (any node should list the same)', default: nil).
opt( :regexp, '-r=REGEXP', '--regexp', 'Filter by template', default: nil). opt( :regexp, '-r=REGEXP', '--regexp', 'Filter by template', default: nil).
opt( :system, '-s', '--system', 'Only system templates', default: nil). opt( :system, '-s', '--system', 'Only system templates', default: nil).
opt( :applications, '-a', '--applications', 'Only applications (non system) templates', default: nil) opt( :applications, '-a', '--applications', 'Only applications (non system) templates', default: nil)
cli_apl.cmd( :system, "Table of provided systems", &lambda {|node:, regexp:| cli_apl.cmd :system, "Table of provided systems" do |node:, regexp:|
connect connect
appliances node, regexp, true, nil appliances node, regexp, true, nil
}). end.
opt( :node, '-n=NODE', '--node', 'Ask this node for appliances (any node should list the same)', default: nil). opt( :node, '-n=NODE', '--node', 'Ask this node for appliances (any node should list the same)', default: nil).
opt( :regexp, '-r=REGEXP', '--regexp', 'Filter by template', default: nil) opt( :regexp, '-r=REGEXP', '--regexp', 'Filter by template', default: nil)
cli_apl.cmd( :applications, "Table of provided applications", &lambda {|node:, regexp:| cli_apl.cmd :applications, "Table of provided applications" do |node:, regexp:|
connect connect
appliances node, regexp, nil, true appliances node, regexp, nil, true
}). end.
opt( :node, '-n=NODE', '--node', 'Ask this node for appliances (any node should list the same)', default: nil). opt( :node, '-n=NODE', '--node', 'Ask this node for appliances (any node should list the same)', default: nil).
opt( :regexp, '-r=REGEXP', '--regexp', 'Filter by template', default: nil) opt( :regexp, '-r=REGEXP', '--regexp', 'Filter by template', default: nil)
cli_apl.cmd( :list, "List provided appliances", aliases: ['ls'], &lambda {|node=nil, regexp:| cli_apl.cmd :list, "List provided appliances", aliases: ['ls'] do |node=nil, regexp:|
connect connect
node = node ? Proxmox::Node.find_by_name!( node) : Proxmox::Node.all.first node = node ? Proxmox::Node.find_by_name!( node) : Proxmox::Node.all.first
node.aplinfo.each do |apl| node.aplinfo.each do |apl|
puts apl.template puts apl.template
end end
}). end.
opt( :regexp, '-r=REGEXP', '--regexp', 'Filters by name', default: nil) opt( :regexp, '-r=REGEXP', '--regexp', 'Filters by name', default: nil)
cli_apl.cmd :download, "Download appliance", aliases: ['dl'], min: 2, &lambda {|template, node, storage=nil| cli_apl.cmd :download, "Download appliance", aliases: ['dl'], min: 2 do |template, node, storage=nil|
storage ||= 'local' storage ||= 'local'
connect connect
node = Proxmox::Node.find_by_name! node node = Proxmox::Node.find_by_name! node
@ -89,7 +89,7 @@ def cli_storage
raise UsageError, "Appliance not found" unless apl raise UsageError, "Appliance not found" unless apl
task = apl.download storage task = apl.download storage
wait task, text: "Download #{apl.template} on #{node.node} to #{storage}" wait task, text: "Download #{apl.template} on #{node.node} to #{storage}"
} end
cli_apl.cmd( :help, '', aliases: ['-h', '--help']) {|*args| help cli_apl, *args } cli_apl.cmd( :help, '', aliases: ['-h', '--help']) {|*args| help cli_apl, *args }
end end

View file

@ -4,7 +4,7 @@ class PVE::Cli
hosted = {} hosted = {}
Proxmox::Hosted.all.each {|h| hosted[h.vmid.to_i] = h } Proxmox::Hosted.all.each {|h| hosted[h.vmid.to_i] = h }
hosted.delete nil hosted.delete nil
exe.call lambda {|t| exe.call do |t|
u = t.upid u = t.upid
v = u.id ? hosted[u.id.to_i] : t.node v = u.id ? hosted[u.id.to_i] : t.node
to.push [ to.push [
@ -24,22 +24,22 @@ class PVE::Cli
end, end,
u.dtype, u.upid u.dtype, u.upid
] ]
} end
to.print order: order to.print order: order
end end
def cli_task def cli_task
cli.sub :task, "Inspect tasks" do |tcli| cli.sub :task, "Inspect tasks" do |tcli|
tcli.cmd :list, "List done tasks", &lambda {|node=nil| tcli.cmd :list, "List done tasks" do |node=nil|
connect connect
nodes = Proxmox::Node.all nodes = Proxmox::Node.all
nodes = nodes.select {|n| node == n.name } if node nodes = nodes.select {|n| node == n.name } if node
nodes.flat_map do |n| nodes.flat_map do |n|
n.tasks.map &:upid n.tasks.map &:upid
end.sort_by(&:upid).each {|upid| puts upid } end.sort_by(&:upid).each {|upid| puts upid }
} end
tcli.cmd :get, "Inspect a task", &lambda {|upid| tcli.cmd :get, "Inspect a task" do |upid|
connect connect
Proxmox::Node.all.each do |n| Proxmox::Node.all.each do |n|
n.tasks.each do |t| n.tasks.each do |t|
@ -49,16 +49,16 @@ def cli_task
return return
end end
end end
} end
tcli.cmd( :status, "Lists tasks with status", aliases: [nil], &lambda {|target=nil, sort: nil, node: nil, status: nil| tcli.cmd :status, "Lists tasks with status", aliases: [nil] do |target=nil, sort: nil, node: nil, status: nil|
connect connect
task_table order: [2] do |push| task_table order: [2] do |push|
Proxmox::Node.all.each {|n| n.tasks.each &push } Proxmox::Node.all.each {|n| n.tasks.each &push }
end end
}) end
tcli.cmd( :monitor, "Monitors running tasks", &lambda {|node: nil| tcli.cmd :monitor, "Monitors running tasks" do |node: nil|
connect connect
nodes = Proxmox::Node.all nodes = Proxmox::Node.all
nodes = nodes.select {|n| node == n.name } if node nodes = nodes.select {|n| node == n.name } if node
@ -81,7 +81,7 @@ def cli_task
rescue Interrupt rescue Interrupt
STDERR.print "\e[2J\e[1;1H" STDERR.print "\e[2J\e[1;1H"
end end
}) end
tcli.cmd( :help, '', aliases: ['-h', '--help']) {|*args| help ct_cli, *args } tcli.cmd( :help, '', aliases: ['-h', '--help']) {|*args| help ct_cli, *args }
end end

View file

@ -155,7 +155,7 @@ module Proxmox
end end
def rest_post path, **data, &exe def rest_post path, **data, &exe
data = __data__( data) data = __data__( **data)
STDERR.puts "POST #{path} <= #{data}" if $DEBUG STDERR.puts "POST #{path} <= #{data}" if $DEBUG
__response__ Proxmox.connection[path].post( data, __headers__( :'Content-Type' => 'application/json')) __response__ Proxmox.connection[path].post( data, __headers__( :'Content-Type' => 'application/json'))
rescue RestClient::Exception rescue RestClient::Exception