Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
505 lines (467 loc) · 18 KB
/
Copy pathMakefile
File metadata and controls
505 lines (467 loc) · 18 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
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
# The Open Horizon organization ID namespace where you will be publishing files
export HZN_ORG_ID ?= myorg
# Blessed Samples configuration
# NOTE: EXPOSE_REGISTRY_PORT no longer maps to a Vagrant forwarded_port.
# Instead, use 'make port-forward' to expose hub services on localhost after provisioning.
export EXPOSE_REGISTRY_PORT ?= false
VMNAME := agent1
# Which system configuration to be provisioned
export SYSTEM_CONFIGURATION ?= unicycle
# Configuration parameters
export NUM_AGENTS ?= 1
export MEMORY ?= 2048
export DISK_SIZE ?= 20
# Multipass Ubuntu cloud image to use
export MULTIPASS_IMAGE ?= 22.04
# Hub IP is discovered after provisioning and stored in mycreds.env
export HUB_IP ?=
# Detect Operating System and Architecture running Make
OS := $(shell uname -s)
ARCH := $(shell uname -m)
# Map system configurations to parameters
ifeq ($(SYSTEM_CONFIGURATION),unicycle)
NUM_AGENTS := 1
MEMORY := 2048
DISK_SIZE := 20
else ifeq ($(SYSTEM_CONFIGURATION),bicycle)
NUM_AGENTS := 3
MEMORY := 2048
DISK_SIZE := 20
else ifeq ($(SYSTEM_CONFIGURATION),car)
NUM_AGENTS := 5
MEMORY := 2048
DISK_SIZE := 20
else ifeq ($(SYSTEM_CONFIGURATION),semi)
NUM_AGENTS := 7
MEMORY := 2048
DISK_SIZE := 20
endif
default: status
check:
@echo "Checking required tools..."
@if ! command -v multipass >/dev/null 2>&1; then \
echo "ERROR: 'multipass' not found. Install from https://multipass.run"; \
else \
echo " ✓ multipass: $$(multipass version | head -1)"; \
fi
@if ! command -v jq >/dev/null 2>&1; then \
echo "ERROR: 'jq' not found. Install with: sudo apt-get install jq (Linux) or brew install jq (macOS)"; \
else \
echo " ✓ jq: $$(jq --version)"; \
fi
@echo ""
@echo "===================== ============================================="
@echo "ENVIRONMENT VARIABLES VALUES"
@echo "===================== ============================================="
@echo "SYSTEM_CONFIGURATION ${SYSTEM_CONFIGURATION}"
@echo "NUM_AGENTS ${NUM_AGENTS}"
@echo "MEMORY ${MEMORY}"
@echo "DISK_SIZE ${DISK_SIZE}"
@echo "MULTIPASS_IMAGE ${MULTIPASS_IMAGE}"
@echo "HUB_IP ${HUB_IP}"
@echo "HZN_ORG_ID ${HZN_ORG_ID}"
@echo "OS ${OS}"
@echo "ARCH ${ARCH}"
@echo "===================== ============================================="
@echo ""
@if [ "${ARCH}" = "arm64" ] || [ "${ARCH}" = "aarch64" ]; then \
echo "WARNING: Running on ${ARCH} architecture. Open Horizon Management Hub (Exchange)"; \
echo " is not compatible with arm64. Only agent VMs should be provisioned"; \
echo " on this host, pointing to an external x86_64 hub."; \
echo ""; \
fi
# Detect host IP address (cross-platform)
detect-host-ip:
ifeq ($(OS),Darwin)
@IFACE=$$(route -n get default 2>/dev/null | grep interface | awk '{print $$2}'); \
if [ -n "$$IFACE" ]; then \
IP=$$(ifconfig $$IFACE 2>/dev/null | grep 'inet ' | grep -v 127.0.0.1 | awk '{print $$2}' | head -1); \
if [ -n "$$IP" ]; then \
echo "$$IP"; \
else \
echo "ERROR: Could not detect IP for interface $$IFACE" >&2; \
exit 1; \
fi; \
else \
echo "ERROR: Could not detect default network interface" >&2; \
exit 1; \
fi
else
@IP=$$(ip route get 1.1.1.1 2>/dev/null | grep -oP 'src \K\S+'); \
if [ -z "$$IP" ]; then \
IP=$$(hostname -I 2>/dev/null | awk '{print $$1}'); \
fi; \
if [ -n "$$IP" ] && [ "$$IP" != "127.0.0.1" ]; then \
echo "$$IP"; \
else \
echo "ERROR: Could not detect host IP address" >&2; \
exit 1; \
fi
endif
# Display detected host IP for verification
check-host-ip:
@echo "Detected host IP address: $$($(MAKE) -s detect-host-ip)"
# Generate agent-install-external.env with host IP
agent-config-external:
@echo "Generating agent-install-external.env..."
@HOST_IP=$$($(MAKE) -s detect-host-ip); \
if [ -z "$$HOST_IP" ]; then \
echo "ERROR: Failed to detect host IP"; \
exit 1; \
fi; \
echo "Using host IP: $$HOST_IP"; \
echo "export HZN_EXCHANGE_URL=http://$$HOST_IP:3090/v1" > agent-install-external.env; \
echo "export HZN_FSS_CSSURL=http://$$HOST_IP:9443/" >> agent-install-external.env; \
echo "export HZN_AGBOT_URL=http://$$HOST_IP:3111" >> agent-install-external.env; \
echo "export HZN_FDO_SVC_URL=http://$$HOST_IP:9008/api" >> agent-install-external.env; \
chmod 644 agent-install-external.env; \
echo "✓ Created agent-install-external.env with host IP $$HOST_IP"
# Generate agent-install-internal.env with hub VM IP
agent-config-internal:
@echo "Generating agent-install-internal.env..."
@if [ ! -f mycreds.env ]; then \
echo "ERROR: mycreds.env not found. Run 'make up-hub' first."; \
exit 1; \
fi; \
. ./mycreds.env; \
if [ -z "$$HUB_IP" ]; then \
echo "ERROR: HUB_IP missing from mycreds.env. Re-run 'make up-hub'."; \
exit 1; \
fi; \
echo "Using hub IP: $$HUB_IP"; \
echo "export HZN_EXCHANGE_URL=http://$$HUB_IP:3090/v1" > agent-install-internal.env; \
echo "export HZN_FSS_CSSURL=http://$$HUB_IP:9443/" >> agent-install-internal.env; \
echo "export HZN_AGBOT_URL=http://$$HUB_IP:3111" >> agent-install-internal.env; \
echo "export HZN_FDO_SVC_URL=http://$$HUB_IP:9008/api" >> agent-install-internal.env; \
chmod 644 agent-install-internal.env; \
echo "✓ Created agent-install-internal.env with hub IP $$HUB_IP"
# Generate both agent configuration files
generate-agent-configs: agent-config-external agent-config-internal
@echo ""
@echo "Agent configuration files generated successfully!"
@echo ""
@echo "Usage:"
@echo " - agent-install-external.env: For agents connecting from the host machine"
@echo " - agent-install-internal.env: For agents connecting from within VMs"
@echo ""
@echo "To use: export \$$(cat agent-install-external.env)"
init: up-hub up
up-hub:
@echo "Checking for existing hub VM..."
@HUB_STATE=$$(multipass info hub --format json 2>/dev/null | jq -r '.info.hub.state // empty' 2>/dev/null); \
if [ -n "$$HUB_STATE" ]; then \
echo " Hub VM exists (state: $$HUB_STATE) - stopping and deleting..."; \
multipass stop hub 2>/dev/null || true; \
multipass delete hub; \
multipass purge; \
echo " ✓ Hub VM deleted"; \
fi; \
echo " Launching fresh hub VM (this takes ~20-40 minutes)..."; \
multipass launch --name hub --cpus 2 --memory 4G --disk 50G \
--cloud-init cloud-init/hub.yaml $(MULTIPASS_IMAGE); \
echo "Waiting for hub IP address..."; \
HUB_IP=""; \
for i in $$(seq 1 10); do \
HUB_IP=$$(multipass info hub --format json 2>/dev/null | jq -r '.info.hub.ipv4[0] // empty' 2>/dev/null); \
if [ -n "$$HUB_IP" ] && [ "$$HUB_IP" != "null" ]; then \
echo "✓ Hub IP: $$HUB_IP"; \
break; \
fi; \
echo " Waiting for IP... (attempt $$i/10)"; \
sleep 5; \
done; \
if [ -z "$$HUB_IP" ] || [ "$$HUB_IP" = "null" ]; then \
echo "ERROR: Could not discover hub VM IP after 10 attempts."; \
exit 1; \
fi; \
echo "Waiting for cloud-init to complete (this takes ~2-5 minutes)..."; \
CLOUD_INIT_DONE=0; \
for i in $$(seq 1 60); do \
if multipass exec hub -- test -f /var/lib/cloud/instance/boot-finished 2>/dev/null; then \
echo "✓ Cloud-init completed"; \
CLOUD_INIT_DONE=1; \
break; \
fi; \
if [ $$((i % 6)) -eq 0 ]; then \
echo " Still provisioning... ($$((i / 6)) minutes elapsed)"; \
fi; \
sleep 10; \
done; \
if [ $$CLOUD_INIT_DONE -eq 0 ]; then \
echo "ERROR: Cloud-init did not complete after 10 minutes."; \
echo "Check hub logs: make connect-hub"; \
exit 1; \
fi; \
echo "Installing Open Horizon Exchange (this takes ~20-40 minutes)..."; \
multipass transfer scripts/install-exchange.sh hub:/tmp/install-exchange.sh; \
multipass exec hub -- sudo bash /tmp/install-exchange.sh; \
if [ $$? -ne 0 ]; then \
echo "ERROR: Exchange installation failed."; \
echo "Check hub logs: make connect-hub"; \
exit 1; \
fi; \
echo "Extracting Open Horizon credentials from hub VM..."; \
multipass exec hub -- sudo cat /root/mycreds.env > mycreds.env; \
if [ $$? -ne 0 ]; then \
echo "ERROR: Failed to extract credentials."; \
echo "Check hub logs: make connect-hub"; \
exit 1; \
fi; \
echo "export HUB_IP=\"$$HUB_IP\"" >> mycreds.env; \
if ! grep -q "HZN_ORG_ID" mycreds.env; then \
echo "ERROR: HZN_ORG_ID missing from mycreds.env"; \
exit 1; \
fi; \
if ! grep -q "HZN_EXCHANGE_USER_AUTH" mycreds.env; then \
echo "ERROR: HZN_EXCHANGE_USER_AUTH missing from mycreds.env"; \
exit 1; \
fi; \
echo "✓ Hub provisioning complete. Credentials saved to mycreds.env."
up:
@if [ ! -f mycreds.env ]; then \
echo "ERROR: mycreds.env not found. Run 'make up-hub' first."; \
exit 1; \
fi
@. ./mycreds.env; \
if [ -z "$$HUB_IP" ]; then \
echo "ERROR: HUB_IP missing from mycreds.env. Re-run 'make up-hub'."; \
exit 1; \
fi; \
echo "Checking for existing agent VMs..."; \
for i in $$(seq 1 $(NUM_AGENTS)); do \
AGENT_STATE=$$(multipass info agent$$i --format json 2>/dev/null | jq -r '.info["agent'$$i'"].state // empty' 2>/dev/null); \
if [ -n "$$AGENT_STATE" ]; then \
echo " agent$$i exists (state: $$AGENT_STATE) - stopping and deleting..."; \
multipass stop agent$$i 2>/dev/null || true; \
multipass delete agent$$i; \
echo " ✓ agent$$i deleted"; \
fi; \
done; \
if multipass list 2>/dev/null | grep -q "^agent"; then \
multipass purge; \
fi; \
echo "Launching $(NUM_AGENTS) agent VM(s) (basic provisioning only)..."; \
PIDS=""; \
for i in $$(seq 1 $(NUM_AGENTS)); do \
export AGENT_NUM=$$i; \
export HUB_IP=$$HUB_IP; \
AGENT_CLOUD_INIT="$$(pwd)/.bob/tmp/agent$$i-cloud-init.yaml"; \
mkdir -p $$(pwd)/.bob/tmp; \
envsubst '$${HUB_IP} $${AGENT_NUM}' < cloud-init/agent.yaml.template > $$AGENT_CLOUD_INIT; \
echo " Launching agent$$i..."; \
multipass launch --name agent$$i \
--cpus 1 \
--memory $(MEMORY)M \
--disk $(DISK_SIZE)G \
--cloud-init $$AGENT_CLOUD_INIT \
$(MULTIPASS_IMAGE) & \
PIDS="$$PIDS $$!"; \
done; \
echo "Waiting for agent VMs to launch..."; \
FAILED=0; \
for PID in $$PIDS; do \
wait $$PID || FAILED=1; \
done; \
if [ $$FAILED -ne 0 ]; then \
echo "ERROR: One or more agent VMs failed to launch."; \
exit 1; \
fi; \
echo "✓ All $(NUM_AGENTS) agent VMs launched."; \
echo "Waiting for cloud-init to complete on agent VMs..."; \
for i in $$(seq 1 $(NUM_AGENTS)); do \
echo " Waiting for agent$$i cloud-init..."; \
CLOUD_INIT_DONE=0; \
for j in $$(seq 1 60); do \
if multipass exec agent$$i -- test -f /var/lib/cloud/instance/boot-finished 2>/dev/null; then \
echo " ✓ agent$$i cloud-init completed"; \
CLOUD_INIT_DONE=1; \
break; \
fi; \
if [ $$((j % 6)) -eq 0 ]; then \
echo " Still provisioning agent$$i... ($$((j / 6)) minutes elapsed)"; \
fi; \
sleep 10; \
done; \
if [ $$CLOUD_INIT_DONE -eq 0 ]; then \
echo "ERROR: Cloud-init did not complete on agent$$i after 10 minutes."; \
exit 1; \
fi; \
done; \
echo "Copying credential files from hub to agent VMs..."; \
for i in $$(seq 1 $(NUM_AGENTS)); do \
echo " Copying credentials to agent$$i..."; \
for cred_file in mycreds.env root-root.env root-hubadmin.env ibm-admin.env myorg-admin.env myorg-node1.env; do \
if multipass exec hub -- sudo test -f /root/$$cred_file 2>/dev/null; then \
multipass exec hub -- sudo cat /root/$$cred_file | multipass exec agent$$i -- sudo tee /root/$$cred_file > /dev/null; \
fi; \
done; \
echo " ✓ Credentials copied to agent$$i"; \
done; \
echo "Installing Open Horizon agent on all VMs (this takes ~5-10 minutes per VM)..."; \
for i in $$(seq 1 $(NUM_AGENTS)); do \
echo " Installing agent on agent$$i..."; \
multipass transfer scripts/install-agent.sh agent$$i:/tmp/install-agent.sh; \
multipass exec agent$$i -- sudo bash /tmp/install-agent.sh $$i $$HUB_IP; \
if [ $$? -ne 0 ]; then \
echo "ERROR: Agent installation failed on agent$$i."; \
exit 1; \
fi; \
echo " ✓ agent$$i installation complete"; \
done; \
echo "✓ All $(NUM_AGENTS) agent VMs provisioned and registered with Exchange."
connect-hub:
@multipass shell hub
connect:
@multipass shell $(VMNAME)
status:
@multipass list
status-hub:
@multipass list | grep -E "^(Name|hub)" || echo "Hub VM not found."
down: destroy destroy-hub clean
clean:
@rm -f mycreds.env summary.txt agent-install-external.env agent-install-internal.env
@rm -f /tmp/agent*-cloud-init.yaml
@rm -f .bob/tmp/agent*-cloud-init.yaml
@echo "✓ Generated files cleaned."
destroy:
@echo "Destroying agent VMs..."
@for i in $$(seq 1 $(NUM_AGENTS)); do \
if multipass list | grep -q "^agent$$i "; then \
echo " Deleting agent$$i..."; \
multipass delete agent$$i; \
fi; \
done; \
multipass purge; \
echo "✓ Agent VMs destroyed."
destroy-hub:
@echo "Destroying hub VM..."
@if multipass list | grep -q "^hub "; then \
multipass delete hub; \
multipass purge; \
echo "✓ Hub VM destroyed."; \
else \
echo "Hub VM not found; nothing to destroy."; \
fi
browse:
ifeq ($(OS),Darwin)
@open http://127.0.0.1:8123
else
@xdg-open http://127.0.0.1:8123
endif
# ---------------------------------------------------------------------------
# Port Forwarding (exposes hub services on localhost via SSH tunnels)
# Port-forwards: Exchange(3090), AgBot(3111), FDO(9008), CSS(9443)
# Previously EXPOSE_REGISTRY_PORT used a Vagrant forwarded_port; now use
# 'make port-forward' instead. Set EXPOSE_REGISTRY_PORT=true to also forward
# the local registry (port 5000).
# ---------------------------------------------------------------------------
port-forward:
@if [ ! -f mycreds.env ]; then \
echo "ERROR: mycreds.env not found. Run 'make up-hub' first."; \
exit 1; \
fi
@echo "Starting port-forward tunnels to hub services..."
@. ./mycreds.env; \
PORTS="3090 3111 9008 9443"; \
if [ "$(EXPOSE_REGISTRY_PORT)" = "true" ]; then \
PORTS="$$PORTS 5000"; \
fi; \
multipass exec hub -- sudo bash -c '\
which socat >/dev/null 2>&1 || apt-get install -q -y socat; \
for port in '"$$PORTS"'; do \
socat TCP-LISTEN:$$port,fork,reuseaddr TCP:127.0.0.1:$$port & \
done' 2>/dev/null &
@echo "✓ Port-forward started"
@echo " Exchange: http://localhost:3090"
@echo " AgBot: http://localhost:3111"
@echo " FDO: http://localhost:9008"
@echo " CSS: http://localhost:9443"
stop-port-forward:
@if [ -f /tmp/port-forward.pid ]; then \
kill $$(cat /tmp/port-forward.pid) 2>/dev/null || true; \
rm -f /tmp/port-forward.pid; \
echo "✓ Port-forward stopped."; \
else \
echo "No port-forward PID file found; nothing to stop."; \
fi
# ---------------------------------------------------------------------------
# Blessed Samples targets
# ---------------------------------------------------------------------------
# Manually trigger the blessed samples build pipeline on the hub VM
build-blessed-samples:
@if ! multipass list 2>/dev/null | grep -q "^hub "; then \
echo "ERROR: Hub VM is not running. Run 'make up-hub' first."; \
exit 1; \
fi
@echo "Transferring build script to hub VM..."
@multipass transfer scripts/build-blessed-samples.sh hub:/tmp/build-blessed-samples.sh
@multipass exec hub -- chmod +x /tmp/build-blessed-samples.sh
@if [ -f blessedSamples.txt ]; then \
multipass transfer blessedSamples.txt hub:/tmp/blessedSamples.txt; \
else \
echo "WARNING: blessedSamples.txt not found; running with empty list."; \
multipass exec hub -- touch /tmp/blessedSamples.txt; \
fi
@. ./mycreds.env; \
multipass exec hub -- bash -c "\
BLESSED_SAMPLES_FILE=/tmp/blessedSamples.txt \
HUB_IP=$$HUB_IP \
REGISTRY_URL=$$HUB_IP:5000 \
BLESSED_SAMPLES_CREDENTIALS=/root/mycreds.env \
/tmp/build-blessed-samples.sh /tmp/blessedSamples.txt"
# List services configured in blessedSamples.txt (host-side, no SSH needed)
list-blessed-samples:
@if [ -f blessedSamples.txt ]; then \
echo "Services in blessedSamples.txt:"; \
grep -v '^#' blessedSamples.txt | grep -v '^[[:space:]]*$$' || echo "(no entries)"; \
else \
echo "blessedSamples.txt not found. Create one to enable blessed samples."; \
fi
# Check whether the local container registry on the hub VM is running
registry-status:
@if ! multipass list 2>/dev/null | grep -q "^hub "; then \
echo "Hub VM is not running."; \
else \
multipass exec hub -- docker ps --filter name=registry --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'; \
fi
# List images in the local registry catalog
registry-catalog:
@if ! multipass list 2>/dev/null | grep -q "^hub "; then \
echo "Hub VM is not running."; \
else \
multipass exec hub -- bash -c "curl -s http://localhost:5000/v2/_catalog | python3 -m json.tool 2>/dev/null || curl -s http://localhost:5000/v2/_catalog"; \
fi
# Print the latest blessed samples build log (host-visible copy)
blessed-samples-logs:
@if [ -f blessed-samples-build-latest.log ]; then \
cat blessed-samples-build-latest.log; \
else \
echo "No log found. Run 'make build-blessed-samples' first."; \
fi
# Clean blessed samples assets from hub VM (cloned repos, logs, optionally Exchange services)
# Set DRY_RUN=true to preview what would be deleted without actually deleting.
clean-blessed-samples:
@echo "Cleaning blessed samples assets..."
@if multipass list 2>/dev/null | grep -q "^hub "; then \
if [ "$(DRY_RUN)" = "true" ]; then \
echo "[DRY RUN] Would remove /tmp/blessed-samples/"; \
echo "[DRY RUN] Would remove /var/log/blessed-samples-build-*.log"; \
echo "[DRY RUN] Would remove local registry images (if any)"; \
else \
multipass exec hub -- bash -c "\
rm -rf /tmp/blessed-samples/ && \
rm -f /var/log/blessed-samples-build-*.log && \
echo '✓ Cloned repos and logs removed'"; \
fi; \
else \
echo "Hub VM is not running; skipping VM-side cleanup."; \
fi
@if [ -f blessed-samples-build-latest.log ]; then rm -f blessed-samples-build-latest.log; echo "✓ Local log removed"; fi
@echo "✓ Blessed samples cleanup complete"
.PHONY: default check init up-hub up status down destroy browse connect clean \
connect-hub status-hub destroy-hub \
detect-host-ip check-host-ip \
agent-config-external agent-config-internal generate-agent-configs \
port-forward stop-port-forward \
build-blessed-samples list-blessed-samples registry-status registry-catalog \
blessed-samples-logs clean-blessed-samples