# Copyright (C) 2015 Red Hat, Inc., Tony Asleson # Distributed under the GNU General Public License, version 2.0. # See: https://www.gnu.org/licenses/gpl-2.0.html # # Bash completion for lsmcli. This may be far from ideal, # suggestions & improvements appreciated! potential_args='' # Skip value lookups by default NO_VALUE_LOOKUP=${LSMCLI_AUTO_COMPLETE_VALUE:=0} function join { local IFS="$1"; shift; echo "$*"; } # Linear search of an array of strings for the specified string function listcontains() { declare -a the_list=("${!1}") for word in "${the_list[@]}" ; do [[ ${word} == $2 ]] && return 0 done return 1 } # Given a list of what is possible and what is on the command line return # what is left. # $1 What is possible # Retults are returned in global string $potential_args function possible_args() { local l=() for i in $1 do listcontains COMP_WORDS[@] "$i" if [[ $? -eq 1 ]] ; then l+=("$i") fi done potential_args=$( join ' ', "${l[@]}" ) } # Returns the position of the value in the COMP_WORDS that contains $1, or # 255 if it doesn't exist function arg_index() { count=0 for i in "${COMP_WORDS[@]}" do if [[ "$i" == "$1" ]] ; then return ${count} fi let count+=1 done return 255 } function _lsm() { local cur prev opts sep='#' COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" opts_short="-b -v -u -P -H -t -e -f -w -b" opts_long=" --help --version --uri --prompt --human --terse --enum \ --force --wait --header --script " opts_cmds="list job-status capabilities plugin-info volume-create \ volume-delete volume-resize volume-replicate \ volume-replicate-range volume-replicate-range-block-size \ volume-dependants volume-dependants-rm volume-access-group \ volume-mask volume-unmask access-group-create \ access-group-delete access-group-add access-group-remove \ volume-enable volume-disable iscsi-chap fs-create fs-delete \ fs-resize fs-export fs-unexport fs-clone fs-snap-create \ fs-snap-delete fs-snap-restore fs-dependants fs-dependants-rm \ file-clone ls lp lv ld la lf lt lb c p vc vd vr vm vi ve vi ac \ aa ar ad vri volume-raid-info pool-member-info pmi \ vrc volume-raid-create vrcc volume-raid-create-cap \ volume-phy-disk-cache-update vpdcu \ volume-read-cache-policy-update vrcpu \ volume-write-cache-policy-update vwcpu \ volume-cache-info vci volume-ident-led-on vilon \ volume-ident-led-off viloff local-disk-list ldl \ system-read-cache-pct-update srcpu \ local-disk-ident-led-on ldilon \ local-disk-ident-led-off ldiloff \ local-disk-fault-led-on ldflon \ local-disk-fault-led-off ldfloff" list_args="--type" list_type_args="volumes pools fs snapshots exports nfs_client_auth \ access_groups systems disks plugins target_ports \ batteries" opts_filter="--sys --pool --vol --disk --ag --fs --nfs" cap_args="--sys" volume_create_args="--name --size --pool" volume_delete_args="--vol --force" # Should force be here, to easy to tab through?" volume_resize_args="--vol --size --force" # Should force be here, to easy to tab through?" volume_replicate_args="--vol --name --rep-type" # Hmmm, this looks like a bug with CLI, should support lower and upper case? volume_rep_types="CLONE COPY MIRROR_ASYNC MIRROR_SYNC" volume_replicate_range_args="--src-vol --dst-vol --rep-type --src-start \ --dst-start --count --force" # Force ? volume_replication_range_bs="--sys" volume_dependants="--vol" volume_access_group_args="--vol" volume_masking_args="--vol --ag" access_group_create_args="--name --init --sys" access_group_delete_args="--ag" access_group_add_remove_args="--ag --init" volume_enable_disable_args="--vol" volume_raidinfo_args="--vol" iscsi_chap_args="--in-user --in-pass --out-user --out-pass" fs_create_args="--name --size --pool" fs_delete_args="--fs --force" # Force ? fs_resize_args="--fs --size --force" # Force ? fs_export_args="--fs --exportpath --anonuid --auth-type --root-host --ro-host --rw-host" fs_unexport_args="--export" fs_clone_args="--src-fs --dst-name" fs_snap_create_args="--name --fs" fs_snap_delete_args="--snap --fs" fs_snap_restore_args="--snap --fs --file --fileas --force" fs_dependants_args="--fs" file_clone_args="--fs --src --dst --backing-snapshot" pool_member_info_args="--pool" volume_raid_create_args="--name --disk --raid-type --strip-size" volume_raid_create_cap_args="--sys" volume_phy_disk_cache_update_args="--vol --policy" volume_read_cache_policy_update_args="--vol --policy" volume_write_cache_policy_update_args="--vol --policy" volume_cache_info_args="--vol" volume_ident_led_on_off_args="--vol" system_read_cache_pct_update_args="--vol --read-pct" local_disk_led_args="--path" # These operations can potentially be slow and cause hangs depending on plugin and configuration if [[ ${NO_VALUE_LOOKUP} -ne 0 ]] ; then # Check if we have somthing present that we can help the user with case "${prev}" in --sys) # Is there a better way todo this? local items=`lsmcli list --type systems -t${sep} | awk -F ${sep} '{print $1}'` COMPREPLY=( $(compgen -W "${items}" -- ${cur}) ) return 0 ;; --pool) # Is there a better way todo this? local items=`lsmcli list --type pools -t${sep} | awk -F ${sep} '{print $1}'` COMPREPLY=( $(compgen -W "${items}" -- ${cur}) ) return 0 ;; --vol|--src-vol|--dst-vol) # Is there a better way todo this? local items=`lsmcli list --type volumes -t${sep} | awk -F ${sep} '{print $1}'` COMPREPLY=( $(compgen -W "${items}" -- ${cur}) ) return 0 ;; --disk) # Is there a better way todo this? local items=`lsmcli list --type disks -t${sep} | awk -F ${sep} '{print $1}'` COMPREPLY=( $(compgen -W "${items}" -- ${cur}) ) return 0 ;; --ag) # Is there a better way todo this? local items=`lsmcli list --type access_groups -t${sep} | awk -F ${sep} '{print $1}'` COMPREPLY=( $(compgen -W "${items}" -- ${cur}) ) return 0 ;; --init) arg_index "--ag" i=$? # We have an access group present on the command line so filter the intiators to it if [[ ${i} -ne 255 ]]; then # It would be better if we filtered the result with the access group # if it's present on the command line already. local items=`lsmcli list --type access_groups -t${sep} --ag ${COMP_WORDS[${i}+1]} | awk -F ${sep} '{print $3}'` COMPREPLY=( $(compgen -W "${items}" -- ${cur}) ) return 0 else local items=`lsmcli list --type access_groups -t${sep} | awk -F ${sep} '{print $3}'` COMPREPLY=( $(compgen -W "${items}" -- ${cur}) ) return 0 fi ;; --nfs-export) # Is there a better way todo this? local items=`lsmcli list --type exports -t${sep} | awk -F ${sep} '{print $1}'` COMPREPLY=( $(compgen -W "${items}" -- ${cur}) ) return 0 ;; --tgt) # Is there a better way todo this? local items=`lsmcli list --type target_ports -t${sep} | awk -F ${sep} '{print $1}'` COMPREPLY=( $(compgen -W "${items}" -- ${cur}) ) return 0 ;; --fs|--src-fs) local items=`lsmcli list --type fs -t${sep} | awk -F ${sep} '{print $1}'` COMPREPLY=( $(compgen -W "${items}" -- ${cur}) ) return 0 ;; --export) local items=`lsmcli list --type exports -t${sep} | awk -F ${sep} '{print $1}'` COMPREPLY=( $(compgen -W "${items}" -- ${cur}) ) return 0 ;; --snap) arg_index "--fs" i=$? # We have an access group present on the command line so filter the snapshots to it if [[ ${i} -ne 255 ]]; then local items=`lsmcli list --type snapshots \ --fs ${COMP_WORDS[${i}+1]} -t${sep} | awk -F ${sep} '{print $1}'` COMPREPLY=( $(compgen -W "${items}" -- ${cur}) ) return 0 else COMPREPLY=( $(compgen -W "" -- ${cur}) ) return 0 fi ;; --auth-type) local items=`lsmcli list --type nfs_client_auth -t ' '` COMPREPLY=( $(compgen -W "${items}" -- ${cur}) ) return 0 ;; *) ;; esac fi # Cases where we don't have to worry about look-up time case "${prev}" in --type) COMPREPLY=( $(compgen -W "${list_type_args}" -- ${cur}) ) return 0 ;; --size|--count|--src-start|--dst-start|--name|--in-user|--in-pass|\ --out-user|--out-pass|--exportpath|--anonuid|--root-host|--ro-host|\ --rw-host|--dest-name|--file|--fileas|--src|--dst) # These we cannot lookup, so don't offer any values COMPREPLY=( $(compgen -W "" -- ${cur}) ) return 0 ;; --rep-type) COMPREPLY=( $(compgen -W "${volume_rep_types}" -- ${cur}) ) return 0 ;; snapshots) # Specific listing case where you need a fs too if [[ ${COMP_WORDS[COMP_CWORD-2]} == '--type' && \ ${COMP_WORDS[COMP_CWORD-3]} == 'list' ]] ; then COMPREPLY=( $(compgen -W "--fs" -- ${cur}) ) return 0 fi ;; *) esac case "${COMP_WORDS[1]}" in job-status) possible_args "--job" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; list) possible_args ${list_args} COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-create|vc) possible_args "${volume_create_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-delete|vd) possible_args "${volume_delete_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-raid-info|vri) possible_args "${volume_raidinfo_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-resize|vr) possible_args "${volume_resize_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-replicate) possible_args "${volume_replicate_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-replicate-range) possible_args "${volume_replicate_range_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-replicate-range-block-size) possible_args "${volume_replication_range_bs}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-dependants|volume-dependants-rm) possible_args "${volume_dependants}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-access-group) possible_args "${volume_access_group_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-mask|volume-unmask|vm|vu) possible_args "${volume_masking_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; access-group-create|ac) possible_args "${access_group_create_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; access-group-delete|ad) possible_args "${access_group_delete_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; access-group-add|access-group-remove|aa|ar) possible_args "${access_group_add_remove_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-enable|volume-disable|ve|vi) possible_args "${volume_enable_disable_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; iscsi-chap) possible_args "${iscsi_chap_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; fs-create) possible_args "${fs_create_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; fs-delete) possible_args "${fs_delete_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; fs-resize) possible_args "${fs_resize_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; fs-export) possible_args "${fs_export_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; fs-unexport) possible_args "${fs_unexport_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; fs-clone) possible_args "${fs_clone_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; fs-snap-create) possible_args "${fs_snap_create_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; fs-snap-delete) possible_args "${fs_snap_delete_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; fs-snap-restore) possible_args "${fs_snap_restore_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; fs-dependants|fs-dependants-rm) possible_args "${fs_dependants_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; file-clone) possible_args "${file_clone_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; capabilities|c) possible_args "${cap_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; pool-member-info|pmi) possible_args "${pool_member_info_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-raid-create|vrc) possible_args "${volume_raid_create_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-raid-create-cap|vrcc) possible_args "${volume_raid_create_cap_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-phy-disk-cache-update|vpdcu) possible_args "${volume_phy_disk_cache_update_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-read-cache-policy-update|vrcpu) possible_args "${volume_read_cache_policy_update_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-write-cache-policy-update|vwcpu) possible_args "${volume_write_cache_policy_update_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-cache-info|vci) possible_args "${volume_cache_info_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; volume-ident-led-on|volume-ident-led-off|vilon|viloff) possible_args "${volume_ident_led_on_off_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; system-read-cache-pct-update|srcpu) possible_args "${system_read_cache_pct_update_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; local-disk-ident-led-on|ldilon| \ local-disk-ident-led-off|ldiloff| \ local-disk-fault-led-on|ldflon| \ local-disk-fault-led-off|ldfloff) possible_args "${local_disk_led_args}" COMPREPLY=( $(compgen -W "${potential_args}" -- ${cur}) ) return 0 ;; *) ;; esac # Handle the case where we are starting out with nothing if [[ ${prev} == 'lsmcli' ]] ; then if [[ ${cur} == --* ]] ; then COMPREPLY=( $(compgen -W "${opts_long}" -- ${cur}) ) return 0 fi if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "${opts_short}${opts_long}" -- ${cur}) ) return 0 fi if [[ ${cur} == * ]] ; then COMPREPLY=( $(compgen -W "${opts_short}${opts_long}${opts_cmds}" -- ${cur}) ) return 0 fi fi } complete -F _lsm lsmcli