added vault

This commit is contained in:
Brad Stein 2025-08-19 01:06:45 -05:00
parent 968532cc55
commit 016cbab0f9
11 changed files with 889 additions and 195 deletions

View File

@ -1,3 +1,4 @@
# dockerfiles/Dockerfile.monero-p2pool
# syntax=docker/dockerfile:1.6
ARG DEBIAN_IMAGE=debian:bookworm-slim
ARG P2POOL_VERSION=v4.9

View File

@ -1,3 +1,4 @@
# dockerfiles/Dockerfile.monero-wallet-rpc
# syntax=docker/dockerfile:1.6
ARG DEBIAN_IMAGE=debian:bookworm-slim
ARG MONERO_VERSION=v0.18.4.1

View File

@ -1,3 +1,4 @@
# dockerfiles/Dockerfile.monerod
# syntax=docker/dockerfile:1.6
FROM debian:bookworm-slim

View File

@ -0,0 +1,54 @@
# syntax=docker/dockerfile:1.6
FROM --platform=$TARGETPLATFORM ubuntu:24.04
ARG TARGETARCH
ARG SUI_REF=mainnet-v1.53.2
# minimal tools + jq + age (optional lock/unlock helpers)
RUN apt-get update && \
apt-get install -y --no-install-recommends ca-certificates curl jq tar age && \
rm -rf /var/lib/apt/lists/*
# Fetch the right prebuilt tarball for this arch and install 'sui'
RUN set -eux; \
case "$TARGETARCH" in \
amd64) want='(x86_64|amd64)' ;; \
arm64) want='(aarch64|arm64)' ;; \
*) echo "unsupported arch: $TARGETARCH" >&2; exit 1 ;; \
esac; \
api="https://api.github.com/repos/MystenLabs/sui/releases/tags/${SUI_REF}"; \
url="$(curl -fsSL --http1.1 --retry 5 --retry-connrefused --retry-delay 2 "$api" \
| jq -r --arg want "$want" '.assets[] | select(.name|test("ubuntu.*" + $want)) | .browser_download_url' \
| head -n1)"; \
test -n "$url"; \
echo "Downloading: $url"; \
curl -fL --http1.1 --retry 5 --retry-connrefused --retry-delay 2 -o /tmp/sui.tgz "$url"; \
mkdir -p /opt/sui; \
tar -xzf /tmp/sui.tgz -C /opt/sui; \
# find and install the 'sui' binary from the extracted tree
f="$(find /opt/sui -type f -name sui -perm -u+x | head -n1)"; \
test -n "$f"; install -m 0755 "$f" /usr/local/bin/sui; \
# sanity check in the image
/usr/local/bin/sui --version
# runtime user and homedir setup
RUN set -eux; \
uid=1000; gid=1000; \
gname="$(getent group "$gid" | cut -d: -f1 || true)"; \
if [ -z "$gname" ]; then \
groupadd -g "$gid" sui; \
gname=sui; \
fi; \
if getent passwd "$uid" >/dev/null; then \
# UID 1000 already exists; create 'sui' with next available UID but keep primary group = gid 1000
useradd -m -g "$gid" sui; \
else \
useradd -m -u "$uid" -g "$gid" sui; \
fi; \
install -d -m 0770 -o sui -g "$gid" /home/sui/.sui/sui_config
USER sui
WORKDIR /home/sui
# keep the container ready to be exec'd into by your scripts
CMD ["/bin/sh","-lc","sleep infinity"]

View File

@ -0,0 +1,12 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: vault
namespace: flux-system
spec:
interval: 10m
path: ./services/vault
prune: true
sourceRef:
kind: GitRepository
name: flux-system

View File

@ -212,12 +212,12 @@ function _probe_monerod -a ADDR
end
echo (set_color red)"Could not speak Monero /get_info to $ADDR. Not a monerod (or blocked)."(set_color normal) >&2
echo "Tip: run your own monerod or set WALLETSVC_SKIP_DAEMON_CHECK=1 to bypass." >&2
echo "Tip: run your own monerod or set xmrwallet_SKIP_DAEMON_CHECK=1 to bypass." >&2
return 1
end
# Wait for wallet RPC to accept connections (digest auth get_version)
function walletsvc_wait_ready -a NS SVC SECS
function xmrwallet_wait_ready -a NS SVC SECS
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
if test -z "$SECS"; set SECS 60; end
@ -249,7 +249,7 @@ end
### ------- main workflow ---------------------------------------------------
function walletsvc_bootstrap --description "Interactive setup of monero-wallet-rpc with PVC+secrets; creates default wallet and prints recovery info"
function xmrwallet_bootstrap --description "Interactive setup of monero-wallet-rpc with PVC+secrets; creates default wallet and prints recovery info"
_need kubectl jq curl awk; or return 1
_banner "Monero wallet RPC bootstrap"
@ -358,7 +358,7 @@ function walletsvc_bootstrap --description "Interactive setup of monero-wallet-r
set daemon_addr $daemon_override
end
if test -z "$WALLETSVC_SKIP_DAEMON_CHECK"
if test -z "$xmrwallet_SKIP_DAEMON_CHECK"
_banner "Probing daemon via temporary port-forward"
set PF_LOCAL 28081
_pf_start crypto monerod $PF_LOCAL 18081
@ -368,7 +368,7 @@ function walletsvc_bootstrap --description "Interactive setup of monero-wallet-r
end
_pf_stop
else
echo "Skipping daemon probe due to WALLETSVC_SKIP_DAEMON_CHECK=1"
echo "Skipping daemon probe due to xmrwallet_SKIP_DAEMON_CHECK=1"
end
# Use your private image by default (in Zot)
@ -445,8 +445,8 @@ function walletsvc_bootstrap --description "Interactive setup of monero-wallet-r
--dry-run=client -o yaml | kubectl -n $ns apply -f -; or return 1
set ts (date -Is)
kubectl -n $ns annotate secret $rpc_secret_name walletsvc.titan/update-ts="$ts" --overwrite >/dev/null 2>&1
kubectl -n $ns annotate secret $wpass_secret_name walletsvc.titan/update-ts="$ts" --overwrite >/dev/null 2>&1
kubectl -n $ns annotate secret $rpc_secret_name xmrwallet.titan/update-ts="$ts" --overwrite >/dev/null 2>&1
kubectl -n $ns annotate secret $wpass_secret_name xmrwallet.titan/update-ts="$ts" --overwrite >/dev/null 2>&1
echo "RPC creds: user='$rpc_user' pass='$rpc_pass'"
echo "Wallet pass: $wallet_pass"
@ -609,27 +609,27 @@ function walletsvc_bootstrap --description "Interactive setup of monero-wallet-r
end
_banner "Waiting for wallet RPC readiness"
walletsvc_wait_ready $ns $svc_name 60; or return 1
xmrwallet_wait_ready $ns $svc_name 60; or return 1
_banner "Creating/opening wallet via JSON-RPC"
if not walletsvc_check_write $ns $app_name >/dev/null
if not xmrwallet_check_write $ns $app_name >/dev/null
echo (set_color red)"PVC is not writable; aborting."(set_color normal)
return 1
end
# Always attempt create; if it exists, open it.
if not walletsvc_create_wallet $ns $svc_name $wallet_file $wallet_pass
if not xmrwallet_create_wallet $ns $svc_name $wallet_file $wallet_pass
echo (set_color yellow)"create_wallet returned non-zero; attempting open anyway…"(set_color normal)
end
if not walletsvc_open $ns $svc_name $wallet_file $wallet_pass
echo (set_color red)"Failed to open wallet $wallet_file. If this wallet already exists, the on-disk password may differ from the Secret. Use walletsvc_open with the correct password or walletsvc_change_wallet_password."(set_color normal)
if not xmrwallet_open $ns $svc_name $wallet_file $wallet_pass
echo (set_color red)"Failed to open wallet $wallet_file. If this wallet already exists, the on-disk password may differ from the Secret. Use xmrwallet_open with the correct password or xmrwallet_change_wallet_password."(set_color normal)
return 1
end
# --- Gather summary data (address, seed if enabled)
set PRIMARY (walletsvc_primary_address $ns $svc_name 2>/dev/null)
set NEWADDR (walletsvc_new_address $ns $svc_name "bootstrap-deposit" 0 2>/dev/null | awk '/New address:/{print $3}' )
set SEEDRAW (walletsvc_show_seed $ns $svc_name 2>&1)
set PRIMARY (xmrwallet_primary_address $ns $svc_name 2>/dev/null)
set NEWADDR (xmrwallet_new_address $ns $svc_name "bootstrap-deposit" 0 2>/dev/null | awk '/New address:/{print $3}' )
set SEEDRAW (xmrwallet_show_seed $ns $svc_name 2>&1)
set SEED (echo $SEEDRAW | awk '/Mnemonic seed:/,0{if($0!~/Mnemonic seed:/)print}' )
_banner "Done"
@ -652,31 +652,31 @@ function walletsvc_bootstrap --description "Interactive setup of monero-wallet-r
echo $SEED
else
echo "Mnemonic seed not retrievable via RPC (image may disable it)."
echo "If needed and supported by your image: walletsvc_show_seed $ns $svc_name"
echo "If needed and supported by your image: xmrwallet_show_seed $ns $svc_name"
end
echo
echo "Access locally: walletsvc_portforward $ns $svc_name # then http://127.0.0.1:18083/json_rpc"
echo "Quick overview: walletsvc_overview $ns $svc_name"
echo "Access locally: xmrwallet_portforward $ns $svc_name # then http://127.0.0.1:18083/json_rpc"
echo "Quick overview: xmrwallet_overview $ns $svc_name"
end
### ------- utilities -------------------------------------------------------
function walletsvc_portforward --description "port-forward RPC to localhost:18083" -a NS SVC
function xmrwallet_portforward --description "port-forward RPC to localhost:18083" -a NS SVC
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
echo "Forwarding $NS/$SVC → http://127.0.0.1:18083 (Ctrl+C to stop)…"
kubectl -n $NS port-forward svc/$SVC 18083:18083
end
function walletsvc_status --description "show pod/service status" -a NS APP
function xmrwallet_status --description "show pod/service status" -a NS APP
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-rpc; end
kubectl -n $NS get deploy,po,svc,netpol -l app=$APP -o wide
end
function walletsvc_stop --description "stop the RPC but keep PVC + secrets" -a NS APP SVC
function xmrwallet_stop --description "stop the RPC but keep PVC + secrets" -a NS APP SVC
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-rpc; end
if test -z "$SVC"; set SVC $APP; end
@ -685,7 +685,7 @@ function walletsvc_stop --description "stop the RPC but keep PVC + secrets" -a N
echo "Stopped $NS/$APP. PVC and secrets retained."
end
function walletsvc_purge --description "IRREVERSIBLY delete PVC + secrets (keys on disk!)" -a NS APP PVC SVC
function xmrwallet_purge --description "IRREVERSIBLY delete PVC + secrets (keys on disk!)" -a NS APP PVC SVC
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-rpc; end
if test -z "$PVC"; set PVC wallet-data; end
@ -704,7 +704,7 @@ function walletsvc_purge --description "IRREVERSIBLY delete PVC + secrets (keys
echo "Purged. Ensure you have the mnemonic backed up if you ever need to restore."
end
function walletsvc_show_seed --description "Try to fetch mnemonic via RPC query_key (wallet must be open)" -a NS SVC RPCUSER RPCPASS
function xmrwallet_show_seed --description "Try to fetch mnemonic via RPC query_key (wallet must be open)" -a NS SVC RPCUSER RPCPASS
_need jq curl; or return 1
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
@ -728,11 +728,11 @@ function walletsvc_show_seed --description "Try to fetch mnemonic via RPC query_
end
# ---------- core JSON-RPC wrapper (raw JSON to stdout) ----------
function walletsvc_rpc_call --description "RPC call with secrets (auto port-forward)" -a NS SVC METHOD PARAMS_JSON
function xmrwallet_rpc_call --description "RPC call with secrets (auto port-forward)" -a NS SVC METHOD PARAMS_JSON
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
if test -z "$METHOD"
echo "Usage: walletsvc_rpc_call [ns] [svc] <method> [params_json]" >&2
echo "Usage: xmrwallet_rpc_call [ns] [svc] <method> [params_json]" >&2
return 1
end
@ -772,12 +772,12 @@ function walletsvc_rpc_call --description "RPC call with secrets (auto port-forw
return 0
end
function walletsvc_rpc_test --description "get_version using secrets" -a NS SVC
walletsvc_rpc_call $NS $SVC get_version | jq .
function xmrwallet_rpc_test --description "get_version using secrets" -a NS SVC
xmrwallet_rpc_call $NS $SVC get_version | jq .
end
# Rotate RPC username/password (updates Secret & restarts Deploy)
function walletsvc_set_rpc_credentials --description "rotate RPC Basic creds" -a NS APP
function xmrwallet_set_rpc_credentials --description "rotate RPC Basic creds" -a NS APP
_need kubectl; or return 1
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-rpc; end
@ -796,7 +796,7 @@ function walletsvc_set_rpc_credentials --description "rotate RPC Basic creds" -a
--from-literal=username="$NEWUSER" \
--from-literal=password="$NEWPASS" \
--dry-run=client -o yaml | kubectl -n $NS apply -f -; or return 1
kubectl -n $NS annotate secret $SNAME walletsvc.titan/update-ts=(date -Is) --overwrite >/dev/null 2>&1
kubectl -n $NS annotate secret $SNAME xmrwallet.titan/update-ts=(date -Is) --overwrite >/dev/null 2>&1
kubectl -n $NS rollout restart deploy/$APP
kubectl -n $NS rollout status deploy/$APP --timeout=180s; or return 1
@ -806,7 +806,7 @@ function walletsvc_set_rpc_credentials --description "rotate RPC Basic creds" -a
end
# Change wallet file password via RPC
function walletsvc_change_wallet_password --description "change password of a wallet file via RPC" -a NS SVC
function xmrwallet_change_wallet_password --description "change password of a wallet file via RPC" -a NS SVC
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
@ -821,13 +821,13 @@ function walletsvc_change_wallet_password --description "change password of a wa
echo
if test -z "$NEW"; set NEW (_rand_alnum32); end
set res (walletsvc_rpc_call $NS $SVC open_wallet (printf '{"filename":"%s","password":"%s"}' $WFILE $OLD))
walletsvc_rpc_call $NS $SVC change_wallet_password (printf '{"old_password":"%s","new_password":"%s"}' $OLD $NEW)
set res (xmrwallet_rpc_call $NS $SVC open_wallet (printf '{"filename":"%s","password":"%s"}' $WFILE $OLD))
xmrwallet_rpc_call $NS $SVC change_wallet_password (printf '{"old_password":"%s","new_password":"%s"}' $OLD $NEW)
echo "New wallet password: $NEW"
end
# --- logs from the deployment (quick tail) ---
function walletsvc_logs -a NS APP LINES
function xmrwallet_logs -a NS APP LINES
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-rpc; end
if test -z "$LINES"; set LINES 200; end
@ -835,7 +835,7 @@ function walletsvc_logs -a NS APP LINES
end
# --- list files in /data inside the pod ---
function walletsvc_wallet_ls -a NS APP
function xmrwallet_wallet_ls -a NS APP
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-rpc; end
echo "Listing /data in $NS/$APP" >&2
@ -843,11 +843,11 @@ function walletsvc_wallet_ls -a NS APP
end
# --- create a wallet (uses Secret password if PASS omitted) ---
function walletsvc_create_wallet -a NS SVC FILE PASS LANG
function xmrwallet_create_wallet -a NS SVC FILE PASS LANG
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
if test -z "$FILE"
echo "Usage: walletsvc_create_wallet [ns] [svc] <filename> [pass] [language]" >&2
echo "Usage: xmrwallet_create_wallet [ns] [svc] <filename> [pass] [language]" >&2
return 1
end
if test -z "$PASS"
@ -856,7 +856,7 @@ function walletsvc_create_wallet -a NS SVC FILE PASS LANG
if test -z "$LANG"; set LANG English; end
set payload (printf '{"filename":"%s","password":"%s","language":"%s"}' $FILE $PASS $LANG)
set res (walletsvc_rpc_call $NS $SVC create_wallet $payload)
set res (xmrwallet_rpc_call $NS $SVC create_wallet $payload)
set rc $status
if test $rc -ne 0
echo (set_color red)"create_wallet RPC transport failed (rc=$rc)."(set_color normal) >&2
@ -877,11 +877,11 @@ function walletsvc_create_wallet -a NS SVC FILE PASS LANG
end
# --- improved opener: closes first, checks files, hints if password mismatch ---
function walletsvc_open -a NS SVC FILE PASS
function xmrwallet_open -a NS SVC FILE PASS
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
if test -z "$FILE"
echo "Usage: walletsvc_open [ns] [svc] <filename> [password]" >&2
echo "Usage: xmrwallet_open [ns] [svc] <filename> [password]" >&2
return 1
end
if test -z "$PASS"
@ -891,9 +891,9 @@ function walletsvc_open -a NS SVC FILE PASS
read -s -P "Wallet password for $FILE: " PASS; echo
end
walletsvc_rpc_call $NS $SVC close_wallet >/dev/null 2>&1; or true
xmrwallet_rpc_call $NS $SVC close_wallet >/dev/null 2>&1; or true
set res (walletsvc_rpc_call $NS $SVC open_wallet (printf '{"filename":"%s","password":"%s"}' $FILE $PASS))
set res (xmrwallet_rpc_call $NS $SVC open_wallet (printf '{"filename":"%s","password":"%s"}' $FILE $PASS))
set rc $status
if test $rc -ne 0
echo (set_color red)"open_wallet RPC transport failed (rc=$rc)."(set_color normal) >&2
@ -903,12 +903,12 @@ function walletsvc_open -a NS SVC FILE PASS
set exists (kubectl -n $NS exec deploy/$SVC -- sh -lc (printf 'test -e /data/%s -o -e /data/%s.keys && echo yes || echo no' $FILE $FILE) 2>/dev/null)
if test "$exists" = "no"
echo "No wallet files at /data/$FILE{,.keys}. If this should be a new wallet, run:" >&2
echo " walletsvc_create_wallet $NS $SVC $FILE" >&2
echo " xmrwallet_create_wallet $NS $SVC $FILE" >&2
return 1
end
set tmp (mktemp)
walletsvc_rpc_call $NS $SVC open_wallet (printf '{"filename":"%s","password":"%s"}' $FILE $PASS) > $tmp
xmrwallet_rpc_call $NS $SVC open_wallet (printf '{"filename":"%s","password":"%s"}' $FILE $PASS) > $tmp
set rc $status
set res (cat $tmp); rm -f $tmp
@ -930,14 +930,14 @@ function walletsvc_open -a NS SVC FILE PASS
echo $res | jq .
end
function walletsvc_check_write -a NS APP
function xmrwallet_check_write -a NS APP
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-rpc; end
kubectl -n $NS exec deploy/$APP -- sh -lc 'echo test-$(date +%s) > /data/.write-test && ls -l /data/.write-test && rm -f /data/.write-test'
end
# --- ensure wallet is open (create if missing) ---
function walletsvc_ensure_open -a NS SVC FILE
function xmrwallet_ensure_open -a NS SVC FILE
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
if test -z "$FILE"; set FILE main; end
@ -945,14 +945,14 @@ function walletsvc_ensure_open -a NS SVC FILE
set exists (kubectl -n $NS exec deploy/$SVC -- sh -lc (printf 'if [ -e "/data/%s" ] || [ -e "/data/%s.keys" ]; then echo yes; else echo no; fi' $FILE $FILE) 2>/dev/null)
if test "$exists" = "no"
echo "No /data/$FILE found. Creating…" >&2
walletsvc_create_wallet $NS $SVC $FILE; or return 1
xmrwallet_create_wallet $NS $SVC $FILE; or return 1
end
walletsvc_open $NS $SVC $FILE; or return 1
xmrwallet_open $NS $SVC $FILE; or return 1
end
# --- quick primary address print (account 0)
function walletsvc_primary_address -a NS SVC
function xmrwallet_primary_address -a NS SVC
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
_pf_start $NS $SVC 18083 18083
@ -966,11 +966,11 @@ function walletsvc_primary_address -a NS SVC
end
# --- show unlocked balance quickly
function walletsvc_unlocked -a NS SVC
function xmrwallet_unlocked -a NS SVC
_need python3; or return 1
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
set res (walletsvc_rpc_call $NS $SVC get_balance '{"account_index":0}')
set res (xmrwallet_rpc_call $NS $SVC get_balance '{"account_index":0}')
set bal (echo $res | jq -r '.result.balance // 0')
set unl (echo $res | jq -r '.result.unlocked_balance // 0')
@ -982,7 +982,7 @@ function walletsvc_unlocked -a NS SVC
end
# --- wait until unlocked balance >= threshold (XMR), timeout seconds
function walletsvc_wait_unlocked -a NS SVC XMR_MIN TIMEOUT
function xmrwallet_wait_unlocked -a NS SVC XMR_MIN TIMEOUT
_need python3; or return 1
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
@ -990,7 +990,7 @@ function walletsvc_wait_unlocked -a NS SVC XMR_MIN TIMEOUT
if test -z "$TIMEOUT"; set TIMEOUT 300; end
set start (date +%s)
while true
set res (walletsvc_rpc_call $NS $SVC get_balance '{"account_index":0}')
set res (xmrwallet_rpc_call $NS $SVC get_balance '{"account_index":0}')
set unl (echo $res | jq -r '.result.unlocked_balance // 0')
set unlx (python3 -c 'from decimal import Decimal; import sys; print(Decimal(sys.argv[1]) / Decimal("1e12"))' -- $unl)
set ge (python3 -c 'from decimal import Decimal; import sys; print(1 if Decimal(sys.argv[1]) >= Decimal(sys.argv[2]) else 0)' -- $unlx $XMR_MIN)
@ -1007,7 +1007,7 @@ function walletsvc_wait_unlocked -a NS SVC XMR_MIN TIMEOUT
end
# ---------- friendly overview ----------
function walletsvc_overview -a NS SVC ACCOUNT
function xmrwallet_overview -a NS SVC ACCOUNT
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
if test -z "$ACCOUNT"; set ACCOUNT 0; end
@ -1032,7 +1032,7 @@ function walletsvc_overview -a NS SVC ACCOUNT
echo "-- Height:"
if test -n "$err"
echo " ERROR: $err"
echo " (Tip: open your wallet: walletsvc_open $NS $SVC main)"
echo " (Tip: open your wallet: xmrwallet_open $NS $SVC main)"
else
echo $resp | jq -r '" wallet_height=\(.result.height)"'
end
@ -1110,7 +1110,7 @@ function walletsvc_overview -a NS SVC ACCOUNT
end
# ---------- list addresses ----------
function walletsvc_list_addresses -a NS SVC ACCOUNT
function xmrwallet_list_addresses -a NS SVC ACCOUNT
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
if test -z "$ACCOUNT"; set ACCOUNT 0; end
@ -1132,7 +1132,7 @@ function walletsvc_list_addresses -a NS SVC ACCOUNT
end
# ---------- new subaddress ----------
function walletsvc_new_address -a NS SVC LABEL ACCOUNT
function xmrwallet_new_address -a NS SVC LABEL ACCOUNT
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
if test -z "$ACCOUNT"; set ACCOUNT 0; end
@ -1155,13 +1155,13 @@ function walletsvc_new_address -a NS SVC LABEL ACCOUNT
end
# --- send a specific amount XMR to a single address (optionally payment_id)
# Usage: walletsvc_send [ns] [svc] <to_address> <amount_xmr> [payment_id_hex]
function walletsvc_send -a NS SVC TO AMT_XMR PID
# Usage: xmrwallet_send [ns] [svc] <to_address> <amount_xmr> [payment_id_hex]
function xmrwallet_send -a NS SVC TO AMT_XMR PID
_need jq curl python3; or return 1
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
if test -z "$TO" -o -z "$AMT_XMR"
echo "Usage: walletsvc_send [ns] [svc] <to_address> <amount_xmr> [payment_id_hex]" >&2
echo "Usage: xmrwallet_send [ns] [svc] <to_address> <amount_xmr> [payment_id_hex]" >&2
return 1
end
@ -1180,7 +1180,7 @@ function walletsvc_send -a NS SVC TO AMT_XMR PID
set body $body_base
end
set res (walletsvc_rpc_call $NS $SVC transfer $body)
set res (xmrwallet_rpc_call $NS $SVC transfer $body)
set err (echo $res | jq -r '.error.message // empty')
if test -n "$err"
echo "ERROR: $err" >&2
@ -1199,18 +1199,18 @@ function walletsvc_send -a NS SVC TO AMT_XMR PID
end
# --- sweep all unlocked funds to an address (account 0)
# Usage: walletsvc_sweep_all [ns] [svc] <to_address>
function walletsvc_sweep_all -a NS SVC TO
# Usage: xmrwallet_sweep_all [ns] [svc] <to_address>
function xmrwallet_sweep_all -a NS SVC TO
_need jq curl; or return 1
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
if test -z "$TO"
echo "Usage: walletsvc_sweep_all [ns] [svc] <to_address>" >&2
echo "Usage: xmrwallet_sweep_all [ns] [svc] <to_address>" >&2
return 1
end
set body (printf '{"address":"%s","account_index":0,"priority":1,"do_not_relay":false,"get_tx_keys":true}' $TO)
set res (walletsvc_rpc_call $NS $SVC sweep_all $body)
set res (xmrwallet_rpc_call $NS $SVC sweep_all $body)
set err (echo $res | jq -r '.error.message // empty')
if test -n "$err"
echo "ERROR: $err" >&2
@ -1221,7 +1221,81 @@ function walletsvc_sweep_all -a NS SVC TO
echo $res | jq -r '.result.tx_hash_list[]? | " tx: " + .'
end
# Optional: non-sensitive cluster snapshot to help tune manifests.
# Return total size (bytes) of /data/<file> + /data/<file>.keys inside the RPC pod
# Usage: xmrwallet_wallet_size_bytes [ns] [app] [file]
function xmrwallet_wallet_size_bytes -a NS APP FILE
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-rpc; end
if test -z "$FILE"; set FILE main; end
set CMD (printf 'f="/data/%s"; k="/data/%s.keys"; s=0; [ -e "$f" ] && s=$(stat -c %%s "$f"); s2=0; [ -e "$k" ] && s2=$(stat -c %%s "$k"); echo $((s+s2))' $FILE $FILE)
set SUM (kubectl -n $NS exec deploy/$APP -- sh -lc "$CMD" 2>/dev/null)
if test -z "$SUM"; set SUM 0; end
echo $SUM
end
# Prometheus-friendly metric line (total bytes)
# Usage: xmrwallet_metrics [ns] [app] [file]
function xmrwallet_metrics -a NS APP FILE
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-rpc; end
if test -z "$FILE"; set FILE main; end
set BYTES (xmrwallet_wallet_size_bytes $NS $APP $FILE)
printf "wallet_size_bytes{chain=\"monero\",namespace=\"%s\",app=\"%s\",wallet=\"%s\"} %s\n" $NS $APP $FILE $BYTES
end
# Restore a wallet file via wallet-RPC from a 25-word seed
# Usage: xmrwallet_restore [ns] [svc] [wallet_file] [restore_height] [language=English]
function xmrwallet_restore -a NS SVC FILE RH LANG
_need jq curl; or return 1
if test -z "$NS"; set NS crypto; end
if test -z "$SVC"; set SVC wallet-rpc; end
if test -z "$FILE"; set FILE main; end
if test -z "$RH"; set RH 0; end
if test -z "$LANG"; set LANG English; end
# Get RPC creds and prompt for wallet password + seed (hidden)
set RPCUSER (kubectl -n $NS get secret {$SVC}-rpc-auth -o jsonpath='{.data.username}' | base64 -d)
set RPCPASS (kubectl -n $NS get secret {$SVC}-rpc-auth -o jsonpath='{.data.password}' | base64 -d)
echo (set_color yellow)"New wallet password (input hidden):"(set_color normal)
read -s WPASS; echo
if test -z "$WPASS"
echo (set_color red)"Error:"(set_color normal)" empty wallet password."; return 1
end
echo (set_color yellow)"Paste your 25-word Monero seed (input hidden):"(set_color normal)
read -s SEED; echo
if test -z "$SEED"
echo (set_color red)"Error:"(set_color normal)" empty seed."; return 1
end
# Open a port-forward for the RPC, call restore_deterministic_wallet
function _pf_start_local
kubectl -n $NS port-forward svc/$SVC 18083:18083 >/dev/null 2>&1 &
set -g PF_PID $last_pid
sleep 1
end
function _pf_stop_local
if test -n "$PF_PID"; kill $PF_PID 2>/dev/null; set -e PF_PID; end
end
_pf_start_local
set body (printf '{"seed":"%s","password":"%s","filename":"%s","language":"%s","restore_height":%s}' $SEED $WPASS $FILE $LANG $RH)
set resp (curl -s --digest -u "$RPCUSER:$RPCPASS" -H 'Content-Type: application/json' \
-d (printf '{"jsonrpc":"2.0","id":"0","method":"restore_deterministic_wallet","params":%s}' "$body") \
http://127.0.0.1:18083/json_rpc)
_pf_stop_local
set err (echo $resp | jq -r '.error.message // empty')
if test -n "$err"
echo (set_color red)"restore_deterministic_wallet error:"(set_color normal) $err >&2
return 1
end
echo "Restored wallet /data/$FILE (from seed). Beginning blockchain sync…"
echo (set_color yellow)"Keep your seed offline and secure."(set_color normal)
end
function cluster_probe
set OUT cluster-snapshot.txt
printf "# Cluster snapshot %s\n" (date -Is) > $OUT
@ -1271,34 +1345,34 @@ function cluster_probe
end
# --- one-line command reference (keep in sync) ---
function walletsvc_help
echo "walletsvc_bootstrap # interactive deploy + secrets + PVC + first wallet (multiwallet RPC), idempotent"
echo "walletsvc_status [ns] [app] # show deploy, pods, service, netpol (default ns=crypto)"
echo "walletsvc_portforward [ns] [svc] # port-forward RPC to localhost:18083 (CTRL+C to stop)"
echo "walletsvc_logs [ns] [app] [N] # tail N (default 200) lines of RPC pod logs"
echo "walletsvc_wallet_ls [ns] [app] # list files under /data in the RPC pod (check wallet files)"
echo "walletsvc_rpc_test [ns] [svc] # JSON-RPC get_version (sanity check)"
echo "walletsvc_rpc_call [ns] [svc] <method> [params_json] # raw JSON (stdout) with digest auth"
echo "walletsvc_open [ns] [svc] <file> [pass] # close_wallet (ignore) -> open_wallet"
echo "walletsvc_create_wallet [ns] [svc] <file> [pass] [lang]# create wallet (defaults: pass from Secret, lang=English)"
echo "walletsvc_ensure_open [ns] [svc] [file] # create if missing, then open (uses Secret pass)"
echo "walletsvc_overview [ns] [svc] [acct=0] # version, height, balances, a few addresses, recent transfers"
echo "walletsvc_list_addresses [ns] [svc] [acct=0] # list all subaddresses for account"
echo "walletsvc_new_address [ns] [svc] [label] [acct=0] # create labeled subaddress"
echo "walletsvc_set_rpc_credentials [ns] [app] # rotate RPC basic auth (secret + rollout)"
echo "walletsvc_change_wallet_password [ns] [svc] # change wallet file password via RPC"
echo "walletsvc_stop [ns] [app] [svc] # delete deployment+service only"
echo "walletsvc_purge [ns] [app] [pvc] [svc] # delete deploy+svc+PVC+secrets (danger!)"
function xmrwallet_help
echo "xmrwallet_bootstrap # interactive deploy + secrets + PVC + first wallet (multiwallet RPC), idempotent"
echo "xmrwallet_status [ns] [app] # show deploy, pods, service, netpol (default ns=crypto)"
echo "xmrwallet_portforward [ns] [svc] # port-forward RPC to localhost:18083 (CTRL+C to stop)"
echo "xmrwallet_logs [ns] [app] [N] # tail N (default 200) lines of RPC pod logs"
echo "xmrwallet_wallet_ls [ns] [app] # list files under /data in the RPC pod (check wallet files)"
echo "xmrwallet_rpc_test [ns] [svc] # JSON-RPC get_version (sanity check)"
echo "xmrwallet_rpc_call [ns] [svc] <method> [params_json] # raw JSON (stdout) with digest auth"
echo "xmrwallet_open [ns] [svc] <file> [pass] # close_wallet (ignore) -> open_wallet"
echo "xmrwallet_create_wallet [ns] [svc] <file> [pass] [lang]# create wallet (defaults: pass from Secret, lang=English)"
echo "xmrwallet_ensure_open [ns] [svc] [file] # create if missing, then open (uses Secret pass)"
echo "xmrwallet_overview [ns] [svc] [acct=0] # version, height, balances, a few addresses, recent transfers"
echo "xmrwallet_list_addresses [ns] [svc] [acct=0] # list all subaddresses for account"
echo "xmrwallet_new_address [ns] [svc] [label] [acct=0] # create labeled subaddress"
echo "xmrwallet_set_rpc_credentials [ns] [app] # rotate RPC basic auth (secret + rollout)"
echo "xmrwallet_change_wallet_password [ns] [svc] # change wallet file password via RPC"
echo "xmrwallet_stop [ns] [app] [svc] # delete deployment+service only"
echo "xmrwallet_purge [ns] [app] [pvc] [svc] # delete deploy+svc+PVC+secrets (danger!)"
end
function walletsvc_help_detailed
function xmrwallet_help_detailed
echo "Commands (defaults: ns=crypto, svc/app=wallet-rpc)"
echo
echo "walletsvc_bootstrap"
echo "xmrwallet_bootstrap"
echo " Interactive deploy: creates/updates secrets, PVC, Deployment (fsGroup+init perms), Service, NetPolicy."
echo " Idempotent: if deploy/svc/netpol already exist, you can clean them up (PVC+secrets kept) and continue."
echo " Uses your in-cluster monerod by default (monerod:18081 in ns=crypto)."
echo " Probes it via a temporary port-forward so it works from your workstation."
echo " Set WALLETSVC_SKIP_DAEMON_CHECK=1 to bypass the daemon probe (not recommended)."
echo " Set xmrwallet_SKIP_DAEMON_CHECK=1 to bypass the daemon probe (not recommended)."
end

View File

@ -1,5 +1,5 @@
### --------- helpers ----------
function _need
function _need --description "ensure a command exists"
for c in $argv
if not type -q $c
echo (set_color red)"Error:"(set_color normal)" missing command: $c" >&2
@ -8,41 +8,61 @@ function _need
end
end
function _banner -a MSG
function _banner --description "pretty section header" -a MSG
set_color cyan; echo; echo "==> $MSG"; set_color normal
end
function _k8s_name -a S
# 32-char alphanumeric generator (fast, no shell-specials)
function _rand_alnum32
if type -q openssl
openssl rand -base64 48 2>/dev/null | tr -dc 'A-Za-z0-9' | head -c 32
else
dd if=/dev/urandom bs=48 count=1 2>/dev/null | base64 | tr -dc 'A-Za-z0-9' | head -c 32
end
end
# Default image chooser (you should override with your own multi-arch image)
function _sui_default_image -a NET
echo registry.bstein.dev/infra/sui-tools:1.53.2
end
# Convert any string to a k8s-safe name (RFC-1123 label-ish)
function _k8s_name --description "sanitize to RFC-1123 label" -a S
set s (string lower -- $S)
set s (string replace -ar -- '[^a-z0-9-]' '-' $s)
set s (string replace -r -- '^-+|(-)+$' '$1' $s)
set s (string replace -r -- '^-+' '' $s)
set s (string replace -r -- '-+$' '' $s)
echo $s
end
function _require -a WHAT VAL
# Simple non-empty check
function _require --description "require a non-empty value" -a WHAT VAL
if test -z "$VAL"
echo (set_color red)"Error:"(set_color normal)" $WHAT cannot be empty." >&2
echo (set_color red)"Error:"(set_color normal)" $WHAT cannot be empty. Aborting." >&2
return 1
end
end
function _sc_list
kubectl get storageclass -o json 2>/dev/null | jq -r '
.items[] | [
.metadata.name,
.provisioner,
(.reclaimPolicy // "Delete"),
( .metadata.annotations["storageclass.kubernetes.io/is-default-class"] == "true"
or .metadata.annotations["storageclass.beta.kubernetes.io/is-default-class"] == "true")
] | @tsv'
function _sc_list --description "list storageclasses as menu"
kubectl get storageclass -o json | jq -r '
.items[]
| {name: .metadata.name,
provisioner: .provisioner,
reclaim: (.reclaimPolicy // "Delete"),
default: ( .metadata.annotations["storageclass.kubernetes.io/is-default-class"] == "true"
or .metadata.annotations["storageclass.beta.kubernetes.io/is-default-class"] == "true") }
| "\(.name)\t\(.provisioner)\t\(.reclaim)\t\((.default|tostring))"
' 2>/dev/null
end
function _choose_sc
# Choose StorageClass by index or name
function _choose_sc --description "interactive StorageClass picker"
set lines (_sc_list)
if test (count $lines) -eq 0
echo (set_color red)"Error:"(set_color normal)" No StorageClasses found." >&2
return 1
end
echo "" >&2
echo "==> Available StorageClasses" >&2
echo " # | name | provisioner | reclaim | default" >&2
@ -56,52 +76,156 @@ function _choose_sc
printf " %2d | %-20s | %-22s | %-7s | %s\n" $i $name $prov $rec $def >&2
set i (math $i + 1)
end
set prefer (printf "%s\n" $lines | awk -F'\t' '$4=="true"{print $1}' | head -n1)
if test -z "$prefer"
set prefer (printf "%s\n" $lines | awk -F'\t' '{print $1}' | head -n1)
end
read -P "Pick StorageClass by number or name (blank = $prefer): " choice
if test -z "$choice"
echo "Using StorageClass: $prefer" >&2
echo $prefer
return 0
end
if string match -qr '^[0-9]+$' -- $choice
set idx (math $choice)
if test $idx -lt 1 -o $idx -gt (count $lines)
echo (set_color red)"Error:"(set_color normal)" Choice out of range." >&2
return 1
end
printf "%s\n" $lines[$idx] | awk -F'\t' '{print $1}'
else
printf "%s\n" $lines | awk -F'\t' -v want="$choice" '$1==want{print $1}'
set sel (printf "%s\n" $lines[$idx] | awk -F'\t' '{print $1}')
echo "Using StorageClass: $sel" >&2
echo $sel
return 0
end
set found (printf "%s\n" $lines | awk -F'\t' -v want="$choice" '$1==want{print $1}')
if test -z "$found"
echo (set_color red)"Error:"(set_color normal)" No StorageClass named '$choice'." >&2
return 1
end
echo "Using StorageClass: $found" >&2
echo $found
end
# ---- probe Sui JSON-RPC endpoint
function _probe_sui_rpc --description "probe Sui JSON-RPC endpoint" -a URL
if test -z "$URL"
echo (set_color red)"Error:"(set_color normal)" _probe_sui_rpc needs an URL" >&2
return 1
end
set payload '{"jsonrpc":"2.0","id":1,"method":"sui_getLatestCheckpointSequenceNumber","params":[]}'
set tmp (mktemp)
set code (curl -sS -o $tmp -w "%{http_code}" -H "Content-Type: application/json" -d "$payload" "$URL")
set rc $status
set body (cat $tmp); rm -f $tmp
if test $rc -ne 0
echo (set_color red)"Transport error probing $URL (curl rc=$rc)."(set_color normal) >&2
return 1
end
if test "$code" != "200"
echo (set_color red)"HTTP $code from $URL"(set_color normal) >&2
echo $body >&2
return 1
end
set seq (printf "%s" $body | jq -r '.result // empty' 2>/dev/null)
if test -z "$seq"
echo (set_color red)"No result from RPC probe at $URL."(set_color normal) >&2
return 1
end
echo "Sui RPC OK: latest checkpoint seq=$seq"
end
### --------- main workflow ----------
function suiwallet_bootstrap --description "Create a Sui wallet (PVC+Deployment) and generate a new address"
_need kubectl jq awk; or return 1
function suiwallet_bootstrap --description "Interactive setup of a Sui wallet pod with PVC; creates address and prints recovery phrase"
_need kubectl jq curl awk; or return 1
_banner "Sui wallet bootstrap"
read -P "Namespace [crypto]: " ns
if test -z "$ns"; set ns crypto; end
set ns (_k8s_name $ns)
# --- Namespace
read -P "Namespace [crypto]: " ns_raw
if test -z "$ns_raw"; set ns_raw crypto; end
set ns (_k8s_name $ns_raw)
_require "Namespace" $ns; or return 1
echo "Ensuring namespace '$ns' exists…"
if not kubectl get ns $ns >/dev/null 2>&1
if kubectl get ns $ns >/dev/null 2>&1
echo "Namespace $ns already exists."
else
kubectl create ns $ns; or return 1
echo "Created namespace $ns."
end
kubectl get storageclass 2>/dev/null
echo "TIP: Prefer a Retain StorageClass so deleting the pod won't delete keys."
# --- StorageClass
kubectl get storageclass
echo "TIP: Prefer a class with reclaimPolicy=Retain so a PVC delete won't delete the PV."
set sc (_choose_sc); or return 1
read -P "Wallet name (e.g. 'brad' → wallet-sui-brad): " wallet_raw
# --- Unified name (prefix wallet-sui-)
read -P "Wallet name (no spaces, e.g. 'brad', base will be wallet-sui-brad): " wallet_raw
_require "Wallet name" $wallet_raw; or return 1
if string match -rq '\s' -- $wallet_raw
echo (set_color red)"Error:"(set_color normal)" Wallet name cannot contain spaces." >&2
return 1
end
set base (_k8s_name $wallet_raw)
set app "wallet-sui-$base"
set pvc $app
set base (string replace -r '^wallet-sui-' '' -- $base)
set name "wallet-sui-$base"
# Bind all k8s object names to the unified base
set pvc_name $name
set app_name $name
# --- Detect existing resources (idempotence)
set exists_any 0
set found_list
for r in "deploy/$app_name" (printf "netpol/%s-deny-ingress" $app_name)
if kubectl -n $ns get $r >/dev/null 2>&1
set -a found_list $r
set exists_any 1
end
end
if kubectl -n $ns get pvc $pvc_name >/dev/null 2>&1
set -a found_list "pvc/$pvc_name"
set exists_any 1
end
if kubectl -n $ns get secret (printf "%s-mnemonic" $app_name) >/dev/null 2>&1
set -a found_list (printf "secret/%s-mnemonic" $app_name)
set exists_any 1
end
if test $exists_any -eq 1
_banner "Existing resources detected for $name"
for r in $found_list
echo " - $ns/$r"
end
read -P "Remove EVERYTHING (deploy/netpol/PVC/secret) and recreate? (y/N): " wipe
if string match -qi 'y*' -- $wipe
kubectl -n $ns delete deploy $app_name --ignore-not-found --wait=true >/dev/null 2>&1; or true
kubectl -n $ns delete netpol (printf "%s-deny-ingress" $app_name) --ignore-not-found --wait=true >/dev/null 2>&1; or true
kubectl -n $ns delete pvc $pvc_name --ignore-not-found --wait=true >/dev/null 2>&1; or true
kubectl -n $ns delete secret (printf "%s-mnemonic" $app_name) --ignore-not-found >/dev/null 2>&1; or true
echo "Cleaned up previous resources."
else
echo "Reusing existing resources; they will be applied in-place."
end
end
# --- Node scheduling (worker-only by default)
read -P "Schedule only on worker nodes? (y/N) [y]: " pin_workers
if test -z "$pin_workers"; set pin_workers y; end
set use_pin 0
if string match -qi 'y*' -- $pin_workers
set use_pin 1
read -P "Worker label key [node-role.kubernetes.io/worker]: " node_label_key
if test -z "$node_label_key"; set node_label_key node-role.kubernetes.io/worker; end
read -P "Worker label value [true]: " node_label_val
if test -z "$node_label_val"; set node_label_val true; end
end
# --- Network and RPC
read -P "Network [mainnet|testnet|devnet] [mainnet]: " net
if test -z "$net"; set net mainnet; end
switch $net
@ -115,8 +239,17 @@ function suiwallet_bootstrap --description "Create a Sui wallet (PVC+Deployment)
echo (set_color red)"Error:"(set_color normal)" network must be mainnet|testnet|devnet"; return 1
end
read -P "Container image [mysten/sui-tools:latest]: " image
if test -z "$image"; set image mysten/sui-tools:latest; end
_banner "Probing Sui RPC endpoint"
if not _probe_sui_rpc $rpc_url
echo (set_color red)"Aborting due to RPC probe failure."(set_color normal)
return 1
end
# --- Image and address alias
set image_default (_sui_default_image $net)
echo "NOTE: Prefer a multi-arch image you built (see instructions below)."
read -P "Container image [$image_default]: " image
if test -z "$image"; set image $image_default; end
read -P "Address alias to create [main]: " alias
if test -z "$alias"; set alias main; end
@ -127,138 +260,479 @@ function suiwallet_bootstrap --description "Create a Sui wallet (PVC+Deployment)
read -P "Store mnemonic as a Kubernetes Secret? (NOT recommended) (y/N): " store_mn
set store_mn (string lower -- $store_mn)
# --- Optional NetworkPolicy
read -P "Add NetworkPolicy (deny all ingress; allow egress) ? (y/N): " want_np
set want_np (string lower -- $want_np)
_banner "Summary"
echo " Namespace: $ns"
echo " App name: $app"
echo " StorageClass: $sc"
echo " PVC: $pvc"
echo " Base name: $name"
echo " PVC: $pvc_name"
echo " App/Deployment:$app_name"
echo " Image: $image"
echo " Network: $net"
echo " RPC URL: $rpc_url"
echo " New alias: $alias (word length: $wl)"
read -P "Proceed? [y/N]: " ok
if not string match -qi 'y*' -- $ok
echo "Aborted."; return 1
if test $use_pin -eq 1
echo " NodeSelector: $node_label_key=$node_label_val"
end
if string match -qi 'y*' -- $want_np
echo " NetworkPolicy: deny-all ingress (egress allowed)"
end
read -P "Proceed? [y/N]: " proceed
if not string match -qi 'y*' -- $proceed
echo (set_color yellow)"Aborted by user at confirmation step."(set_color normal)
return 1
end
_banner "Applying PVC"
kubectl -n $ns get pvc $pvc >/dev/null 2>&1; or begin
printf "%s\n" \
"apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: $pvc
namespace: $ns
spec:
accessModes: [\"ReadWriteOnce\"]
storageClassName: $sc
resources:
requests:
storage: 1Gi" | kubectl apply -f -; or return 1
if kubectl -n $ns get pvc $pvc_name >/dev/null 2>&1
echo "PVC $ns/$pvc_name exists; keeping as-is."
else
set pvcfile (mktemp -t $pvc_name-pvc.XXXX.yaml)
begin
echo "apiVersion: v1"
echo "kind: PersistentVolumeClaim"
echo "metadata:"
echo " name: $pvc_name"
echo " namespace: $ns"
echo "spec:"
echo " accessModes: [\"ReadWriteOnce\"]"
echo " storageClassName: $sc"
echo " resources:"
echo " requests:"
echo " storage: 1Gi"
end > $pvcfile
echo "--- PVC manifest ($pvcfile) ---"
cat $pvcfile
kubectl apply -f $pvcfile; or return 1
end
_banner "Applying Deployment"
printf "%s\n" \
"apiVersion: apps/v1
kind: Deployment
metadata:
name: $app
namespace: $ns
labels: { app: $app }
spec:
replicas: 1
selector: { matchLabels: { app: $app } }
template:
metadata:
labels: { app: $app }
spec:
containers:
- name: sui-tools
image: $image
imagePullPolicy: IfNotPresent
command: [\"bash\",\"-lc\",\"sleep infinity\"]
volumeMounts:
- name: data
mountPath: /root/.sui
resources:
requests: { cpu: 50m, memory: 128Mi }
limits: { cpu: 1, memory: 512Mi }
volumes:
- name: data
persistentVolumeClaim: { claimName: $pvc }" | kubectl apply -f -; or return 1
set dply (mktemp -t $app_name-deploy.XXXX.yaml)
begin
echo "apiVersion: apps/v1"
echo "kind: Deployment"
echo "metadata:"
echo " name: $app_name"
echo " namespace: $ns"
echo " labels: { app: $app_name }"
echo "spec:"
echo " replicas: 1"
echo " strategy: { type: Recreate }"
echo " selector: { matchLabels: { app: $app_name } }"
echo " template:"
echo " metadata:"
echo " labels: { app: $app_name }"
echo " spec:"
if test $use_pin -eq 1
echo " nodeSelector:"
echo " $node_label_key: \"$node_label_val\""
end
echo " securityContext:"
echo " fsGroup: 1000"
echo " fsGroupChangePolicy: OnRootMismatch"
echo " initContainers:"
echo " - name: volume-permissions"
echo " image: busybox:1.36"
echo " command: [\"/bin/sh\",\"-lc\",\"mkdir -p /home/sui/.sui/sui_config && chown -R 1000:1000 /home/sui/.sui && chmod -R 0770 /home/sui/.sui\"]"
echo " securityContext: { runAsUser: 0 }"
echo " volumeMounts: [ { name: data, mountPath: /home/sui/.sui } ]"
echo " containers:"
echo " - name: sui-tools"
echo " image: $image"
echo " imagePullPolicy: IfNotPresent"
echo " command: [\"/bin/sh\",\"-lc\"]"
echo " args:"
echo " - |"
echo " # keep container ready for execs"
echo " sleep infinity"
echo " volumeMounts:"
echo " - name: data"
echo " mountPath: /home/sui/.sui"
echo " resources:"
echo " requests: { cpu: \"50m\", memory: \"128Mi\" }"
echo " limits: { cpu: \"1\", memory: \"512Mi\" }"
echo " volumes:"
echo " - name: data"
echo " persistentVolumeClaim: { claimName: $pvc_name }"
end > $dply
echo "--- Deployment manifest ($dply) ---"
head -n 70 $dply
echo "..."
kubectl apply -f $dply; or return 1
if string match -qi 'y*' -- $want_np
_banner "Applying NetworkPolicy (deny-all ingress; allow all egress)"
set np (mktemp -t $app_name-netpol.XXXX.yaml)
begin
echo "apiVersion: networking.k8s.io/v1"
echo "kind: NetworkPolicy"
echo "metadata:"
printf " name: %s-deny-ingress\n" $app_name
echo " namespace: $ns"
echo "spec:"
echo " podSelector: { matchLabels: { app: $app_name } }"
echo " policyTypes: [\"Ingress\",\"Egress\"]"
echo " ingress: []"
echo " egress:"
echo " - {}"
end > $np
echo "--- NetworkPolicy manifest ($np) ---"
cat $np
kubectl apply -f $np; or return 1
end
_banner "Waiting for rollout"
kubectl -n $ns rollout status deploy/$app --timeout=120s; or return 1
if not kubectl -n $ns rollout status deploy/$app_name --timeout=300s
echo (set_color red)"Rollout did not finish in time. Recent events:"(set_color normal) >&2
kubectl -n $ns get events --sort-by=.lastTimestamp | tail -n 40
return 1
end
_banner "Validating Sui CLI inside the pod"
set ARCH (kubectl -n $ns exec deploy/$app_name -- sh -lc 'uname -m' 2>/dev/null)
set GLIBC (kubectl -n $ns exec deploy/$app_name -- sh -lc 'ldd --version 2>&1 | head -n1 || true' 2>/dev/null)
set SUIV (kubectl -n $ns exec deploy/$app_name -- sh -lc 'sui --version 2>&1 || true' 2>/dev/null)
echo "Node arch: $ARCH"
echo "GLIBC: $GLIBC"
echo "sui: $SUIV"
if test -z "$SUIV"; or string match -q "*not found*" -- $SUIV
echo (set_color red)"Error:"(set_color normal)" 'sui' did not run inside the pod."
echo "If you see GLIBC < 2.38 here, rebuild the image on Ubuntu 24.04 as shown in section A."
return 1
end
_banner "Initializing Sui client env ($net) and creating a new address"
# new-env: writes client.yaml; new-address: writes to sui.keystore and prints the phrase
set OUT (mktemp)
kubectl -n $ns exec deploy/$app -- bash -lc \
(printf 'mkdir -p /root/.sui/sui_config ;
sui client new-env --alias %s --rpc %s >/dev/null 2>&1 || true ;
sui client new-address ed25519 --word-length %s --alias %s' \
$net $rpc_url $wl $alias) | tee $OUT
# Create/switch env, then create a new address with alias.
# Try JSON first; fall back to parsing text.
set TMP (mktemp)
set ADDR (kubectl -n $ns exec deploy/$app -- bash -lc \
(printf 'sui client addresses | awk "/%s/{print \$NF}" | tail -n1' $alias))
# Ensure config dir exists (inside the pod) and env points to your chosen RPC.
kubectl -n $ns exec deploy/$app_name -- sh -lc \
(printf 'mkdir -p /home/sui/.sui/sui_config ;
sui client new-env --alias %s --rpc %s >/dev/null 2>&1 || true ;
sui client switch --env %s >/dev/null 2>&1 || true' $net $rpc_url $net)
# Try JSON (preferred)
set JSON (kubectl -n $ns exec deploy/$app_name -- sh -lc \
(printf 'sui client new-address ed25519 --word-length %s --alias %s --json 2>/dev/null || true' $wl $alias))
set MN (printf "%s" $JSON | jq -r '.secretRecoveryPhrase // .mnemonic // .mnemonicPhrase // empty' 2>/dev/null)
set ADDR (printf "%s" $JSON | jq -r '.address // empty' 2>/dev/null)
if test -n "$MN"
kubectl -n $ns logs deploy/$app_name --since=10s >/dev/null 2>&1 || true
kubectl -n $ns exec deploy/$app_name -- sh -lc \
(printf 'echo "SECRET RECOVERY PHRASE: %s" >> /home/sui/README_MNEMONIC && chmod 0600 /home/sui/README_MNEMONIC' "$MN")
end
if test -z "$MN" -o -z "$ADDR"
# Fall back to plain text (robust across CLI changes)
kubectl -n $ns exec deploy/$app_name -- sh -lc \
(printf 'sui client new-address ed25519 --word-length %s --alias %s 2>&1 || true' $wl $alias) | tee $TMP >/dev/null
if test -z "$MN"
# Usually phrase is printed on the line right after the "Secret Recovery Phrase" header
set MN (awk '/Secret Recovery Phrase/ {getline; print; exit}' $TMP)
end
if test -z "$ADDR"
# Typical line: "Address: 0xabc..."; extract the RHS
set ADDR (awk -F': ' '/^Address:/ {print $2; exit}' $TMP)
end
end
# Make the generated address active (address wins; alias as backup)
if test -n "$ADDR"
kubectl -n $ns exec deploy/$app_name -- sh -lc (printf 'sui client switch --address %s >/dev/null 2>&1 || true' $ADDR)
else
kubectl -n $ns exec deploy/$app_name -- sh -lc (printf 'sui client switch --alias %s >/dev/null 2>&1 || true' $alias)
end
echo
echo (set_color yellow)"IMPORTANT — Secret Recovery Phrase (write down & store offline):"(set_color normal)
grep -E 'Secret Recovery Phrase|Mnemon' $OUT -A2 | sed -e 's/^\s\+//'
if test -n "$MN"
echo $MN
else
echo "(mnemonic not detected — check 'kubectl -n $ns logs deploy/$app_name' output)"
end
echo
echo "Address alias '$alias' appears to be: $ADDR"
rm -f $OUT
# Optional: store mnemonic in a Secret (not recommended)
if test "$store_mn" = "y" -o "$store_mn" = "yes"
set MN (kubectl -n $ns exec deploy/$app -- bash -lc \
(printf 'sui client addresses >/dev/null 2>&1 ; sui client new-address ed25519 --word-length %s --alias %s --json 2>/dev/null | jq -r .secretRecoveryPhrase || true' $wl "${alias}-dup"))
if test -n "$MN" -a "$MN" != "null"
kubectl -n $ns create secret generic {$app}-mnemonic \
if test -n "$MN"
kubectl -n $ns create secret generic "$app_name-mnemonic" \
--from-literal=mnemonic="$MN" --dry-run=client -o yaml | kubectl -n $ns apply -f -
echo (set_color yellow)"Stored mnemonic in Secret $ns/{$app}-mnemonic. Treat your cluster as sensitive."(set_color normal)
# clean the duplicate alias we created to harvest JSON
kubectl -n $ns exec deploy/$app -- bash -lc "sui client remove-address --alias ${alias}-dup >/dev/null 2>&1 || true" >/dev/null 2>&1
echo (set_color yellow)"Stored mnemonic in Secret $ns/{$app_name}-mnemonic. Treat your cluster as sensitive."(set_color normal)
else
echo (set_color red)"Warning:"(set_color normal)" could not capture mnemonic via --json, not storing."
echo (set_color red)"Warning:"(set_color normal)" mnemonic empty; not storing."
end
end
echo
echo "Done. Files inside the pod:"
kubectl -n $ns exec deploy/$app -- bash -lc 'ls -l /root/.sui/sui_config || true'
kubectl -n $ns exec deploy/$app_name -- sh -lc 'ls -l /home/sui/.sui/sui_config || true'
echo
echo "Useful commands:"
echo " suiwallet_addresses $ns $app"
echo " suiwallet_export_keystore $ns $app ./sui.keystore.$base"
echo " kubectl -n $ns exec -it deploy/$app -- bash # interactive CLI"
echo " suiwallet_addresses $ns $app_name"
echo " suiwallet_gas $ns $app_name"
echo " suiwallet_export_keystore $ns $app_name ./sui.keystore.$base"
echo " suiwallet_metrics $ns $app_name $base"
echo " kubectl -n $ns exec -it deploy/$app_name -- sh # interactive CLI"
end
### --------- utilities ----------
function suiwallet_status -a NS APP
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-sui-main; end
kubectl -n $NS get deploy,po,pvc,netpol -l app=$APP -o wide
end
function suiwallet_logs -a NS APP LINES
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-sui-main; end
if test -z "$LINES"; set LINES 200; end
kubectl -n $NS logs deploy/$APP --tail=$LINES
end
function suiwallet_wallet_ls -a NS APP
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-sui-main; end
echo "Listing /home/sui/.sui/sui_config in $NS/$APP" >&2
kubectl -n $NS exec deploy/$APP -- sh -lc 'ls -la /home/sui/.sui/sui_config || true'
end
function suiwallet_addresses -a NS APP
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-sui-main; end
kubectl -n $NS exec deploy/$APP -- bash -lc 'sui client addresses || true'
kubectl -n $NS exec deploy/$APP -- sh -lc 'sui client addresses || true'
end
function suiwallet_export_keystore -a NS APP DEST
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-sui-main; end
if test -z "$DEST"; set DEST ./sui.keystore; end
echo "Copying keystore to $DEST (keep it safe!)"
kubectl -n $NS cp deploy/$APP:/root/.sui/sui_config/sui.keystore $DEST
set POD (kubectl -n $NS get pod -l app=$APP -o jsonpath='{.items[0].metadata.name}' 2>/dev/null)
if test -z "$POD"
echo (set_color red)"Error:"(set_color normal)" no pod found for app=$APP in ns=$NS" >&2
return 1
end
echo "Copying keystore from $POD to $DEST (keep it safe!)"
kubectl -n $NS cp $POD:/home/sui/.sui/sui_config/sui.keystore $DEST
end
function suiwallet_status -a NS APP
# Summarize gas coins and total balance; tolerant to schema differences
function suiwallet_gas -a NS APP
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-sui-main; end
kubectl -n $NS get deploy,po,pvc -l app=$APP -o wide
set J (kubectl -n $NS exec deploy/$APP -- sh -lc 'sui client gas --json' 2>/dev/null)
if test -z "$J"
echo "No JSON from 'sui client gas' (is the address set and env working?)" >&2
return 1
end
set NUM (printf "%s" $J | jq -r '[.. | .gasObjects? // empty | length] | add // 0')
if test -z "$NUM" -o "$NUM" = "null"
set NUM (printf "%s" $J | jq -r '[.. | .coins? // empty | length] | add // 0')
end
set SUM (printf "%s" $J | jq -r '
(.. | .totalBalance? // empty) as $t
| if $t != null then ($t|tonumber)
else [.. | .gasObjects? // empty | .[]? | .balance? | tonumber] | add
end // 0
')
# Convert Mist -> SUI using python -c
set SUM_SUI (python3 -c 'from decimal import Decimal; import sys; q=Decimal(sys.argv[1]) if sys.argv[1] else Decimal(0); print((q/Decimal("1e9")).quantize(Decimal("0.000000001")))' -- $SUM)
echo "Gas coins: $NUM Total: $SUM ($SUM_SUI SUI)"
end
# Wait until balance >= threshold (SUI), timeout seconds
function suiwallet_wait_balance -a NS APP MIN_SUI TIMEOUT
_need python3; or return 1
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-sui-main; end
if test -z "$MIN_SUI"; set MIN_SUI 0; end
if test -z "$TIMEOUT"; set TIMEOUT 300; end
set start (date +%s)
while true
set J (kubectl -n $NS exec deploy/$APP -- sh -lc 'sui client gas --json' 2>/dev/null)
set SUM (printf "%s" $J | jq -r '
(.. | .totalBalance? // empty) as $t
| if $t != null then ($t|tonumber)
else [.. | .gasObjects? // empty | .[]? | .balance? | tonumber] | add
end // 0
')
set SUM_SUI (python3 -c 'from decimal import Decimal; import sys; q=Decimal(sys.argv[1]) if sys.argv[1] else Decimal(0); print(q/Decimal("1e9"))' -- $SUM)
set ge (python3 -c 'from decimal import Decimal; import sys; print(1 if Decimal(sys.argv[1]) >= Decimal(sys.argv[2]) else 0)' -- $SUM_SUI $MIN_SUI)
if test "$ge" = "1"
echo "Balance ready: $SUM_SUI SUI (>= $MIN_SUI)"
return 0
end
if test (math (date +%s) - $start) -ge $TIMEOUT
echo "Timed out waiting for balance >= $MIN_SUI SUI (current $SUM_SUI SUI)."
return 1
end
sleep 6
end
end
# Send SUI using `transfer-sui` picking the largest coin
# Usage: suiwallet_transfer_sui [ns] [app] <to_addr> <amount_sui> [gas_budget_mist=10000000]
function suiwallet_transfer_sui -a NS APP TO AMT_SUI GAS_BUDGET
_need jq python3; or return 1
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-sui-main; end
if test -z "$TO" -o -z "$AMT_SUI"
echo "Usage: suiwallet_transfer_sui [ns] [app] <to_address> <amount_sui> [gas_budget_mist]" >&2
return 1
end
if test -z "$GAS_BUDGET"; set GAS_BUDGET 10000000; end
set AMT_MIST (python3 -c 'from decimal import Decimal; import sys; print(int((Decimal(sys.argv[1])*Decimal("1e9")).to_integral_value()))' -- $AMT_SUI)
set J (kubectl -n $NS exec deploy/$APP -- sh -lc 'sui client gas --json' 2>/dev/null)
set COIN (printf "%s" $J | jq -r '
([.. | .gasObjects? // empty | .[]?] // [])
| sort_by(.balance|tonumber) | last | .coinObjectId // empty
')
if test -z "$COIN"
echo (set_color red)"No gas coins found to send from."(set_color normal) >&2
return 1
end
echo "Using coin: $COIN"
kubectl -n $NS exec deploy/$APP -- sh -lc \
(printf 'sui client transfer-sui --to %s --sui-coin-object-id %s --amount %s --gas-budget %s' $TO $COIN $AMT_MIST $GAS_BUDGET)
end
# Merge all gas coins into the largest one
function suiwallet_merge_gas -a NS APP
_need jq; or return 1
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-sui-main; end
set J (kubectl -n $NS exec deploy/$APP -- sh -lc 'sui client gas --json' 2>/dev/null)
set IDS (printf "%s" $J | jq -r '([.. | .gasObjects? // empty | .[]?] // []) | sort_by(.balance|tonumber) | reverse | .[].coinObjectId')
set coins $IDS
if test (count $coins) -lt 2
echo "Nothing to merge (need >=2 gas coins)."
return 0
end
set primary $coins[1]
for i in (seq 2 (count $coins))
set c $coins[$i]
echo "Merging $c -> $primary"
kubectl -n $NS exec deploy/$APP -- sh -lc (printf 'sui client merge-coin --primary-coin %s --coin-to-merge %s --gas-budget 10000000' $primary $c)
end
end
# Restore an address from a Secret Recovery Phrase into the running pod
# Usage: suiwallet_restore [ns] [app] [alias] [network=mainnet]
function suiwallet_restore -a NS APP ALIAS NET
_need kubectl jq; or return 1
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-sui-main; end
if test -z "$ALIAS"; set ALIAS restored; end
if test -z "$NET"; set NET mainnet; end
switch $NET
case mainnet
set RPC https://fullnode.mainnet.sui.io:443
case testnet
set RPC https://fullnode.testnet.sui.io:443
case devnet
set RPC https://fullnode.devnet.sui.io:443
case '*'
echo (set_color red)"Error:"(set_color normal)" NET must be mainnet|testnet|devnet"; return 1
end
echo (set_color yellow)"Paste your 12/24-word Sui Secret Recovery Phrase (input hidden):"(set_color normal)
read -s MNEMONIC
echo
if test -z "$MNEMONIC"
echo (set_color red)"Error:"(set_color normal)" empty mnemonic."; return 1
end
# Ensure env is configured and active
kubectl -n $NS exec deploy/$APP -- sh -lc \
(printf 'mkdir -p /home/sui/.sui/sui_config ;
sui client new-env --alias %s --rpc %s >/dev/null 2>&1 || true ;
sui client switch --env %s >/dev/null 2>&1 || true' $NET $RPC $NET); or return 1
# Import mnemonic into keystore (non-interactive; enter scheme then phrase)
# keytool is interactive; we feed "ed25519" then the phrase via stdin.
set TMP (mktemp)
printf "ed25519\n%s\n" "$MNEMONIC" \
| kubectl -n $NS exec -i deploy/$APP -- sh -lc 'sui keytool import 2>&1' \
| tee $TMP >/dev/null
# Create a named alias pointing to one of the imported keys by re-using new-address --recover
# (new-address --recover will prompt for phrase; we feed it again to bind an alias)
set OUT (mktemp)
printf "%s\n" "$MNEMONIC" \
| kubectl -n $NS exec -i deploy/$APP -- sh -lc \
(printf 'sui client new-address ed25519 --alias %s --recover 2>&1' $ALIAS) \
| tee $OUT >/dev/null
# Try to extract the resulting address
set ADDR (awk -F': ' '/^Address:/ {print $2; exit}' $OUT)
if test -z "$ADDR"
# fallback: pick the address for the alias from the address table
set ADDR (kubectl -n $NS exec deploy/$APP -- sh -lc (printf 'sui client addresses | awk "/ %s\\s*$/ {print \\$NF}" | tail -n1' $ALIAS) 2>/dev/null)
end
echo
echo "Restored alias: $ALIAS"
echo "Address: $ADDR"
echo (set_color yellow)"IMPORTANT:"(set_color normal)" store your recovery phrase offline. Do NOT keep it in the cluster."
# Make it active for the client
if test -n "$ADDR"
kubectl -n $NS exec deploy/$APP -- sh -lc (printf 'sui client switch --address %s >/dev/null 2>&1 || true' $ADDR)
end
end
function suiwallet_stop -a NS APP
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-sui-main; end
kubectl -n $NS delete deploy $APP --ignore-not-found
echo "Stopped $NS/$APP (PVC kept)."
echo "Stopped $NS/$APP. PVC retained."
end
# Print the primary (first) address by alias search
function suiwallet_primary_address -a NS APP
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-sui-main; end
kubectl -n $NS exec deploy/$APP -- sh -lc \
"sui client addresses | awk 'NF{print \$NF}' | head -n1" 2>/dev/null
end
# Quick overview
function suiwallet_overview -a NS APP
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-sui-main; end
echo "== Sui wallet overview (ns=$NS app=$APP)"
kubectl -n $NS exec deploy/$APP -- sh -lc 'echo "-- Addresses:"; sui client addresses || true'
kubectl -n $NS exec deploy/$APP -- sh -lc 'echo "-- Gas objects:"; sui client gas 2>/dev/null || true'
end
# Sui keystore size (for Grafana/Prometheus)
function suiwallet_keystore_size_bytes -a NS APP
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-sui-main; end
set SZ (kubectl -n $NS exec deploy/$APP -- sh -lc \
'test -e /home/sui/.sui/sui_config/sui.keystore && stat -c %s /home/sui/.sui/sui_config/sui.keystore || echo 0' 2>/dev/null)
echo $SZ
end
# Prometheus-friendly one-liner metric
# Example usage: suiwallet_metrics crypto wallet-sui-test mywallet
function suiwallet_metrics -a NS APP WALLET_NAME
if test -z "$NS"; set NS crypto; end
if test -z "$APP"; set APP wallet-sui-main; end
if test -z "$WALLET_NAME"; set WALLET_NAME main; end
set BYTES (suiwallet_keystore_size_bytes $NS $APP)
printf "wallet_size_bytes{chain=\"sui\",namespace=\"%s\",app=\"%s\",wallet=\"%s\"} %s\n" $NS $APP $WALLET_NAME $BYTES
end
function suiwallet_purge -a NS APP PVC
@ -268,8 +742,27 @@ function suiwallet_purge -a NS APP PVC
echo "Type to confirm: PURGE $NS $PVC"
read CONFIRM
if test "$CONFIRM" != "PURGE $NS $PVC"
echo "Aborted."; return 1
echo "Aborted."
return 1
end
kubectl -n $NS delete deploy $APP --ignore-not-found
kubectl -n $NS delete pvc $PVC --ignore-not-found --wait=true
kubectl -n $NS delete netpol (printf "%s-deny-ingress" $APP) --ignore-not-found >/dev/null 2>&1
echo "Purged. Ensure you have the mnemonic backed up if you ever need to restore."
end
function suiwallet_help
echo "suiwallet_bootstrap # interactive deploy + PVC + optional NP; creates env+address, prints mnemonic"
echo "suiwallet_status [ns] [app] # show deploy/pods/pvc/netpol"
echo "suiwallet_logs [ns] [app] [N] # tail N (default 200) lines of pod logs"
echo "suiwallet_wallet_ls [ns] [app] # list ~/.sui/sui_config inside pod"
echo "suiwallet_addresses [ns] [app] # list addresses"
echo "suiwallet_gas [ns] [app] # summarize gas coins and total (Mist & SUI)"
echo "suiwallet_wait_balance [ns] [app] <min_sui> [timeout_s=300]"
echo "suiwallet_transfer_sui [ns] [app] <to> <amount_sui> [gas_budget_mist]"
echo "suiwallet_merge_gas [ns] [app] # merge many gas coins into one"
echo "suiwallet_export_keystore [ns] [app] [dest=./sui.keystore]"
echo "suiwallet_metrics [ns] [app] [walletname] # Prometheus line: wallet_size_bytes{chain=\"sui\",...}"
echo "suiwallet_stop [ns] [app] # delete deployment (keep PVC)"
echo "suiwallet_purge [ns] [app] [pvc] # delete deployment + PVC (danger!)"
end

View File

@ -0,0 +1,39 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta2
kind: HelmRelease
metadata:
name: vault
namespace: vault
spec:
interval: 15m
chart:
spec:
chart: vault
version: "0.28.x"
sourceRef:
kind: HelmRepository
name: hashicorp
namespace: flux-system
values:
global:
enabled: true
server:
ha:
enabled: true
replicas: 3
raft:
enabled: true
dataStorage:
enabled: true
size: 5Gi
storageClassName: astreae
service:
type: ClusterIP
ingress:
enabled: false
resources:
requests: { cpu: "100m", memory: "256Mi" }
limits: { cpu: "500m", memory: "512Mi" }
injector:
enabled: true
csi:
enabled: true

View File

@ -0,0 +1,8 @@
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
name: hashicorp
namespace: vault
spec:
interval: 1h
url: https://helm.releases.hashicorp.com

View File

@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: vault
resources:
- namespace.yaml
- helmrepo.yaml
- helmrelease.yaml

View File

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: vault