Setting the file. One moment. Generate Test Traffic · AKS Network Capture · microsoft/azure-skills · Skills Docs Shellscripts/generate-test-traffic.sh
Shell·176 lines·6 KB
=
"default"
13DURATION="30s"
14INTERVAL="1"
15ALLOW_DEBUG_CONTAINER=0
16
17usage() {
18 cat <<EOF
19Usage: $0 --source-pod <pod> --target <ip-or-hostname> [options]
20
21Required:
22 --source-pod <name> Source pod
23 --target <host> Target IP address or hostname
24
25Options:
26 --type <type> http, https, dns, tcp, or ping (default: http)
27 --target-port <1-65535> Target port; required for tcp
28 --source-namespace <ns> Source namespace (default: default)
29 --duration <Ns|Nm|Nh> Duration (default: 30s; maximum: 1h)
30 --interval <seconds> Whole seconds between attempts (default: 1)
31 --allow-debug-container Use an ephemeral debug container after separate approval
32 -h, --help Show this help
33EOF
34}
35
36usage_error() {
37 echo "Error: $*" >&2
38 usage >&2
39 exit 2
40}
41
42die() {
43 echo "Error: $*" >&2
44 exit 1
45}
46
47require_value() {
48 [ "$#" -ge 2 ] && [ -n "$2" ] || usage_error "$1 requires a value"
49}
50
51valid_single_line() {
52 case "$1" in
53 *$'\r'*|*$'\n'*) return 1 ;;
54 esac
55}
56
57valid_rfc1123() {
58 valid_single_line "$1" && [ "${#1}" -le 253 ] \
59 && printf '%s' "$1" \
60 | grep -Eq '^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
61}
62
63valid_host() {
64 valid_single_line "$1" && [ "${#1}" -le 253 ] \
65 && printf '%s' "$1" | grep -Eq '^[A-Za-z0-9._:-]+$'
66}
67
68valid_uint() {
69 valid_single_line "$1" && printf '%s' "$1" | grep -Eq '^[0-9]+$'
70}
71
72valid_duration() {
73 valid_single_line "$1" && printf '%s' "$1" | grep -Eq '^[0-9]+[smh]$'
74}
75
76duration_to_seconds() {
77 local duration="$1"
78 local number="${duration%[smh]}"
79 local unit="${duration##*[0-9]}"
80 number=$((10#$number))
81 case "$unit" in
82 s) printf '%s\n' "$number" ;;
83 m) printf '%s\n' "$((number * 60))" ;;
84 h) printf '%s\n' "$((number * 3600))" ;;
85 esac
86}
87
88while [ "$#" -gt 0 ]; do
89 case "$1" in
90 --source-pod)
91 require_value "$@"; SOURCE_POD="$2"; shift 2 ;;
92 --source-namespace)
93 require_value "$@"; SOURCE_NAMESPACE="$2"; shift 2 ;;
94 --target)
95 require_value "$@"; TARGET="$2"; shift 2 ;;
96 --target-port)
97 require_value "$@"; TARGET_PORT="$2"; shift 2 ;;
98 --type)
99 require_value "$@"; TRAFFIC_TYPE="$2"; shift 2 ;;
100 --duration)
101 require_value "$@"; DURATION="$2"; shift 2 ;;
102 --interval)
103 require_value "$@"; INTERVAL="$2"; shift 2 ;;
104 --allow-debug-container)
105 ALLOW_DEBUG_CONTAINER=1; shift ;;
106 -h|--help)
107 usage; exit 0 ;;
108 *)
109 usage_error "unknown option: $1" ;;
110 esac
111done
112
113[ -n "$SOURCE_POD" ] || usage_error "--source-pod is required"
114[ -n "$TARGET" ] || usage_error "--target is required"
115valid_rfc1123 "$SOURCE_POD" || usage_error "--source-pod must be a DNS subdomain"
116valid_rfc1123 "$SOURCE_NAMESPACE" || usage_error "--source-namespace must be a DNS subdomain"
117valid_host "$TARGET" || usage_error "--target has invalid characters"
118valid_duration "$DURATION" || usage_error "--duration must look like 30s, 5m, or 1h"
119DURATION_SECONDS="$(duration_to_seconds "$DURATION")"
120[ "$DURATION_SECONDS" -ge 1 ] && [ "$DURATION_SECONDS" -le 3600 ] \
121 || usage_error "--duration must be between 1s and 1h"
122valid_uint "$INTERVAL" || usage_error "--interval must be a non-negative integer"
123
124case "$TRAFFIC_TYPE" in
125 dns) TARGET_PORT="${TARGET_PORT:-53}" ;;
126 https) TARGET_PORT="${TARGET_PORT:-443}" ;;
127 http) TARGET_PORT="${TARGET_PORT:-80}" ;;
128 tcp) [ -n "$TARGET_PORT" ] || usage_error "--target-port is required for tcp" ;;
129 ping) TARGET_PORT="0" ;;
130 *) usage_error "--type must be one of: http https dns tcp ping" ;;
131esac
132valid_uint "$TARGET_PORT" || usage_error "--target-port must be an integer"
133if [ "$TRAFFIC_TYPE" != "ping" ]; then
134 [ "$TARGET_PORT" -ge 1 ] && [ "$TARGET_PORT" -le 65535 ] \
135 || usage_error "--target-port must be between 1 and 65535"
136fi
137
138command -v kubectl >/dev/null 2>&1 || die "kubectl is not installed or not on PATH"
139
140# This fixed script must expand only inside the target pod.
141# shellcheck disable=SC2016
142POD_SCRIPT='
143set -u
144target="$1"; port="$2"; duration="$3"; interval="$4"; traffic_type="$5"
145case "$target" in *:*) url_host="[$target]";; *) url_host="$target";; esac
146end=$(( $(date +%s) + duration ))
147while [ "$(date +%s)" -lt "$end" ]; do
148 case "$traffic_type" in
149 http) wget -q -O /dev/null -T 5 "http://$url_host:$port/" && echo "http ok" || echo "http fail" ;;
150 https) wget -q -O /dev/null -T 5 --no-check-certificate "https://$url_host:$port/" && echo "https ok" || echo "https fail" ;;
151 dns) nslookup "$target" >/dev/null 2>&1 && echo "dns ok" || echo "dns fail" ;;
152 tcp) nc -z -w 5 "$target" "$port" && echo "tcp ok" || echo "tcp fail" ;;
153 ping) ping -c 1 -W 5 "$target" >/dev/null 2>&1 && echo "ping ok" || echo "ping fail" ;;
154 esac
155 [ "$interval" -eq 0 ] || sleep "$interval"
156done
157'
158
159echo "Generating $TRAFFIC_TYPE traffic from $SOURCE_POD to $TARGET for ${DURATION_SECONDS}s"
160if kubectl exec -n "$SOURCE_NAMESPACE" "$SOURCE_POD" -- sh -c 'exit 0' >/dev/null 2>&1; then
161 kubectl exec -n "$SOURCE_NAMESPACE" "$SOURCE_POD" -- \
162 sh -c "$POD_SCRIPT" _ "$TARGET" "$TARGET_PORT" "$DURATION_SECONDS" "$INTERVAL" "$TRAFFIC_TYPE"
163else
164 [ "$ALLOW_DEBUG_CONTAINER" -eq 1 ] || die \
165 "direct pod exec is unavailable; obtain separate approval before retrying with --allow-debug-container"
166 if ! target_container="$(kubectl get pod -n "$SOURCE_NAMESPACE" "$SOURCE_POD" \
167 -o jsonpath='{.spec.containers[0].name}')"; then
168 die "could not resolve the source pod container"
169 fi
170 [ -n "$target_container" ] || die "source pod has no application container"
171 kubectl debug -n "$SOURCE_NAMESPACE" "$SOURCE_POD" \
172 --image="$DEBUG_IMAGE" --target="$target_container" -q -- \
173 sh -c "$POD_SCRIPT" _ "$TARGET" "$TARGET_PORT" "$DURATION_SECONDS" "$INTERVAL" "$TRAFFIC_TYPE"
174fi
175
176echo "Traffic generation complete"