#! /bin/bash
# vim: shiftwidth=4 tabstop=4 expandtab

subcommand__help() {
    if [[ -z "$2" ]] || [[ "$2" == "ls" ]]; then
        echo "$COMMAND ls [VM]"
        if [[ "$1" == "details" ]] && [[ "$2" == "ls" ]]; then
            echo "  List VM volumes"
        fi
    fi
    if [[ -z "$2" ]] || [[ "$2" == "info" ]]; then
        echo "$COMMAND info [volume RBD path]"
        if [[ "$1" == "details" ]] && [[ "$2" == "info" ]]; then
            echo "  Show volume (specified by RBD path) information"
        fi
    fi
    if [[ -z "$2" ]] || [[ "$2" == "owner" ]]; then
        echo "$COMMAND owner [volume RBD path]"
        if [[ "$1" == "details" ]] && [[ "$2" == "owner" ]]; then
            echo "  Show volume (specified by RBD path) VM owner"
        fi
    fi
    if [[ -z "$2" ]] || [[ "$2" == "add" ]]; then
        echo "$COMMAND add [VM] [suffix] [size] [pool]"
        if [[ "$1" == "details" ]] && [[ "$2" == "add" ]]; then
            echo "  Create and attach a new volume to a VM"
            echo "    [VM]               VM name"
            echo "    [suffix]           Volume name suffix (format: '[VM]-[suffix]')"
            echo "    [size]             Size (in GiB)"
            echo -n "    [pool]             RBD pool name"
            [[ -n "$DEFAULT_VOLUME_POOL" ]] && \
                echo " (optional, default: $DEFAULT_VOLUME_POOL)" || \
                echo
        fi
    fi
    if [[ -z "$2" ]] || [[ "$2" == "attach" ]]; then
        echo "$COMMAND attach [VM] [volume RBD path]"
        if [[ "$1" == "details" ]] && [[ "$2" == "attach" ]]; then
            echo "  Attach an existing volume to a VM"
            echo "    [VM]               VM name"
            echo "    [volume RBD path]  Volume RBD path"
        fi
    fi
    if [[ -z "$2" ]] || [[ "$2" == "resize" ]]; then
        echo "$COMMAND resize [VM] [volume RBD path] [+|-][size]"
        if [[ "$1" == "details" ]] && [[ "$2" == "resize" ]]; then
            echo "  Resize a VM's volume"
            echo "    [VM]               VM name"
            echo "    [volume RBD path]  Volume RBD path"
            echo "    [+|-][size]        New volume size (in GiB). Could be prefix by '+' or '-'"
            echo "                       to respectively enlarge or reduce the size of the volume."
        fi
    fi
    if [[ -z "$2" ]] || [[ "$2" == "children" ]]; then
        echo "$COMMAND children [VM] [volume RBD path]"
        if [[ "$1" == "details" ]] && [[ "$2" == "children" ]]; then
            echo "  Show children of VM's volumes"
            echo "    [VM]               VM name"
            echo "    [volume RBD path]  Volume RBD path (optional, default: all VM's volumes)"
        fi
    fi
    if [[ -z "$2" ]] || [[ "$2" == "flatten" ]]; then
        echo "$COMMAND flatten [VM] [volume RBD path]"
        if [[ "$1" == "details" ]] && [[ "$2" == "flatten" ]]; then
            echo "  Flatten VM's volumes"
            echo "    [VM]               VM name"
            echo "    [volume RBD path]  Volume RBD path (optional, default: all VM's volumes)"
        fi
    fi
    if [[ -z "$2" ]] || [[ "$2" == "map" ]]; then
        echo "$COMMAND map [VM] [volume RBD path]"
        if [[ "$1" == "details" ]] && [[ "$2" == "map" ]]; then
            echo "  Map VM's volumes on local hypervisor"
            echo "    [VM]               VM name"
            echo "    [volume RBD path]  Volume RBD path to map (optional, default: map all VM's" \
                "volumes)"
            echo
            echo "  Note: This command will offer the possibility to scan and enable LVM VG on" \
                "VM's mapped volumes."
        fi
    fi
    if [[ -z "$2" ]] || [[ "$2" == "lsmap" ]]; then
        echo "$COMMAND lsmap"
        if [[ "$1" == "details" ]] && [[ "$2" == "lsmap" ]]; then
            echo "  List VMs volumes currently mapped on local hypervisor"
        fi
    fi
    if [[ -z "$2" ]] || [[ "$2" == "unmap" ]]; then
        echo "$COMMAND unmap [VM] [volume RBD path]"
        if [[ "$1" == "details" ]] && [[ "$2" == "unmap" ]]; then
            echo "  Unmap VM's volumes on local hypervisor"
            echo "    [VM]               VM name"
            echo "    [volume RBD path]  Volume RBD path to unmap (optional, default: unmap all" \
                "VM's volumes)"
            echo
            echo "  Note: This command will handle to disable LVM VG on VM's mapped volumes" \
                "before unmapping them."
        fi
    fi
    if [[ -z "$2" ]] || [[ "$2" == "detach" ]]; then
        echo "$COMMAND detach [VM] [volume RBD path]"
        if [[ "$1" == "details" ]] && [[ "$2" == "detach" ]]; then
            echo "  Detach a VM's volume"
            echo "    [VM]               VM name"
            echo "    [volume RBD path]  Volume RBD path"
        fi
    fi
    if [[ -z "$2" ]] || [[ "$2" == "rm" ]]; then
        echo "$COMMAND rm [volume RBD path]"
        if [[ "$1" == "details" ]] && [[ "$2" == "rm" ]]; then
            echo "  Remove volume specified by its RBD path"
            echo
            echo "  Note: The specified volume must be unprotected and attached to any VM."
        fi
    fi
    if [[ -z "$2" ]] || [[ "$2" == "locate" ]]; then
        echo "$COMMAND locate [RBD pool] [RBD volume name]"
        if [[ "$1" == "details" ]] && [[ "$2" == "locate" ]]; then
            echo "  FIXME: run 'ceph osd map [pool] [X]' command for all volume block_name_prefix."
        fi
    fi
}

subcommand__ls() {
    check_generate_script_not_supported
    local vm=$1 hyp volumes volume
    [[ -z "$vm" ]] && usage "VM name is missing"
    hyp=$( locate "$vm" )
    check_hyp "$hyp" || usage "Unknown VM $vm"
    mapfile -t volumes < <( list_volumes "$vm" "$hyp" )
    for volume in "${volumes[@]}"; do
        echo "$volume ($(get_volume_size "$volume"))"
    done
}

subcommand__info() {
    local volume=$1
    [[ -z "$volume" ]] && usage "Volume path is missing"
    run_external rbd info "$volume"
}

subcommand__owner() {
    check_generate_script_not_supported
    local volume=$1
    [[ -z "$volume" ]] && usage "Volume path is missing"
    load_volume_to_vm_mapping verbose
    if [[ "${SHARED_VOLUMES[$volume]:-null}" != "null" ]]; then
        display "The volume $volume is shared by the following VMs: ${SHARED_VOLUMES[$volume]}"
    elif [[ "${VOLUME_TO_VM[$volume]:-null}" != "null" ]]; then
        display "The volume $volume is owned by ${VOLUME_TO_VM[$volume]}"
    else
        display "No VM owner found for volume $volume"
    fi
}

subcommand__add() {
    local vm=$1 suffix=$2 size=$3 hyp
    [[ -z "$vm" ]] && usage "VM name is missing"

    hyp=$( locate "$vm" )
    check_hyp "$hyp" || usage "Unknown VM $vm"

    [[ -z "$suffix" ]] && usage "Volume name suffix is missing"
    check_volume_name "$suffix" || usage "Invalid volume name suffix"

    [[ -z "$size" ]] && usage "Volume size is missing"
    if ! check_int "$size" 1; then
        usage "Invalid volume size (must be a positive integer)"
    fi

    local pool=${4:-$DEFAULT_VOLUME_POOL}
    [[ -z "$pool" ]] && usage "Volume pool name is missing"
    check_volumes_pool "$pool" || usage "Invalid volume pool name '$pool'"

    local volume="$pool/${vm}-${suffix}"
    rbd info "$volume" > /dev/null 2>&1 && fatal_error "Volume $volume already exists!"

    confirm "Add a new volume $volume of ${size}GiB to VM $vm (on $hyp)" || exit 0

    run_external qemu-img create -f rbd rbd:"$volume" "${size}G" || \
        fatal_error "Failed to create volume $volume of ${size}GiB in pool $pool"

    NO_CONFIRM=1 subcommand__attach "$vm" "$volume"
}

subcommand__attach() {
    local vm=$1 volume=$2 hyp
    [[ -z "$vm" ]] && usage "VM name is missing"

    hyp=$( locate "$vm" )
    check_hyp "$hyp" || usage "Unknown VM $vm"

    [[ -z "$volume" ]] && usage "Volume path is missing"
    check_volume_path "$volume" || usage "Invalid volume path"

    if [[ -z "$NO_CONFIRM" ]]; then
        rbd info "$volume" > /dev/null 2>&1 || fatal_error "Unknown volume $volume!"
        local volume_target
        volume_target=$(get_volume_target_from_path "$vm" "$volume" "$hyp")
        [[ -n "$volume_target" ]] && \
            fatal_error "Volume $volume is already attach to VM $vm (as $volume_target)!"

        confirm "Attach volume $volume to VM $vm on $hyp" || exit 1
    fi

    echo "Prepare disk configuration:"

    echo -n "- Dump existing VM network disk as template..."
    TMP=$(mktemp -t "vm-$vm-disk-XXX" --suffix .xml)
    LC_ALL=C ssh "$hyp" "$REAL_VIRSH" dumpxml --inactive "$vm" | \
        xmlstarlet select -t -c '/domain/devices/disk[@type="network"][last()]' > "$TMP" || \
        fatal_error "Failed to dump or locate an existing VM network disk as template"
    echo " done."

    echo -n "- Set volume path..."
    if xmlstarlet edit --inplace --update '/disk/source/@name' --value "$volume" "$TMP"; then
        echo " done."
    else
        error "Failed to set volume path to $volume. Please do it manually!"
    fi

    echo -n "- Increase target device name..."
    local original_dev target_dev
    if ! original_dev="$(xmlstarlet select -t -v '/disk/target/@dev' "$TMP")" || \
        [[ -z "$original_dev" ]]; then
        error "Failed to detect original target device name. Please increase it manually!"
    else
        target_dev="${original_dev::-1}$(
            echo "${original_dev:((${#original_dev}-1))}" |
            tr "0-9a-z" "1-9a-z_"
        )"
        echo -n " ($original_dev => $target_dev)"
        if xmlstarlet edit --inplace --update '/disk/target/@dev' --value "$target_dev" "$TMP"; then
            echo " done."
        else
            error "Failed to change target device name to $target_dev. Please do it manually!"
        fi
    fi

    if xmlstarlet select -t -c '/disk/alias' "$TMP" > /dev/null 2>&1; then
        echo -n "- Remove disk alias..."
        if xmlstarlet edit --inplace --delete '/disk/alias' "$TMP"; then
            echo " done."
        else
            error "Failed to remove disk alias. Please do it manually!"
        fi
    fi

    if xmlstarlet select -t -c '/disk/address' "$TMP" > /dev/null 2>&1; then
        echo -n "- Remove disk address..."
        if xmlstarlet edit --inplace --delete '/disk/address' "$TMP"; then
            echo " done."
        else
            error "Failed to remove disk address. Please do it manually!"
        fi
    fi

    if xmlstarlet select -t -c '/disk/boot' "$TMP" > /dev/null 2>&1; then
        echo -n "- Remove disk boot option..."
        if xmlstarlet edit --inplace --delete '/disk/boot' "$TMP"; then
            echo " done."
        else
            error "Failed to remove disk boot option. Please do it manually!"
        fi
    fi

    echo "done."

    if [[ $AUTO -ne 1 ]]; then
        echo
        echo "Please control and adjust the generated configuration"
        echo "[Press enter to continue]"
        read -r
        vi "$TMP"
        confirm "Continue" || exit 1
    fi

    echo "Attach volume $volume to VM $vm on $hyp..."
    if [[ "$hyp" != "$(hostname)" ]]; then
        run_external scp -q "$TMP" "$hyp":"$TMP" || \
            fatal_error "Failed to copy generated disk configuration file ($TMP) to $hyp."
        run_external ssh "$hyp" "$REAL_VIRSH" attach-device "$vm" "$TMP" --persistent --live || \
            fatal_error "Failed to attach volume $volume to $vm on $hyp."
    else
        run_external "$REAL_VIRSH" attach-device "$vm" "$TMP" --persistent --live || \
            fatal_error "Failed to attach volume $volume to $vm on $hyp."
    fi

    if [[ -z "$GENERATE_SCRIPT" ]]; then
        echo -n "Remove temporary files..."
        run_external rm -f "$TMP"
        [[ "$hyp" != "$(hostname)" ]] && run_external ssh "$hyp" rm -f "$TMP"
    fi
    echo " done."
}

subcommand__resize() {
    local vm=$1 volume=$2 size=$3 hyp cur_sizeb sizeb volume_target
    [[ -z "$vm" ]] && usage "VM name is missing"

    hyp=$( locate "$vm" )
    check_hyp "$hyp" || usage "Unknown VM $vm"

    [[ -z "$volume" ]] && usage "Volume path is missing"
    check_volume_path "$volume" || usage "Invalid volume path"
    cur_sizeb=$(rbd info --format json "$volume" 2> /dev/null |jq .size 2> /dev/null) || \
        fatal_error "Unknown volume $volume!"
    volume_target=$(get_volume_target_from_path "$vm" "$volume" "$hyp") || \
        fatal_error "Volume $volume not use by VM $vm (or fail to detect its target)!"

    [[ -z "$size" ]] && usage "New volume size is missing"
    check_regex "$size" "^[\+\-]?[0-9]+$" || \
        usage "Invalid volume size (must be a positive integer, possibly prefix with + or - to"\
            "respectively enlarge or reduce the size of the volume)"

    if [[ "${size:0:1}" == "+" ]]; then
        (( sizeb=cur_sizeb+${size:1}*1073741824 ))
    elif [[ "${size:0:1}" == "-" ]]; then
        (( sizeb=cur_sizeb-${size:1}*1073741824 ))
    else
        (( sizeb=size*1073741824 ))
    fi

    # Control new size is greater than current size
    [[ $sizeb -eq $cur_sizeb ]] && \
        echo "Volume $volume ($volume_target) size is already " \
            "$(format_size -b "${cur_sizeb}")." && \
        exit 0
    if [[ $sizeb -lt $cur_sizeb ]]; then
        echo "/!\\ WARNING /!\\"
        echo "The volume $volume ($volume_target) current size is greater than the desired new" \
            "size ($(format_size -b "${sizeb}") < $(format_size -b "${cur_sizeb}"))!"
        [[ $AUTO -eq 1 ]] && [[ $FORCE -ne 1 ]] && \
            fatal_error "Auto mode enabled without force mode, deny volume size reducing." \
            "Run again this command with -F/--force parameter to force it."
        confirm "Are you sure you want to reduce the volume $volume ($volume_target) size to" \
            "$(format_size -b "${sizeb}")" || exit 1
    else
        confirm "Resize volume $volume ($volume_target) of VM $vm on $hyp from" \
            "$(format_size -b "${cur_sizeb}") to $(format_size -b "${sizeb}")" || exit 1
    fi

    echo "Resizing..."
    run_external ssh "$hyp" "$REAL_VIRSH" blockresize "$vm" --path "$volume_target" --size "${sizeb}B" || \
        fatal_error "Failed to resize volume $volume ($volume_target) of VM $vm on $hyp from" \
            "$(format_size -b "${cur_sizeb}") to $(format_size -b "${sizeb}")"
}

subcommand__children() {
    local vm=$1 only_volume=$2 hyp
    [[ -z "$vm" ]] && usage "VM name is missing"
    hyp=$( locate "$vm" )
    check_hyp "$hyp" || usage "Unknown VM $vm"

    local volume children
    for volume in $(list_volumes "$vm" "$hyp"); do
        [[ -n "$only_volume" ]] && [[ "$only_volume" != "$volume" ]] && continue
        if [[ -n "$GENERATE_SCRIPT" ]]; then
            run_external echo "Volume ${volume} children:"
            run_external rbd children "${volume}"
            continue
        fi
        children=$(rbd children "${volume}") || \
            fatal_error "Failed to list children of volume ${volume}!"

        if [[ -n "$children" ]]; then
            echo "Volume $volume children:"
            echo -e "$children" | sed 's/^/ - /'
        else
            echo "Volume $volume have no children."
        fi
    done
}

subcommand__flatten() {
    local vm=$1 only_volume=$2 hyp
    [[ -z "$vm" ]] && usage "VM name is missing"
    hyp=$( locate "$vm" )
    check_hyp "$hyp" || usage "Unknown VM $vm"
    if [[ -z "$only_volume" ]]; then
        confirm "Flatten VM $vm volumes" || exit 1
    else
        confirm "Flatten VM $vm volume $only_volume" || exit 1
    fi

    if in_working_hours; then
        [[ $AUTO -eq 1 ]] && [[ $FORCE -ne 1 ]] && \
            fatal_error "Auto mode enabled without force mode, deny flattening volumes during" \
            "working hours. Run again this command with -F/--force parameter to force it."
        echo
        echo "/!\\   WARNING   /!\\"
        echo "Flattening a snapshot imposes a significant load on the Ceph cluster. It is highly"
        echo "recommended not to perform this type of operation during the day!"
        echo
        confirm || exit 1
    fi

    local volume
    for volume in $(list_volumes "$vm" "$hyp"); do
        [[ -n "$only_volume" ]] && [[ "$only_volume" != "$volume" ]] && continue
        [[ $(rbd info "${volume}"|grep -c 'parent:') -eq 0 ]] && \
            echo "Volume $volume is already flatten." && continue
        run_external rbd flatten "${volume}" || fatal_error "Failed to flatten volume ${volume}!"
    done
}

get_volume_mapped_dev() {
    local pool image
    pool=$(echo "$1"|cut -d '/' -f 1)
    image=$(echo "$1"|cut -d '/' -f 2)
    rbd-nbd list-mapped --format json 2>/dev/null | \
        jq -r ".[] | select(.pool == \"$pool\") | select(.image == \"$image\").device" 2>/dev/null
}

subcommand__map() {
    check_generate_script_not_supported
    check_just_try_not_supported
    local vm=$1 only_volume=$2 hyp
    [[ -z "$vm" ]] && usage "VM name is missing"
    hyp=$( locate "$vm" )
    check_hyp "$hyp" || usage "Unknown VM $vm"
    is_running "$vm" "$hyp" && fatal_error "VM $vm is running, can't map it's volumes."
    if [[ -z "$only_volume" ]]; then
        confirm "Map all VM $vm volumes on local hypervisor" || exit 1
        echo "Mapping VM $vm volumes on local hypervisor..."
    else
        confirm "Map VM $vm volume $only_volume on local hypervisor" || exit 1
        echo "Mapping VM $vm volume $only_volume on local hypervisor..."
    fi

    local nbd_devs=() nbd_dev volume volumes
    mapfile -t volumes < <( list_volumes "$vm" "$hyp" )
    for volume in "${volumes[@]}"; do
        [[ -n "$only_volume" ]] && [[ "$only_volume" != "$volume" ]] && continue
        nbd_dev=$(get_volume_mapped_dev "$volume")
        if [[ -n "$nbd_dev" ]]; then
            echo "- Volume $volume already mapped as $nbd_dev"
            nbd_devs+=( "$nbd_dev" )
        else
            nbd_dev=$(rbd-nbd --exclusive map "${volume}") || \
                fatal_error "Failed to map volume ${volume}!"
            echo "- Volume $volume mapped as $nbd_dev"
            nbd_devs+=( "$nbd_dev" )
        fi
    done
    echo "done."

    confirm "Looking for LVM PV & VG on mapped device(s)" || exit 0
    local pvs_vgs
    pvs_vgs="$(
        pvscan |
        grep -E "PV ($(implode '|' "${nbd_devs[@]}"))" |
        awk '{print $2 "|" $4}'
    )"
    [[ -z "$pvs_vgs" ]] && echo "No VG found on mapped devices" && exit 0

    echo "Enable VG on mapped devices:"
    local enabled_vgs=() pv vg
    for pv_vg in $pvs_vgs; do
        pv=$( cut -d "|" -f 1 <<< "$pv_vg" )
        vg=$( cut -d "|" -f 2 <<< "$pv_vg" )
        in_array "$vg" "${enabled_vgs[@]}" && continue
        echo -n "- Enable VG $vg on $pv: "
        vgchange -ay "$vg"
        enabled_vgs+=( "$vg" )
    done
    echo "done."
}

subcommand__lsmap() {
    run_external rbd-nbd list-mapped
}

subcommand__unmap() {
    check_generate_script_not_supported
    check_just_try_not_supported
    local vm=$1 only_volume=$2 hyp
    [[ -z "$vm" ]] && usage "VM name is missing"
    hyp=$( locate "$vm" )
    check_hyp "$hyp" || usage "Unknown VM $vm"
    if [[ -z "$only_volume" ]]; then
        confirm "Unmap all VM $vm volumes on local hypervisor" || exit 1
        echo "Looking for VM $vm mapped devices..."
    else
        confirm "Unmap VM $vm volume $only_volume on local hypervisor" || exit 1
        echo "Looking for VM $vm volume $only_volume mapped device..."
    fi

    local nbd_devs=() nbd_dev volume volumes
    mapfile -t volumes < <( list_volumes "$vm" "$hyp" )
    for volume in "${volumes[@]}"; do
        [[ -n "$only_volume" ]] && [[ "$only_volume" != "$volume" ]] && continue
        nbd_dev=$(get_volume_mapped_dev "$volume")
        [[ -z "$nbd_dev" ]] && echo "- No mapped device found for VM volume $volume" && continue
        echo "- VM volume $volume mapped as $nbd_dev"
        nbd_devs+=( "$nbd_dev" )
    done
    echo "done."

    [[ ${#nbd_devs[@]} -eq 0 ]] && echo "No mapped volume found for VM $vm" && exit 0

    echo "Looking for LVM VG corresponding to mapped devices..."
    for nbd_dev in "${nbd_devs[@]}"; do
        local vgs vg
        mapfile -t vgs < <( pvs | grep -E "^\s*${nbd_dev}[\sp]" | awk '{print $2}' )
        [[ ${#vgs[@]} -eq 0 ]] && echo "- No VG found for mapped device $nbd_dev" && continue
        for vg in "${vgs[@]}"; do
            echo -n "- Disable VG $vg on $nbd_dev..."
            vgchange -an "$vg" || fatal_error "Failed to disable VG $vg on $nbd_dev"
        done
    done
    echo "done."

    echo "Unmap device(s)..."
    for nbd_dev in "${nbd_devs[@]}"; do
        echo -n "- $nbd_dev... "
        rbd-nbd unmap "$nbd_dev" || fatal_error "Failed to unmap $nbd_dev"
        echo "done."
    done
    echo "done."
}

subcommand__detach() {
    local vm=$1 volume=$2 hyp volume_target
    [[ -z "$vm" ]] && usage "VM name is missing"

    hyp=$( locate "$vm" )
    check_hyp "$hyp" || usage "Unknown VM $vm"

    [[ -z "$volume" ]] && usage "Volume path is missing"
    check_volume_path "$volume" || usage "Invalid volume path"
    volume_target=$(get_volume_target_from_path "$vm" "$volume" "$hyp") || \
        fatal_error "Volume $volume not use by VM $vm (or fail to detect its target)!"

    confirm "Detach volume $volume ($volume_target) of VM $vm on $hyp" || exit 1

    run_external ssh "$hyp" "$REAL_VIRSH" detach-disk "$vm" "$volume_target" --persistent --live || \
        fatal_error "Failed to detach volume $volume ($volume_target) of VM $vm on $hyp"
}

subcommand__rm() {
    local volume=$1
    [[ -z "$volume" ]] && usage "Volume path is missing"
    check_volume_path "$volume" || usage "Invalid volume path"
    rbd info "$volume" > /dev/null 2>&1 || usage "Unknown volume $volume"

    [[ $AUTO -eq 1 ]] && [[ $FORCE -ne 1 ]] && \
        fatal_error "Auto mode enabled without force mode, deny deleting volume." \
        "Run again this command with -F/--force parameter to force it."
    confirm "Delete volume $volume" || exit 1

    run_external rbd rm "$volume"
}

subcommand__locate() {
    check_generate_script_not_supported
    check_just_try_not_supported
    local pool=$1 volume=$2 rbd_prefix
    [[ -z "$pool" ]] && usage "Pool name is missing"
    [[ -z "$volume" ]] && usage "Volume name is missing"

    rbd_prefix=$(rbd -p "${pool}" info "${volume}" | grep block_name_prefix | awk '{print $2}')
    for i in $(rados -p "${pool}" ls | grep "${rbd_prefix}"); do
        ceph osd map "${pool}" "${i}"
    done
}

run_subcommand "${COMMAND_ARGS[@]}"
