From 68e8f3c52c1fb483fd78ff985f066b092bcc32af Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Wed, 2 Sep 2015 15:27:43 +0200 Subject: [PATCH] add bash completion support --- src/Makefile | 4 +- src/PVE/API2/LXC.pm | 14 +++--- src/PVE/API2/LXC/Config.pm | 4 +- src/PVE/API2/LXC/Snapshot.pm | 4 +- src/PVE/API2/LXC/Status.pm | 10 ++--- src/PVE/LXC.pm | 85 ++++++++++++++++++++++++++++++++++++ src/pct | 4 +- src/pct.bash-completion | 8 ++++ 8 files changed, 116 insertions(+), 17 deletions(-) create mode 100644 src/pct.bash-completion diff --git a/src/Makefile b/src/Makefile index 49f0613..281c4e3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,6 +12,7 @@ LXC_COMMON_CONFIG_DIR=${LXC_SCRIPT_DIR}/config/common.conf.d PODDIR=${DOCDIR}/pod MAN1DIR=${MANDIR}/man1/ MAN5DIR=${MANDIR}/man5/ +BASHCOMPLDIR=${PREFIX}/share/bash-completion/completions/ export PERLDIR=${PREFIX}/share/perl5 all: @@ -40,7 +41,7 @@ lxc-pve-poststop-hook.1.pod: lxc-pve-poststop-hook perl -I. -T ./lxc-pve-poststop-hook printmanpod >$@ .PHONY: install -install: pct lxc-pve.conf lxc-pve-prestart-hook lxc-pve-mount-hook lxc-pve-poststop-hook lxcnetaddbr lxc-pve-prestart-hook.1.pod lxc-pve-prestart-hook.1.gz lxc-pve-mount-hook.1.pod lxc-pve-mount-hook.1.gz lxc-pve-poststop-hook.1.pod lxc-pve-poststop-hook.1.gz pct.1.pod pct.1.gz pct.conf.5.pod pct.conf.5.gz pve-update-lxc-config +install: pct lxc-pve.conf lxc-pve-prestart-hook lxc-pve-mount-hook lxc-pve-poststop-hook lxcnetaddbr lxc-pve-prestart-hook.1.pod lxc-pve-prestart-hook.1.gz lxc-pve-mount-hook.1.pod lxc-pve-mount-hook.1.gz lxc-pve-poststop-hook.1.pod lxc-pve-poststop-hook.1.gz pct.1.pod pct.1.gz pct.conf.5.pod pct.conf.5.gz pve-update-lxc-config pct.bash-completion perl -T -I. ./pct verifyapi install -d ${SBINDIR} install -m 0755 pct ${SBINDIR} @@ -53,6 +54,7 @@ install: pct lxc-pve.conf lxc-pve-prestart-hook lxc-pve-mount-hook lxc-pve-posts install -m 0755 lxc-pve-poststop-hook ${LXC_HOOK_DIR} install -d ${LXC_COMMON_CONFIG_DIR} install -m 0644 lxc-pve.conf ${LXC_COMMON_CONFIG_DIR}/01-pve.conf + install -m 0644 -D pct.bash-completion ${BASHCOMPLDIR}/pct make -C PVE install install -d ${MAN1DIR} install -d ${MAN5DIR} diff --git a/src/PVE/API2/LXC.pm b/src/PVE/API2/LXC.pm index 0595e35..c8868fb 100644 --- a/src/PVE/API2/LXC.pm +++ b/src/PVE/API2/LXC.pm @@ -180,11 +180,12 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => PVE::LXC::json_config_properties({ node => get_standard_option('pve-node'), - vmid => get_standard_option('pve-vmid'), + vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_next_vmid }), ostemplate => { description => "The OS template or backup file.", type => 'string', maxLength => 255, + completion => \&PVE::LXC::complete_os_templates, }, password => { optional => 1, @@ -513,7 +514,7 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => { node => get_standard_option('pve-node'), - vmid => get_standard_option('pve-vmid'), + vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_stopped }), }, }, returns => { @@ -767,8 +768,11 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => { node => get_standard_option('pve-node'), - vmid => get_standard_option('pve-vmid'), - target => get_standard_option('pve-node', { description => "Target node." }), + vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }), + target => get_standard_option('pve-node', { + description => "Target node.", + completion => \&PVE::LXC::complete_migration_target, + }), online => { type => 'boolean', description => "Use online/live migration.", @@ -920,7 +924,7 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => { node => get_standard_option('pve-node'), - vmid => get_standard_option('pve-vmid'), + vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_stopped }), }, }, returns => { type => 'null'}, diff --git a/src/PVE/API2/LXC/Config.pm b/src/PVE/API2/LXC/Config.pm index 71da37b..95eafaa 100644 --- a/src/PVE/API2/LXC/Config.pm +++ b/src/PVE/API2/LXC/Config.pm @@ -34,7 +34,7 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => { node => get_standard_option('pve-node'), - vmid => get_standard_option('pve-vmid'), + vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }), }, }, returns => { @@ -80,7 +80,7 @@ __PACKAGE__->register_method({ properties => PVE::LXC::json_config_properties( { node => get_standard_option('pve-node'), - vmid => get_standard_option('pve-vmid'), + vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }), delete => { type => 'string', format => 'pve-configid-list', description => "A list of settings you want to delete.", diff --git a/src/PVE/API2/LXC/Snapshot.pm b/src/PVE/API2/LXC/Snapshot.pm index 3938d7d..5bb73b1 100644 --- a/src/PVE/API2/LXC/Snapshot.pm +++ b/src/PVE/API2/LXC/Snapshot.pm @@ -32,7 +32,7 @@ __PACKAGE__->register_method({ parameters => { additionalProperties => 0, properties => { - vmid => get_standard_option('pve-vmid'), + vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }), node => get_standard_option('pve-node'), }, }, @@ -90,7 +90,7 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => { node => get_standard_option('pve-node'), - vmid => get_standard_option('pve-vmid'), + vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }), snapname => get_standard_option('pve-lxc-snapshot-name'), # vmstate => { # optional => 1, diff --git a/src/PVE/API2/LXC/Status.pm b/src/PVE/API2/LXC/Status.pm index 14a4415..036fa57 100644 --- a/src/PVE/API2/LXC/Status.pm +++ b/src/PVE/API2/LXC/Status.pm @@ -110,7 +110,7 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => { node => get_standard_option('pve-node'), - vmid => get_standard_option('pve-vmid'), + vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_stopped }), }, }, returns => { @@ -188,7 +188,7 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => { node => get_standard_option('pve-node'), - vmid => get_standard_option('pve-vmid'), + vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }), }, }, returns => { @@ -257,7 +257,7 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => { node => get_standard_option('pve-node'), - vmid => get_standard_option('pve-vmid'), + vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }), timeout => { description => "Wait maximal timeout seconds.", type => 'integer', @@ -341,7 +341,7 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => { node => get_standard_option('pve-node'), - vmid => get_standard_option('pve-vmid'), + vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }), }, }, returns => { @@ -391,7 +391,7 @@ __PACKAGE__->register_method({ additionalProperties => 0, properties => { node => get_standard_option('pve-node'), - vmid => get_standard_option('pve-vmid'), + vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_stopped }), }, }, returns => { diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm index eb69fac..1c9c1a5 100644 --- a/src/PVE/LXC.pm +++ b/src/PVE/LXC.pm @@ -2096,4 +2096,89 @@ sub get_vm_volumes { return $vollist; } +# bash completion helper + +sub complete_os_templates { + my ($cmdname, $pname, $cvalue) = @_; + + my $cfg = PVE::Storage::config(); + + my $storeid; + + if ($cvalue =~ m/^([^:]+):/) { + $storeid = $1; + } + + my $vtype = $cmdname eq 'restore' ? 'backup' : 'vztmpl'; + my $data = PVE::Storage::template_list($cfg, $storeid, $vtype); + + my $res = []; + foreach my $id (keys %$data) { + foreach my $item (@{$data->{$id}}) { + push @$res, $item->{volid} if defined($item->{volid}); + } + } + + return $res; +} + +sub complete_migration_target { + + my $res = []; + + my $nodelist = PVE::Cluster::get_nodelist(); + foreach my $node (@$nodelist) { + next if $node eq $nodename; + push @$res, $node; + } + + return $res; +} + +sub complete_next_vmid { + + my $vmlist = PVE::Cluster::get_vmlist() || {}; + my $idlist = $vmlist->{ids} || {}; + + for (my $i = 100; $i < 10000; $i++) { + return [$i] if !defined($idlist->{$i}); + } + + return []; +} + +my $complete_ctid_full = sub { + my ($running) = @_; + + my $idlist = vmstatus(); + + my $active_hash = list_active_containers(); + + my $res = []; + + foreach my $id (keys %$idlist) { + my $d = $idlist->{$id}; + if (defined($running)) { + next if $d->{template}; + next if $running && !$active_hash->{$id}; + next if !$running && $active_hash->{$id}; + } + push @$res, $id; + + } + return $res; +}; + +sub complete_ctid { + return &$complete_ctid_full(); +} + +sub complete_ctid_stopped { + return &$complete_ctid_full(0); +} + +sub complete_ctid_running { + return &$complete_ctid_full(1); +} + 1; diff --git a/src/pct b/src/pct index 6821ea3..45f5d1c 100755 --- a/src/pct +++ b/src/pct @@ -49,7 +49,7 @@ __PACKAGE__->register_method ({ parameters => { additionalProperties => 0, properties => { - vmid => get_standard_option('pve-vmid'), + vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }), }, }, returns => { type => 'null' }, @@ -72,7 +72,7 @@ __PACKAGE__->register_method ({ parameters => { additionalProperties => 0, properties => { - vmid => get_standard_option('pve-vmid'), + vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_running }), }, }, returns => { type => 'null' }, diff --git a/src/pct.bash-completion b/src/pct.bash-completion new file mode 100644 index 0000000..7d0a9f3 --- /dev/null +++ b/src/pct.bash-completion @@ -0,0 +1,8 @@ +# pct(1) bash completion + +# see http://tiswww.case.edu/php/chet/bash/FAQ +# and __ltrim_colon_completions() in /usr/share/bash-completion/bash_completion +# this modifies global var, but I found no better way +COMP_WORDBREAKS=${COMP_WORDBREAKS//:} + +complete -C 'pct bashcomplete' pct -- 2.39.2