mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 11:03:59 +00:00
- ansible.sh: export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES (fixes macOS fork safety abort when pywinrm loads ObjC frameworks before fork()) - hosts.ini: add winrm scheme=http port=5985, transport=ntlm for Windows hosts; remove hardcoded ansible_user (now per-host) - group_vars/workstations_windows/vars.yml: created; WinRM connection vars (ansible_user/password resolved per-host) - host_vars/morgoth.prole.org.yml: ansible_user=chrisfu + vault ref - host_vars/fairyland.prole.org.yml: ansible_user=minecraft + vault ref - windows_ollama_models.yml: fix PowerShell ollama show check — wrap in try/catch so ErrorActionPreference=Stop does not abort on model-not-found Result: mxbai-embed-large-2k (num_ctx=2048) created on both hosts. Idempotent — re-running only recreates if Modelfile hash changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
149 lines
4.8 KiB
Bash
Executable File
149 lines
4.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
export ANSIBLE_CONFIG="${ROOT_DIR}/ansible.cfg"
|
|
|
|
# macOS: prevent Objective-C runtime from aborting forked worker processes.
|
|
# Required for WinRM connections (pywinrm/requests uses Foundation framework
|
|
# internally; macOS kills forked children that load ObjC before fork()).
|
|
export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
|
|
|
|
# Defaults
|
|
MODE="fg" # fg|bg
|
|
PLAYBOOK="infrastructure/playbooks/site.yml"
|
|
VAULT_PASS_FILE=""
|
|
if [[ -f "${ROOT_DIR}/.vault_pass" ]]; then
|
|
VAULT_PASS_FILE="${ROOT_DIR}/.vault_pass"
|
|
fi
|
|
LIMIT="" # optional
|
|
TAGS="" # optional
|
|
EXTRA_ARGS=() # passthrough
|
|
# Use local logs if PROLE_LOGS is not writable or looks like a remote path
|
|
LOG_BASE="${ROOT_DIR}/.ansible/logs"
|
|
if [[ -n "${PROLE_LOGS:-}" ]]; then
|
|
# If it's a relative path, or it exists and is writable, or its parent is writable
|
|
if [[ ! "${PROLE_LOGS}" =~ ^/ ]] || [[ -w "${PROLE_LOGS}" ]] || [[ -w "$(dirname "${PROLE_LOGS}" 2>/dev/null)" ]]; then
|
|
LOG_BASE="${PROLE_LOGS}"
|
|
fi
|
|
fi
|
|
LOG_BASE="${LOG_BASE%/}"
|
|
LOG_DIR="${LOG_BASE}/ansible"
|
|
SYSLOG_HOST="" # e.g. loghost.prole.org
|
|
SYSLOG_PORT="514"
|
|
SYSLOG_TAG="ansible"
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: ./ansible.sh [options] [-- <extra ansible-playbook args>]
|
|
|
|
Options:
|
|
-p, --playbook PATH Playbook path (default: ${PLAYBOOK})
|
|
-l, --limit HOSTS Limit hosts
|
|
-t, --tags TAGS Tags
|
|
-v, --vault-pass-file FILE Vault password file
|
|
-m, --mode fg|bg Run in foreground or background (default: fg)
|
|
--syslog-host HOST Send start/end markers via UDP syslog to HOST
|
|
--syslog-port PORT Syslog UDP port (default: 514)
|
|
--syslog-tag TAG Syslog tag (default: ansible)
|
|
-h, --help Show help
|
|
|
|
Examples:
|
|
./ansible.sh -l pi.prole.org -t iscsi -v .vault_pass
|
|
./ansible.sh -m bg -p infrastructure/playbooks/site.yml -v .vault_pass
|
|
./ansible.sh --syslog-host loghost.prole.org -m bg -v .vault_pass -- -vv
|
|
EOF
|
|
}
|
|
|
|
send_syslog() {
|
|
local msg="$1"
|
|
if [[ -n "${SYSLOG_HOST}" ]]; then
|
|
# -d = UDP, -n host, -P port
|
|
logger -d -n "${SYSLOG_HOST}" -P "${SYSLOG_PORT}" -t "${SYSLOG_TAG}" -- "${msg}" || true
|
|
fi
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-p|--playbook) PLAYBOOK="$2"; shift 2 ;;
|
|
-l|--limit) LIMIT="$2"; shift 2 ;;
|
|
-t|--tags) TAGS="$2"; shift 2 ;;
|
|
-v|--vault-pass-file) VAULT_PASS_FILE="$2"; shift 2 ;;
|
|
-m|--mode) MODE="$2"; shift 2 ;;
|
|
--syslog-host) SYSLOG_HOST="$2"; shift 2 ;;
|
|
--syslog-port) SYSLOG_PORT="$2"; shift 2 ;;
|
|
--syslog-tag) SYSLOG_TAG="$2"; shift 2 ;;
|
|
--) shift; EXTRA_ARGS+=("$@"); break ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) EXTRA_ARGS+=("$1"); shift ;;
|
|
esac
|
|
done
|
|
|
|
# Default to k3s hosts for the main site run (avoid touching non-k3s Linux/Pi hosts unless explicitly requested)
|
|
if [[ -z "${LIMIT}" ]]; then
|
|
if [[ "${PLAYBOOK}" =~ (^|/)infrastructure/playbooks/site\.yml$ ]]; then
|
|
LIMIT="k3s_hosts"
|
|
fi
|
|
fi
|
|
|
|
mkdir -p "${LOG_DIR}"
|
|
|
|
ts="$(date +%Y%m%d-%H%M%S)"
|
|
logfile="${LOG_DIR}/ansible-${ts}.log"
|
|
|
|
cmd=(ansible-playbook "${PLAYBOOK}")
|
|
[[ -n "${LIMIT}" ]] && cmd+=("--limit" "${LIMIT}")
|
|
[[ -n "${TAGS}" ]] && cmd+=("--tags" "${TAGS}")
|
|
[[ -n "${VAULT_PASS_FILE}" ]] && cmd+=("--vault-password-file" "${VAULT_PASS_FILE}")
|
|
cmd+=("${EXTRA_ARGS[@]}")
|
|
|
|
send_syslog "START playbook=${PLAYBOOK} limit=${LIMIT:-<none>} tags=${TAGS:-<none>} log=${logfile}"
|
|
|
|
echo "ANSIBLE_CONFIG=${ANSIBLE_CONFIG}"
|
|
echo "LOGFILE=${logfile}"
|
|
echo "CMD: ${cmd[*]}"
|
|
|
|
if [[ "${MODE}" == "fg" ]]; then
|
|
# Stream to terminal and file
|
|
color_env=()
|
|
use_pty=false
|
|
if [[ -z "${NO_COLOR:-}" ]] && [[ -z "${ANSIBLE_NOCOLOR:-}" ]]; then
|
|
[[ -z "${ANSIBLE_FORCE_COLOR:-}" ]] && color_env+=("ANSIBLE_FORCE_COLOR=true")
|
|
[[ -z "${PY_COLORS:-}" ]] && color_env+=("PY_COLORS=1")
|
|
|
|
# Ensure a useful terminal type for ANSI colors when invoked from wrappers.
|
|
if [[ -z "${TERM:-}" ]] || [[ "${TERM}" == "dumb" ]]; then
|
|
color_env+=("TERM=xterm-256color")
|
|
fi
|
|
|
|
if command -v script >/dev/null 2>&1; then
|
|
use_pty=true
|
|
fi
|
|
fi
|
|
|
|
run_cmd=("${cmd[@]}")
|
|
if [[ "${use_pty}" == "true" ]]; then
|
|
# `tee` breaks TTY detection; wrap in a pseudo-tty so Ansible keeps colors.
|
|
run_cmd=(script -qF /dev/null "${cmd[@]}")
|
|
fi
|
|
|
|
set +e
|
|
env "${color_env[@]}" "${run_cmd[@]}" 2>&1 | tee "${logfile}"
|
|
rc=${PIPESTATUS[0]}
|
|
set -e
|
|
else
|
|
# Background: nohup to logfile
|
|
nohup "${cmd[@]}" >"${logfile}" 2>&1 &
|
|
rc=0
|
|
echo "Started in background (pid $!)"
|
|
fi
|
|
|
|
if [[ "${MODE}" == "fg" ]]; then
|
|
if [[ $rc -eq 0 ]]; then
|
|
send_syslog "END OK playbook=${PLAYBOOK} limit=${LIMIT:-<none>} tags=${TAGS:-<none>} log=${logfile}"
|
|
else
|
|
send_syslog "END FAIL rc=${rc} playbook=${PLAYBOOK} limit=${LIMIT:-<none>} tags=${TAGS:-<none>} log=${logfile}"
|
|
fi
|
|
exit $rc
|
|
fi
|