|
|
@@ -10,6 +10,8 @@ PREFIX=""
|
|
|
GATEWAY=""
|
|
|
DNS_CSV=""
|
|
|
DO_APPLY=0
|
|
|
+DHCP4=0
|
|
|
+APPLY_DECISION="confirm"
|
|
|
|
|
|
usage() {
|
|
|
cat <<'EOF'
|
|
|
@@ -25,9 +27,11 @@ Default behavior:
|
|
|
|
|
|
Validate only:
|
|
|
linux-smoke-test.sh --interface ens33 --ip 192.168.10.20 --prefix 24 --gateway 192.168.10.1 --dns 8.8.8.8,1.1.1.1
|
|
|
+ linux-smoke-test.sh --interface ens33 --dhcp4
|
|
|
|
|
|
Apply and poll task:
|
|
|
linux-smoke-test.sh --interface ens33 --ip 192.168.10.20 --prefix 24 --gateway 192.168.10.1 --dns 8.8.8.8,1.1.1.1 --apply
|
|
|
+ linux-smoke-test.sh --interface ens33 --dhcp4 --apply
|
|
|
|
|
|
Options:
|
|
|
--host <ip> Server host, default: 169.254.100.2
|
|
|
@@ -38,12 +42,15 @@ Options:
|
|
|
--prefix <cidr> Prefix length for validate/apply
|
|
|
--gateway <ipv4> Optional gateway
|
|
|
--dns <csv> Optional DNS CSV, e.g. 8.8.8.8,1.1.1.1
|
|
|
+ --dhcp4 Validate/apply DHCP IPv4 mode instead of static IPv4
|
|
|
--apply Actually call /api/network/apply after validate
|
|
|
+ --cancel-apply With --apply, cancel at confirmation step and expect rollback
|
|
|
--help Show this help
|
|
|
|
|
|
Notes:
|
|
|
- Without --apply, the script never changes netplan.
|
|
|
- - With --apply, the server will rewrite netplan YAML and run netplan apply.
|
|
|
+ - With --apply, the server rewrites netplan YAML, runs netplan apply, then waits 20 seconds for confirmation.
|
|
|
+ - By default the script confirms apply tasks automatically when they enter confirming.
|
|
|
EOF
|
|
|
}
|
|
|
|
|
|
@@ -81,10 +88,18 @@ while [[ $# -gt 0 ]]; do
|
|
|
DNS_CSV="$2"
|
|
|
shift 2
|
|
|
;;
|
|
|
+ --dhcp4)
|
|
|
+ DHCP4=1
|
|
|
+ shift
|
|
|
+ ;;
|
|
|
--apply)
|
|
|
DO_APPLY=1
|
|
|
shift
|
|
|
;;
|
|
|
+ --cancel-apply)
|
|
|
+ APPLY_DECISION="cancel"
|
|
|
+ shift
|
|
|
+ ;;
|
|
|
--help|-h)
|
|
|
usage
|
|
|
exit 0
|
|
|
@@ -200,28 +215,40 @@ PY
|
|
|
}
|
|
|
|
|
|
build_payload() {
|
|
|
- python3 - "$INTERFACE" "$IP" "$PREFIX" "$GATEWAY" "$DNS_CSV" <<'PY'
|
|
|
+ python3 - "$INTERFACE" "$IP" "$PREFIX" "$GATEWAY" "$DNS_CSV" "$DHCP4" <<'PY'
|
|
|
import json
|
|
|
import sys
|
|
|
|
|
|
-interface, ip, prefix, gateway, dns_csv = sys.argv[1:6]
|
|
|
+interface, ip, prefix, gateway, dns_csv, dhcp4 = sys.argv[1:7]
|
|
|
+is_dhcp4 = dhcp4 == "1"
|
|
|
dns = [item.strip() for item in dns_csv.split(',') if item.strip()]
|
|
|
payload = {
|
|
|
"interface": interface,
|
|
|
- "ip": ip,
|
|
|
- "prefix": int(prefix),
|
|
|
- "gateway": gateway,
|
|
|
- "dns": dns,
|
|
|
+ "dhcp4": is_dhcp4,
|
|
|
+ "ip": "" if is_dhcp4 else ip,
|
|
|
+ "prefix": 0 if is_dhcp4 else int(prefix),
|
|
|
+ "gateway": "" if is_dhcp4 else gateway,
|
|
|
+ "dns": [] if is_dhcp4 else dns,
|
|
|
}
|
|
|
print(json.dumps(payload, ensure_ascii=False))
|
|
|
PY
|
|
|
}
|
|
|
|
|
|
+build_task_payload() {
|
|
|
+ python3 - "$1" <<'PY'
|
|
|
+import json
|
|
|
+import sys
|
|
|
+
|
|
|
+print(json.dumps({"task_id": sys.argv[1]}, ensure_ascii=False))
|
|
|
+PY
|
|
|
+}
|
|
|
+
|
|
|
poll_task() {
|
|
|
local task_id="$1"
|
|
|
local max_attempts=20
|
|
|
local attempt=1
|
|
|
local connection_failures=0
|
|
|
+ local confirmation_sent=0
|
|
|
|
|
|
while (( attempt <= max_attempts )); do
|
|
|
local result http_code body status step detail rollback
|
|
|
@@ -246,11 +273,38 @@ poll_task() {
|
|
|
rollback="$(json_get "$body" "data.rollback")"
|
|
|
log "task=${task_id} status=${status} step=${step} rollback=${rollback} detail=${detail}"
|
|
|
|
|
|
+ if [[ "$status" == "running" && "$step" == "confirming" && "$confirmation_sent" -eq 0 ]]; then
|
|
|
+ local decision_path decision_op decision_result decision_code decision_body
|
|
|
+ if [[ "$APPLY_DECISION" == "cancel" ]]; then
|
|
|
+ decision_path="/api/network/apply/cancel"
|
|
|
+ decision_op="cancel apply ${task_id}"
|
|
|
+ else
|
|
|
+ decision_path="/api/network/apply/confirm"
|
|
|
+ decision_op="confirm apply ${task_id}"
|
|
|
+ fi
|
|
|
+ log "task=${task_id} ${APPLY_DECISION} at confirmation step"
|
|
|
+ decision_result="$(request POST "$decision_path" "$(build_task_payload "$task_id")")"
|
|
|
+ decision_code="$(printf '%s\n' "$decision_result" | read_http_code)"
|
|
|
+ decision_body="$(printf '%s\n' "$decision_result" | read_body)"
|
|
|
+ assert_api_ok "$decision_op" "$decision_code" "$decision_body"
|
|
|
+ confirmation_sent=1
|
|
|
+ fi
|
|
|
+
|
|
|
case "$status" in
|
|
|
success)
|
|
|
+ if [[ "$APPLY_DECISION" == "cancel" ]]; then
|
|
|
+ echo "Expected rollback after cancel, but task succeeded: ${task_id}" >&2
|
|
|
+ return 1
|
|
|
+ fi
|
|
|
return 0
|
|
|
;;
|
|
|
- failed|rolled_back)
|
|
|
+ rolled_back)
|
|
|
+ if [[ "$APPLY_DECISION" == "cancel" ]]; then
|
|
|
+ return 0
|
|
|
+ fi
|
|
|
+ return 1
|
|
|
+ ;;
|
|
|
+ failed)
|
|
|
return 1
|
|
|
;;
|
|
|
esac
|
|
|
@@ -299,11 +353,11 @@ result="$(request GET "/api/network/config?interface=${INTERFACE}")"
|
|
|
http_code="$(printf '%s\n' "$result" | read_http_code)"
|
|
|
body="$(printf '%s\n' "$result" | read_body)"
|
|
|
assert_api_ok "config ${INTERFACE}" "$http_code" "$body"
|
|
|
-log "current ip=$(json_get "$body" "data.ip") prefix=$(json_get "$body" "data.prefix") gateway=$(json_get "$body" "data.gateway")"
|
|
|
+log "current dhcp4=$(json_get "$body" "data.dhcp4") ip=$(json_get "$body" "data.ip") prefix=$(json_get "$body" "data.prefix") gateway=$(json_get "$body" "data.gateway")"
|
|
|
|
|
|
-if [[ -n "$IP" || -n "$PREFIX" || -n "$GATEWAY" || -n "$DNS_CSV" || "$DO_APPLY" -eq 1 ]]; then
|
|
|
- if [[ -z "$IP" || -z "$PREFIX" ]]; then
|
|
|
- echo "--ip and --prefix are required for validate/apply" >&2
|
|
|
+if [[ -n "$IP" || -n "$PREFIX" || -n "$GATEWAY" || -n "$DNS_CSV" || "$DO_APPLY" -eq 1 || "$DHCP4" -eq 1 ]]; then
|
|
|
+ if [[ "$DHCP4" -eq 0 && ( -z "$IP" || -z "$PREFIX" ) ]]; then
|
|
|
+ echo "--ip and --prefix are required for static validate/apply; use --dhcp4 for DHCP mode" >&2
|
|
|
exit 2
|
|
|
fi
|
|
|
|
|
|
@@ -324,7 +378,11 @@ if [[ -n "$IP" || -n "$PREFIX" || -n "$GATEWAY" || -n "$DNS_CSV" || "$DO_APPLY"
|
|
|
task_id="$(json_get "$body" "data.task_id")"
|
|
|
log "apply submitted task_id=${task_id}"
|
|
|
poll_task "$task_id"
|
|
|
- log "apply task completed successfully"
|
|
|
+ if [[ "$APPLY_DECISION" == "cancel" ]]; then
|
|
|
+ log "apply task rolled back after cancellation as expected"
|
|
|
+ else
|
|
|
+ log "apply task completed successfully"
|
|
|
+ fi
|
|
|
fi
|
|
|
else
|
|
|
log "read-only smoke checks completed"
|