Verbose deploy.sh, fix driver upsert, and fix pip cache warning
deploy.sh now prints each step with what it's doing, adds the invoking user to the pipekit group automatically, uses --home-dir /nonexistent for the system user, and passes --no-cache-dir to pip to suppress the home directory warning. cli.py: removed the kind-based early-exit in drivers register that was short-circuiting before the upsert logic, so re-running deploy now correctly updates existing driver rows rather than printing "already registered". Also removed the now-unused --force flag. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c34fcb38ed
commit
f32706be01
136
deploy.sh
136
deploy.sh
@ -2,14 +2,15 @@
|
|||||||
# Pipekit deployment — idempotent. Re-run after any code update.
|
# Pipekit deployment — idempotent. Re-run after any code update.
|
||||||
#
|
#
|
||||||
# What it does:
|
# What it does:
|
||||||
# 1. Creates the 'pipekit' system user (if absent)
|
# 1. Creates the 'pipekit' system user and group (if absent)
|
||||||
# 2. Chowns /opt/pipekit to pipekit:pipekit
|
# 2. Adds the invoking user to the 'pipekit' group
|
||||||
# 3. Creates Python venv (as pipekit) and installs requirements
|
# 3. Sets ownership of /opt/pipekit to pipekit:pipekit (group-writable)
|
||||||
# 4. Installs /usr/local/bin/pipekit launcher
|
# 4. Creates Python venv (as pipekit) and installs requirements
|
||||||
# 5. Creates /etc/pipekit/secrets.env (mode 0640, group pipekit)
|
# 5. Installs /usr/local/bin/pipekit launcher
|
||||||
# 6. Runs 'pipekit init' to create/upgrade the SQLite schema
|
# 6. Creates /etc/pipekit/secrets.env (mode 0640, group pipekit)
|
||||||
# 7. Registers JDBC driver rows for every jar shipped with jrunner
|
# 7. Runs 'pipekit init' to create/upgrade the SQLite schema
|
||||||
# 8. Installs and enables the systemd unit (does not start it)
|
# 8. Registers JDBC driver rows for every jar shipped with jrunner
|
||||||
|
# 9. Installs and enables the systemd unit (does not start it)
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# ./deploy.sh # re-execs itself with sudo if needed
|
# ./deploy.sh # re-execs itself with sudo if needed
|
||||||
@ -29,57 +30,95 @@ SERVICE_NAME="pipekit"
|
|||||||
UNIT_SRC="$REPO_DIR/systemd/pipekit.service"
|
UNIT_SRC="$REPO_DIR/systemd/pipekit.service"
|
||||||
UNIT_DST="/etc/systemd/system/pipekit.service"
|
UNIT_DST="/etc/systemd/system/pipekit.service"
|
||||||
|
|
||||||
|
# Capture the invoking user before re-execing as root
|
||||||
|
INVOKING_USER="${SUDO_USER:-${USER:-}}"
|
||||||
|
|
||||||
# Re-exec as root if needed
|
# Re-exec as root if needed
|
||||||
if [ "$EUID" -ne 0 ]; then
|
if [ "$EUID" -ne 0 ]; then
|
||||||
exec sudo -H -E "$0" "$@"
|
exec sudo -E "$0" "$@"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
step() { echo ""; echo "── $* ──"; }
|
||||||
|
|
||||||
echo "== pipekit deploy =="
|
echo "== pipekit deploy =="
|
||||||
echo "repo: $REPO_DIR"
|
echo "repo: $REPO_DIR"
|
||||||
echo "venv: $VENV_DIR"
|
echo "venv: $VENV_DIR"
|
||||||
echo "secrets: $SECRETS_FILE"
|
echo "secrets: $SECRETS_FILE"
|
||||||
echo ""
|
echo "user: $SERVICE_NAME (invoking user: ${INVOKING_USER:-unknown})"
|
||||||
|
|
||||||
# ── Prerequisites ─────────────────────────────────────────────────────────────
|
# ── Prerequisites ─────────────────────────────────────────────────────────────
|
||||||
|
step "Checking prerequisites"
|
||||||
command -v python3 >/dev/null || { echo "ERROR: python3 not on PATH"; exit 1; }
|
command -v python3 >/dev/null || { echo "ERROR: python3 not on PATH"; exit 1; }
|
||||||
|
echo " python3: $(python3 --version)"
|
||||||
command -v jrunner >/dev/null || { echo "ERROR: jrunner not on PATH — install /opt/jrunner first"; exit 1; }
|
command -v jrunner >/dev/null || { echo "ERROR: jrunner not on PATH — install /opt/jrunner first"; exit 1; }
|
||||||
|
echo " jrunner: $(command -v jrunner)"
|
||||||
|
|
||||||
# ── 1. System user ────────────────────────────────────────────────────────────
|
# ── 1. System user ────────────────────────────────────────────────────────────
|
||||||
|
step "System user"
|
||||||
if ! id -u "$SERVICE_NAME" >/dev/null 2>&1; then
|
if ! id -u "$SERVICE_NAME" >/dev/null 2>&1; then
|
||||||
echo "Creating system user: $SERVICE_NAME"
|
echo " Creating system user: $SERVICE_NAME"
|
||||||
useradd --system --no-create-home --shell /usr/sbin/nologin "$SERVICE_NAME"
|
useradd --system --no-create-home --home-dir /nonexistent \
|
||||||
|
--shell /usr/sbin/nologin "$SERVICE_NAME"
|
||||||
|
echo " Done."
|
||||||
else
|
else
|
||||||
echo "User $SERVICE_NAME already exists."
|
echo " User '$SERVICE_NAME' already exists (uid=$(id -u "$SERVICE_NAME"))."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── 2. Ownership ──────────────────────────────────────────────────────────────
|
# ── 2. Add invoking user to pipekit group ─────────────────────────────────────
|
||||||
echo "Setting ownership of $REPO_DIR to $SERVICE_NAME:$SERVICE_NAME"
|
step "Group membership"
|
||||||
chown -R "$SERVICE_NAME:$SERVICE_NAME" "$REPO_DIR"
|
if [ -n "$INVOKING_USER" ] && [ "$INVOKING_USER" != "$SERVICE_NAME" ]; then
|
||||||
|
if id -nG "$INVOKING_USER" | grep -qw "$SERVICE_NAME"; then
|
||||||
|
echo " $INVOKING_USER is already in the '$SERVICE_NAME' group."
|
||||||
|
else
|
||||||
|
echo " Adding $INVOKING_USER to the '$SERVICE_NAME' group."
|
||||||
|
usermod -aG "$SERVICE_NAME" "$INVOKING_USER"
|
||||||
|
echo " Done. Log out and back in for this to take effect."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " Skipping — could not determine invoking user."
|
||||||
|
fi
|
||||||
|
|
||||||
# ── 3. Venv + deps ────────────────────────────────────────────────────────────
|
# ── 3. Ownership ──────────────────────────────────────────────────────────────
|
||||||
|
step "File ownership and permissions"
|
||||||
|
echo " Setting $REPO_DIR → $SERVICE_NAME:$SERVICE_NAME (group-writable)"
|
||||||
|
chown -R "$SERVICE_NAME:$SERVICE_NAME" "$REPO_DIR"
|
||||||
|
chmod -R g+w "$REPO_DIR"
|
||||||
|
echo " Done."
|
||||||
|
|
||||||
|
# ── 4. Venv + deps ────────────────────────────────────────────────────────────
|
||||||
|
step "Python venv"
|
||||||
if [ -d "$VENV_DIR" ] && [ "$(stat -c '%U' "$VENV_DIR")" != "$SERVICE_NAME" ]; then
|
if [ -d "$VENV_DIR" ] && [ "$(stat -c '%U' "$VENV_DIR")" != "$SERVICE_NAME" ]; then
|
||||||
echo "Removing root-owned venv and recreating as $SERVICE_NAME"
|
echo " Venv exists but is not owned by $SERVICE_NAME — recreating."
|
||||||
rm -rf "$VENV_DIR"
|
rm -rf "$VENV_DIR"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -d "$VENV_DIR" ]; then
|
if [ ! -d "$VENV_DIR" ]; then
|
||||||
echo "Creating venv at $VENV_DIR"
|
echo " Creating venv at $VENV_DIR"
|
||||||
sudo -u "$SERVICE_NAME" python3 -m venv "$VENV_DIR"
|
sudo -u "$SERVICE_NAME" HOME=/nonexistent python3 -m venv "$VENV_DIR"
|
||||||
|
else
|
||||||
|
echo " Venv already exists at $VENV_DIR."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Installing Python dependencies"
|
echo " Upgrading pip"
|
||||||
sudo -u "$SERVICE_NAME" "$VENV_DIR/bin/pip" install --quiet --upgrade pip
|
sudo -u "$SERVICE_NAME" HOME=/nonexistent \
|
||||||
sudo -u "$SERVICE_NAME" "$VENV_DIR/bin/pip" install --quiet -r "$REPO_DIR/requirements.txt"
|
"$VENV_DIR/bin/pip" install --quiet --no-cache-dir --upgrade pip
|
||||||
echo "Dependencies installed."
|
|
||||||
|
|
||||||
# ── 4. Launcher ───────────────────────────────────────────────────────────────
|
echo " Installing requirements"
|
||||||
|
sudo -u "$SERVICE_NAME" HOME=/nonexistent \
|
||||||
|
"$VENV_DIR/bin/pip" install --quiet --no-cache-dir -r "$REPO_DIR/requirements.txt"
|
||||||
|
echo " Done."
|
||||||
|
|
||||||
|
# ── 5. Launcher ───────────────────────────────────────────────────────────────
|
||||||
|
step "Launcher"
|
||||||
chmod +x "$REPO_DIR/bin/pipekit"
|
chmod +x "$REPO_DIR/bin/pipekit"
|
||||||
ln -sf "$REPO_DIR/bin/pipekit" "$LAUNCHER"
|
ln -sf "$REPO_DIR/bin/pipekit" "$LAUNCHER"
|
||||||
echo "Launcher: $LAUNCHER -> $REPO_DIR/bin/pipekit"
|
echo " $LAUNCHER -> $REPO_DIR/bin/pipekit"
|
||||||
|
|
||||||
# ── 5. Secrets file ───────────────────────────────────────────────────────────
|
# ── 6. Secrets file ───────────────────────────────────────────────────────────
|
||||||
|
step "Secrets file"
|
||||||
install -d -m 0755 "$CONFIG_DIR"
|
install -d -m 0755 "$CONFIG_DIR"
|
||||||
if [ ! -f "$SECRETS_FILE" ]; then
|
if [ ! -f "$SECRETS_FILE" ]; then
|
||||||
|
echo " Creating $SECRETS_FILE (mode 0640, group $SERVICE_NAME)"
|
||||||
install -m 0640 /dev/null "$SECRETS_FILE"
|
install -m 0640 /dev/null "$SECRETS_FILE"
|
||||||
chown "root:$SERVICE_NAME" "$SECRETS_FILE"
|
chown "root:$SERVICE_NAME" "$SECRETS_FILE"
|
||||||
cat > "$SECRETS_FILE" <<'EOF'
|
cat > "$SECRETS_FILE" <<'EOF'
|
||||||
@ -87,46 +126,56 @@ if [ ! -f "$SECRETS_FILE" ]; then
|
|||||||
# Connection passwords are stored as $KEY references in the DB.
|
# Connection passwords are stored as $KEY references in the DB.
|
||||||
# Add entries with: sudo pipekit secrets set KEY VALUE
|
# Add entries with: sudo pipekit secrets set KEY VALUE
|
||||||
EOF
|
EOF
|
||||||
echo "Created $SECRETS_FILE"
|
|
||||||
else
|
else
|
||||||
# Ensure correct permissions even if file pre-existed
|
echo " $SECRETS_FILE already exists — keeping contents."
|
||||||
chown "root:$SERVICE_NAME" "$SECRETS_FILE"
|
chown "root:$SERVICE_NAME" "$SECRETS_FILE"
|
||||||
chmod 0640 "$SECRETS_FILE"
|
chmod 0640 "$SECRETS_FILE"
|
||||||
echo "Keeping existing $SECRETS_FILE"
|
echo " Permissions ensured: 0640 group $SERVICE_NAME."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── 6. Schema init ────────────────────────────────────────────────────────────
|
# ── 7. Schema init ────────────────────────────────────────────────────────────
|
||||||
sudo -u "$SERVICE_NAME" "$LAUNCHER" init
|
step "Database schema"
|
||||||
echo "Schema initialised."
|
echo " Running pipekit init"
|
||||||
|
sudo -u "$SERVICE_NAME" HOME=/nonexistent "$LAUNCHER" init
|
||||||
|
echo " Done."
|
||||||
|
|
||||||
# ── 7. Driver registration ────────────────────────────────────────────────────
|
# ── 8. Driver registration ────────────────────────────────────────────────────
|
||||||
|
step "JDBC driver registration"
|
||||||
JR_LIB="$(dirname "$(readlink -f "$(command -v jrunner)")")/../lib"
|
JR_LIB="$(dirname "$(readlink -f "$(command -v jrunner)")")/../lib"
|
||||||
|
echo " jrunner lib dir: $JR_LIB"
|
||||||
register_jar() {
|
register_jar() {
|
||||||
local kind="$1" pattern="$2"
|
local kind="$1" pattern="$2"
|
||||||
local jar
|
local jar
|
||||||
jar="$(find "$JR_LIB" -maxdepth 1 -name "$pattern" 2>/dev/null | head -1)"
|
jar="$(find "$JR_LIB" -maxdepth 1 -name "$pattern" 2>/dev/null | head -1)"
|
||||||
if [ -n "$jar" ]; then
|
if [ -n "$jar" ]; then
|
||||||
sudo -u "$SERVICE_NAME" "$LAUNCHER" drivers register "$kind" --jar "$jar"
|
echo " Registering $kind: $(basename "$jar")"
|
||||||
|
sudo -u "$SERVICE_NAME" HOME=/nonexistent "$LAUNCHER" drivers register "$kind" --jar "$jar"
|
||||||
else
|
else
|
||||||
echo " (no $pattern in $JR_LIB — skipping $kind)"
|
echo " No $pattern found in $JR_LIB — skipping $kind"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
register_jar db2 "jt400-*.jar"
|
register_jar db2 "jt400-*.jar"
|
||||||
register_jar pg "postgresql-*.jar"
|
register_jar pg "postgresql-*.jar"
|
||||||
register_jar mssql "mssql-jdbc-*.jar"
|
register_jar mssql "mssql-jdbc-*.jar"
|
||||||
|
|
||||||
# ── 8. Systemd unit ───────────────────────────────────────────────────────────
|
# ── 9. Systemd unit ───────────────────────────────────────────────────────────
|
||||||
|
step "Systemd unit"
|
||||||
if [ ! -f "$UNIT_SRC" ]; then
|
if [ ! -f "$UNIT_SRC" ]; then
|
||||||
echo "WARNING: $UNIT_SRC not found — skipping systemd install"
|
echo " WARNING: $UNIT_SRC not found — skipping"
|
||||||
else
|
else
|
||||||
|
echo " Installing $UNIT_DST"
|
||||||
cp "$UNIT_SRC" "$UNIT_DST"
|
cp "$UNIT_SRC" "$UNIT_DST"
|
||||||
|
echo " Running systemctl daemon-reload"
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
|
echo " Enabling $SERVICE_NAME service"
|
||||||
systemctl enable "$SERVICE_NAME"
|
systemctl enable "$SERVICE_NAME"
|
||||||
echo "Systemd unit installed and enabled."
|
echo " Done."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "pipekit deployed."
|
echo "════════════════════════════════════"
|
||||||
|
echo " pipekit deployed successfully."
|
||||||
|
echo "════════════════════════════════════"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Next steps:"
|
echo "Next steps:"
|
||||||
echo " 1. Add connection passwords:"
|
echo " 1. Add connection passwords:"
|
||||||
@ -137,3 +186,10 @@ echo " sudo systemctl start pipekit"
|
|||||||
echo " 3. Check it:"
|
echo " 3. Check it:"
|
||||||
echo " sudo systemctl status pipekit"
|
echo " sudo systemctl status pipekit"
|
||||||
echo " journalctl -u pipekit -f"
|
echo " journalctl -u pipekit -f"
|
||||||
|
if [ -n "$INVOKING_USER" ]; then
|
||||||
|
if ! id -nG "$INVOKING_USER" 2>/dev/null | grep -qw "$SERVICE_NAME"; then
|
||||||
|
echo ""
|
||||||
|
echo " NOTE: $INVOKING_USER was added to the '$SERVICE_NAME' group."
|
||||||
|
echo " Log out and back in for write access to take effect."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|||||||
@ -59,13 +59,6 @@ def cmd_drivers_register(args) -> int:
|
|||||||
print(f"error: {e}")
|
print(f"error: {e}")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
existing = [d for d in repo.list_drivers() if d["kind"] == args.kind]
|
|
||||||
if existing and not args.force:
|
|
||||||
print(f"driver kind {args.kind!r} already registered as "
|
|
||||||
f"{existing[0]['name']!r} (id={existing[0]['id']}). "
|
|
||||||
f"Use --force to add a second row.")
|
|
||||||
return 0
|
|
||||||
|
|
||||||
class_name = args.class_name or _DEFAULT_JDBC_CLASSES.get(args.kind)
|
class_name = args.class_name or _DEFAULT_JDBC_CLASSES.get(args.kind)
|
||||||
if not class_name:
|
if not class_name:
|
||||||
print(f"error: no built-in JDBC class for kind {args.kind!r}; "
|
print(f"error: no built-in JDBC class for kind {args.kind!r}; "
|
||||||
@ -315,8 +308,6 @@ def main(argv: list[str] | None = None) -> int:
|
|||||||
help="JDBC Driver class (default: built-in per kind)")
|
help="JDBC Driver class (default: built-in per kind)")
|
||||||
p_drv_reg.add_argument("--url-template",
|
p_drv_reg.add_argument("--url-template",
|
||||||
help="optional JDBC URL template for the wizard")
|
help="optional JDBC URL template for the wizard")
|
||||||
p_drv_reg.add_argument("--force", action="store_true",
|
|
||||||
help="register even if a row for this kind exists")
|
|
||||||
p_drv_reg.set_defaults(func=cmd_drivers_register)
|
p_drv_reg.set_defaults(func=cmd_drivers_register)
|
||||||
|
|
||||||
p_run = sub.add_parser("run", help="run a module by name (synchronous)")
|
p_run = sub.add_parser("run", help="run a module by name (synchronous)")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user