homelab infrastructure services
1#!/bin/bash
2# tin machine rm - Remove machine environment
3
4set -euo pipefail
5
6# Get tinsnip root and source libraries
7SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8TINSNIP_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
9source "$TINSNIP_ROOT/lib/core.sh"
10source "$TINSNIP_ROOT/lib/uid.sh"
11source "$TINSNIP_ROOT/lib/registry.sh"
12source "$TINSNIP_ROOT/lib/nas.sh"
13
14# Remove machine environment
15remove_machine() {
16 local service_env="$1"
17 local delete_data="${2:-false}"
18 local no_confirm="${3:-false}"
19
20 # Parse service-environment
21 local parsed_output
22 if ! parsed_output=$(parse_machine_name "$service_env" 2>/dev/null); then
23 error_with_prefix "Machine Remove" "Invalid machine environment format: '$service_env'"
24 echo "Expected: <service>-<environment> (e.g., pds-dev, bsky-pds-dev)" >&2
25 exit 1
26 fi
27
28 local service=$(echo "$parsed_output" | sed -n '1p')
29 local environment=$(echo "$parsed_output" | sed -n '2p')
30 local service_user="$service_env"
31
32 log_with_prefix "Machine Remove" "Removing machine: $service_env"
33 echo
34
35 # Check if user exists
36 if ! id "$service_user" &>/dev/null 2>&1; then
37 warn_with_prefix "Machine Remove" "User '$service_user' does not exist"
38 echo "Machine may have already been removed or never created." >&2
39 exit 0
40 fi
41
42 local service_uid=$(id -u "$service_user")
43 local mount_point="/mnt/$service_env"
44
45 echo "Machine Details:"
46 echo " User: $service_user"
47 echo " UID: $service_uid"
48 echo " Mount: $mount_point"
49 echo
50
51 # Check for deployed services
52 local services=()
53 if [[ -d "$mount_point/service" ]]; then
54 while IFS= read -r -d '' service_dir; do
55 services+=("$(basename "$service_dir")")
56 done < <(find "$mount_point/service" -mindepth 1 -maxdepth 1 -type d -print0 2>/dev/null)
57 fi
58
59 if [[ ${#services[@]} -gt 0 ]]; then
60 echo "WARNING: Found ${#services[@]} deployed service(s):"
61 for svc in "${services[@]}"; do
62 echo " - $svc"
63 done
64 echo
65
66 if [[ "$no_confirm" == "true" ]]; then
67 # Auto-confirm when called from sheet removal
68 log_with_prefix "Machine Remove" "Removing all services..."
69 else
70 read -p "Remove all services first? [Y/n]: " remove_services
71 case "${remove_services:-y}" in
72 [Yy]*|"")
73 ;;
74 *)
75 error_with_prefix "Machine Remove" "Cannot remove machine with deployed services"
76 echo "Remove services first with: tin service rm $service_env <service>" >&2
77 exit 1
78 ;;
79 esac
80 fi
81
82 for svc in "${services[@]}"; do
83 log_with_prefix "Machine Remove" "Removing service: $svc"
84 "$TINSNIP_ROOT/cmd/service/rm.sh" "$service_env" "$svc" <<< "y"
85 done
86 echo
87 fi
88
89 # Show data policy
90 if [[ "$delete_data" == "true" ]]; then
91 echo "WARNING: NAS data will be DELETED"
92 else
93 echo "SUCCESS: NAS data will be PRESERVED"
94 fi
95 echo
96
97 if [[ "$no_confirm" == "true" ]]; then
98 # Auto-confirm when called from sheet removal
99 log_with_prefix "Machine Remove" "Proceeding with removal..."
100 else
101 read -p "Remove this machine? [y/N]: " confirm
102 case "${confirm}" in
103 [Yy])
104 log_with_prefix "Machine Remove" "Proceeding with removal..."
105 ;;
106 *)
107 log_with_prefix "Machine Remove" "Removal cancelled"
108 exit 0
109 ;;
110 esac
111 fi
112
113 # Delete NAS data if requested
114 if [[ "$delete_data" == "true" ]]; then
115 log_with_prefix "Machine Remove" "Deleting NAS data..."
116
117 # Find NAS server from fstab
118 local nas_path=$(grep "$mount_point" /etc/fstab 2>/dev/null | awk '{print $1}' | head -1)
119 if [[ -n "$nas_path" ]]; then
120 echo " NAS path: $nas_path"
121 local nas_server=$(echo "$nas_path" | cut -d: -f1)
122 local nas_dir=$(echo "$nas_path" | cut -d: -f2)
123
124 echo " Deleting data on NAS: $nas_server"
125 echo " This will require sudo password on the NAS..."
126 echo ""
127
128 # Use interactive SSH with -t flag to enable password prompt
129 # This also removes the NFS export and reloads
130 if ssh -t "$nas_server" "echo 'Removing NAS data and export...' && \
131 sudo rm -rf '$nas_dir' && \
132 echo 'Data deleted: $nas_dir' && \
133 sudo sed -i '\|$nas_dir|d' /etc/exports && \
134 echo 'Export removed from /etc/exports' && \
135 sudo exportfs -ra && \
136 echo 'NFS exports reloaded'"; then
137 echo ""
138 log_with_prefix "Machine Remove" "✅ NAS data and export deleted successfully"
139 else
140 echo ""
141 warn_with_prefix "Machine Remove" "Failed to delete NAS data"
142 echo " Manually delete with:" >&2
143 echo " ssh $nas_server" >&2
144 echo " sudo rm -rf '$nas_dir'" >&2
145 echo " sudo sed -i '\|$nas_dir|d' /etc/exports" >&2
146 echo " sudo exportfs -ra" >&2
147 fi
148 else
149 warn_with_prefix "Machine Remove" "Could not find NAS path in /etc/fstab"
150 echo " NFS mount information not available for cleanup" >&2
151 fi
152 else
153 log_with_prefix "Machine Remove" "Preserving NAS data (use --delete-data to remove)"
154 fi
155
156 # Unmount NFS
157 log_with_prefix "Machine Remove" "Unmounting NFS..."
158 if mountpoint -q "$mount_point" 2>/dev/null; then
159 sudo umount "$mount_point" 2>/dev/null || sudo umount -l "$mount_point"
160 fi
161
162 # Remove from fstab
163 log_with_prefix "Machine Remove" "Removing from /etc/fstab..."
164 sudo sed -i "\|$mount_point|d" /etc/fstab
165
166 # Remove user
167 log_with_prefix "Machine Remove" "Removing user $service_user..."
168
169 # Kill any processes owned by the user first
170 if id "$service_user" &>/dev/null; then
171 sudo pkill -9 -u "$service_user" 2>/dev/null || true
172 sleep 1 # Give processes time to terminate
173 fi
174
175 # Remove user and home directory
176 if sudo userdel -r "$service_user" 2>/dev/null; then
177 log_with_prefix "Machine Remove" "User removed successfully"
178 else
179 warn_with_prefix "Machine Remove" "Failed to remove user (may need manual cleanup)"
180 fi
181
182 # Remove mount point directory
183 if [[ -d "$mount_point" ]]; then
184 sudo rmdir "$mount_point" 2>/dev/null || sudo rm -rf "$mount_point"
185 fi
186
187 # Remove service from registry
188 log_with_prefix "Machine Remove" "Removing from machine registry..."
189
190 # Detect sheet from UID
191 local sheet=$(get_sheet_from_uid "$service_uid")
192 log_with_prefix "Machine Remove" "Detected sheet: $sheet (from UID $service_uid)"
193
194 if unregister_service "$service" "$sheet" 2>/dev/null; then
195 log_with_prefix "Machine Remove" "Service unregistered from $sheet registry"
196 else
197 warn_with_prefix "Machine Remove" "Service was not in registry for sheet $sheet"
198 fi
199
200 echo
201 log_with_prefix "Machine Remove" "Machine '$service_env' removed successfully"
202 if [[ "$delete_data" != "true" ]]; then
203 echo
204 log_with_prefix "Machine Remove" "NAS data preserved. To restore:"
205 log_with_prefix "Machine Remove" " tin machine create $service $environment <nas-server>"
206 log_with_prefix "Machine Remove" " tin service deploy $service_env <service-name>"
207 fi
208}
209
210show_help() {
211 cat << EOF
212tin machine rm - Remove machine environment
213
214USAGE:
215 tin machine rm <service-env> [--delete-data] [--no-confirm]
216
217DESCRIPTION:
218 Remove a machine environment including user and NFS mount.
219 By default, NAS data is PRESERVED for recovery.
220 Automatically removes all deployed services first.
221
222ARGUMENTS:
223 <service-env> Machine to remove (e.g., pds-dev)
224
225OPTIONS:
226 --delete-data Also delete data on NAS (DANGEROUS!)
227 --no-confirm Skip confirmation prompts (for automation)
228
229EXAMPLES:
230 tin machine rm pds-dev # Remove machine, keep NAS data
231 tin machine rm pds-dev --delete-data # Remove machine AND delete NAS data
232 tin machine rm pds-dev --no-confirm # Remove without prompts
233
234NOTES:
235 - Automatically removes deployed services (with confirmation unless --no-confirm)
236 - Default behavior preserves NAS data (CD-friendly)
237 - Machine can be recreated and data remounted for recovery
238 - Use --delete-data only when permanently decommissioning
239 - NAS deletion requires sudo password (interactive prompt)
240 - Also removes NFS export from /etc/exports and reloads
241 - --no-confirm keeps stdin as terminal for interactive NAS password
242
243WARNING:
244 --delete-data will PERMANENTLY DELETE all data on the NAS!
245 You will be prompted for the NAS sudo password during deletion.
246
247EOF
248}
249
250# Handle help flags
251case "${1:-}" in
252 --help|-h|help)
253 show_help
254 exit 0
255 ;;
256esac
257
258# Main execution
259if [[ $# -eq 0 ]]; then
260 error_with_prefix "Machine Remove" "Service environment required"
261 echo "Usage: tin machine rm <service-env> [--delete-data] [--no-confirm]" >&2
262 exit 1
263fi
264
265service_env="$1"
266delete_data="false"
267no_confirm="false"
268
269# Parse flags
270shift
271while [[ $# -gt 0 ]]; do
272 case "$1" in
273 --delete-data)
274 delete_data="true"
275 ;;
276 --no-confirm)
277 no_confirm="true"
278 ;;
279 *)
280 error_with_prefix "Machine Remove" "Unknown flag: $1"
281 echo "Usage: tin machine rm <service-env> [--delete-data] [--no-confirm]" >&2
282 exit 1
283 ;;
284 esac
285 shift
286done
287
288remove_machine "$service_env" "$delete_data" "$no_confirm"