Tested all mutating tools (nc_table/nc_add_route/nc_insert_protocol/
nc_create_thread/nc_make_jump/nc_tclgen) on a throwaway copy: every change is
journaled and rolls back byte-identical across --session/--entry/--target/
--last granularities. Fixed nc-create-thread --host brace-collision (emitted
invalid TCL { HOST x} }; now balanced { HOST x }, and { HOST {} } when omitted)
and lessons.sh:142 printf option-injection. Read fixture verified untouched.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
206 lines
6.1 KiB
Bash
Executable File
206 lines
6.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# nc-create-thread.sh — high-level: create a new thread in a NetConfig and
|
|
# (optionally) wire a route from another thread to it.
|
|
#
|
|
# Combines nc-make-jump's emit helpers + nc-insert-protocol for a single
|
|
# user-facing operation. Goes through the journal.
|
|
#
|
|
# Usage:
|
|
# nc-create-thread.sh --name NEW_THREAD --site SITE --netconfig PATH
|
|
# --type tcpip|file
|
|
# --direction inbound|outbound
|
|
# --port PORT [--host HOST]
|
|
# [--process PROC]
|
|
# [--encoding ASCII]
|
|
# [--connect-from EXISTING_THREAD] # add a route on EXISTING → NEW
|
|
# [--route-type raw|xlate|generate] # default raw
|
|
# [--xlate XLATENAME] # if route-type=xlate
|
|
# [--trxid REGEX] # default .*
|
|
#
|
|
# Example: create a new outbound thread `to_metrics` in process `metrics` on
|
|
# 10.0.0.50:51999, raw-route from existing `IB_ADT_muxS` to it.
|
|
set -o pipefail
|
|
|
|
NC_SELF="$0"
|
|
LIB_DIR="$(cd "$(dirname "$NC_SELF")" && pwd)"
|
|
NCP="$LIB_DIR/nc-parse.sh"
|
|
NCI="$LIB_DIR/nc-insert-protocol.sh"
|
|
|
|
die() { printf 'nc-create-thread: %s\n' "$*" >&2; exit 1; }
|
|
|
|
NAME=""; SITE="${HCISITE:-}"; NC=""
|
|
TYPE="tcpip"; DIRECTION="outbound"; PORT=""; HOST=""
|
|
PROCESS=""; ENCODING="ASCII"
|
|
CONNECT_FROM=""; ROUTE_TYPE="raw"; XLATE=""; TRXID=".*"
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--name) shift; NAME="$1" ;;
|
|
--site) shift; SITE="$1" ;;
|
|
--netconfig) shift; NC="$1" ;;
|
|
--type) shift; TYPE="$1" ;;
|
|
--direction) shift; DIRECTION="$1" ;;
|
|
--port) shift; PORT="$1" ;;
|
|
--host) shift; HOST="$1" ;;
|
|
--process) shift; PROCESS="$1" ;;
|
|
--encoding) shift; ENCODING="$1" ;;
|
|
--connect-from) shift; CONNECT_FROM="$1" ;;
|
|
--route-type) shift; ROUTE_TYPE="$1" ;;
|
|
--xlate) shift; XLATE="$1" ;;
|
|
--trxid) shift; TRXID="$1" ;;
|
|
-h|--help) sed -n '2,20p' "$NC_SELF"; exit 0 ;;
|
|
*) die "unknown arg: $1" ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
[ -n "$NAME" ] || die "missing --name"
|
|
[ -n "$PORT" ] || die "missing --port"
|
|
[ -n "$NC" ] || NC="${HCIROOT:-}/${SITE}/NetConfig"
|
|
[ -f "$NC" ] || die "no such netconfig: $NC"
|
|
[ -z "$PROCESS" ] && PROCESS="$SITE"
|
|
|
|
is_server=0
|
|
outonly=1
|
|
obib=0
|
|
case "$DIRECTION" in
|
|
inbound) is_server=1; outonly=0; obib=1 ;;
|
|
outbound) is_server=0; outonly=1; obib=0 ;;
|
|
*) die "bad --direction" ;;
|
|
esac
|
|
|
|
# HOST field value: a real host when --host given, else the empty Tcl list {}.
|
|
# NB: do NOT inline this as ${HOST:-{}} inside the heredoc — the trailing `}`
|
|
# of the parameter default collides with the template's closing brace and
|
|
# emits `{ HOST 10.9.9.9} }` (one extra `}`, malformed TCL). v0.8.30.
|
|
if [ -n "$HOST" ]; then HOST_FIELD="$HOST"; else HOST_FIELD="{}"; fi
|
|
|
|
# Build the protocol block
|
|
build_block() {
|
|
cat <<EOF
|
|
protocol ${NAME} {
|
|
{ AUTOSTART 1 }
|
|
{ BITMAP {} }
|
|
{ COORDS {0 0} }
|
|
{ DATAFORMAT {
|
|
{ FRLTYPE offlen }
|
|
{ OFFLEN { { LEN 0 } { OFF 0 } } }
|
|
{ TYPE frl }
|
|
} }
|
|
{ DATAXLATE {
|
|
|
|
} }
|
|
{ EDIBATCH {
|
|
{ IN_DATA { { TYPE {} } { VERSION {} } } }
|
|
{ OUT_DATA { { HEADER {} } { TRIGGER { { COUNT {} } { SCHEDULER {} } { TIMER {} } } } { TYPE {} } { VERSION {} } } }
|
|
} }
|
|
{ ENCODING ${ENCODING} }
|
|
{ ENCODING_BOM_IB 0 }
|
|
{ ENCODING_BOM_OB 0 }
|
|
{ ENCODING_HL7 0 }
|
|
{ ENCODING_XML 0 }
|
|
{ EOCONFIG {} }
|
|
{ ERRDBTPS {
|
|
{ ERRTPSPROCS { { ARGS {} } { PROCS {} } { PROCSCONTROL {} } } }
|
|
{ RETRIES -1 }
|
|
} }
|
|
{ GROUPS {larry_created} }
|
|
{ HOSTDOWN 0 }
|
|
{ ICLSERVERPORT {} }
|
|
{ KEEPMSGONDISK 0 }
|
|
{ META {} }
|
|
{ OBWORKASIB ${obib} }
|
|
{ OUTBOUNDONLY ${outonly} }
|
|
{ PROCESSNAME ${PROCESS} }
|
|
{ PROTOCOL {
|
|
{ CA_FILE {} }
|
|
{ CA_PATH {} }
|
|
{ CERT_FILE {} }
|
|
{ CIPHERSUITES {} }
|
|
{ CLOSE 0 }
|
|
{ CONTROLMSGS 0 }
|
|
{ COPYCLIENTIPP 0 }
|
|
{ DELAYCONNECT 0 }
|
|
{ ENCODE_FILL {} }
|
|
{ ENCODE_INCLUSIVE 1 }
|
|
{ ENCODE_ISNATIVE 0 }
|
|
{ ENCODE_JUST r }
|
|
{ ENCODE_LEN 4 }
|
|
{ ENCODE_TYPE encapsulated }
|
|
{ HOST ${HOST_FIELD} }
|
|
{ IPV4_V6_DUAL 0 }
|
|
{ IS_SSL 0 }
|
|
{ ISMULTI 0 }
|
|
{ ISSERVER ${is_server} }
|
|
{ LOCAL_IP {} }
|
|
{ MAXCLIENT 0 }
|
|
{ MAXOBQD 0 }
|
|
{ MAXPREXLTQD 0 }
|
|
{ MLP_ERROR RESET }
|
|
{ MLP_MODE MLP }
|
|
{ MLP_TIMEOUT 30 }
|
|
{ MODE {} }
|
|
{ PASSWORD {} }
|
|
{ PORT ${PORT} }
|
|
{ PRIVATE_KEY {} }
|
|
{ RECONNECT 1 }
|
|
{ REOPEN 5 }
|
|
{ SSL_PROTOCOL All }
|
|
{ TCP_CONNECTION_TIMEOUT {} }
|
|
{ TYPE ${TYPE} }
|
|
{ WRITEZERO 0 }
|
|
} }
|
|
{ RECVCONTROL { { ACKCONTROL { { ARGS {} } { PROCS {} } { PROCSCONTROL {} } } } { EOMSG {} } { HOLDMSGS 0 } { MSGPRIO 5120 } } }
|
|
{ SAVECONTROL { { ARGS {} } { PROCS {} } { PROCSCONTROL {} } } }
|
|
{ TPS_INBOUND { { ARGS {} } { PROCS {} } { PROCSCONTROL {} } } }
|
|
{ TPS_OUTBOUND { { ARGS {} } { PROCS {} } { PROCSCONTROL {} } } }
|
|
{ TRACING 0 }
|
|
}
|
|
EOF
|
|
}
|
|
|
|
build_route_entry() {
|
|
local xlate_block="{ PROCS { { ARGS {} } { PROCS {} } { PROCSCONTROL {} } } }"
|
|
local extra=""
|
|
if [ "$ROUTE_TYPE" = "xlate" ] && [ -n "$XLATE" ]; then
|
|
extra="{ XLATE ${XLATE} }"
|
|
fi
|
|
cat <<EOF
|
|
{
|
|
{ CACHEMSG 0 }
|
|
{ DEL_ON_ERR_ROUTE 0 }
|
|
{ ROUTE_DETAILS {
|
|
{
|
|
{ DEST ${NAME} }
|
|
${xlate_block}
|
|
${extra}
|
|
{ TYPE ${ROUTE_TYPE} }
|
|
}
|
|
} }
|
|
{ ROUTE_ENABLED 1 }
|
|
{ TRXID ${TRXID} }
|
|
{ WILDCARD ON }
|
|
}
|
|
EOF
|
|
}
|
|
|
|
# Generate block
|
|
BLOCK_FILE=$(mktemp); build_block > "$BLOCK_FILE"
|
|
printf '\n=== Generated protocol block for %s ===\n\n' "$NAME"
|
|
cat "$BLOCK_FILE"
|
|
printf '\n'
|
|
|
|
# Insert it
|
|
"$NCI" insert "$NC" "$BLOCK_FILE"
|
|
|
|
# If --connect-from, also splice a route into the source thread's DATAXLATE
|
|
if [ -n "$CONNECT_FROM" ]; then
|
|
ROUTE_FILE=$(mktemp); build_route_entry > "$ROUTE_FILE"
|
|
printf '\n=== Route to splice into %s DATAXLATE ===\n\n' "$CONNECT_FROM"
|
|
cat "$ROUTE_FILE"
|
|
printf '\n'
|
|
"$NCI" add-route "$NC" "$CONNECT_FROM" "$ROUTE_FILE"
|
|
rm -f "$ROUTE_FILE"
|
|
fi
|
|
rm -f "$BLOCK_FILE"
|