mirror of
https://github.com/gravitl/netmaker.git
synced 2025-09-26 21:01:32 +08:00
add interface up and teardown option to ci script
This commit is contained in:
@@ -466,23 +466,6 @@ func getExtClientHAConf(w http.ResponseWriter, r *http.Request) {
|
|||||||
extclient.IngressGatewayID = targetGwID
|
extclient.IngressGatewayID = targetGwID
|
||||||
extclient.Network = networkid
|
extclient.Network = networkid
|
||||||
extclient.Tags = make(map[models.TagID]struct{})
|
extclient.Tags = make(map[models.TagID]struct{})
|
||||||
// extclient.Tags[models.TagID(fmt.Sprintf("%s.%s", extclient.Network,
|
|
||||||
// models.RemoteAccessTagName))] = struct{}{}
|
|
||||||
// set extclient dns to ingressdns if extclient dns is not explicitly set
|
|
||||||
if (extclient.DNS == "") && (gwnode.IngressDNS != "") {
|
|
||||||
network, _ := logic.GetNetwork(gwnode.Network)
|
|
||||||
dns := gwnode.IngressDNS
|
|
||||||
if len(network.NameServers) > 0 {
|
|
||||||
if dns == "" {
|
|
||||||
dns = strings.Join(network.NameServers, ",")
|
|
||||||
} else {
|
|
||||||
dns += "," + strings.Join(network.NameServers, ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
extclient.DNS = dns
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
listenPort := logic.GetPeerListenPort(host)
|
listenPort := logic.GetPeerListenPort(host)
|
||||||
extclient.IngressGatewayEndpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), listenPort)
|
extclient.IngressGatewayEndpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), listenPort)
|
||||||
@@ -506,6 +489,11 @@ func getExtClientHAConf(w http.ResponseWriter, r *http.Request) {
|
|||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
logic.SetDNSOnWgConfig(&gwnode, &client)
|
||||||
|
defaultDNS := ""
|
||||||
|
if client.DNS != "" {
|
||||||
|
defaultDNS = "DNS = " + client.DNS
|
||||||
|
}
|
||||||
addrString := client.Address
|
addrString := client.Address
|
||||||
if addrString != "" {
|
if addrString != "" {
|
||||||
addrString += "/32"
|
addrString += "/32"
|
||||||
@@ -551,13 +539,6 @@ func getExtClientHAConf(w http.ResponseWriter, r *http.Request) {
|
|||||||
} else {
|
} else {
|
||||||
gwendpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), host.ListenPort)
|
gwendpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), host.ListenPort)
|
||||||
}
|
}
|
||||||
defaultDNS := ""
|
|
||||||
if client.DNS != "" {
|
|
||||||
defaultDNS = "DNS = " + client.DNS
|
|
||||||
} else if gwnode.IngressDNS != "" {
|
|
||||||
defaultDNS = "DNS = " + gwnode.IngressDNS
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultMTU := 1420
|
defaultMTU := 1420
|
||||||
if host.MTU != 0 {
|
if host.MTU != 0 {
|
||||||
defaultMTU = host.MTU
|
defaultMTU = host.MTU
|
||||||
@@ -630,6 +611,7 @@ Endpoint = %s
|
|||||||
|
|
||||||
name := client.ClientID + ".conf"
|
name := client.ClientID + ".conf"
|
||||||
w.Header().Set("Content-Type", "application/config")
|
w.Header().Set("Content-Type", "application/config")
|
||||||
|
w.Header().Set("Client-ID", client.ClientID)
|
||||||
w.Header().Set("Content-Disposition", "attachment; filename=\""+name+"\"")
|
w.Header().Set("Content-Disposition", "attachment; filename=\""+name+"\"")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_, err = fmt.Fprint(w, config)
|
_, err = fmt.Fprint(w, config)
|
||||||
|
@@ -1,89 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Fetch WireGuard config from Netmaker via /api/v1/client_conf/{network} and bring it up.
|
|
||||||
# Required env:
|
|
||||||
# NETMAKER_BASE_URL, NETMAKER_API_JWT, NETMAKER_NETWORK
|
|
||||||
# WG_IFACE (default: netmaker), WG_CONF_DIR (default: /etc/wireguard)
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# --- Fail fast if mandatory variables missing ---
|
|
||||||
: "${NETMAKER_BASE_URL:?ERROR: NETMAKER_BASE_URL not set}"
|
|
||||||
: "${NETMAKER_NETWORK:?ERROR: NETMAKER_NETWORK not set}"
|
|
||||||
: "${NETMAKER_API_JWT:?ERROR: NETMAKER_API_JWT not set}"
|
|
||||||
|
|
||||||
# --- Ensure required packages are present ---
|
|
||||||
echo "[*] Checking dependencies ..."
|
|
||||||
DEPS=(curl jq wg-quick ip)
|
|
||||||
MISSING=()
|
|
||||||
for bin in "${DEPS[@]}"; do
|
|
||||||
if ! command -v "$bin" >/dev/null 2>&1; then
|
|
||||||
MISSING+=("$bin")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ ${#MISSING[@]} -gt 0 ]]; then
|
|
||||||
echo "[*] Installing missing deps: ${MISSING[*]} ..."
|
|
||||||
if command -v apt-get >/dev/null 2>&1; then
|
|
||||||
sudo apt-get update -y
|
|
||||||
sudo apt-get install -y wireguard-tools jq curl iproute2 resolvconf
|
|
||||||
elif command -v yum >/dev/null 2>&1; then
|
|
||||||
sudo yum install -y wireguard-tools jq curl iproute iproute-tc
|
|
||||||
elif command -v dnf >/dev/null 2>&1; then
|
|
||||||
sudo dnf install -y wireguard-tools jq curl iproute
|
|
||||||
else
|
|
||||||
echo "ERROR: Package manager not found. Install ${MISSING[*]} manually." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "[*] All dependencies found."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Inputs & defaults ---
|
|
||||||
BASE_URL="${NETMAKER_BASE_URL:?NETMAKER_BASE_URL not set}"
|
|
||||||
NETWORK="${NETMAKER_NETWORK:?NETMAKER_NETWORK not set}"
|
|
||||||
JWT="${NETMAKER_API_JWT:?NETMAKER_API_JWT not set}"
|
|
||||||
WG_IFACE="${WG_IFACE:-netmaker}"
|
|
||||||
WG_CONF_DIR="${WG_CONF_DIR:-/etc/wireguard}"
|
|
||||||
TMP_CONF="/tmp/${WG_IFACE}.conf"
|
|
||||||
|
|
||||||
EP="${BASE_URL}/api/v1/client_conf/${NETWORK}"
|
|
||||||
|
|
||||||
echo "[*] Requesting client configuration from: ${EP}"
|
|
||||||
|
|
||||||
HDRS=(-H "Authorization: Bearer ${JWT}")
|
|
||||||
[[ -n "${NM_CLIENT_LABEL:-}" ]] && HDRS+=(-H "X-NM-Client-Label: ${NM_CLIENT_LABEL}")
|
|
||||||
[[ -n "${NM_REQUESTED_NAME:-}" ]] && HDRS+=(-H "X-NM-Requested-Name: ${NM_REQUESTED_NAME}")
|
|
||||||
|
|
||||||
# --- Fetch config ---
|
|
||||||
HTTP_STATUS="$(curl -sS -L -w '%{http_code}' -o "${TMP_CONF}" "${HDRS[@]}" "${EP}")"
|
|
||||||
|
|
||||||
if [[ "${HTTP_STATUS}" != "200" ]]; then
|
|
||||||
echo "ERROR: client_conf returned HTTP ${HTTP_STATUS}" >&2
|
|
||||||
curl -sS -L "${HDRS[@]}" "${EP}" | head -c 400 >&2 || true
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Sanity check ---
|
|
||||||
if ! grep -q "^\[Interface\]" "${TMP_CONF}"; then
|
|
||||||
echo "ERROR: Response does not look like a WireGuard config." >&2
|
|
||||||
head -n 20 "${TMP_CONF}" >&2 || true
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Add interface-name for traceability ---
|
|
||||||
if ! grep -q "^#interface-name=" "${TMP_CONF}"; then
|
|
||||||
echo "#interface-name=${WG_IFACE}" | cat - "${TMP_CONF}" > "${TMP_CONF}.tmp" && mv "${TMP_CONF}.tmp" "${TMP_CONF}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Move into place ---
|
|
||||||
sudo mkdir -p "${WG_CONF_DIR}"
|
|
||||||
sudo mv "${TMP_CONF}" "${WG_CONF_DIR}/${WG_IFACE}.conf"
|
|
||||||
sudo chmod 600 "${WG_CONF_DIR}/${WG_IFACE}.conf"
|
|
||||||
|
|
||||||
# --- Bring it up ---
|
|
||||||
echo "[*] Bringing up ${WG_IFACE} ..."
|
|
||||||
sudo wg-quick up "${WG_IFACE}"
|
|
||||||
|
|
||||||
echo "==== ${WG_IFACE} is up ===="
|
|
||||||
ip addr show "${WG_IFACE}" || true
|
|
||||||
wg show "${WG_IFACE}" || true
|
|
189
scripts/netmaker-ci-runner.sh
Normal file
189
scripts/netmaker-ci-runner.sh
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Netmaker CI helper: bring WireGuard up/down and manage ephemeral client lifecycle.
|
||||||
|
# Subcommands:
|
||||||
|
# up - fetch config, capture Client-ID, bring interface up, save state
|
||||||
|
# down - bring interface down, delete local conf, delete client via API
|
||||||
|
#
|
||||||
|
# Env vars (can be overridden by flags):
|
||||||
|
# NETMAKER_BASE_URL (required) e.g. https://nm.example.com or pass --base-url
|
||||||
|
# NETMAKER_NETWORK (required) e.g. corpnet or pass --network
|
||||||
|
# NETMAKER_API_JWT (required) Bearer token or pass --jwt
|
||||||
|
# WG_IFACE (default netmaker) or pass --iface
|
||||||
|
# WG_CONF_DIR (default /etc/wireguard) or pass --confdir
|
||||||
|
# NETMAKER_STATE_FILE (default RUNNER_TEMP or /tmp)
|
||||||
|
# You may also pass --client-id on `down` to avoid relying on the state file.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ---------- defaults ----------
|
||||||
|
WG_IFACE="${WG_IFACE:-netmaker}"
|
||||||
|
WG_CONF_DIR="${WG_CONF_DIR:-/etc/wireguard}"
|
||||||
|
SUBCMD=""
|
||||||
|
CLIENT_ID_OVERRIDE=""
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<USAGE
|
||||||
|
Usage:
|
||||||
|
$0 up [--iface IFACE] [--confdir DIR] [--base-url URL] [--network NET] [--jwt TOKEN]
|
||||||
|
$0 down [--iface IFACE] [--confdir DIR] [--base-url URL] [--network NET] [--jwt TOKEN] [--client-id ID]
|
||||||
|
|
||||||
|
Flags override env vars. Env vars documented at top of the script.
|
||||||
|
Examples:
|
||||||
|
NETMAKER_BASE_URL=https://nm.example.com NETMAKER_NETWORK=corpnet NETMAKER_API_JWT=... $0 up
|
||||||
|
$0 down --base-url https://nm.example.com --network corpnet --jwt ... --client-id icy-water
|
||||||
|
USAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------- arg parse ----------
|
||||||
|
if [[ $# -lt 1 ]]; then usage; exit 2; fi
|
||||||
|
SUBCMD="$1"; shift || true
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--iface) WG_IFACE="$2"; shift 2;;
|
||||||
|
--confdir) WG_CONF_DIR="$2"; shift 2;;
|
||||||
|
--base-url) NETMAKER_BASE_URL="$2"; shift 2;;
|
||||||
|
--network) NETMAKER_NETWORK="$2"; shift 2;;
|
||||||
|
--jwt) NETMAKER_API_JWT="$2"; shift 2;;
|
||||||
|
--client-id) CLIENT_ID_OVERRIDE="$2"; shift 2;;
|
||||||
|
-h|--help) usage; exit 0;;
|
||||||
|
*) echo "Unknown arg: $1" >&2; usage; exit 2;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
STATE_FILE="${NETMAKER_STATE_FILE:-${RUNNER_TEMP:-/tmp}/netmaker_ci_${WG_IFACE}.env}"
|
||||||
|
|
||||||
|
require_env() {
|
||||||
|
: "${NETMAKER_BASE_URL:?ERROR: NETMAKER_BASE_URL not set}"
|
||||||
|
: "${NETMAKER_NETWORK:?ERROR: NETMAKER_NETWORK not set}"
|
||||||
|
: "${NETMAKER_API_JWT:?ERROR: NETMAKER_API_JWT not set}"
|
||||||
|
}
|
||||||
|
|
||||||
|
install_deps() {
|
||||||
|
echo "[*] Checking dependencies ..."
|
||||||
|
local need=(curl jq wg-quick ip)
|
||||||
|
local miss=()
|
||||||
|
for b in "${need[@]}"; do command -v "$b" >/dev/null 2>&1 || miss+=("$b"); done
|
||||||
|
if [[ ${#miss[@]} -eq 0 ]]; then
|
||||||
|
echo "[*] All dependencies present."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo "[*] Installing missing deps: ${miss[*]}"
|
||||||
|
if command -v apt-get >/dev/null 2>&1; then
|
||||||
|
sudo apt-get update -y
|
||||||
|
sudo apt-get install -y wireguard-tools jq curl iproute2 resolvconf
|
||||||
|
elif command -v yum >/dev/null 2>&1; then
|
||||||
|
sudo yum install -y wireguard-tools jq curl iproute iproute-tc
|
||||||
|
elif command -v dnf >/dev/null 2>&1; then
|
||||||
|
sudo dnf install -y wireguard-tools jq curl iproute
|
||||||
|
else
|
||||||
|
echo "ERROR: no supported package manager found; install: curl jq wireguard-tools iproute" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
do_up() {
|
||||||
|
require_env
|
||||||
|
install_deps
|
||||||
|
|
||||||
|
local ep="${NETMAKER_BASE_URL}/api/v1/client_conf/${NETMAKER_NETWORK}"
|
||||||
|
local tmp_conf="/tmp/${WG_IFACE}.conf"
|
||||||
|
local tmp_hdr="/tmp/${WG_IFACE}.headers"
|
||||||
|
|
||||||
|
echo "[*] Requesting client config: ${ep}"
|
||||||
|
# Optional headers
|
||||||
|
declare -a hdrs
|
||||||
|
hdrs=(-H "Authorization: Bearer ${NETMAKER_API_JWT}")
|
||||||
|
[[ -n "${NM_CLIENT_LABEL:-}" ]] && hdrs+=(-H "X-NM-Client-Label: ${NM_CLIENT_LABEL}")
|
||||||
|
[[ -n "${NM_REQUESTED_NAME:-}" ]] && hdrs+=(-H "X-NM-Requested-Name: ${NM_REQUESTED_NAME}")
|
||||||
|
|
||||||
|
local code
|
||||||
|
code="$(curl -sS -L --dump-header "${tmp_hdr}" -w '%{http_code}' -o "${tmp_conf}" "${hdrs[@]}" "${ep}")"
|
||||||
|
if [[ "${code}" != "200" ]]; then
|
||||||
|
echo "ERROR: client_conf HTTP ${code}" >&2
|
||||||
|
curl -sS -L "${hdrs[@]}" "${ep}" | head -c 400 >&2 || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
grep -q "^\[Interface\]" "${tmp_conf}" || { echo "ERROR: not a WireGuard conf"; head -n 20 "${tmp_conf}"; exit 1; }
|
||||||
|
|
||||||
|
# --- Extract Client-ID (one-liner, trim spaces/quotes) ---
|
||||||
|
local client_id
|
||||||
|
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/'$//")"
|
||||||
|
if [[ -z "${client_id}" ]]; then
|
||||||
|
echo "ERROR: Client-ID header missing in response; cannot manage lifecycle." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "[*] Client-ID: ${client_id}"
|
||||||
|
|
||||||
|
# Optional marker
|
||||||
|
if ! grep -q "^#interface-name=" "${tmp_conf}"; then
|
||||||
|
echo "#interface-name=${WG_IFACE}" | cat - "${tmp_conf}" > "${tmp_conf}.tmp" && mv "${tmp_conf}.tmp" "${tmp_conf}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install & bring up
|
||||||
|
sudo mkdir -p "${WG_CONF_DIR}"
|
||||||
|
sudo mv "${tmp_conf}" "${WG_CONF_DIR}/${WG_IFACE}.conf"
|
||||||
|
sudo chmod 600 "${WG_CONF_DIR}/${WG_IFACE}.conf"
|
||||||
|
echo "[*] Bringing up ${WG_IFACE} ..."
|
||||||
|
sudo wg-quick up "${WG_IFACE}"
|
||||||
|
|
||||||
|
echo "==== ${WG_IFACE} is up ===="
|
||||||
|
ip addr show "${WG_IFACE}" || true
|
||||||
|
wg show "${WG_IFACE}" || true
|
||||||
|
|
||||||
|
# Persist state
|
||||||
|
cat > "${STATE_FILE}" <<EOF
|
||||||
|
NETMAKER_BASE_URL='${NETMAKER_BASE_URL}'
|
||||||
|
NETMAKER_NETWORK='${NETMAKER_NETWORK}'
|
||||||
|
NETMAKER_API_JWT='${NETMAKER_API_JWT}'
|
||||||
|
WG_IFACE='${WG_IFACE}'
|
||||||
|
WG_CONF_DIR='${WG_CONF_DIR}'
|
||||||
|
CLIENT_ID='${client_id}'
|
||||||
|
EOF
|
||||||
|
chmod 600 "${STATE_FILE}"
|
||||||
|
echo "[*] Saved state: ${STATE_FILE}"
|
||||||
|
}
|
||||||
|
|
||||||
|
do_down() {
|
||||||
|
# Load state if present; flags/env can still override
|
||||||
|
if [[ -f "${STATE_FILE}" ]]; then
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
source "${STATE_FILE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
require_env
|
||||||
|
|
||||||
|
local client_id="${CLIENT_ID_OVERRIDE:-${CLIENT_ID:-}}"
|
||||||
|
echo "[*] Bringing down ${WG_IFACE} ..."
|
||||||
|
sudo wg-quick down "${WG_IFACE}" || echo "WARN: wg-quick down failed (already down?)."
|
||||||
|
|
||||||
|
# Remove local conf
|
||||||
|
if [[ -f "${WG_CONF_DIR}/${WG_IFACE}.conf" ]]; then
|
||||||
|
sudo shred -u "${WG_CONF_DIR}/${WG_IFACE}.conf" 2>/dev/null || sudo rm -f "${WG_CONF_DIR}/${WG_IFACE}.conf"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Delete ephemeral client on server (if we know its ID)
|
||||||
|
if [[ -n "${client_id}" ]]; then
|
||||||
|
local del_ep="${NETMAKER_BASE_URL}/api/extclients/${NETMAKER_NETWORK}/${client_id}"
|
||||||
|
echo "[*] Deleting client: DELETE ${del_ep}"
|
||||||
|
local http
|
||||||
|
http="$(curl -sS -o /dev/null -w '%{http_code}' -X DELETE -H "Authorization: Bearer ${NETMAKER_API_JWT}" "${del_ep}")"
|
||||||
|
if [[ "${http}" =~ ^20[0-9]$ ]]; then
|
||||||
|
echo "[*] Client deleted (HTTP ${http})."
|
||||||
|
else
|
||||||
|
echo "WARN: deletion returned HTTP ${http}; verify server state."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "WARN: client id not known (missing --client-id and state file); skipping server delete."
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "${STATE_FILE}" || true
|
||||||
|
echo "[*] Teardown finished."
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${SUBCMD}" in
|
||||||
|
up) do_up ;;
|
||||||
|
down) do_down ;;
|
||||||
|
*) usage; exit 2 ;;
|
||||||
|
esac
|
||||||
|
|
Reference in New Issue
Block a user