Files
portfolio/infra-run/scripts/bash/veritas/00_env.sh
T

239 lines
4.4 KiB
Bash
Raw Normal View History

#!/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
}