Skip to content

Commit 061ae11

Browse files
committed
add interface up and teardown option to ci script
1 parent 91a227f commit 061ae11

File tree

3 files changed

+195
-113
lines changed

3 files changed

+195
-113
lines changed

controllers/ext_client.go

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -466,23 +466,6 @@ func getExtClientHAConf(w http.ResponseWriter, r *http.Request) {
466466
extclient.IngressGatewayID = targetGwID
467467
extclient.Network = networkid
468468
extclient.Tags = make(map[models.TagID]struct{})
469-
// extclient.Tags[models.TagID(fmt.Sprintf("%s.%s", extclient.Network,
470-
// models.RemoteAccessTagName))] = struct{}{}
471-
// set extclient dns to ingressdns if extclient dns is not explicitly set
472-
if (extclient.DNS == "") && (gwnode.IngressDNS != "") {
473-
network, _ := logic.GetNetwork(gwnode.Network)
474-
dns := gwnode.IngressDNS
475-
if len(network.NameServers) > 0 {
476-
if dns == "" {
477-
dns = strings.Join(network.NameServers, ",")
478-
} else {
479-
dns += "," + strings.Join(network.NameServers, ",")
480-
}
481-
482-
}
483-
extclient.DNS = dns
484-
485-
}
486469

487470
listenPort := logic.GetPeerListenPort(host)
488471
extclient.IngressGatewayEndpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), listenPort)
@@ -506,6 +489,11 @@ func getExtClientHAConf(w http.ResponseWriter, r *http.Request) {
506489
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
507490
return
508491
}
492+
logic.SetDNSOnWgConfig(&gwnode, &client)
493+
defaultDNS := ""
494+
if client.DNS != "" {
495+
defaultDNS = "DNS = " + client.DNS
496+
}
509497
addrString := client.Address
510498
if addrString != "" {
511499
addrString += "/32"
@@ -551,13 +539,6 @@ func getExtClientHAConf(w http.ResponseWriter, r *http.Request) {
551539
} else {
552540
gwendpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), host.ListenPort)
553541
}
554-
defaultDNS := ""
555-
if client.DNS != "" {
556-
defaultDNS = "DNS = " + client.DNS
557-
} else if gwnode.IngressDNS != "" {
558-
defaultDNS = "DNS = " + gwnode.IngressDNS
559-
}
560-
561542
defaultMTU := 1420
562543
if host.MTU != 0 {
563544
defaultMTU = host.MTU
@@ -630,6 +611,7 @@ Endpoint = %s
630611

631612
name := client.ClientID + ".conf"
632613
w.Header().Set("Content-Type", "application/config")
614+
w.Header().Set("Client-ID", client.ClientID)
633615
w.Header().Set("Content-Disposition", "attachment; filename=\""+name+"\"")
634616
w.WriteHeader(http.StatusOK)
635617
_, err = fmt.Fprint(w, config)

scripts/ci-runner.sh

Lines changed: 0 additions & 89 deletions
This file was deleted.

scripts/netmaker-ci-runner.sh

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
#!/usr/bin/env bash
2+
# Netmaker CI helper: bring WireGuard up/down and manage ephemeral client lifecycle.
3+
# Subcommands:
4+
# up - fetch config, capture Client-ID, bring interface up, save state
5+
# down - bring interface down, delete local conf, delete client via API
6+
#
7+
# Env vars (can be overridden by flags):
8+
# NETMAKER_BASE_URL (required) e.g. https://nm.example.com or pass --base-url
9+
# NETMAKER_NETWORK (required) e.g. corpnet or pass --network
10+
# NETMAKER_API_JWT (required) Bearer token or pass --jwt
11+
# WG_IFACE (default netmaker) or pass --iface
12+
# WG_CONF_DIR (default /etc/wireguard) or pass --confdir
13+
# NETMAKER_STATE_FILE (default RUNNER_TEMP or /tmp)
14+
# You may also pass --client-id on `down` to avoid relying on the state file.
15+
16+
set -euo pipefail
17+
18+
# ---------- defaults ----------
19+
WG_IFACE="${WG_IFACE:-netmaker}"
20+
WG_CONF_DIR="${WG_CONF_DIR:-/etc/wireguard}"
21+
SUBCMD=""
22+
CLIENT_ID_OVERRIDE=""
23+
24+
usage() {
25+
cat <<USAGE
26+
Usage:
27+
$0 up [--iface IFACE] [--confdir DIR] [--base-url URL] [--network NET] [--jwt TOKEN]
28+
$0 down [--iface IFACE] [--confdir DIR] [--base-url URL] [--network NET] [--jwt TOKEN] [--client-id ID]
29+
30+
Flags override env vars. Env vars documented at top of the script.
31+
Examples:
32+
NETMAKER_BASE_URL=https://nm.example.com NETMAKER_NETWORK=corpnet NETMAKER_API_JWT=... $0 up
33+
$0 down --base-url https://nm.example.com --network corpnet --jwt ... --client-id icy-water
34+
USAGE
35+
}
36+
37+
# ---------- arg parse ----------
38+
if [[ $# -lt 1 ]]; then usage; exit 2; fi
39+
SUBCMD="$1"; shift || true
40+
41+
while [[ $# -gt 0 ]]; do
42+
case "$1" in
43+
--iface) WG_IFACE="$2"; shift 2;;
44+
--confdir) WG_CONF_DIR="$2"; shift 2;;
45+
--base-url) NETMAKER_BASE_URL="$2"; shift 2;;
46+
--network) NETMAKER_NETWORK="$2"; shift 2;;
47+
--jwt) NETMAKER_API_JWT="$2"; shift 2;;
48+
--client-id) CLIENT_ID_OVERRIDE="$2"; shift 2;;
49+
-h|--help) usage; exit 0;;
50+
*) echo "Unknown arg: $1" >&2; usage; exit 2;;
51+
esac
52+
done
53+
54+
STATE_FILE="${NETMAKER_STATE_FILE:-${RUNNER_TEMP:-/tmp}/netmaker_ci_${WG_IFACE}.env}"
55+
56+
require_env() {
57+
: "${NETMAKER_BASE_URL:?ERROR: NETMAKER_BASE_URL not set}"
58+
: "${NETMAKER_NETWORK:?ERROR: NETMAKER_NETWORK not set}"
59+
: "${NETMAKER_API_JWT:?ERROR: NETMAKER_API_JWT not set}"
60+
}
61+
62+
install_deps() {
63+
echo "[*] Checking dependencies ..."
64+
local need=(curl jq wg-quick ip)
65+
local miss=()
66+
for b in "${need[@]}"; do command -v "$b" >/dev/null 2>&1 || miss+=("$b"); done
67+
if [[ ${#miss[@]} -eq 0 ]]; then
68+
echo "[*] All dependencies present."
69+
return
70+
fi
71+
echo "[*] Installing missing deps: ${miss[*]}"
72+
if command -v apt-get >/dev/null 2>&1; then
73+
sudo apt-get update -y
74+
sudo apt-get install -y wireguard-tools jq curl iproute2 resolvconf
75+
elif command -v yum >/dev/null 2>&1; then
76+
sudo yum install -y wireguard-tools jq curl iproute iproute-tc
77+
elif command -v dnf >/dev/null 2>&1; then
78+
sudo dnf install -y wireguard-tools jq curl iproute
79+
else
80+
echo "ERROR: no supported package manager found; install: curl jq wireguard-tools iproute" >&2
81+
exit 1
82+
fi
83+
}
84+
85+
do_up() {
86+
require_env
87+
install_deps
88+
89+
local ep="${NETMAKER_BASE_URL}/api/v1/client_conf/${NETMAKER_NETWORK}"
90+
local tmp_conf="/tmp/${WG_IFACE}.conf"
91+
local tmp_hdr="/tmp/${WG_IFACE}.headers"
92+
93+
echo "[*] Requesting client config: ${ep}"
94+
# Optional headers
95+
declare -a hdrs
96+
hdrs=(-H "Authorization: Bearer ${NETMAKER_API_JWT}")
97+
[[ -n "${NM_CLIENT_LABEL:-}" ]] && hdrs+=(-H "X-NM-Client-Label: ${NM_CLIENT_LABEL}")
98+
[[ -n "${NM_REQUESTED_NAME:-}" ]] && hdrs+=(-H "X-NM-Requested-Name: ${NM_REQUESTED_NAME}")
99+
100+
local code
101+
code="$(curl -sS -L --dump-header "${tmp_hdr}" -w '%{http_code}' -o "${tmp_conf}" "${hdrs[@]}" "${ep}")"
102+
if [[ "${code}" != "200" ]]; then
103+
echo "ERROR: client_conf HTTP ${code}" >&2
104+
curl -sS -L "${hdrs[@]}" "${ep}" | head -c 400 >&2 || true
105+
exit 1
106+
fi
107+
grep -q "^\[Interface\]" "${tmp_conf}" || { echo "ERROR: not a WireGuard conf"; head -n 20 "${tmp_conf}"; exit 1; }
108+
109+
# --- Extract Client-ID (one-liner, trim spaces/quotes) ---
110+
local client_id
111+
client_id="$(grep -i '^Client-ID:' "${tmp_hdr}" | head -n1 | cut -d: -f2- | tr -d '\r' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/^"//; s/"$//' -e "s/^'//; s/'$//")"
112+
if [[ -z "${client_id}" ]]; then
113+
echo "ERROR: Client-ID header missing in response; cannot manage lifecycle." >&2
114+
exit 1
115+
fi
116+
echo "[*] Client-ID: ${client_id}"
117+
118+
# Optional marker
119+
if ! grep -q "^#interface-name=" "${tmp_conf}"; then
120+
echo "#interface-name=${WG_IFACE}" | cat - "${tmp_conf}" > "${tmp_conf}.tmp" && mv "${tmp_conf}.tmp" "${tmp_conf}"
121+
fi
122+
123+
# Install & bring up
124+
sudo mkdir -p "${WG_CONF_DIR}"
125+
sudo mv "${tmp_conf}" "${WG_CONF_DIR}/${WG_IFACE}.conf"
126+
sudo chmod 600 "${WG_CONF_DIR}/${WG_IFACE}.conf"
127+
echo "[*] Bringing up ${WG_IFACE} ..."
128+
sudo wg-quick up "${WG_IFACE}"
129+
130+
echo "==== ${WG_IFACE} is up ===="
131+
ip addr show "${WG_IFACE}" || true
132+
wg show "${WG_IFACE}" || true
133+
134+
# Persist state
135+
cat > "${STATE_FILE}" <<EOF
136+
NETMAKER_BASE_URL='${NETMAKER_BASE_URL}'
137+
NETMAKER_NETWORK='${NETMAKER_NETWORK}'
138+
NETMAKER_API_JWT='${NETMAKER_API_JWT}'
139+
WG_IFACE='${WG_IFACE}'
140+
WG_CONF_DIR='${WG_CONF_DIR}'
141+
CLIENT_ID='${client_id}'
142+
EOF
143+
chmod 600 "${STATE_FILE}"
144+
echo "[*] Saved state: ${STATE_FILE}"
145+
}
146+
147+
do_down() {
148+
# Load state if present; flags/env can still override
149+
if [[ -f "${STATE_FILE}" ]]; then
150+
# shellcheck disable=SC1090
151+
source "${STATE_FILE}"
152+
fi
153+
154+
require_env
155+
156+
local client_id="${CLIENT_ID_OVERRIDE:-${CLIENT_ID:-}}"
157+
echo "[*] Bringing down ${WG_IFACE} ..."
158+
sudo wg-quick down "${WG_IFACE}" || echo "WARN: wg-quick down failed (already down?)."
159+
160+
# Remove local conf
161+
if [[ -f "${WG_CONF_DIR}/${WG_IFACE}.conf" ]]; then
162+
sudo shred -u "${WG_CONF_DIR}/${WG_IFACE}.conf" 2>/dev/null || sudo rm -f "${WG_CONF_DIR}/${WG_IFACE}.conf"
163+
fi
164+
165+
# Delete ephemeral client on server (if we know its ID)
166+
if [[ -n "${client_id}" ]]; then
167+
local del_ep="${NETMAKER_BASE_URL}/api/extclients/${NETMAKER_NETWORK}/${client_id}"
168+
echo "[*] Deleting client: DELETE ${del_ep}"
169+
local http
170+
http="$(curl -sS -o /dev/null -w '%{http_code}' -X DELETE -H "Authorization: Bearer ${NETMAKER_API_JWT}" "${del_ep}")"
171+
if [[ "${http}" =~ ^20[0-9]$ ]]; then
172+
echo "[*] Client deleted (HTTP ${http})."
173+
else
174+
echo "WARN: deletion returned HTTP ${http}; verify server state."
175+
fi
176+
else
177+
echo "WARN: client id not known (missing --client-id and state file); skipping server delete."
178+
fi
179+
180+
rm -f "${STATE_FILE}" || true
181+
echo "[*] Teardown finished."
182+
}
183+
184+
case "${SUBCMD}" in
185+
up) do_up ;;
186+
down) do_down ;;
187+
*) usage; exit 2 ;;
188+
esac
189+

0 commit comments

Comments
 (0)