239 lines
4.4 KiB
Bash
Executable File
239 lines
4.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -o errexit
|
|
set -o nounset
|
|
set -o pipefail
|
|
|
|
DRY_RUN=true
|
|
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
|
|
LOG_FILE="${LOG_FILE:-/tmp/veritas_extend_${TIMESTAMP}.log}"
|
|
|
|
SERVICE_GROUP=""
|
|
DISKGROUP=""
|
|
VOLUME=""
|
|
MOUNTPOINT=""
|
|
SIZE=""
|
|
DISKS=""
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
log() {
|
|
local level="${1:-INFO}"
|
|
shift || true
|
|
local message="$*"
|
|
local line
|
|
|
|
line="$(printf '%s [%s] %s' "$(date '+%Y-%m-%d %H:%M:%S')" "$level" "$message")"
|
|
printf '%s\n' "$line"
|
|
printf '%s\n' "$line" >> "$LOG_FILE"
|
|
}
|
|
|
|
ok() {
|
|
log "OK" "$*"
|
|
}
|
|
|
|
warning() {
|
|
log "WARNING" "$*"
|
|
}
|
|
|
|
critical() {
|
|
log "CRITICAL" "$*"
|
|
}
|
|
|
|
require_cmd() {
|
|
local cmd="$1"
|
|
|
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
|
critical "required command not found: $cmd"
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
run_cmd() {
|
|
local description="$1"
|
|
shift
|
|
|
|
if (( "$#" == 0 )); then
|
|
critical "run_cmd called without a command"
|
|
return 2
|
|
fi
|
|
|
|
log "INFO" "$description"
|
|
log "INFO" "command: $*"
|
|
|
|
if [[ "$DRY_RUN" == "true" ]]; then
|
|
log "INFO" "DRY-RUN: command not executed"
|
|
return 0
|
|
fi
|
|
|
|
"$@" 2>&1 | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
confirm_execute() {
|
|
local prompt="${1:-Type EXECUTE to continue with real changes}"
|
|
local answer=""
|
|
|
|
if [[ "$DRY_RUN" == "true" ]]; then
|
|
ok "dry-run mode active; confirmation not required"
|
|
return 0
|
|
fi
|
|
|
|
warning "real execution mode requested with --execute"
|
|
warning "$prompt"
|
|
printf 'Type EXECUTE to continue: '
|
|
read -r answer
|
|
|
|
if [[ "$answer" != "EXECUTE" ]]; then
|
|
critical "confirmation failed; no changes made"
|
|
exit 2
|
|
fi
|
|
}
|
|
|
|
usage_common() {
|
|
cat <<'USAGE'
|
|
Common options:
|
|
--sg <service_group>
|
|
--dg <diskgroup>
|
|
--vol <volume>
|
|
--mount <mountpoint>
|
|
--size <+SIZE>
|
|
--disks "disk1 disk2"
|
|
--execute
|
|
--help
|
|
USAGE
|
|
}
|
|
|
|
parse_common_args() {
|
|
while (( "$#" > 0 )); do
|
|
case "$1" in
|
|
--sg)
|
|
if [[ -z "${2:-}" ]]; then
|
|
critical "missing value for --sg"
|
|
exit 2
|
|
fi
|
|
SERVICE_GROUP="${2:-}"
|
|
shift 2
|
|
;;
|
|
--dg)
|
|
if [[ -z "${2:-}" ]]; then
|
|
critical "missing value for --dg"
|
|
exit 2
|
|
fi
|
|
DISKGROUP="${2:-}"
|
|
shift 2
|
|
;;
|
|
--vol)
|
|
if [[ -z "${2:-}" ]]; then
|
|
critical "missing value for --vol"
|
|
exit 2
|
|
fi
|
|
VOLUME="${2:-}"
|
|
shift 2
|
|
;;
|
|
--mount)
|
|
if [[ -z "${2:-}" ]]; then
|
|
critical "missing value for --mount"
|
|
exit 2
|
|
fi
|
|
MOUNTPOINT="${2:-}"
|
|
shift 2
|
|
;;
|
|
--size)
|
|
if [[ -z "${2:-}" ]]; then
|
|
critical "missing value for --size"
|
|
exit 2
|
|
fi
|
|
SIZE="${2:-}"
|
|
shift 2
|
|
;;
|
|
--disks)
|
|
if [[ -z "${2:-}" ]]; then
|
|
critical "missing value for --disks"
|
|
exit 2
|
|
fi
|
|
DISKS="${2:-}"
|
|
shift 2
|
|
;;
|
|
--execute)
|
|
DRY_RUN=false
|
|
shift
|
|
;;
|
|
--help|-h)
|
|
usage_common
|
|
exit 0
|
|
;;
|
|
*)
|
|
critical "unknown argument: $1"
|
|
usage_common
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
require_nonempty() {
|
|
local value="$1"
|
|
local name="$2"
|
|
|
|
if [[ -z "$value" ]]; then
|
|
critical "missing required argument: $name"
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
require_inputs() {
|
|
local failed=0
|
|
local name
|
|
|
|
for name in "$@"; do
|
|
case "$name" in
|
|
sg) require_nonempty "$SERVICE_GROUP" "--sg" || failed=1 ;;
|
|
dg) require_nonempty "$DISKGROUP" "--dg" || failed=1 ;;
|
|
vol) require_nonempty "$VOLUME" "--vol" || failed=1 ;;
|
|
mount) require_nonempty "$MOUNTPOINT" "--mount" || failed=1 ;;
|
|
size) require_nonempty "$SIZE" "--size" || failed=1 ;;
|
|
disks) require_nonempty "$DISKS" "--disks" || failed=1 ;;
|
|
*) critical "internal error: unknown required input '$name'"; failed=1 ;;
|
|
esac
|
|
done
|
|
|
|
if (( failed != 0 )); then
|
|
usage_common
|
|
exit 2
|
|
fi
|
|
}
|
|
|
|
has_cmd() {
|
|
command -v "$1" >/dev/null 2>&1
|
|
}
|
|
|
|
capture_cmd() {
|
|
local description="$1"
|
|
shift
|
|
|
|
log "INFO" "$description"
|
|
log "INFO" "command: $*"
|
|
"$@" 2>&1 | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
disk_status_line() {
|
|
local disk="$1"
|
|
vxdisk list "$disk" 2>/dev/null | awk -F': *' '
|
|
/device:/ {device=$2}
|
|
/status:/ {status=$2}
|
|
END {
|
|
if (device != "" || status != "") {
|
|
print device "|" status
|
|
}
|
|
}'
|
|
}
|
|
|
|
vxprint_volume_device() {
|
|
local dg="$1"
|
|
local vol="$2"
|
|
vxprint -g "$dg" -F '%device' "$vol" 2>/dev/null || true
|
|
}
|