Compare commits
10 Commits
c3a92e8ca8
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28485a9be6 | ||
|
|
72ffe3c30d | ||
|
|
b23f5d7e5f | ||
|
|
d25dac1897 | ||
|
|
67926c37bd | ||
|
|
074ab05908 | ||
|
|
0fc1b3cba0 | ||
|
|
3860c8a33d | ||
|
|
16cbadd016 | ||
|
|
a6296da5df |
5
.bashrc
5
.bashrc
@@ -32,3 +32,8 @@ fi
|
||||
|
||||
# Legacy aliases file (kept for compatibility)
|
||||
[ -f ~/.aliases ] && source ~/.aliases
|
||||
|
||||
# OpenClaw Completion
|
||||
#source "/Users/kenjim/.openclaw/completions/openclaw.bash"
|
||||
#export OPENCLAW_MODEL=kimi-k2.5:cloud
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
|
||||
@@ -14,7 +14,7 @@ _is_work_host() {
|
||||
[[ "${MACHINE_PROFILE:-}" == "work" ]] && return 0
|
||||
# Fallback hostname pattern for work servers where .bashrc.local may not exist
|
||||
case "$(hostname -s)" in
|
||||
kenjim-mbp*|etqc-*|etbg-*|engtech-dev-*|zet*) return 0 ;;
|
||||
kenjim-mbp*|etqc-*|etbg-*|engtech-dev-*|qnc-kenjim-toby-shell*|qtaas*|bng-kenjim-toby-shell*|btaas*|kenjim-taas*) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
@@ -20,3 +20,4 @@ email = kenjim@juniper.net
|
||||
br = branch
|
||||
ci = commit
|
||||
unstage = reset HEAD --
|
||||
tree = log --graph --oneline --all --decorate
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -33,6 +33,10 @@
|
||||
*.secrets
|
||||
vault/
|
||||
|
||||
# Machine-local overrides — never commit (written by setup_enterprise_ai_bash.sh)
|
||||
# Machine-local overrides at HOME level — never commit (written by setup_enterprise_ai_bash.sh)
|
||||
.bashrc.local
|
||||
.bash_profile.local
|
||||
|
||||
# Per-host .bashrc.local files ARE committed — managed centrally in dotfiles/hosts/
|
||||
# Files are named <hostname>.bashrc.local and deployed via: dotfiles deploy-to user@host
|
||||
# hosts/*.bashrc.local is intentionally tracked (gitignore rules above only match exact name)
|
||||
|
||||
@@ -84,9 +84,12 @@ Host kold
|
||||
HostName etqc-kenjim-01.juniper.net
|
||||
|
||||
# TaaS dev machine
|
||||
Host ktaas
|
||||
Host qtaas
|
||||
HostName kenjim-taas.qengk8.juniper.net
|
||||
|
||||
Host btaas
|
||||
HostName kenjim-taas.bengk8.juniper.net
|
||||
|
||||
# Temp machine — Bangalore K8
|
||||
Host ktb
|
||||
HostName kenjim-temp.bengk8.juniper.net
|
||||
|
||||
121
README.md
121
README.md
@@ -75,6 +75,8 @@ Three scripts drive the system:
|
||||
│ │ ├── setup_enterprise_ai_bash.sh → symlinked from ~/scripts/setup_enterprise_ai_bash.sh
|
||||
│ │ └── bootstrap.sh → symlinked from ~/scripts/bootstrap.sh
|
||||
│ ├── .dotfiles_manifest # internal list of tracked HOME-relative paths
|
||||
│ ├── hosts/
|
||||
│ │ └── <hostname>.bashrc.local # per-server local configs (deployed via deploy-to)
|
||||
│ ├── install.sh # portable restore script (auto-generated)
|
||||
│ └── README.md # this file
|
||||
│
|
||||
@@ -230,6 +232,13 @@ on the remote.
|
||||
# Push everything (dotfiles + scripts):
|
||||
dotfiles deploy-to user@server
|
||||
|
||||
# After file transfer, also run setup_enterprise_ai_bash.sh on the remote
|
||||
# to create ~/workspace, ~/data, ~/models and write shell config:
|
||||
dotfiles deploy-to user@server --run-setup
|
||||
|
||||
# Specify a machine profile for the setup script (default: work):
|
||||
dotfiles deploy-to user@server --run-setup --profile work
|
||||
|
||||
# Scripts only (dotfiles_manager.sh, bootstrap.sh, setup script):
|
||||
dotfiles deploy-to user@server --scripts-only
|
||||
|
||||
@@ -249,6 +258,38 @@ Files are copied directly (not symlinked). Re-run `deploy-to` any time you
|
||||
want to push updates. `~/.ssh/` is skipped by default to avoid accidentally
|
||||
pushing private keys or your personal known_hosts to a shared server.
|
||||
|
||||
> **First-time setup on a server?** Use `--run-setup` to create the full
|
||||
> directory structure after file transfer, or answer `y` when prompted
|
||||
> interactively at the end of a normal `deploy-to` run.
|
||||
|
||||
### Centrally managing `~/.bashrc.local` for servers
|
||||
|
||||
Work servers can't reach the Gitea repo, so their `~/.bashrc.local` is managed
|
||||
centrally from `kenjim-mbp` using per-host files in `dotfiles/hosts/`:
|
||||
|
||||
```
|
||||
dotfiles/hosts/
|
||||
└── <hostname>.bashrc.local # deployed as ~/.bashrc.local on that server
|
||||
```
|
||||
|
||||
`deploy-to` automatically detects and deploys the matching file:
|
||||
|
||||
```bash
|
||||
# Edit the server's local config on kenjim-mbp:
|
||||
$EDITOR ~/dotfiles/hosts/etqc-kenjim-11.bashrc.local
|
||||
|
||||
# Commit and push from kenjim-mbp:
|
||||
dotfiles push "fix: update etqc-kenjim-11 local config"
|
||||
|
||||
# Deploy to the server (no git access needed on the server):
|
||||
dotfiles deploy-to kenjim@etqc-kenjim-11
|
||||
```
|
||||
|
||||
The `hosts/` files are committed to git. They may contain non-secret
|
||||
machine-specific variables (`MACHINE_PROFILE`, `MACHINE_HOST`, `AWS_PROFILE`,
|
||||
etc.). **Do not commit real passwords or tokens** — use `CHANGEME` placeholders
|
||||
and set real values manually on the server after first deploy.
|
||||
|
||||
---
|
||||
|
||||
## Dotfiles Management — How Symlinks Work
|
||||
@@ -315,3 +356,83 @@ To add manually:
|
||||
sudo tmutil addexclusion ~/data/raw
|
||||
sudo tmutil addexclusion ~/models
|
||||
```
|
||||
|
||||
**Ollama Bootstrap & Usage**
|
||||
|
||||
- **Bootstrap (macOS)**: Run the macOS installer/check + create model folders:
|
||||
|
||||
```bash
|
||||
bash scripts/bootstrap_ollama_mac.sh
|
||||
```
|
||||
|
||||
- **Bootstrap (Linux)**: Run the Linux helper (attempts to detect package manager and prepares model folders):
|
||||
|
||||
```bash
|
||||
bash scripts/bootstrap_ollama_linux.sh
|
||||
```
|
||||
|
||||
- The scripts create the model directory referenced by the setup script as `OLLAMA_MODELS` (by default `$HOME/models/ollama`).
|
||||
|
||||
- Start the Ollama server inside a tmux session (helper functions):
|
||||
|
||||
```bash
|
||||
# Load helper functions (one-liner to source from dotfiles workspace)
|
||||
source scripts/ollama_tmux.sh
|
||||
|
||||
# Start the server in a detached tmux session named 'ollama' (default command):
|
||||
start_ollama_tmux
|
||||
|
||||
# To attach to the session:
|
||||
tmux attach -t ollama
|
||||
|
||||
# To stop the server session:
|
||||
stop_ollama_tmux
|
||||
```
|
||||
|
||||
- Model management (two simple options):
|
||||
|
||||
- Pull a remote model (via the `ollama` CLI):
|
||||
|
||||
```bash
|
||||
# example: pull a model by reference
|
||||
pull_ollama_model <model-ref>
|
||||
```
|
||||
|
||||
- Import or stage a local model into the $OLLAMA_MODELS path (creates a symlink):
|
||||
|
||||
```bash
|
||||
import_local_model /path/to/local/model-dir-or-file
|
||||
# The helper will link it into the directory created by setup_enterprise_ai_bash.sh
|
||||
```
|
||||
|
||||
- Scripts referenced:
|
||||
|
||||
- [scripts/bootstrap_ollama_mac.sh](scripts/bootstrap_ollama_mac.sh)
|
||||
- [scripts/bootstrap_ollama_linux.sh](scripts/bootstrap_ollama_linux.sh)
|
||||
- [scripts/ollama_tmux.sh](scripts/ollama_tmux.sh)
|
||||
|
||||
- How to use Ollama from other AI applications:
|
||||
|
||||
- Run the server with `start_ollama_tmux` (above). By default the helper uses `ollama serve --host 127.0.0.1 --port 11434`.
|
||||
- Many client apps can be pointed at the local Ollama HTTP API (default: `http://127.0.0.1:11434`). Check the Ollama docs for exact endpoints and payloads.
|
||||
- Example using the `ollama` CLI to run a model directly from scripts or other programs:
|
||||
|
||||
```bash
|
||||
# Run a model locally (interactive / CLI). Replace <model> with the model name.
|
||||
ollama run <model> --prompt "Write a short haiku about trees"
|
||||
```
|
||||
|
||||
- Example (generic) using HTTP from another application (replace endpoint/payload per Ollama docs):
|
||||
|
||||
```bash
|
||||
curl -X POST "http://127.0.0.1:11434/api/generate" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"model":"<model>","prompt":"Hello from my app"}'
|
||||
```
|
||||
|
||||
- When integrating from other AI tooling, supply the Ollama host/port (e.g. `OLLAMA_URL=http://127.0.0.1:11434`) or call the `ollama` CLI directly from the application process.
|
||||
|
||||
If you want, I can also:
|
||||
|
||||
- Make the new scripts executable (`chmod +x`) automatically in the repo
|
||||
- Attempt to detect the Ollama default model storage path and auto-configure a symlink
|
||||
|
||||
41
hosts/etqc-kenjim-11.bashrc.local
Normal file
41
hosts/etqc-kenjim-11.bashrc.local
Normal file
@@ -0,0 +1,41 @@
|
||||
### MACHINE_LOCAL — managed centrally in dotfiles/hosts/ on kenjim-mbp
|
||||
### Deployed via: dotfiles deploy-to kenjim@etqc-kenjim-11
|
||||
### DO NOT edit directly on the server — edit in ~/dotfiles/hosts/ and re-deploy
|
||||
### NFS NOTE: On NFS-home servers, this file lives at /opt/kenjim/.bashrc.local
|
||||
### with a symlink from ~/.bashrc.local → /opt/kenjim/.bashrc.local
|
||||
# Host : etqc-kenjim-11
|
||||
# Profile : work (server)
|
||||
# =============================================================================
|
||||
|
||||
export MACHINE_PROFILE="work"
|
||||
export MACHINE_HOST="etqc-kenjim-11"
|
||||
|
||||
# Prevent shell auto-logout on idle
|
||||
unset TMOUT
|
||||
|
||||
# =============================================================================
|
||||
# ServiceNow API credentials
|
||||
# =============================================================================
|
||||
export SN_USERNAME='_integ-soap-read'
|
||||
export SN_PASSWORD='CHANGEME' # set real value — never commit
|
||||
|
||||
# =============================================================================
|
||||
# LDAP bind credentials
|
||||
# Referenced by ldaps() and ldaps2() in ~/.bashrc.d/30_work.sh
|
||||
# =============================================================================
|
||||
export JNPR_LDAP_BIND_PW='CHANGEME' # was: xqYzhL%lLe!FIr!67LJX%7a^PWOWY0
|
||||
export JNPR_LDAP_BIND_PW2='CHANGEME' # was: tF#w3St@nGqq36XZDym#857U)v4xKw
|
||||
|
||||
# =============================================================================
|
||||
# Unified Hub (Artifactory) credentials
|
||||
# Referenced by unified-hub-login() and unified-hub-engtech-bin-upload()
|
||||
# in ~/.bashrc.d/30_work.sh
|
||||
# =============================================================================
|
||||
export UNIFIED_HUB_USERNAME='kenjim@juniper.net'
|
||||
export UNIFIED_HUB_TOKEN='CHANGEME' # base64 API token from Artifactory
|
||||
|
||||
# =============================================================================
|
||||
# AWS — server uses named profiles from ~/.aws/config loaded by k8configs env
|
||||
# =============================================================================
|
||||
export AWS_PROFILE=pgdb-qnc
|
||||
export AWS_SDK_LOAD_CONFIG=1
|
||||
40
scripts/bootstrap_ollama_linux.sh
Executable file
40
scripts/bootstrap_ollama_linux.sh
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "🔧 Ollama Linux bootstrap — starting"
|
||||
|
||||
# Load environment (MODEL_ROOT, OLLAMA_MODELS)
|
||||
# Temporarily disable "nounset" when sourcing user shell files to avoid
|
||||
# failures from system /etc/bashrc referencing undefined vars like PS1.
|
||||
if [ -f "$HOME/.bashrc" ]; then
|
||||
set +u
|
||||
# shellcheck disable=SC1091
|
||||
source "$HOME/.bashrc" || true
|
||||
set -u
|
||||
fi
|
||||
|
||||
: "${OLLAMA_MODELS:=$HOME/models/ollama}"
|
||||
mkdir -p "$OLLAMA_MODELS"
|
||||
|
||||
if command -v ollama >/dev/null 2>&1; then
|
||||
echo "✅ ollama already installed: $(ollama version 2>/dev/null || echo 'unknown')"
|
||||
else
|
||||
echo "ℹ️ Attempting to install ollama on Linux"
|
||||
if command -v apt-get >/dev/null 2>&1; then
|
||||
echo "Using apt to install prerequisites..."
|
||||
sudo apt-get update -y || true
|
||||
sudo apt-get install -y ca-certificates curl gnupg lsb-release || true
|
||||
echo "⚠️ Please follow the official ollama Linux install instructions if a package is not available: https://ollama.com/docs/install"
|
||||
echo "If you have a .deb from Ollama, install it with: sudo dpkg -i <file.deb>"
|
||||
elif command -v dnf >/dev/null 2>&1; then
|
||||
echo "Using dnf; please refer to Ollama docs for distro-specific instructions: https://ollama.com/docs/install"
|
||||
else
|
||||
echo "⚠️ Could not detect package manager. Please install ollama manually. See: https://ollama.com/docs/install"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "📁 Ensuring model directory exists: $OLLAMA_MODELS"
|
||||
mkdir -p "$OLLAMA_MODELS"
|
||||
|
||||
echo "✅ Linux Ollama bootstrap complete."
|
||||
echo "Next steps: run scripts/ollama_tmux.sh to start the server in tmux, and place models under $OLLAMA_MODELS"
|
||||
41
scripts/bootstrap_ollama_mac.sh
Executable file
41
scripts/bootstrap_ollama_mac.sh
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "🔧 Ollama macOS bootstrap — starting"
|
||||
|
||||
# Load environment (MODEL_ROOT, OLLAMA_MODELS)
|
||||
# Temporarily disable "nounset" when sourcing user shell files to avoid
|
||||
# failures from system /etc/bashrc referencing undefined vars like PS1.
|
||||
if [ -f "$HOME/.bashrc" ]; then
|
||||
set +u
|
||||
# shellcheck disable=SC1091
|
||||
source "$HOME/.bashrc" || true
|
||||
set -u
|
||||
fi
|
||||
|
||||
: "${OLLAMA_MODELS:=$HOME/models/ollama}"
|
||||
mkdir -p "$OLLAMA_MODELS"
|
||||
|
||||
if command -v ollama >/dev/null 2>&1; then
|
||||
echo "✅ ollama already installed: $(ollama version 2>/dev/null || echo 'unknown')"
|
||||
else
|
||||
if command -v brew >/dev/null 2>&1; then
|
||||
echo "🍺 Installing ollama via Homebrew..."
|
||||
brew update || true
|
||||
brew install ollama || {
|
||||
echo "⚠️ Homebrew install failed. See https://ollama.com/docs/install"
|
||||
exit 1
|
||||
}
|
||||
echo "✅ ollama installed"
|
||||
else
|
||||
echo "⚠️ Homebrew not found. Install Homebrew first: https://brew.sh"
|
||||
echo "Then re-run this script: $0"
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "📁 Ensuring model directory exists: $OLLAMA_MODELS"
|
||||
mkdir -p "$OLLAMA_MODELS"
|
||||
|
||||
echo "✅ macOS Ollama bootstrap complete."
|
||||
echo "Next steps: run scripts/ollama_tmux.sh to start the server in tmux, and place models under $OLLAMA_MODELS"
|
||||
@@ -883,20 +883,24 @@ cmd_remote_bootstrap() {
|
||||
# COMMAND: deploy-to (push dotfiles to a server that can't reach Gitea)
|
||||
# -----------------------------------------------------------------------
|
||||
cmd_deploy_to() {
|
||||
[ $# -ge 1 ] || die "Usage: deploy-to <user@host> [--scripts-only] [--include-ssh] [--no-backup] [--dry-run]"
|
||||
[ $# -ge 1 ] || die "Usage: deploy-to <user@host> [--scripts-only] [--include-ssh] [--no-backup] [--run-setup] [--profile work|personal] [--dry-run]"
|
||||
|
||||
local target="$1"; shift
|
||||
local scripts_only=false
|
||||
local skip_ssh=true # default: skip .ssh/ — avoid pushing keys/config to servers
|
||||
local no_backup=false
|
||||
local run_setup=false
|
||||
local setup_profile="work" # default profile for servers
|
||||
local dry_run=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--scripts-only) scripts_only=true; shift ;;
|
||||
--include-ssh) skip_ssh=false; shift ;;
|
||||
--no-backup) no_backup=true; shift ;;
|
||||
--dry-run) dry_run=true; shift ;;
|
||||
--scripts-only) scripts_only=true; shift ;;
|
||||
--include-ssh) skip_ssh=false; shift ;;
|
||||
--no-backup) no_backup=true; shift ;;
|
||||
--run-setup) run_setup=true; shift ;;
|
||||
--profile) setup_profile="${2:-work}"; shift 2 ;;
|
||||
--dry-run) dry_run=true; shift ;;
|
||||
*) die "Unknown option: $1" ;;
|
||||
esac
|
||||
done
|
||||
@@ -944,11 +948,17 @@ cmd_deploy_to() {
|
||||
|
||||
local backed_up=0
|
||||
for rel in "${remote_paths[@]}"; do
|
||||
# Check if the file actually exists on the remote before fetching
|
||||
if ssh "$target" "[ -f ~/$rel ]" 2>/dev/null; then
|
||||
# Check if the file/dir actually exists on the remote before fetching
|
||||
if ssh "$target" "[ -e ~/$rel ]" 2>/dev/null; then
|
||||
local local_dest="$backup_base/$rel"
|
||||
mkdir -p "$(dirname "$local_dest")"
|
||||
if scp -q "$target:~/$rel" "$local_dest" 2>/dev/null; then
|
||||
# Use -r for directories, plain scp for files
|
||||
if ssh "$target" "[ -d ~/$rel ]" 2>/dev/null; then
|
||||
mkdir -p "$local_dest"
|
||||
if scp -rq "$target:~/$rel/." "$local_dest/" 2>/dev/null; then
|
||||
(( backed_up++ )) || true
|
||||
fi
|
||||
elif scp -q "$target:~/$rel" "$local_dest" 2>/dev/null; then
|
||||
(( backed_up++ )) || true
|
||||
fi
|
||||
fi
|
||||
@@ -1018,17 +1028,107 @@ cmd_deploy_to() {
|
||||
fi
|
||||
|
||||
if $dry_run; then
|
||||
echo " [dry-run] ~/$rel"
|
||||
echo " [dry-run] ~/$rel$([ -d "$src" ] && echo '/')"
|
||||
else
|
||||
# Ensure parent directory exists on remote
|
||||
local parent; parent="$(dirname "$rel")"
|
||||
[[ "$parent" != "." ]] && ssh "$target" "mkdir -p ~/$parent"
|
||||
scp -q "$src" "$target:~/$rel"
|
||||
if [ -d "$src" ]; then
|
||||
# For directories: remove stale dest first (avoids double-nesting on re-run)
|
||||
# then scp -r into the parent so the dir name is preserved correctly.
|
||||
ssh "$target" "rm -rf ~/$rel"
|
||||
if [[ "$parent" == "." ]]; then
|
||||
scp -rq "$src" "$target:~/"
|
||||
else
|
||||
ssh "$target" "mkdir -p ~/$parent"
|
||||
scp -rq "$src" "$target:~/$parent/"
|
||||
fi
|
||||
else
|
||||
[[ "$parent" != "." ]] && ssh "$target" "mkdir -p ~/$parent"
|
||||
scp -q "$src" "$target:~/$rel"
|
||||
fi
|
||||
success "Deployed: ~/$rel"
|
||||
(( deployed++ )) || true
|
||||
fi
|
||||
done < "$MANIFEST"
|
||||
|
||||
# ---- 5. Deploy hosts/<hostname>.bashrc.local → ~/.bashrc.local ----
|
||||
# Strip user@ prefix, then strip domain suffix to get short hostname
|
||||
local remote_short; remote_short="${target##*@}"
|
||||
remote_short="${remote_short%%.*}"
|
||||
local host_local="$DOTFILES_DIR/hosts/${remote_short}.bashrc.local"
|
||||
|
||||
if [ -f "$host_local" ]; then
|
||||
echo
|
||||
info "Found host-specific config: hosts/${remote_short}.bashrc.local"
|
||||
if $dry_run; then
|
||||
echo " [dry-run] hosts/${remote_short}.bashrc.local → ~/.bashrc.local"
|
||||
else
|
||||
# Back up existing remote .bashrc.local if not already captured above
|
||||
if $no_backup; then
|
||||
: # skip
|
||||
elif ssh "$target" '[ -L ~/.bashrc.local ]' 2>/dev/null; then
|
||||
# It's a symlink (NFS setup) — back up the target file
|
||||
local real_path
|
||||
real_path=$(ssh "$target" 'readlink -f ~/.bashrc.local' 2>/dev/null || true)
|
||||
if [[ -n "$real_path" ]]; then
|
||||
local bl_backup="$HOME/.dotfiles_backup/remote-${remote_short}-$(date +%Y%m%d_%H%M%S)"
|
||||
mkdir -p "$bl_backup"
|
||||
scp -q "$target:$real_path" "$bl_backup/.bashrc.local" 2>/dev/null || true
|
||||
info "Backed up remote $real_path → $bl_backup/.bashrc.local"
|
||||
fi
|
||||
elif ssh "$target" '[ -f ~/.bashrc.local ]' 2>/dev/null; then
|
||||
local bl_backup="$HOME/.dotfiles_backup/remote-${remote_short}-$(date +%Y%m%d_%H%M%S)"
|
||||
mkdir -p "$bl_backup"
|
||||
scp -q "$target:~/.bashrc.local" "$bl_backup/.bashrc.local" 2>/dev/null || true
|
||||
info "Backed up remote ~/.bashrc.local → $bl_backup/.bashrc.local"
|
||||
fi
|
||||
|
||||
# Detect NFS home on the remote and deploy to /opt/kenjim/ if needed
|
||||
local _remote_nfs=false
|
||||
if ssh "$target" 'df -P "$HOME" 2>/dev/null | tail -1 | grep -qE ":|nfs"' 2>/dev/null; then
|
||||
_remote_nfs=true
|
||||
fi
|
||||
|
||||
if $_remote_nfs; then
|
||||
info "NFS home detected on $target — deploying to /opt/kenjim/.bashrc.local"
|
||||
# Ensure /opt/kenjim exists — skip sudo if it already does
|
||||
if ! ssh "$target" '[ -d /opt/kenjim ]' 2>/dev/null; then
|
||||
info "Creating /opt/kenjim on $target (requires sudo)..."
|
||||
ssh -t "$target" 'sudo mkdir -p /opt/kenjim && sudo chown $(id -u):$(id -g) /opt/kenjim && chmod 700 /opt/kenjim'
|
||||
fi
|
||||
scp -q "$host_local" "$target:/opt/kenjim/.bashrc.local"
|
||||
ssh "$target" 'chmod 600 /opt/kenjim/.bashrc.local && ln -sfn /opt/kenjim/.bashrc.local ~/.bashrc.local'
|
||||
success "Deployed: hosts/${remote_short}.bashrc.local → /opt/kenjim/.bashrc.local (symlinked from ~)"
|
||||
else
|
||||
scp -q "$host_local" "$target:~/.bashrc.local"
|
||||
success "Deployed: hosts/${remote_short}.bashrc.local → ~/.bashrc.local"
|
||||
fi
|
||||
(( deployed++ )) || true
|
||||
fi
|
||||
else
|
||||
info "No host-specific config found at hosts/${remote_short}.bashrc.local — skipping."
|
||||
info "Create one to manage ~/.bashrc.local centrally: dotfiles/hosts/${remote_short}.bashrc.local"
|
||||
fi
|
||||
|
||||
# ---- 6. Optionally run setup on the remote ----
|
||||
if ! $dry_run; then
|
||||
local do_setup=$run_setup
|
||||
if ! $run_setup; then
|
||||
echo
|
||||
read -r -p "Run setup_enterprise_ai_bash.sh on $target now? Creates dirs, writes shell config. (y/n): " _ans
|
||||
[[ "$_ans" == [yY] ]] && do_setup=true
|
||||
fi
|
||||
|
||||
if $do_setup; then
|
||||
echo
|
||||
info "Running setup on $target (profile=$setup_profile)..."
|
||||
info "This will create the directory structure and write shell config."
|
||||
echo
|
||||
ssh -t "$target" \
|
||||
"MACHINE_PROFILE=${setup_profile} DOTFILES_REMOTE=${DOTFILES_REMOTE} bash ~/scripts/setup_enterprise_ai_bash.sh"
|
||||
success "Setup complete on $target."
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
if $dry_run; then
|
||||
info "Dry run complete. Re-run without --dry-run to transfer files."
|
||||
@@ -1036,6 +1136,7 @@ cmd_deploy_to() {
|
||||
bold "Deploy complete: $deployed file(s) deployed, $skipped skipped."
|
||||
info "Files were copied directly (no symlinks). Re-run deploy-to to push updates."
|
||||
$skip_ssh && info "~/.ssh/ was skipped. Use --include-ssh to also deploy ~/.ssh/config."
|
||||
! $run_setup && info "Tip: add --run-setup to also create directories and shell config on the remote."
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1067,14 +1168,17 @@ ${BOLD}COMMANDS — SSH & Keys${RESET}
|
||||
${BOLD}COMMANDS — Multi-machine${RESET}
|
||||
remote-bootstrap <user@host> [--profile work|personal]
|
||||
Upload scripts and run full setup on a remote machine
|
||||
deploy-to <user@host> [--scripts-only] [--include-ssh] [--no-backup] [--dry-run]
|
||||
deploy-to <user@host> [--scripts-only] [--include-ssh] [--no-backup] [--run-setup] [--profile work|personal] [--dry-run]
|
||||
SCP tracked dotfiles + scripts directly to a server.
|
||||
Use when the server can't reach the Gitea repo.
|
||||
Backs up existing remote files locally before overwriting.
|
||||
--scripts-only Only push ~/scripts/, skip dotfiles
|
||||
--include-ssh Also deploy ~/.ssh/config (skipped by default)
|
||||
--no-backup Skip the pre-deploy remote backup
|
||||
--dry-run Preview what would be transferred
|
||||
--scripts-only Only push ~/scripts/, skip dotfiles
|
||||
--include-ssh Also deploy ~/.ssh/config (skipped by default)
|
||||
--no-backup Skip the pre-deploy remote backup
|
||||
--run-setup Run setup_enterprise_ai_bash.sh on the remote
|
||||
after deploy (creates dirs, shell config)
|
||||
--profile work|personal Profile to pass to setup (default: work)
|
||||
--dry-run Preview what would be transferred
|
||||
|
||||
${BOLD}QUICK START — this machine (work)${RESET}
|
||||
./dotfiles_manager.sh init
|
||||
|
||||
53
scripts/ollama_detect_and_link.sh
Executable file
53
scripts/ollama_detect_and_link.sh
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "🔍 Detecting Ollama model directories and linking into OLLAMA_MODELS"
|
||||
|
||||
# Load env if available
|
||||
if [ -f "$HOME/.bashrc" ]; then
|
||||
set +u
|
||||
# shellcheck disable=SC1091
|
||||
source "$HOME/.bashrc" || true
|
||||
set -u
|
||||
fi
|
||||
|
||||
OLLAMA_MODELS="${OLLAMA_MODELS:-$HOME/models/ollama}"
|
||||
mkdir -p "$OLLAMA_MODELS"
|
||||
|
||||
candidates=(
|
||||
"$HOME/.ollama/models"
|
||||
"$HOME/.local/share/ollama/models"
|
||||
"/var/lib/ollama/models"
|
||||
"/usr/local/var/ollama/models"
|
||||
"$HOME/.ollama"
|
||||
)
|
||||
|
||||
linked=0
|
||||
for cand in "${candidates[@]}"; do
|
||||
if [ -d "$cand" ]; then
|
||||
# skip empty directories
|
||||
if [ -z "$(ls -A "$cand" 2>/dev/null)" ]; then
|
||||
echo "ℹ️ Found $cand but it's empty — skipping"
|
||||
continue
|
||||
fi
|
||||
|
||||
name=$(basename "$cand")
|
||||
dest="$OLLAMA_MODELS/$name"
|
||||
if [ -e "$dest" ]; then
|
||||
echo "ℹ️ Destination exists: $dest — skipping"
|
||||
continue
|
||||
fi
|
||||
ln -sfn "$cand" "$dest"
|
||||
echo "✅ Linked $cand → $dest"
|
||||
linked=$((linked+1))
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $linked -eq 0 ]; then
|
||||
echo "⚠️ No existing Ollama model directories detected in common locations."
|
||||
echo "You can place models in: $OLLAMA_MODELS or run: pull_ollama_model <model-ref> (see scripts/ollama_tmux.sh)"
|
||||
else
|
||||
echo "🎉 Completed linking ($linked). Verify with: ls -la $OLLAMA_MODELS"
|
||||
fi
|
||||
|
||||
echo "Done."
|
||||
144
scripts/ollama_tmux.sh
Executable file
144
scripts/ollama_tmux.sh
Executable file
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Ollama tmux helper and model utilities
|
||||
# Source this file or call functions directly: source scripts/ollama_tmux.sh
|
||||
|
||||
# Ensure environment variables exist
|
||||
if [ -f "$HOME/.bashrc" ]; then
|
||||
set +u
|
||||
# shellcheck disable=SC1091
|
||||
source "$HOME/.bashrc" || true
|
||||
set -u
|
||||
fi
|
||||
: "${OLLAMA_MODELS:=$HOME/models/ollama}"
|
||||
|
||||
start_ollama_tmux() {
|
||||
session="ollama"
|
||||
# Use provided command or sensible default. Ollama uses env vars (OLLAMA_HOST)
|
||||
# Example: OLLAMA_HOST=0.0.0.0:11434 ollama serve
|
||||
default_cmd="${OLLAMA_CMD:-ollama serve}"
|
||||
cmd="${1:-$default_cmd}"
|
||||
echo "Using command: $cmd"
|
||||
if [ -n "${OLLAMA_HOST:-}" ]; then
|
||||
echo "OLLAMA_HOST is set to: $OLLAMA_HOST"
|
||||
fi
|
||||
|
||||
if ! command -v tmux >/dev/null 2>&1; then
|
||||
echo "⚠️ tmux not installed. Install tmux and re-run."
|
||||
return 2
|
||||
fi
|
||||
|
||||
# Create models dir if needed
|
||||
mkdir -p "$OLLAMA_MODELS"
|
||||
|
||||
if tmux has-session -t "$session" 2>/dev/null; then
|
||||
echo "ℹ️ tmux session '$session' already running. Attach with: tmux attach -t $session"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "🔁 Starting ollama in tmux session '$session' with command: $cmd"
|
||||
tmux new-session -d -s "$session" "$cmd"
|
||||
sleep 0.5
|
||||
if tmux has-session -t "$session" 2>/dev/null; then
|
||||
echo "✅ Started. Attach: tmux attach -t $session"
|
||||
else
|
||||
echo "❌ Failed to start tmux session. Check logs or run the command directly: $cmd"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
pull_ollama_model() {
|
||||
if [ "$#" -lt 1 ]; then
|
||||
echo "Usage: pull_ollama_model <model-ref>"
|
||||
return 2
|
||||
fi
|
||||
if ! command -v ollama >/dev/null 2>&1; then
|
||||
echo "⚠️ ollama CLI not found. Install first."
|
||||
return 3
|
||||
fi
|
||||
model="$1"
|
||||
echo "⬇️ Pulling model: $model"
|
||||
ollama pull "$model"
|
||||
}
|
||||
|
||||
import_local_model() {
|
||||
if [ "$#" -lt 1 ]; then
|
||||
echo "Usage: import_local_model <path-to-model-dir-or-file>"
|
||||
return 2
|
||||
fi
|
||||
src="$1"
|
||||
if [ ! -e "$src" ]; then
|
||||
echo "⚠️ Source not found: $src"
|
||||
return 3
|
||||
fi
|
||||
mkdir -p "$OLLAMA_MODELS"
|
||||
dest="$OLLAMA_MODELS/$(basename "$src")"
|
||||
ln -sfn "$src" "$dest"
|
||||
echo "🔗 Linked $src → $dest"
|
||||
echo "Note: depending on your ollama installation you may need to reindex or use the ollama CLI to register the model."
|
||||
}
|
||||
|
||||
stop_ollama_tmux() {
|
||||
session="ollama"
|
||||
if tmux has-session -t "$session" 2>/dev/null; then
|
||||
tmux kill-session -t "$session"
|
||||
echo "🛑 Stopped tmux session '$session'"
|
||||
else
|
||||
echo "ℹ️ No tmux session named '$session' running"
|
||||
fi
|
||||
}
|
||||
|
||||
print_usage() {
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0") <command> [args]
|
||||
|
||||
Commands:
|
||||
start [<cmd>] Start ollama in tmux (optional command overrides default)
|
||||
stop Stop the tmux session named 'ollama'
|
||||
pull <model-ref> Pull a model using the ollama CLI
|
||||
import <path> Import/link a local model directory/file into OLLAMA_MODELS
|
||||
help Show this help
|
||||
|
||||
If you want to use these as shell functions, source this file instead:
|
||||
source scripts/ollama_tmux.sh
|
||||
EOF
|
||||
}
|
||||
|
||||
if [ "${BASH_SOURCE[0]}" == "${0}" ]; then
|
||||
# Script executed directly; provide a simple CLI wrapper
|
||||
cmd="${1:-}"
|
||||
case "$cmd" in
|
||||
start)
|
||||
# shift and pass remaining args as the command
|
||||
shift || true
|
||||
start_ollama_tmux "$@"
|
||||
exit $?
|
||||
;;
|
||||
stop)
|
||||
stop_ollama_tmux
|
||||
exit $?
|
||||
;;
|
||||
pull)
|
||||
shift || true
|
||||
pull_ollama_model "$@"
|
||||
exit $?
|
||||
;;
|
||||
import)
|
||||
shift || true
|
||||
import_local_model "$@"
|
||||
exit $?
|
||||
;;
|
||||
help|--help|-h|"")
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown command: $cmd"
|
||||
print_usage
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo "Loaded ollama tmux helper. Functions: start_ollama_tmux, stop_ollama_tmux, pull_ollama_model, import_local_model"
|
||||
fi
|
||||
@@ -186,6 +186,69 @@ fi
|
||||
|
||||
echo "✅ .bashrc.local written for profile: $MACHINE_PROFILE"
|
||||
|
||||
# ---- NFS-aware placement for work servers ----
|
||||
# Work servers with NFS-mounted home dirs share ~/.bashrc.local across hosts.
|
||||
# To keep per-machine overrides, store the real file in /opt/kenjim/ and symlink.
|
||||
if [[ "$MACHINE_PROFILE" == "work" ]]; then
|
||||
_is_nfs_home=false
|
||||
case "$(hostname -s)" in
|
||||
etqc-*|etbg-*|engtech-dev-*|qnc-kenjim-toby-shell*|qtaas*|bng-kenjim-toby-shell*|btaas*|kenjim-taas*)
|
||||
if df -P "$HOME" 2>/dev/null | tail -1 | grep -qE ':|nfs'; then
|
||||
_is_nfs_home=true
|
||||
elif mount | grep -q "on ${HOME%%/} .*type nfs"; then
|
||||
_is_nfs_home=true
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if $_is_nfs_home; then
|
||||
OPT_DIR="/opt/kenjim"
|
||||
OPT_LOCAL="$OPT_DIR/.bashrc.local"
|
||||
echo "🔗 NFS home detected — relocating .bashrc.local to $OPT_LOCAL"
|
||||
|
||||
if [ ! -d "$OPT_DIR" ]; then
|
||||
echo " Creating $OPT_DIR ..."
|
||||
sudo mkdir -p "$OPT_DIR"
|
||||
sudo chown "$(id -u):$(id -g)" "$OPT_DIR"
|
||||
chmod 700 "$OPT_DIR"
|
||||
fi
|
||||
|
||||
# If ~/.bashrc.local is already a symlink (previous run), the cat above
|
||||
# wrote through it into the target. Remove the symlink first so mv
|
||||
# doesn't see source and destination as the same file.
|
||||
if [ -L "$BASHRC_LOCAL" ]; then
|
||||
rm -f "$BASHRC_LOCAL"
|
||||
# Content already landed at the symlink target; just ensure perms
|
||||
chmod 600 "$OPT_LOCAL"
|
||||
else
|
||||
mv "$BASHRC_LOCAL" "$OPT_LOCAL"
|
||||
chmod 600 "$OPT_LOCAL"
|
||||
fi
|
||||
|
||||
ln -sfn "$OPT_LOCAL" "$BASHRC_LOCAL"
|
||||
echo " Linked: ~/.bashrc.local → $OPT_LOCAL"
|
||||
|
||||
# VS Code Remote stores large caches in ~/.vscode-server and
|
||||
# ~/.vscode-remote-containers — keep them on local disk, not NFS.
|
||||
for _vsdir in .vscode-server .vscode-remote-containers; do
|
||||
_opt_target="$OPT_DIR/$_vsdir"
|
||||
_home_link="$HOME_DIR/$_vsdir"
|
||||
mkdir -p "$_opt_target"
|
||||
if [ -d "$_home_link" ] && [ ! -L "$_home_link" ]; then
|
||||
# Existing real directory — move contents then replace with symlink
|
||||
echo " Moving ~/$_vsdir → $OPT_DIR/$_vsdir ..."
|
||||
rsync -a "$_home_link/" "$_opt_target/" 2>/dev/null || \
|
||||
cp -a "$_home_link/." "$_opt_target/" 2>/dev/null || true
|
||||
rm -rf "$_home_link"
|
||||
fi
|
||||
ln -sfn "$_opt_target" "$_home_link"
|
||||
echo " Linked: ~/$_vsdir → $_opt_target"
|
||||
done
|
||||
|
||||
echo "✅ Per-machine .bashrc.local and VS Code dirs stored outside NFS at $OPT_DIR"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------
|
||||
# 4️⃣ INITIALIZE DOTFILES REPO (with Gitea remote)
|
||||
# ------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user