-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsetup-vm.sh
More file actions
executable file
·454 lines (392 loc) · 12.1 KB
/
setup-vm.sh
File metadata and controls
executable file
·454 lines (392 loc) · 12.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
#!/usr/bin/env bash
set -euo pipefail
# Global variables
DIR=$(cd "$(dirname "$0")" && pwd -P)
STACKROX_REPO="${STACKROX_REPO:-${HOME}/src/go/src/github.com/stackrox/stackrox}"
AGENT_DIR="${STACKROX_REPO}/compliance/virtualmachines/roxagent"
NAMESPACE="${NAMESPACE:-openshift-cnv}"
SSH_USER="${SSH_USER:-cloud-user}"
VM_PASSWORD="${VM_PASSWORD:-password}"
VMI_NAME=""
YES_FLAG=false
declare -a SSH_OPTS
# Check all prerequisites before proceeding
check_prerequisites() {
echo "Checking prerequisites..."
if ! command -v kubectl &> /dev/null; then
echo "ERROR: kubectl is not installed or not in PATH"
exit 1
fi
if ! command -v virtctl &> /dev/null; then
echo "ERROR: virtctl is not installed or not in PATH"
echo "Install it with: kubectl krew install virt"
exit 1
fi
if ! command -v go &> /dev/null; then
echo "ERROR: go is not installed or not in PATH"
exit 1
fi
if ! command -v git &> /dev/null; then
echo "ERROR: git is not installed or not in PATH"
exit 1
fi
if ! kubectl cluster-info &> /dev/null; then
echo "ERROR: Cannot connect to Kubernetes cluster"
exit 1
fi
if ! test -d "${STACKROX_REPO}"; then
echo "ERROR: StackRox repository not found at: ${STACKROX_REPO}"
echo "Please specify the location via STACKROX_REPO environment variable"
exit 1
fi
if ! test -d "${AGENT_DIR}"; then
echo "ERROR: Agent directory not found at: ${AGENT_DIR}"
exit 1
fi
if ! test -f "${DIR}/vm-agent.service"; then
echo "ERROR: vm-agent.service file not found at: ${DIR}/vm-agent.service"
echo "Please create this file before running the script"
exit 1
fi
if ! test -f "${DIR}/vm-agent.timer"; then
echo "ERROR: vm-agent.timer file not found at: ${DIR}/vm-agent.timer"
echo "Please create this file before running the script"
exit 1
fi
echo "Prerequisites OK"
echo ""
# Check SSH agent
check_ssh_agent
}
# Check if SSH agent is running and has keys loaded
check_ssh_agent() {
echo "Checking SSH agent..."
# Check if ssh-agent is running
if [ -z "${SSH_AUTH_SOCK:-}" ]; then
echo "⚠️ WARNING: SSH agent is not running"
echo " You will likely be prompted for your SSH key passphrase multiple times"
echo ""
echo " To avoid this, start ssh-agent and add your key:"
echo " eval \$(ssh-agent)"
echo " ssh-add ~/.ssh/id_ed25519"
echo ""
return 0
fi
# Check if any keys are loaded
local key_count
if ssh-add -l &>/dev/null; then
key_count=$(ssh-add -l 2>/dev/null | wc -l | tr -d ' ')
else
key_count=0
fi
if [ "${key_count:-0}" -eq 0 ]; then
echo "⚠️ WARNING: No SSH keys loaded in ssh-agent"
echo " You will be prompted for your SSH key passphrase multiple times"
echo ""
echo " To fix this, add your SSH key:"
echo " ssh-add ~/.ssh/id_ed25519"
echo ""
if [ "$YES_FLAG" = true ]; then
echo " (-y flag set, continuing anyway)"
echo ""
else
read -p "Do you want to continue anyway? (y/N): " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted by user"
exit 1
fi
echo ""
fi
else
echo "✓ SSH agent is running with $key_count key(s) loaded"
echo ""
fi
}
# Get and set VMI name from argument or auto-detect
get_vmi_name() {
local vmi_arg="${1:-}"
if [ -n "$vmi_arg" ]; then
VMI_NAME="$vmi_arg"
else
echo "No VMI name provided, searching for available VMIs..."
VMI_NAME=$(kubectl -n "$NAMESPACE" get vmi -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || echo "")
if [ -z "$VMI_NAME" ]; then
echo "ERROR: No VMI found in namespace $NAMESPACE"
echo "Usage: $0 <vmi-name>"
exit 1
fi
echo "Found VMI: $VMI_NAME"
fi
echo "Setting up VMI: ${VMI_NAME} in namespace: ${NAMESPACE}"
echo ""
}
# Validate that VMI exists and is running
validate_vmi() {
if ! kubectl -n "$NAMESPACE" get vmi "$VMI_NAME" &> /dev/null; then
echo "ERROR: VMI '${VMI_NAME}' not found in namespace '${NAMESPACE}'"
exit 1
fi
local vmi_phase
vmi_phase=$(kubectl -n "$NAMESPACE" get vmi "$VMI_NAME" -o jsonpath='{.status.phase}')
if [ "$vmi_phase" != "Running" ]; then
echo "ERROR: VMI '${VMI_NAME}' is not running (current phase: ${vmi_phase})"
exit 1
fi
echo "VMI is running"
echo ""
}
# Setup SSH options for virtctl commands
setup_ssh_opts() {
SSH_OPTS=(
--namespace "$NAMESPACE"
--local-ssh-opts="-o StrictHostKeyChecking=no"
--local-ssh-opts="-o UserKnownHostsFile=/dev/null"
--local-ssh-opts="-o ConnectTimeout=10"
)
# Clean SSH known hosts
echo "Cleaning SSH known hosts for VMI..."
ssh-keygen -R "vmi.${VMI_NAME}.${NAMESPACE}" 2> /dev/null || true
echo ""
}
# Test SSH connection to ensure keys are loaded
test_ssh_connection() {
echo "Testing SSH connection to VMI..."
# Try a simple SSH command with BatchMode for the test
if virtctl ssh \
--namespace "$NAMESPACE" \
--local-ssh-opts="-o StrictHostKeyChecking=no" \
--local-ssh-opts="-o UserKnownHostsFile=/dev/null" \
--local-ssh-opts="-o BatchMode=yes" \
--local-ssh-opts="-o ConnectTimeout=10" \
--command "echo SSH_TEST_OK" \
"${SSH_USER}@vmi/${VMI_NAME}" 2>&1 | grep -q "SSH_TEST_OK"; then
echo "✓ SSH connection successful (using SSH keys)"
echo ""
return 0
fi
# If we got here, SSH with keys failed
echo "⚠️ SSH key authentication failed"
echo ""
echo " This is likely because:"
echo " 1. Your SSH key has a passphrase and is not loaded in ssh-agent"
echo " 2. Your SSH key is not authorized on the VM"
echo ""
echo " To fix this, run:"
echo " ssh-add ~/.ssh/id_ed25519"
echo ""
echo " Alternatively, you can use password authentication"
echo " Password: ${VM_PASSWORD:-password}"
echo ""
if [ "$YES_FLAG" = true ]; then
echo " (-y flag set, continuing with password authentication)"
echo ""
else
read -p "Continue with password authentication? (y/N): " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted by user"
exit 1
fi
fi
echo "Continuing... (you will be prompted for passwords)"
echo ""
}
# Check git repository branch and warn if not on master
check_git_branch() {
echo "Checking git repository status..."
cd "${STACKROX_REPO}"
# Check if it's a git repository
if ! git rev-parse --git-dir &> /dev/null; then
echo "WARNING: ${STACKROX_REPO} is not a git repository"
echo ""
return 0
fi
# Get current branch
local current_branch
current_branch=$(git branch --show-current 2>/dev/null || git rev-parse --short HEAD)
echo "Current branch: $current_branch"
# Check for uncommitted changes
if ! git diff-index --quiet HEAD -- 2>/dev/null; then
echo "WARNING: Repository has uncommitted changes"
echo "The built binary will include these local modifications"
echo ""
fi
# Show the commit that will be built
local commit_info
commit_info=$(git log -1 --oneline 2>/dev/null || echo "unknown")
echo "Building from commit: $commit_info"
echo ""
# Warn if not on master branch
if [ "$current_branch" != "master" ] && [ "$current_branch" != "main" ]; then
echo "⚠️ WARNING: You are not on the master/main branch!"
echo " Current branch: $current_branch"
echo ""
if [ "$YES_FLAG" = true ]; then
echo " (-y flag set, continuing anyway)"
echo ""
else
read -p "Do you want to continue? (y/N): " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted by user"
exit 1
fi
echo ""
fi
fi
}
# Configure VM environment (timezone, roxroot bind mounts)
configure_vm() {
echo "Configuring VM environment..."
local configure_cmd
configure_cmd="sudo timedatectl set-timezone Europe/Berlin && \
sudo mkdir -p /tmp/roxroot/{etc,var,usr,root} && \
sudo mount --bind /etc /tmp/roxroot/etc 2>/dev/null || true && \
sudo mount --bind /var /tmp/roxroot/var 2>/dev/null || true && \
sudo mount --bind /usr /tmp/roxroot/usr 2>/dev/null || true && \
sudo mount --bind /root /tmp/roxroot/root 2>/dev/null || true"
if ! virtctl ssh "${SSH_OPTS[@]}" \
--command "$configure_cmd" \
"${SSH_USER}@vmi/${VMI_NAME}"; then
echo "ERROR: Failed to configure VM environment"
exit 1
fi
echo "Timezone set to Europe/Berlin"
echo "roxroot bind mounts created at /tmp/roxroot"
echo ""
}
# Check if service/timer is already installed and stop it if running
check_existing_service() {
echo "Checking if vm-agent timer/service is already installed..."
local timer_status
timer_status=$(virtctl ssh "${SSH_OPTS[@]}" \
--command "sudo systemctl is-active vm-agent.timer 2>/dev/null || echo 'not-found'" \
"${SSH_USER}@vmi/${VMI_NAME}" 2>/dev/null || echo "not-found")
if [ "$timer_status" = "active" ]; then
echo "vm-agent timer is already running on VMI '${VMI_NAME}'"
echo "Stopping timer and service to update..."
virtctl ssh "${SSH_OPTS[@]}" \
--command "sudo systemctl stop vm-agent.timer vm-agent.service 2>/dev/null || true" \
"${SSH_USER}@vmi/${VMI_NAME}"
echo "Timer and service stopped"
elif [ "$timer_status" = "inactive" ] || [ "$timer_status" = "failed" ]; then
echo "vm-agent timer exists but is not running (status: $timer_status)"
echo "Will update and restart..."
else
echo "vm-agent timer not found, will perform fresh installation"
fi
echo ""
}
# Build the VM agent binary
build_agent() {
echo "Building VM agent binary..."
cd "${AGENT_DIR}"
if ! GOOS=linux GOARCH=amd64 go build -o "${DIR}/vm-agent-amd64" .; then
echo "ERROR: Failed to build vm-agent binary"
exit 1
fi
echo "Build successful: ${DIR}/vm-agent-amd64"
echo ""
}
# Copy binary and service file to VMI
copy_files_to_vmi() {
echo "Copying VM agent binary to VMI..."
if ! virtctl scp "${SSH_OPTS[@]}" \
"${DIR}/vm-agent-amd64" \
"${SSH_USER}@vmi/${VMI_NAME}:"; then
echo "ERROR: Failed to copy agent binary"
exit 1
fi
echo "Binary copied successfully"
echo ""
echo "Copying systemd service file to VMI..."
if ! virtctl scp "${SSH_OPTS[@]}" \
"${DIR}/vm-agent.service" \
"${SSH_USER}@vmi/${VMI_NAME}:"; then
echo "ERROR: Failed to copy service file"
exit 1
fi
echo "Service file copied successfully"
echo ""
echo "Copying systemd timer file to VMI..."
if ! virtctl scp "${SSH_OPTS[@]}" \
"${DIR}/vm-agent.timer" \
"${SSH_USER}@vmi/${VMI_NAME}:"; then
echo "ERROR: Failed to copy timer file"
exit 1
fi
echo "Timer file copied successfully"
echo ""
}
# Install and start the systemd service and timer
install_and_start_service() {
echo "Installing and starting vm-agent service and timer..."
local install_cmd
install_cmd="sudo mv ~/vm-agent.service /etc/systemd/system/ && \
sudo mv ~/vm-agent.timer /etc/systemd/system/ && \
sudo restorecon -v /etc/systemd/system/vm-agent.service /etc/systemd/system/vm-agent.timer 2>/dev/null || true && \
sudo chmod +x ~/vm-agent-amd64 && \
sudo chcon -t bin_t ~/vm-agent-amd64 2>/dev/null || true && \
sudo systemctl daemon-reload && \
sudo systemctl enable vm-agent.timer && \
sudo systemctl start vm-agent.timer"
if ! virtctl ssh "${SSH_OPTS[@]}" \
--command "$install_cmd" \
"${SSH_USER}@vmi/${VMI_NAME}"; then
echo "ERROR: Failed to install and start service/timer"
exit 1
fi
echo "Service and timer installed and started"
echo ""
}
# Verify that the timer is running correctly
verify_service() {
echo "Verifying timer status..."
sleep 2 # Give timer a moment to start
local timer_result
timer_result=$(virtctl ssh "${SSH_OPTS[@]}" \
--command "sudo systemctl status vm-agent.timer --no-pager" \
"${SSH_USER}@vmi/${VMI_NAME}" 2>&1 || true)
echo "$timer_result"
echo ""
if echo "$timer_result" | grep -q "Active: active (waiting)"; then
echo "=== Installation Complete ==="
echo "vm-agent timer is active and waiting on VMI '${VMI_NAME}'"
echo "The agent will run every minute"
return 0
else
echo "WARNING: Timer may not be running correctly"
echo "Check the status above for details"
return 1
fi
}
# Main execution flow
main() {
local vmi_arg=""
while [[ $# -gt 0 ]]; do
case "$1" in
-y|--yes) YES_FLAG=true; shift ;;
-*) echo "Unknown option: $1"; exit 1 ;;
*) vmi_arg="$1"; shift ;;
esac
done
echo "=== VMI Agent Setup Script ==="
echo ""
check_prerequisites
get_vmi_name "${vmi_arg}"
validate_vmi
setup_ssh_opts
test_ssh_connection
check_git_branch
configure_vm
check_existing_service
build_agent
copy_files_to_vmi
install_and_start_service
verify_service
}
# Execute main function if script is run directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi